? ? ? ?Redis是一種高級(jí)key-value數(shù)據(jù)庫(kù)从诲。它跟memcached類(lèi)似抖锥,不過(guò)數(shù)據(jù)可以持久化荆烈,而且支持的數(shù)據(jù)類(lèi)型很豐富。有字符串,鏈表,集 合和有序集合。支持在服務(wù)器端計(jì)算集合的并,交和補(bǔ)集(difference)等,還支持多種排序功能。所以Redis也可以被看成是一個(gè)數(shù)據(jù)結(jié)構(gòu)服務(wù) 器纫骑。Redis的所有數(shù)據(jù)都是保存在內(nèi)存中煤墙,然后不定期的通過(guò)異步方式保存到磁盤(pán)上(這稱(chēng)為“半持久化模式”)脚作;也可以把每一次數(shù)據(jù)變化都寫(xiě)入到一個(gè)append only file(aof)里面(這稱(chēng)為“全持久化模式”)亿扁。
? ? ? ? ?第一種方法filesnapshotting:默認(rèn)redis是會(huì)以快照的形式將數(shù)據(jù)持久化到磁盤(pán)的(一個(gè)二進(jìn) 制文件哄褒,dump.rdb,這個(gè)文件名字可以指定),在配置文件中的格式是:save N M表示在N秒之內(nèi)霹琼,redis至少發(fā)生M次修改則redis抓快照到磁盤(pán)。當(dāng)然我們也可以手動(dòng)執(zhí)行save或者bgsave(異步)做快照。
工作原理簡(jiǎn)單介紹一下:當(dāng)redis需要做持久化時(shí)介却,redis會(huì)fork一個(gè)子進(jìn)程轴或;子進(jìn)程將數(shù)據(jù)寫(xiě)到磁盤(pán)上一個(gè)臨時(shí)RDB文件中饺蚊;當(dāng)子進(jìn)程完成寫(xiě)臨時(shí)文件后燕酷,將原來(lái)的RDB替換掉,這樣的好處就是可以copy-on-write
還有一種持久化方法是Append-only:filesnapshotting方法在redis異常死掉時(shí)泻肯, 最近的數(shù)據(jù)會(huì)丟失(丟失數(shù)據(jù)的多少視你save策略的配置),所以這是它最大的缺點(diǎn)曹锨,當(dāng)業(yè)務(wù)量很大時(shí)捧灰,丟失的數(shù)據(jù)是很多的阀溶。Append-only方法可 以做到全部數(shù)據(jù)不丟失徒仓,但redis的性能就要差些誊垢。AOF就可以做到全程持久化乎芳,只需要在配置文件中開(kāi)啟(默認(rèn)是no)肴甸,appendonly yes開(kāi)啟AOF之后庶柿,redis每執(zhí)行一個(gè)修改數(shù)據(jù)的命令,都會(huì)把它添加到aof文件中,當(dāng)redis重啟時(shí)会钝,將會(huì)讀取AOF文件進(jìn)行“重放”以恢復(fù)到 redis關(guān)閉前的最后時(shí)刻宏多。
LOG Rewriting隨著修改數(shù)據(jù)的執(zhí)行AOF文件會(huì)越來(lái)越大,其中很多內(nèi)容記錄某一個(gè)key的變化情況澡罚。因此redis有了一種比較有意思的特性:在后臺(tái)重建AOF文件绷落,而不會(huì)影響client端操作。在任何時(shí)候執(zhí)行BGREWRITEAOF命令始苇,都會(huì)把當(dāng)前內(nèi)存中最短序列的命令寫(xiě)到磁盤(pán),這些命令可以完全構(gòu)建當(dāng)前的數(shù)據(jù)情況筐喳,而不會(huì)存在多余的變化情況(比如狀態(tài)變化催式,計(jì)數(shù)器變化等),縮小的AOF文件的大小避归。所以當(dāng)使用AOF時(shí)荣月,redis推薦同時(shí)使用BGREWRITEAOF。
AOF文件刷新的方式梳毙,有三種哺窄,參考配置參數(shù)appendfsync:appendfsync always每提交一個(gè)修改命令都調(diào)用fsync刷新到AOF文件,非常非常慢账锹,但也非常安全萌业;appendfsync everysec每秒鐘都調(diào)用fsync刷新到AOF文件,很快奸柬,但可能會(huì)丟失一秒以?xún)?nèi)的數(shù)據(jù)生年;appendfsync no依靠OS進(jìn)行刷新,redis不主動(dòng)刷新AOF廓奕,這樣最快抱婉,但安全性就差。默認(rèn)并推薦每秒刷新桌粉,這樣在速度和安全上都做到了兼顧蒸绩。
可能由于系統(tǒng)原因?qū)е铝薃OF損壞,redis無(wú)法再加載這個(gè)AOF铃肯,可以按照下面步驟來(lái)修復(fù):首先做一個(gè)AOF文件的備份患亿,復(fù)制到其他地方;修復(fù)原始AOF文件缘薛,執(zhí)行:$ redis-check-aof –fix ;可以通過(guò)diff –u命令來(lái)查看修復(fù)前后文件不一致的地方窍育;重啟redis服務(wù)卡睦。
LOG Rewrite的工作原理:同樣用到了copy-on-write:首先redis會(huì)fork一個(gè)子進(jìn)程;子進(jìn)程將最新的AOF寫(xiě)入一個(gè)臨時(shí)文件漱抓;父進(jìn)程 增量的把內(nèi)存中的最新執(zhí)行的修改寫(xiě)入(這時(shí)仍寫(xiě)入舊的AOF表锻,rewrite如果失敗也是安全的);當(dāng)子進(jìn)程完成rewrite臨時(shí)文件后乞娄,父進(jìn)程會(huì)收到 一個(gè)信號(hào)瞬逊,并把之前內(nèi)存中增量的修改寫(xiě)入臨時(shí)文件末尾;這時(shí)redis將舊AOF文件重命名仪或,臨時(shí)文件重命名确镊,開(kāi)始向新的AOF中寫(xiě)入。
最后范删,為以防萬(wàn)一(機(jī)器壞掉或磁盤(pán)壞掉)蕾域,記得定期把使用 filesnapshotting 或 Append-only 生成的*rdb *.aof文件備份到遠(yuǎn)程機(jī)器上。我是用crontab每半小時(shí)SCP一次到旦。我沒(méi)有使用redis的主從功能 旨巷,因?yàn)榘胄r(shí)備份一次應(yīng)該是可以了,而且我覺(jué)得有如果做主從有點(diǎn)浪費(fèi)機(jī)器添忘。這個(gè)最終還是看應(yīng)用來(lái)定了采呐。
========================
數(shù)據(jù)持久化通俗講就是把數(shù)據(jù)保存到磁盤(pán)上,保證不會(huì)因?yàn)閿嚯姷纫蛩貋G失數(shù)據(jù)搁骑。
redis 需要經(jīng)常將內(nèi)存中的數(shù)據(jù)同步到磁盤(pán)來(lái)保證持久化斧吐。redis支持兩種持久化方式,一種是 Snapshotting(快照)也是默認(rèn)方式仲器,另一種是Append-only file(縮寫(xiě)aof)的方式煤率。先介紹下這兩種dump方式再講講自己遇到的一些現(xiàn)象和想法,前面的內(nèi)容是從網(wǎng)上整理出來(lái)的乏冀。
Snapshotting
快照是默認(rèn)的持久化方式涕侈。這種方式是就是將內(nèi)存中數(shù)據(jù)以快照的方式寫(xiě)入到二進(jìn)制文件中,默認(rèn)的文件名為dump.rdb∶罕妫可以通過(guò)配置設(shè)置自動(dòng)做快照持久 化的方式裳涛。我們可以配置redis在n秒內(nèi)如果超過(guò)m個(gè)key被修改就自動(dòng)做快照,下面是默認(rèn)的快照保存配置
save 900 1? #900秒內(nèi)如果超過(guò)1個(gè)key被修改众辨,則發(fā)起快照保存
save 300 10 #300秒內(nèi)容如超過(guò)10個(gè)key被修改端三,則發(fā)起快照保存
save 60 10000
下面介紹詳細(xì)的快照保存過(guò)程
1.redis調(diào)用fork,現(xiàn)在有了子進(jìn)程和父進(jìn)程。
2. 父進(jìn)程繼續(xù)處理client請(qǐng)求鹃彻,子進(jìn)程負(fù)責(zé)將內(nèi)存內(nèi)容寫(xiě)入到臨時(shí)文件郊闯。由于os的寫(xiě)時(shí)復(fù)制機(jī)制(copy on write)父子進(jìn)程會(huì)共享相同的物理頁(yè)面,當(dāng)父進(jìn)程處理寫(xiě)請(qǐng)求時(shí)os會(huì)為父進(jìn)程要修改的頁(yè)面創(chuàng)建副本,而不是寫(xiě)共享的頁(yè)面团赁。所以子進(jìn)程的地址空間內(nèi)的數(shù) 據(jù)是fork時(shí)刻整個(gè)數(shù)據(jù)庫(kù)的一個(gè)快照育拨。
3.當(dāng)子進(jìn)程將快照寫(xiě)入臨時(shí)文件完畢后,用臨時(shí)文件替換原來(lái)的快照文件,然后子進(jìn)程退出。
client 也可以使用save或者bgsave命令通知redis做一次快照持久化舵鳞。save操作是在主線(xiàn)程中保存快照的,由于redis是用一個(gè)主線(xiàn)程來(lái)處理所有 client的請(qǐng)求析蝴,這種方式會(huì)阻塞所有client請(qǐng)求。所以不推薦使用绿淋。另一點(diǎn)需要注意的是闷畸,每次快照持久化都是將內(nèi)存數(shù)據(jù)完整寫(xiě)入到磁盤(pán)一次,并不 是增量的只同步臟數(shù)據(jù)吞滞。如果數(shù)據(jù)量大的話(huà)佑菩,而且寫(xiě)操作比較多,必然會(huì)引起大量的磁盤(pán)io操作裁赠,可能會(huì)嚴(yán)重影響性能倘待。
另外由于快照方式是在一定間隔時(shí)間做一次的,所以如果redis意外down掉的話(huà)组贺,就會(huì)丟失最后一次快照后的所有修改。如果應(yīng)用要求不能丟失任何修改的話(huà)祖娘,可以采用aof持久化方式失尖。下面介紹
Append-only file
aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式時(shí),redis會(huì)將每一個(gè)收到的寫(xiě)命令都通過(guò)write函數(shù)追加到文件中(默認(rèn)是 appendonly.aof)渐苏。當(dāng)redis重啟時(shí)會(huì)通過(guò)重新執(zhí)行文件中保存的寫(xiě)命令來(lái)在內(nèi)存中重建整個(gè)數(shù)據(jù)庫(kù)的內(nèi)容掀潮。當(dāng)然由于os會(huì)在內(nèi)核中緩存 write做的修改,所以可能不是立即寫(xiě)到磁盤(pán)上琼富。這樣aof方式的持久化也還是有可能會(huì)丟失部分修改仪吧。不過(guò)我們可以通過(guò)配置文件告訴redis我們想要 通過(guò)fsync函數(shù)強(qiáng)制os寫(xiě)入到磁盤(pán)的時(shí)機(jī)。有三種方式如下(默認(rèn)是:每秒fsync一次)
appendonly yes????????????? //啟用aof持久化方式
# appendfsync always????? //每次收到寫(xiě)命令就立即強(qiáng)制寫(xiě)入磁盤(pán)鞠眉,最慢的薯鼠,但是保證完全的持久化,不推薦使用
appendfsync everysec???? //每秒鐘強(qiáng)制寫(xiě)入磁盤(pán)一次械蹋,在性能和持久化方面做了很好的折中出皇,推薦
# appendfsync no?? ?//完全依賴(lài)os,性能最好,持久化沒(méi)保證
aof 的方式也同時(shí)帶來(lái)了另一個(gè)問(wèn)題哗戈。持久化文件會(huì)變的越來(lái)越大郊艘。例如我們調(diào)用incr test命令100次,文件中必須保存全部的100條命令,其實(shí)有99條都是多余的纱注。因?yàn)橐謴?fù)數(shù)據(jù)庫(kù)的狀態(tài)其實(shí)文件中保存一條set test 100就夠了畏浆。為了壓縮aof的持久化文件。redis提供了bgrewriteaof命令狞贱。收到此命令redis將使用與快照類(lèi)似的方式將內(nèi)存中的數(shù)據(jù) 以命令的方式保存到臨時(shí)文件中刻获,最后替換原來(lái)的文件。具體過(guò)程如下
1. redis調(diào)用fork 斥滤,現(xiàn)在有父子兩個(gè)進(jìn)程
2. 子進(jìn)程根據(jù)內(nèi)存中的數(shù)據(jù)庫(kù)快照将鸵,往臨時(shí)文件中寫(xiě)入重建數(shù)據(jù)庫(kù)狀態(tài)的命令
3.父進(jìn)程繼續(xù)處理client請(qǐng)求,除了把寫(xiě)命令寫(xiě)入到原來(lái)的aof文件中佑颇。同時(shí)把收到的寫(xiě)命令緩存起來(lái)顶掉。這樣就能保證如果子進(jìn)程重寫(xiě)失敗的話(huà)并不會(huì)出問(wèn)題。
4.當(dāng)子進(jìn)程把快照內(nèi)容寫(xiě)入已命令方式寫(xiě)到臨時(shí)文件中后挑胸,子進(jìn)程發(fā)信號(hào)通知父進(jìn)程痒筒。然后父進(jìn)程把緩存的寫(xiě)命令也寫(xiě)入到臨時(shí)文件。
5.現(xiàn)在父進(jìn)程可以使用臨時(shí)文件替換老的aof文件茬贵,并重命名簿透,后面收到的寫(xiě)命令也開(kāi)始往新的aof文件中追加。
需要注意到是重寫(xiě)aof文件的操作解藻,并沒(méi)有讀取舊的aof文件老充,而是將整個(gè)內(nèi)存中的數(shù)據(jù)庫(kù)內(nèi)容用命令的方式重寫(xiě)了一個(gè)新的aof文件,這點(diǎn)和快照有點(diǎn)類(lèi)似。
運(yùn)維上的想法
其實(shí)快照和aof一樣螟左,都使用了Copy-on-write技術(shù)啡浊。多次試驗(yàn)發(fā)現(xiàn)每次做數(shù)據(jù)dump的時(shí)候,內(nèi)存都會(huì)擴(kuò)大一倍(關(guān)于這個(gè)問(wèn)題可以參考我去年寫(xiě)的redis的內(nèi)存陷阱胶背,很多人用redis做為緩存巷嚣,數(shù)據(jù)量小,dump耗時(shí)非常短暫钳吟,所以不太容易發(fā)現(xiàn))廷粒,這個(gè)時(shí)候會(huì)有三種情況:
一:物理內(nèi)存足以滿(mǎn)足,這個(gè)時(shí)候dump非澈烨遥快坝茎,性能最好
二:物理內(nèi)存+虛擬內(nèi)存可以滿(mǎn)足,這個(gè)時(shí)候dump速度會(huì)比較慢暇番,磁盤(pán)swap繁忙景东,服務(wù)性能也會(huì)下降。所幸的是經(jīng)過(guò)一段比較長(zhǎng)的時(shí)候數(shù)據(jù)dump完成了奔誓,然后內(nèi)存恢復(fù)正常斤吐。這個(gè)情況系統(tǒng)穩(wěn)定性差搔涝。
三: 物理內(nèi)存+虛擬內(nèi)存不能滿(mǎn)足,這個(gè)時(shí)候dump一直死著和措,時(shí)間久了機(jī)器掛掉庄呈。這個(gè)情況就是災(zāi)難!
如果數(shù)據(jù)要做持久化又想保證穩(wěn)定性派阱,建議留空一半的物理內(nèi)存诬留。如果覺(jué)得無(wú)法接受還是有辦法,下面講:
快照和aof雖然都使用Copy-on-write贫母,但有個(gè)不同點(diǎn)文兑,快照你無(wú)法預(yù)測(cè)redis什么時(shí)候做dump,aof可以通過(guò)bgrewriteaof命令控制dump的時(shí)機(jī)腺劣。
根據(jù)這點(diǎn)我可以在一個(gè)服務(wù)器上開(kāi)啟多個(gè)redis節(jié)點(diǎn)(利用多CPU)绿贞,使用aof的持久化方式。
例 如在24G內(nèi)存的服務(wù)器上開(kāi)啟3個(gè)節(jié)點(diǎn)橘原,每天用bgrewriteaof定期重新整理數(shù)據(jù)籍铁,每個(gè)節(jié)點(diǎn)dump的時(shí)間都不一樣,這 樣理論上每個(gè)節(jié)點(diǎn)可以消耗6G內(nèi)存趾断,一共使用18G內(nèi)存拒名,另外6G內(nèi)存在單個(gè)節(jié)點(diǎn)dump時(shí)用到,內(nèi)存一下多利用了6G芋酌! 當(dāng)然節(jié)點(diǎn)開(kāi)的越多內(nèi)存的利用率也越高增显。如果帶寬不是問(wèn)題,節(jié)點(diǎn)數(shù)建議 = CPU數(shù)脐帝。
我的應(yīng)用里為了保證高性能同云,數(shù)據(jù)沒(méi)有做dump,也沒(méi)有用aof腮恩。因?yàn)椴蛔鰀ump發(fā)生的故障遠(yuǎn)遠(yuǎn)低于做dump的時(shí)候,即使數(shù)據(jù)丟失了温兼,自動(dòng)修復(fù)腳本可以馬上數(shù)據(jù)恢復(fù)秸滴。畢竟對(duì)海量數(shù)據(jù)redis只能做數(shù)據(jù)分片,那么落到每個(gè)節(jié)點(diǎn)上的數(shù)據(jù)量也不會(huì)很多募判。
redis的虛擬內(nèi)存建議也不要用荡含,用redis本來(lái)就是為了達(dá)到變態(tài)的性能,虛擬內(nèi)存届垫、aof看起來(lái)都有些雞肋释液。
現(xiàn)在還離不開(kāi)redis,因?yàn)樗膍get是現(xiàn)在所有db里性能最好的装处,以前也考慮過(guò)用tokyocabinet hash方式做mget误债,性能不給力浸船。直接用redis,基本上單個(gè)redis節(jié)點(diǎn)mget可以達(dá)到10W/s
糾錯(cuò)
之前說(shuō)過(guò)redis做數(shù)據(jù)dump的時(shí)候內(nèi)容會(huì)擴(kuò)大一倍寝蹈,后來(lái)我又做了些測(cè)試李命,發(fā)現(xiàn)有些地方說(shuō)的不對(duì)。
top 命令并不是反映真實(shí)的內(nèi)存占用情況箫老,在top里盡管fork出來(lái)的子進(jìn)程占了和父進(jìn)程一樣的內(nèi)存封字,但是當(dāng)做dump的時(shí)候沒(méi)有寫(xiě)操作,實(shí)際使 用的是同一份內(nèi)存的數(shù)據(jù)耍鬓。當(dāng)有寫(xiě)操作的時(shí)候內(nèi)存才會(huì)真實(shí)的擴(kuò)大(具體是不是真實(shí)的擴(kuò)大一倍不確定阔籽,可能數(shù)據(jù)是按照頁(yè)分片的),這才是真正的Copy- on-write牲蜀。
基于這點(diǎn)在做數(shù)據(jù)持久化會(huì)更加靈活笆制。