Redis--COW(Copy On Write)
摘要
問(wèn)題概述:
1、RDB的過(guò)程中是否會(huì)停止對(duì)外提供服務(wù)?
2、RDB的過(guò)程中數(shù)據(jù)修改了,備份的是修改前的還是修改后的?
3、RDB時(shí)是不是先把內(nèi)容中的所有KV復(fù)制一份,保證數(shù)據(jù)不會(huì)被修改?
問(wèn)題解決:使用Copy On Write?寫(xiě)時(shí)復(fù)制
詳細(xì)
在看Redis持久化方式中的RDB方式時(shí),想到了幾個(gè)問(wèn)題:
1、 Redis是單線程的,那在RDB的過(guò)程中,是不是就沒(méi)法對(duì)外提供服務(wù)了?
Redis操作快的一個(gè)重要原因是Redis的數(shù)據(jù)是在內(nèi)存中存儲(chǔ)和操作的,持久化本身是磁盤(pán)的IO操作,IO操作又是特別耗時(shí)的,RDB備份的過(guò)程對(duì)Redis來(lái)說(shuō)是挺漫長(zhǎng)的,如果Redis沒(méi)法對(duì)外提供服務(wù)的話,對(duì)Redis的影響是很大的吧;
2、知道備份時(shí)不會(huì)阻塞對(duì)外服務(wù),那在數(shù)據(jù)備份的過(guò)程中,有新的數(shù)據(jù)變更的操作發(fā)生時(shí),備份的是變更前的數(shù)據(jù)還是變更后的數(shù)據(jù)呢?
另一個(gè)角度:RDB快照的是精確的一個(gè)時(shí)刻的內(nèi)存數(shù)據(jù)呢?還是一段時(shí)間內(nèi)的內(nèi)存數(shù)據(jù)?
另一個(gè)角度:RDB快照是精確的還是模糊的?
3、既然是數(shù)據(jù)備份,在開(kāi)始備份的時(shí)候,是不是要把Redis的所有數(shù)據(jù)現(xiàn)在內(nèi)存中拷貝一份呢?那樣的話平時(shí)Redis服務(wù)器的內(nèi)存利用率就不能大于50%了啊?
解答
1、RDB過(guò)程中會(huì)fork一個(gè)子進(jìn)程,子進(jìn)程做數(shù)據(jù)備份操作,主進(jìn)程繼續(xù)對(duì)外提供服務(wù),所有Redis服務(wù)不會(huì)阻塞;
2、Copy On Write 機(jī)制,備份的是開(kāi)始那個(gè)時(shí)刻內(nèi)存中的數(shù)據(jù);
3、Copy On Write 機(jī)制不需要把整個(gè)內(nèi)存的數(shù)據(jù)都復(fù)制一份;
Copy On Write 機(jī)制
核心思路:fork一個(gè)子進(jìn)程,只有在父進(jìn)程發(fā)生寫(xiě)操作修改內(nèi)存數(shù)據(jù)時(shí),才會(huì)真正去分配內(nèi)存空間,并復(fù)制內(nèi)存數(shù)據(jù),而且也只是復(fù)制被修改的內(nèi)存頁(yè)中的數(shù)據(jù),并不是全部?jī)?nèi)存數(shù)據(jù);- Redis中執(zhí)行BGSAVE命令生成RDB文件時(shí),本質(zhì)就是調(diào)用Linux中的fork()命令,Linux下的fork()系統(tǒng)調(diào)用實(shí)現(xiàn)了copy-on-write寫(xiě)時(shí)復(fù)制;
- fork()是類Unix操作系統(tǒng)上創(chuàng)建線程的主要方法,fork用于創(chuàng)建子進(jìn)程(等同于當(dāng)前進(jìn)程的副本);
- 傳統(tǒng)的普通進(jìn)程復(fù)制,會(huì)直接將父進(jìn)程的數(shù)據(jù)拷貝到子進(jìn)程中,拷貝完成后,父進(jìn)程和子進(jìn)程之間的數(shù)據(jù)段和堆棧是相互獨(dú)立的;
- copy-on-write技術(shù),在fork出子進(jìn)程后,與父進(jìn)程共享內(nèi)存空間,兩者只是虛擬空間不同,但是其對(duì)應(yīng)的物理空間是同一個(gè);
Linux中CopyOnWrite實(shí)現(xiàn)原理
fork()之后,kernel把父進(jìn)程中所有的內(nèi)存頁(yè)的權(quán)限都設(shè)為read-only,然后子進(jìn)程的地址空間指向父進(jìn)程。當(dāng)父子進(jìn)程都只讀內(nèi)存時(shí),相安無(wú)事。當(dāng)其中某個(gè)進(jìn)程寫(xiě)內(nèi)存時(shí),CPU硬件檢測(cè)到內(nèi)存頁(yè)是read-only的,于是觸發(fā)頁(yè)異常中斷(page-fault),陷入kernel的一個(gè)中斷例程。中斷例程中,kernel就會(huì)把觸發(fā)的異常的頁(yè)復(fù)制一份,于是父子進(jìn)程各自持有獨(dú)立的一份。
CopyOnWrite的好處:
1、減少分配和復(fù)制資源時(shí)帶來(lái)的瞬時(shí)延遲;
2、減少不必要的資源分配;
CopyOnWrite的缺點(diǎn):
1、如果父子進(jìn)程都需要進(jìn)行大量的寫(xiě)操作,會(huì)產(chǎn)生大量的分頁(yè)錯(cuò)誤(頁(yè)異常中斷page-fault);
Redis中的CopyOnWrite
- Redis在持久化時(shí),如果是采用BGSAVE命令或者BGREWRITEAOF的方式,那Redis會(huì)fork出一個(gè)子進(jìn)程來(lái)讀取數(shù)據(jù),從而寫(xiě)到磁盤(pán)中。
- 總體來(lái)看,Redis還是讀操作比較多。如果子進(jìn)程存在期間,發(fā)生了大量的寫(xiě)操作,那可能就會(huì)出現(xiàn)很多的分頁(yè)錯(cuò)誤(頁(yè)異常中斷page-fault),這樣就得耗費(fèi)不少性能在復(fù)制上。
- 而在rehash階段上,寫(xiě)操作是無(wú)法避免的。所以Redis在fork出子進(jìn)程之后,將負(fù)載因子閾值提高,盡量減少寫(xiě)操作,避免不必要的內(nèi)存寫(xiě)入操作,最大限度地節(jié)約內(nèi)存。
總結(jié)
以上是生活随笔為你收集整理的Redis--COW(Copy On Write)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 数据湖探索与实践
- 下一篇: Redis的架构模式