Redis 存儲方案

Redis

RedisPersistence(持久化存儲)

Redis提供了不同的持久化方案

  • TheRDB(方案):定期對內存中的數據進行快照,永久存儲快照。

  • theAOF(方案):每個修改操作記錄在日誌中,服務器重啓時,根據日誌重新構造數據集。

  • 禁止持久化存儲,數據全部存在內存中。

  • AOFRDB方案可以結合在一起。

2、分佈式控制

目前只支持Master-replication,一個Master用於寫,多個Slave用於讀。也沒有負載均衡,讀寫分離需要靠客戶端顯示設置。

Master-replication方案不同的是,Jedis客戶端支持一種一致性哈希可以把key-value均勻分佈到不同的server上。這種方案有些缺點:1不能使用事務,流水線,pub/sub2,不能動態增加,減少服務器。


3
、代碼量

Redissource code is not very big (just 20k lines of code for the 2.2release)


附錄一:Redis 永久化存儲方案介紹。


以下是不同存儲方案的詳細介紹,大部分沒來的及翻譯,主要是一些細節問題。


RDB方案的優點(db代表database?)

YoucanconfigureRedistohaveitsavethedataseteveryNsecondsifthereareatleastMchangesinthedataset,oryoucanmanuallycalltheSAVEorBGSAVEcommands.

For example,this configuration will make Redis automatically dump the dataset todisk every 60 seconds if at least 1000 keys changed:

save 60 1000


  • 壓縮的,單文件格式。

  • 易於做數據備份ForinstanceyoumaywanttoarchiveyourRDBfileseveryhourforthelatest24hours,andtosaveanRDBsnapshoteverydayfor30days.Thisallowsyoutoeasilyrestoredifferentversionsofthedatasetincaseofdisasters.

  • RDB文件易於進行故障轉移:RDBisverygoodfordisasterrecovery,beingasinglecompactfilecanbetransferedtofardatacenters,oronAmazonS3(possiblyencrypted).

  • RDB方案最大的提升了Redis的性能。父進程fork子進程進行數據的永久性存儲。父進程不進行磁盤I/O

  • RDB相比AOF來說,可以使服務器快速重啓。

RDB的缺點

  • 會引起數據丟失,因爲快照不是實時的。

  • RDB needs tofork() often in order to persist on disk using a child process.Fork() can be time consuming if the dataset is big, and may resultin Redis to stop serving clients for some millisecond or even forone second if the dataset is very big and the CPU performance notgreat.

AOF優點aof代表append-only-file)

  • AOF不同的日誌同步方案,可以是數據durable(不知道怎麼翻譯):

Howdurableistheappendonlyfile?(同步日誌文件)

YoucanconfigurehowmanytimesRediswillfsyncdataondisk.Therearethreeoptions:

fsynceverytimeanewcommandisappendedtotheAOF.Veryveryslow,verysafe.(數據不丟失)

Fsynceverysecond.Fastenough(in2.4likelytobeasfastassnapshotting),andyoucanlose1secondofdataifthereisadisaster.(推薦)(最多丟失1s內的數據)

Neverfsync,justputyourdatainthehandsoftheOperatingSystem.Thefasterandlesssafemethod.(不同步日誌,數據的同步完全交由OS控制)


  • TheAOFlogisanappendonlylog,sotherearenoseeks,norcorruptionproblemsifthereisapoweroutage.Evenifthelogendswithanhalf-writtencommandforsomereason(diskfullorotherreasons)theredis-check-aoftoolisabletofixiteasily.(append-only格式的日誌具有優勢).

  • RedisisabletoautomaticallyrewritetheAOFinbackgroundwhenitgetstoobig.TherewriteiscompletelysafeaswhileRediscontinuesappendingtotheoldfile,acompletelynewoneisproducedwiththeminimalsetofoperationsneededtocreatethecurrentdataset,andoncethissecondfileisreadyRedisswitchesthetwoandstartsappendingtothenewone.(可以對太大的日誌中的操作進行等價合併重寫,生成一個較小的日誌)

  • AOFcontainsalogofalltheoperationsoneaftertheotherinaneasytounderstandandparseformat.YoucaneveneasilyexportanAOFfile.ForinstanceevenifyouflushedeverythingforanerrorusingaFLUSHALLcommand,ifnorewriteofthelogwasperformedinthemeantimeyoucanstillsaveyourdatasetjuststoppingtheserver,removingthelatestcommand,andrestartingRedisagain.(不會引起數據不一致)

AOFdisadvantages

  • AOFfilesareusuallybiggerthantheequivalentRDBfilesforthesamedataset.(沒有壓縮,大量日誌信息)

  • AOF通常比RDB方案要慢。

  • In the pastwe experienced rare bugs in specific commands (for instance therewas one involving blocking commands like BRPOPLPUSH) causing the AOFproduced to don't reproduce exactly the same dataset on reloading.This bugs are rare and we have tests in the test suite creatingrandom complex datasets automatically and reloading them to checkeverything is ok, but this kind of bugs are almost impossible withRDB persistence. To make this point more clear: the Redis AOF worksincrementally updating an existing state, like MySQL or MongoDBdoes, while the RDB snapshotting creates everything from scratchagain and again, that is conceptually more robust. However 1) Itshould be noted that every time the AOF is rewritten by Redis it isrecreated from scratch starting from the actual data contained inthe data set, making resistance to bugs stronger compared to analways appending AOF file (or one rewritten reading the old AOFinstead of reading the data in memory). 2) We never had a singlereport from users about an AOF corruption that was detected in thereal world.

