redis是一個內存數(shù)據(jù)庫,一旦服務器宕機扭屁,內存中的數(shù)據(jù)將全部丟失算谈。所以,對 Redis 來說料滥,實現(xiàn)數(shù)據(jù)的持久化然眼,避免從后端數(shù)據(jù)庫中進行恢復,是至關重要的葵腹。
目前高每,Redis 的持久化主要有兩大機制,即 AOF(Append Only File)日志和 RDB 快照践宴。
一鲸匿、AOF日志的實現(xiàn)
我們知道數(shù)據(jù)庫的寫前日志(Write Ahead Log, WAL)是在在實際寫數(shù)據(jù)前,先把修改的數(shù)據(jù)記到日志文件中阻肩,以便故障時進行恢復晒骇。不過,AOF 日志正好相反磺浙,它是寫后日志,“寫后”的意思是 Redis 是先執(zhí)行命令徒坡,把數(shù)據(jù)寫入內存撕氧,然后才記錄日志,如下圖所示:
那 AOF 為什么要先執(zhí)行命令再記日志呢喇完?
傳統(tǒng)數(shù)據(jù)庫的日志伦泥,例如 redo log(重做日志),記錄的是修改后的數(shù)據(jù),而 AOF 里記錄的是 Redis 收到的每一條命令不脯,這些命令是以文本形式保存的府怯。我們以 Redis 收到“set testkey testvalue”命令后記錄的日志為例,看看 AOF 日志的內容防楷。其中牺丙,“*3”表示當前命令有三個部分,每部分都是由“3 set”表示這部分有 3 個字節(jié)吝沫,也就是“set”命令。
但是递礼,為了避免額外的檢查開銷惨险,Redis 在向 AOF 里面記錄日志的時候,并不會先去對這些命令進行語法檢查宰衙。所以平道,如果先記日志再執(zhí)行命令的話,日志中就有可能記錄了錯誤的命令供炼,Redis 在使用日志恢復數(shù)據(jù)時一屋,就可能會出錯。
而寫后日志這種方式袋哼,就是先讓系統(tǒng)執(zhí)行命令冀墨,只有命令能執(zhí)行成功,才會被記錄到日志中涛贯,否則诽嘉,系統(tǒng)就會直接向客戶端報錯。所以弟翘,Redis 使用寫后日志這一方式的一大好處是虫腋,可以避免出現(xiàn)記錄錯誤命令的情況。除此之外稀余,AOF 還有一個好處:它是在命令執(zhí)行后才記錄日志悦冀,所以不會阻塞當前的寫操作。
AOF 也有兩個潛在的風險:
首先睛琳,如果剛執(zhí)行完一個命令盒蟆,還沒有來得及記日志就宕機了踏烙,那么這個命令和相應的數(shù)據(jù)就有丟失的風險。如果此時 Redis 是用作緩存历等,還可以從后端數(shù)據(jù)庫重新讀入數(shù)據(jù)進行恢復讨惩,但是,如果 Redis 是直接用作數(shù)據(jù)庫的話寒屯,此時荐捻,因為命令沒有記入日志,所以就無法用日志進行恢復了浩螺。
其次靴患,AOF 雖然避免了對當前命令的阻塞,但可能會給下一個操作帶來阻塞風險要出。這是因為鸳君,AOF 日志也是在主線程中執(zhí)行的,如果在把日志文件寫入磁盤時患蹂,磁盤寫壓力大或颊,就會導致寫盤很慢,進而導致后續(xù)的操作也無法執(zhí)行了传于。
這兩個風險都是和 AOF 寫回磁盤的時機相關的囱挑。這也就意味著,如果我們能夠控制一個寫命令執(zhí)行完后 AOF 日志寫回磁盤的時機沼溜,這兩個風險就解除了平挑。
AOF的回寫策略
AOF 機制給我們提供了三個選擇,也就是 AOF 配置項 appendfsync 的三個可選值系草。
Always通熄,同步寫回:每個寫命令執(zhí)行完,立馬同步地將日志寫回磁盤找都;
Everysec唇辨,每秒寫回:每個寫命令執(zhí)行完,只是先把日志寫到 AOF 文件的內存緩沖區(qū)能耻,每隔一秒把緩沖區(qū)中的內容寫入磁盤赏枚;
No,操作系統(tǒng)控制的寫回:每個寫命令執(zhí)行完晓猛,只是先把日志寫到 AOF 文件的內存緩沖區(qū)饿幅,由操作系統(tǒng)決定何時將緩沖區(qū)內容寫回磁盤。
針對避免主線程阻塞和減少數(shù)據(jù)丟失問題戒职,這三種寫回策略都無法做到兩全其美栗恩。我們來分析下其中的原因。
“同步寫回”可以做到基本不丟數(shù)據(jù)帕涌,但是它在每一個寫命令后都有一個慢速的落盤操作摄凡,不可避免地會影響主線程性能;
雖然“操作系統(tǒng)控制的寫回”在寫完緩沖區(qū)后蚓曼,就可以繼續(xù)執(zhí)行后續(xù)的命令亲澡,但是落盤的時機已經(jīng)不在 Redis 手中了,只要 AOF 記錄沒有寫回磁盤纫版,一旦宕機對應的數(shù)據(jù)就丟失了床绪;
“每秒寫回”采用一秒寫回一次的頻率,避免了“同步寫回”的性能開銷其弊,雖然減少了對系統(tǒng)性能的影響癞己,但是如果發(fā)生宕機,上一秒內未落盤的命令操作仍然會丟失梭伐。所以痹雅,這只能算是,在避免影響主線程性能和避免數(shù)據(jù)丟失兩者間取了個折中糊识。
總結一下就是:想要獲得高性能绩社,就選擇 No 策略;如果想要得到高可靠性保證赂苗,就選擇 Always 策略愉耙;如果允許數(shù)據(jù)有一點丟失,又希望性能別受太大影響的話拌滋,那么就選擇 Everysec 策略朴沿。
按照系統(tǒng)的性能需求選定了寫回策略,并不是“高枕無憂”了败砂。畢竟赌渣,AOF 是以文件的形式在記錄接收到的所有寫命令。隨著接收的寫命令越來越多吠卷,AOF 文件會越來越大锡垄。這也就意味著,我們一定要小心 AOF 文件過大帶來的性能問題祭隔。
這里的“性能問題”货岭,主要在于以下三個方面:
一是,文件系統(tǒng)本身對文件大小有限制疾渴,無法保存過大的文件千贯;
二是崭别,如果文件太大雳殊,之后再往里面追加命令記錄的話,效率也會變低驶沼;
三是桩撮,如果發(fā)生宕機敦第,AOF 中記錄的命令要一個個被重新執(zhí)行峰弹,用于故障恢復,如果日志文件太大芜果,整個恢復過程就會非常緩慢鞠呈,這就會影響到 Redis 的正常使用。
因此我們需要AOF重寫機制
簡單來說右钾,AOF 重寫機制就是在重寫時蚁吝,Redis 根據(jù)數(shù)據(jù)庫的現(xiàn)狀創(chuàng)建一個新的 AOF 文件,也就是說舀射,讀取數(shù)據(jù)庫中的所有鍵值對窘茁,然后對每一個鍵值對用一條命令記錄它的寫入。
為什么重寫機制可以把日志文件變小呢?
實際上脆烟,重寫機制具有“多變一”功能山林。所謂的“多變一”,也就是說浩淘,舊日志文件中的多條命令捌朴,在重寫后的新日志中變成了一條命令。
AOF 文件是以追加的方式张抄,逐一記錄接收到的寫命令的砂蔽。當一個鍵值對被多條寫命令反復修改時,AOF 文件會記錄相應的多條命令署惯。但是左驾,在重寫的時候,是根據(jù)這個鍵值對當前的最新狀態(tài)极谊,為它生成對應的寫入命令诡右。這樣一來,一個鍵值對在重寫日志中只用一條命令就行了轻猖,而且帆吻,在日志恢復時,只用執(zhí)行這條命令咙边,就可以直接完成這個鍵值對的寫入了猜煮。
下面這張圖就是一個例子:
當我們對一個列表先后做了 6 次修改操作后,列表的最后狀態(tài)是[“D”, “C”, “N”]败许,此時王带,只用 LPUSH u:list “N”, “C”, "D"這一條命令就能實現(xiàn)該數(shù)據(jù)的恢復,這就節(jié)省了五條命令的空間市殷。對于被修改過成百上千次的鍵值對來說愕撰,重寫能節(jié)省的空間當然就更大了。
不過,雖然 AOF 重寫后搞挣,日志文件會縮小带迟,但是,要把整個數(shù)據(jù)庫的最新數(shù)據(jù)的操作日志都寫回磁盤囱桨,仍然是一個非常耗時的過程邮旷。這時,我們就要繼續(xù)關注另一個問題了:重寫會不會阻塞主線程蝇摸?
AOF 重寫會阻塞嗎?
和 AOF 日志由主線程寫回不同,重寫過程是由后臺子進程 bgrewriteaof 來完成的办陷,這也是為了避免阻塞主線程貌夕,導致數(shù)據(jù)庫性能下降。
我把重寫的過程總結為“一個拷貝民镜,兩處日志”啡专。
“一個拷貝”就是指,每次執(zhí)行重寫時制圈,主線程 fork 出后臺的 bgrewriteaof 子進程们童。此時,fork 會把主線程的內存拷貝一份給 bgrewriteaof 子進程鲸鹦,這里面就包含了數(shù)據(jù)庫的最新數(shù)據(jù)慧库。然后,bgrewriteaof 子進程就可以在不影響主線程的情況下馋嗜,逐一把拷貝的數(shù)據(jù)寫成操作齐板,記入重寫日志。
“兩處日志”又是什么呢葛菇?
因為主線程未阻塞甘磨,仍然可以處理新來的操作。此時眯停,如果有寫操作济舆,第一處日志就是指正在使用的 AOF 日志,Redis 會把這個操作寫到它的緩沖區(qū)莺债。這樣一來滋觉,即使宕機了,這個 AOF 日志的操作仍然是齊全的九府,可以用于恢復椎瘟。
而第二處日志,就是指新的 AOF 重寫日志侄旬。這個操作也會被寫到重寫日志的緩沖區(qū)肺蔚。這樣,重寫日志也不會丟失最新的操作儡羔。等到拷貝數(shù)據(jù)的所有操作記錄重寫完成后宣羊,重寫日志記錄的這些最新操作也會寫入新的 AOF 文件璧诵,以保證數(shù)據(jù)庫最新狀態(tài)的記錄。此時仇冯,我們就可以用新的 AOF 文件替代舊文件了之宿。
總結來說,每次 AOF 重寫時苛坚,Redis 會先執(zhí)行一個內存拷貝比被,用于重寫;然后泼舱,使用兩個日志保證在重寫過程中等缀,新寫入的數(shù)據(jù)不會丟失。而且娇昙,因為 Redis 采用額外的線程進行數(shù)據(jù)重寫尺迂,所以,這個過程并不會阻塞主線程冒掌。
AOF 日志重寫的時候噪裕,是由 bgrewriteaof 子進程來完成的,不用主線程參與股毫,我們今天說的非阻塞也是指子進程的執(zhí)行不阻塞主線程膳音。但是,你覺得铃诬,這個重寫過程有沒有其他潛在的阻塞風險呢严蓖?如果有的話,會在哪里阻塞氧急?
1.fork子進程颗胡,fork這個瞬間一定是會阻塞主線程的(注意,fork時并不會一次性拷貝所有內存數(shù)據(jù)給子進程)吩坝,fork采用操作系統(tǒng)提供的寫實復制(Copy On Write)機制毒姨,就是為了避免一次性拷貝大量內存數(shù)據(jù)給子進程造成的長時間阻塞問題,但fork子進程需要拷貝進程必要的數(shù)據(jù)結構钉寝,其中有一項就是拷貝內存頁表(虛擬內存和物理內存的映射索引表)弧呐,這個拷貝過程會消耗大量CPU資源,拷貝完成之前整個進程是會阻塞的嵌纲,阻塞時間取決于整個實例的內存大小俘枫,實例越大,內存頁表越大逮走,fork阻塞時間越久鸠蚪。拷貝內存頁表完成后,子進程與父進程指向相同的內存地址空間茅信,也就是說此時雖然產生了子進程盾舌,但是并沒有申請與父進程相同的內存大小。那什么時候父子進程才會真正內存分離呢蘸鲸?“寫實復制”顧名思義妖谴,就是在寫發(fā)生時,才真正拷貝內存真正的數(shù)據(jù)酌摇,這個過程中膝舅,父進程也可能會產生阻塞的風險,就是下面介紹的場景窑多。
2.fork出的子進程指向與父進程相同的內存地址空間铸史,此時子進程就可以執(zhí)行AOF重寫,把內存中的所有數(shù)據(jù)寫入到AOF文件中怯伊。但是此時父進程依舊是會有流量寫入的,如果父進程操作的是一個已經(jīng)存在的key判沟,那么這個時候父進程就會真正拷貝這個key對應的內存數(shù)據(jù)耿芹,申請新的內存空間,這樣逐漸地挪哄,父子進程內存數(shù)據(jù)開始分離吧秕,父子進程逐漸擁有各自獨立的內存空間。因為內存分配是以頁為單位進行分配的迹炼,默認4k砸彬,如果父進程此時操作的是一個bigkey,重新申請大塊內存耗時會變長斯入,可能會產阻塞風險砂碉。另外,如果操作系統(tǒng)開啟了內存大頁機制(Huge Page刻两,頁面大小2M)增蹭,那么父進程申請內存時阻塞的概率將會大大提高,所以在Redis機器上需要關閉Huge Page機制磅摹。Redis每次fork生成RDB或AOF重寫完成后滋迈,都可以在Redis log中看到父進程重新申請了多大的內存空間。
AOF 重寫也有一個重寫日志户誓,為什么它不共享使用 AOF 本身的日志呢饼灿?
AOF重寫不復用AOF本身的日志,一個原因是父子進程寫同一個文件必然會產生競爭問題帝美,控制競爭就意味著會影響父進程的性能碍彭。二是如果AOF重寫過程中失敗了,那么原本的AOF文件相當于被污染了,無法做恢復使用硕旗。所以Redis AOF重寫一個新文件窗骑,重寫失敗的話,直接刪除這個文件就好了漆枚,不會對原先的AOF文件產生影響创译。等重寫完成之后,直接替換舊文件即可墙基。
二软族、RDB內存快照
所謂內存快照,就是指內存中的數(shù)據(jù)在某一個時刻的狀態(tài)記錄残制。這就類似于照片立砸,當你給朋友拍照時,一張照片就能把朋友一瞬間的形象完全記下來初茶。
對 Redis 來說颗祝,它實現(xiàn)類似照片記錄效果的方式,就是把某一時刻的狀態(tài)以文件的形式寫到磁盤上恼布,也就是快照螺戳。這樣一來,即使宕機折汞,快照文件也不會丟失倔幼,數(shù)據(jù)的可靠性也就得到了保證。這個快照文件就稱為 RDB 文件爽待,其中损同,RDB 就是 Redis DataBase 的縮寫。
和 AOF 相比鸟款,RDB 記錄的是某一時刻的數(shù)據(jù)膏燃,并不是操作,所以何什,在做數(shù)據(jù)恢復時蹄梢,我們可以直接把 RDB 文件讀入內存,很快地完成恢復富俄。聽起來好像很不錯禁炒,但內存快照也并不是最優(yōu)選項。為什么這么說呢霍比?
我們還要考慮兩個關鍵問題:
對哪些數(shù)據(jù)做快照幕袱?這關系到快照的執(zhí)行效率問題;
做快照時悠瞬,數(shù)據(jù)還能被增刪改嗎们豌?這關系到 Redis 是否被阻塞涯捻,能否同時正常處理請求。
對哪些數(shù)據(jù)做快照望迎?
Redis 的數(shù)據(jù)都在內存中障癌,為了提供所有數(shù)據(jù)的可靠性保證,它執(zhí)行的是全量快照辩尊,也就是說涛浙,把內存中的所有數(shù)據(jù)都記錄到磁盤中,這樣做的好處是摄欲,一次性記錄了所有數(shù)據(jù)轿亮,一個都不少。
給內存的全量數(shù)據(jù)做快照胸墙,把它們全部寫入磁盤也會花費很多時間我注。而且,全量數(shù)據(jù)越多迟隅,RDB 文件就越大但骨,往磁盤上寫數(shù)據(jù)的時間開銷就越大。
對于 Redis 而言智袭,它的單線程模型就決定了奔缠,我們要盡量避免所有會阻塞主線程的操作,所以补履,針對任何操作,我們都會提一個靈魂之問:“它會阻塞主線程嗎?”RDB 文件的生成是否會阻塞主線程剿另,這就關系到是否會降低 Redis 的性能箫锤。
Redis 提供了兩個命令來生成 RDB 文件,分別是 save 和 bgsave雨女。
save:在主線程中執(zhí)行谚攒,會導致阻塞;
bgsave:創(chuàng)建一個子進程氛堕,專門用于寫入 RDB 文件馏臭,避免了主線程的阻塞,這也是 Redis RDB 文件生成的默認配置讼稚。
好了括儒,這個時候,我們就可以通過 bgsave 命令來執(zhí)行全量快照锐想,這既提供了數(shù)據(jù)的可靠性保證帮寻,也避免了對 Redis 的性能影響。
快照期間赠摇,是否可以對數(shù)據(jù)進行改動固逗?
舉個例子浅蚪。我們在時刻 t 給內存做快照,假設內存數(shù)據(jù)量是 4GB烫罩,磁盤的寫入帶寬是 0.2GB/s惜傲,簡單來說,至少需要 20s(4/0.2 = 20)才能做完贝攒。如果在時刻 t+5s 時盗誊,一個還沒有被寫入磁盤的內存數(shù)據(jù) A,被修改成了 A’饿这,那么就會破壞快照的完整性浊伙,因為 A’不是時刻 t 時的狀態(tài)。因此长捧,和拍照類似嚣鄙,我們在做快照時也不希望數(shù)據(jù)“動”,也就是不能被修改串结。
如果快照執(zhí)行期間數(shù)據(jù)不能被修改哑子,是會有潛在問題的。對于剛剛的例子來說肌割,在做快照的 20s 時間里卧蜓,如果這 4GB 的數(shù)據(jù)都不能被修改,Redis 就不能處理對這些數(shù)據(jù)的寫操作把敞,那無疑就會給業(yè)務服務造成巨大的影響弥奸。
為了快照而暫停寫操作,肯定是不能接受的奋早。所以這個時候盛霎,Redis 就會借助操作系統(tǒng)提供的寫時復制技術(Copy-On-Write, COW),在執(zhí)行快照的同時耽装,正常處理寫操作愤炸。
簡單來說,bgsave 子進程是由主線程 fork 生成的掉奄,可以共享主線程的所有內存數(shù)據(jù)规个。bgsave 子進程運行后,開始讀取主線程的內存數(shù)據(jù)姓建,并把它們寫入 RDB 文件诞仓。
此時,如果主線程對這些數(shù)據(jù)也都是讀操作(例如圖中的鍵值對 A)速兔,那么狂芋,主線程和 bgsave 子進程相互不影響。但是憨栽,如果主線程要修改一塊數(shù)據(jù)(例如圖中的鍵值對 C)帜矾,那么翼虫,這塊數(shù)據(jù)就會被復制一份,生成該數(shù)據(jù)的副本(鍵值對 C’)屡萤。然后珍剑,主線程在這個數(shù)據(jù)副本上進行修改。同時死陆,bgsave 子進程可以繼續(xù)把原來的數(shù)據(jù)(鍵值對 C)寫入 RDB 文件招拙。
這既保證了快照的完整性,也允許主線程同時對數(shù)據(jù)進行修改措译,避免了對正常業(yè)務的影響别凤。到這里,我們就解決了對“哪些數(shù)據(jù)做快照”以及“做快照時數(shù)據(jù)能否修改”這兩大問題:Redis 會使用 bgsave 對當前內存中的所有數(shù)據(jù)做快照领虹,這個操作是子進程在后臺完成的规哪,這就允許主線程同時可以修改數(shù)據(jù)。
如果頻繁地執(zhí)行全量快照塌衰,也會帶來兩方面的開銷诉稍。
一方面,頻繁將全量數(shù)據(jù)寫入磁盤最疆,會給磁盤帶來很大壓力杯巨,多個快照競爭有限的磁盤帶寬,前一個快照還沒有做完努酸,后一個又開始做了服爷,容易造成惡性循環(huán)。
另一方面获诈,bgsave 子進程需要通過 fork 操作從主線程創(chuàng)建出來仍源。雖然,子進程在創(chuàng)建后不會再阻塞主線程烙荷,但是镜会,fork 這個創(chuàng)建過程本身會阻塞主線程檬寂,而且主線程的內存越大终抽,阻塞時間越長。如果頻繁 fork 出 bgsave 子進程桶至,這就會頻繁阻塞主線程了(所以昼伴,在 Redis 中如果有一個 bgsave 在運行,就不會再啟動第二個 bgsave 子進程)镣屹。那么圃郊,有什么其他好方法嗎?
此時女蜈,我們可以做增量快照持舆,所謂增量快照色瘩,就是指,做了一次全量快照后逸寓,后續(xù)的快照只對修改的數(shù)據(jù)進行快照記錄居兆,這樣可以避免每次全量快照的開銷。
在第一次做完全量快照后竹伸,T1 和 T2 時刻如果再做快照泥栖,我們只需要將被修改的數(shù)據(jù)寫入快照文件就行。但是勋篓,這么做的前提是吧享,我們需要記住哪些數(shù)據(jù)被修改了。你可不要小瞧這個“記住”功能譬嚣,它需要我們使用額外的元數(shù)據(jù)信息去記錄哪些數(shù)據(jù)被修改了钢颂,這會帶來額外的空間開銷問題。如下圖所示:
如果我們對每一個鍵值對的修改孤荣,都做個記錄甸陌,那么,如果有 1 萬個被修改的鍵值對盐股,我們就需要有 1 萬條額外的記錄钱豁。而且,有的時候疯汁,鍵值對非常小牲尺,比如只有 32 字節(jié),而記錄它被修改的元數(shù)據(jù)信息幌蚊,可能就需要 8 字節(jié)谤碳,這樣的畫,為了“記住”修改溢豆,引入的額外空間開銷比較大蜒简。這對于內存資源寶貴的 Redis 來說,有些得不償失漩仙。
到這里搓茬,你可以發(fā)現(xiàn),雖然跟 AOF 相比队他,快照的恢復速度快卷仑,但是,快照的頻率不好把握麸折,如果頻率太低锡凝,兩次快照間一旦宕機,就可能有比較多的數(shù)據(jù)丟失垢啼。如果頻率太高窜锯,又會產生額外開銷张肾,那么,還有什么方法既能利用 RDB 的快速恢復锚扎,又能以較小的開銷做到盡量少丟數(shù)據(jù)呢捌浩?
Redis 4.0 中提出了一個混合使用 AOF 日志和內存快照的方法。
簡單來說工秩,內存快照以一定的頻率執(zhí)行尸饺,在兩次快照之間,使用 AOF 日志記錄這期間的所有命令操作助币。這樣一來浪听,快照不用很頻繁地執(zhí)行,這就避免了頻繁 fork 對主線程的影響眉菱。而且迹栓,AOF 日志也只用記錄兩次快照間的操作,也就是說俭缓,不需要記錄所有操作了克伊,因此,就不會出現(xiàn)文件過大的情況了华坦,也可以避免重寫開銷愿吹。
如下圖所示,T1 和 T2 時刻的修改惜姐,用 AOF 日志記錄犁跪,等到第二次做全量快照時,就可以清空 AOF 日志歹袁,因為此時的修改都已經(jīng)記錄到快照中了坷衍,恢復時就不再用日志了。
這個方法既能享受到 RDB 文件快速恢復的好處条舔,又能享受到 AOF 只記錄操作命令的簡單優(yōu)勢枫耳,頗有點“魚和熊掌可以兼得”的感覺,建議你在實踐中用起來孟抗。
場景:我們使用一個 2 核 CPU迁杨、4GB 內存、500GB 磁盤的云主機運行 Redis夸浅,Redis 數(shù)據(jù)庫的數(shù)據(jù)量大小差不多是 2GB仑最,我們使用了 RDB 做持久化保證扔役。當時 Redis 的運行負載以修改操作為主帆喇,寫讀比例差不多在 8:2 左右,也就是說亿胸,如果有 100 個請求坯钦,80 個請求執(zhí)行的是修改操作预皇。你覺得,在這個場景下婉刀,用 RDB 做持久化有什么風險嗎吟温?
內存資源風險:Redis fork子進程做RDB持久化,由于寫的比例為80%突颊,那么在持久化過程中鲁豪,“寫實復制”會重新分配整個實例80%的內存副本,大約需要重新分配1.6GB內存空間律秃,這樣整個系統(tǒng)的內存使用接近飽和爬橡,如果此時父進程又有大量新key寫入,很快機器內存就會被吃光棒动,如果機器開啟了Swap機制糙申,那么Redis會有一部分數(shù)據(jù)被換到磁盤上,當Redis訪問這部分在磁盤上的數(shù)據(jù)時船惨,性能會急劇下降柜裸,已經(jīng)達不到高性能的標準(可以理解為武功被廢)。如果機器沒有開啟Swap粱锐,會直接觸發(fā)OOM疙挺,父子進程會面臨被系統(tǒng)kill掉的風險。
CPU資源風險:雖然子進程在做RDB持久化怜浅,但生成RDB快照過程會消耗大量的CPU資源衔统,雖然Redis處理處理請求是單線程的,但Redis Server還有其他線程在后臺工作海雪,例如AOF每秒刷盤锦爵、異步關閉文件描述符這些操作。由于機器只有2核CPU奥裸,這也就意味著父進程占用了超過一半的CPU資源险掀,此時子進程做RDB持久化,可能會產生CPU競爭湾宙,導致的結果就是父進程處理請求延遲增大樟氢,子進程生成RDB快照的時間也會變長,整個Redis Server性能下降侠鳄。
另外埠啃,可以再延伸一下,Redis進程是否綁定了CPU伟恶,如果綁定了CPU碴开,那么子進程會繼承父進程的CPU親和性屬性,子進程必然會與父進程爭奪同一個CPU資源,整個Redis Server的性能必然會受到影響潦牛!所以如果Redis需要開啟定時RDB和AOF重寫眶掌,進程一定不要綁定CPU。