Ok,so what should I use?

There aremany users using AOF alone, but we discourage it since to have an RDBsnapshot from time to time is a great idea for doing databasebackups, for faster restarts, and in the event of bugs in the AOFengine.

Whatshould I do if my AOF gets corrupted?

It ispossible that the server crashes while writing the AOF file (thisstill should never lead to inconsistencies), corrupting the file in away that is no longer loadable by Redis. When this happens you canfix this problem using the following procedure:

  • Make abackup copy of your AOF file.

  • Fixtheoriginalfileusingtheredis-check-aoftoolthatshipswithRedis:

$ redis-check-aof --fix <filename>
  • Optionallyusediff-utocheckwhatisthedifferencebetweentwofiles.

  • Restart theserver with the fixed file.

HowI can switch to AOF, if I'm currently using dump.rdb snapshots?

Interactionsbetween AOF and RDB persistence

Redis >=2.4 makes sure to avoid triggering an AOF rewrite when an RDBsnapshotting operation is already in progress, or allowing a BGSAVEwhile the the AOF rewrite is in progress. This prevents two Redisbackground processes from doing heavy disk I/O at the same time.

Whensnapshotting is in progress and the user explicitly requests a logrewrite operation using BGREWRITEAOF the server will reply with an OKstatus code telling the user the operation is scheduled, and therewirte will start once the snapshotting is completed.

In the caseboth AOF and RDB persistence are enabled and Redis restarts the AOFfile will be used to reconstruct the original dataset since it isguaranteed to be the most complete.

Backingup Redis data

Beforestartingthissection,makesuretoreadthefollowingsentence: MakeSuretoBackupYourDatabase.Disksbreak,instancesintheclouddisappear,andsoforth:nobackupsmeanshugeriskofdatadisappearinginto/dev/null.

Redis is verydata backup friendly since you can copy RDB files while the databaseis running: the RDB is never modified once produced, and while itgets produced it uses a temporary name and is renamed into its finaldestination atomically using rename(2) only when the new snapshot iscomplete.

This meansthat copying the RDB file is completely safe while the server isrunning. This is what we suggest:

  • Create acron job in your server creating hourly snapshots of the RDB file inone directory, and daily snapshots in a different directory.

  • Everytimethecronscriptruns,makesuretocallthe find commandtomakesuretoooldsnapshotsaredeleted:forinstanceyoucantakehourlysnapshotsforthelatest48hours,anddailysnapshotsforoneortwomonths.Makesuretonamethesnapshotswithdataandtimeinformation.

  • AtleastonetimeeverydaymakesuretotransferanRDBsnapshot outsideyourdatacenter oratleastoutsidethephysicalmachinerunningyourRedisinstance.

Disasterrecovery

RDB恢復Redis


數據持久化通俗講就是把數據保存到磁盤上,保證不會因爲斷電等因素丟失數據。

redis需要經常將內存中的數據同步到磁盤來保證持久化。redis支持兩種持久化方式,一種是 Snapshotting(快照)也是默認方式,另一種是Append-only file(縮寫aof)的方式。先介紹下這兩種dump方式再講講自己遇到的一些現象和想法,前面的內容是從網上整理出來的。

Snapshotting
快照是默認的持久化方式。這種方式是就是將內存中數據以快照的方式寫入到二進制文件中,默認的文件名爲dump.rdb。可以通過配置設置自動做快照持久 化的方式。我們可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是默認的快照保存配置

save 900 1  #900秒內如果超過1個key被修改,則發起快照保存
save 300 10 #300秒內容如超過10個key被修改,則發起快照保存
save 60 10000

下面介紹詳細的快照保存過程

1.redis調用fork,現在有了子進程和父進程。

2. 父進程繼續處理client請求,子進程負責將內存內容寫入到臨時文件。由於os的寫時複製機制(copy on write)父子進程會共享相同的物理頁面,當父進程處理寫請求時os會爲父進程要修改的頁面創建副本,而不是寫共享的頁面。所以子進程的地址空間內的數 據是fork時刻整個數據庫的一個快照。

3.當子進程將快照寫入臨時文件完畢後,用臨時文件替換原來的快照文件,然後子進程退出。

client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主線程中保存快照的,由於redis是用一個主線程來處理所有 client的請求,這種方式會阻塞所有client請求。所以不推薦使用。另一點需要注意的是,每次快照持久化都是將內存數據完整寫入到磁盤一次,並不 是增量的只同步髒數據。如果數據量大的話,而且寫操作比較多,必然會引起大量的磁盤io操作,可能會嚴重影響性能。

另外由於快照方式是在一定間隔時間做一次的,所以如果redis意外down掉的話,就會丟失最後一次快照後的所有修改。如果應用要求不能丟失任何修改的話,可以採用aof持久化方式。下面介紹

Append-only file

aof 比快照方式有更好的持久化性,是由於在使用aof持久化方式時,redis會將每一個收到的寫命令都通過write函數追加到文件中(默認是 appendonly.aof)。當redis重啓時會通過重新執行文件中保存的寫命令來在內存中重建整個數據庫的內容。當然由於os會在內核中緩存 write做的修改,所以可能不是立即寫到磁盤上。這樣aof方式的持久化也還是有可能會丟失部分修改。不過我們可以通過配置文件告訴redis我們想要 通過fsync函數強制os寫入到磁盤的時機。有三種方式如下(默認是:每秒fsync一次)

appendonly yes              //啓用aof持久化方式
# appendfsync always      //每次收到寫命令就立即強制寫入磁盤,最慢的,但是保證完全的持久化,不推薦使用
appendfsync everysec     //每秒鐘強制寫入磁盤一次,在性能和持久化方面做了很好的折中,推薦
# appendfsync no    //完全依賴os,性能最好,持久化沒保證

aof 的方式也同時帶來了另一個問題。持久化文件會變的越來越大。例如我們調用incr test命令100次,文件中必須保存全部的100條命令,其實有99條都是多餘的。因爲要恢復數據庫的狀態其實文件中保存一條set test 100就夠了。爲了壓縮aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照類似的方式將內存中的數據 以命令的方式保存到臨時文件中,最後替換原來的文件。具體過程如下

1. redis調用fork ,現在有父子兩個進程
2. 子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令
3.父進程繼續處理client請求,除了把寫命令寫入到原來的aof文件中。同時把收到的寫命令緩存起來。這樣就能保證如果子進程重寫失敗的話並不會出問題。
4.當子進程把快照內容寫入已命令方式寫到臨時文件中後,子進程發信號通知父進程。然後父進程把緩存的寫命令也寫入到臨時文件。
5.現在父進程可以使用臨時文件替換老的aof文件,並重命名,後面收到的寫命令也開始往新的aof文件中追加。

需要注意到是重寫aof文件的操作,並沒有讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點類似。

運維上的想法

其實快照和aof一樣,都使用了Copy-on-write技術。多次試驗發現每次做數據dump的時候,內存都會擴大一倍(關於這個問題可以參考我去年寫的redis的內存陷阱,很多人用redis做爲緩存,數據量小,dump耗時非常短暫,所以不太容易發現),這個時候會有三種情況:

一:物理內存足以滿足,這個時候dump非常快,性能最好

二:物理內存+虛擬內存可以滿足,這個時候dump速度會比較慢,磁盤swap繁忙,服務性能也會下降。所幸的是經過一段比較長的時候數據dump完成了,然後內存恢復正常。這個情況系統穩定性差。

三: 物理內存+虛擬內存不能滿足,這個時候dump一直死着,時間久了機器掛掉。這個情況就是災難!

如果數據要做持久化又想保證穩定性,建議留空一半的物理內存。如果覺得無法接受還是有辦法,下面講:

快照和aof雖然都使用Copy-on-write,但有個不同點,快照你無法預測redis什麼時候做dump,aof可以通過bgrewriteaof命令控制dump的時機。

根據這點我可以在一個服務器上開啓多個redis節點(利用多CPU),使用aof的持久化方式。

例如在24G內存的服務器上開啓3個節點,每天用bgrewriteaof定期重新整理數據,每個節點dump的時間都不一樣,這樣理論上每個節點可以消耗6G內存,一共使用18G內存,另外6G內存在單個節點dump時用到,內存一下多利用了6G! 當然節點開的越多內存的利用率也越高。如果帶寬不是問題,節點數建議 = CPU數。

我的應用裏爲了保證高性能,數據沒有做dump,也沒有用aof。因爲不做dump發生的故障遠遠低於做dump的時候,即使數據丟失了,自動修復腳本可以馬上數據恢復。畢竟對海量數據redis只能做數據分片,那麼落到每個節點上的數據量也不會很多。

redis的虛擬內存建議也不要用,用redis本來就是爲了達到變態的性能,虛擬內存、aof看起來都有些雞肋。

現在還離不開redis,因爲它的mget是現在所有db裏性能最好的,以前也考慮過用tokyocabinet hash方式做mget,性能不給力。直接用redis,基本上單個redis節點mget可以達到10W/s

糾錯

之前說過redis做數據dump的時候內容會擴大一倍,後來我又做了些測試,發現有些地方說的不對。

top命令並不是反映真實的內存佔用情況,在top裏儘管fork出來的子進程佔了和父進程一樣的內存,但是當做dump的時候沒有寫操作,實際使用的是同一份內存的數據。當有寫操作的時候內存纔會真實的擴大(具體是不是真實的擴大一倍不確定,可能數據是按照頁分片的),這纔是真正的Copy-on-write。

基於這點在做數據持久化會更加靈活







發佈了29 篇原創文章 · 獲贊 4 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章