redis持久化策略梳理及主從環境下的策略調整記錄

散盡浮華發表於2017-01-09

 

redis是一個支援持久化的記憶體資料庫,也就是說redis需要經常將記憶體中的資料同步到磁碟來保證持久化。可以不定期的通過非同步方式儲存到磁碟上(即“半持久化模式”);也可以把每一次資料變化都寫入到一個Append Only File(AOF)裡面(即“完全持久化模式”)。redis支援兩種持久化方式,一種是預設方式的RDB(Snapshotting快照)持久化,另一種是AOF(Append-only file)持久化方式。這兩種持久化方式都可以將記憶體中的資料庫狀態儲存到磁碟上,redis對應的也有兩種落地檔案:資料檔案(預設檔名dump.rdb,也即快照檔案)、AOF持久化檔案。接下來詳細說明它們之間的用法:

1.RDB是在指定時間間隔內生成資料集的時間點快照(point-in-time snapshot)持久化,是記錄一段時間內的操作,一段時間內操作超過多少次就持久化。
預設是會以快照的形式將資料持久化到磁碟的(一個二進位制檔案,dump.rdb,這個檔名字可以指定),在配置檔案中的格式是:save N M表示在N秒之內,redis至少發生M次修改則redis抓快照到磁碟。當然也可以手動執行save或者bgsave(非同步)做快照。
工作原理:
當redis需要做持久化時,redis會fork一個子程式;子程式將資料寫到磁碟上一個臨時RDB檔案中;當子程式完成寫臨時檔案後,將原來的RDB替換掉,這樣的好處就是可以copy-on-write(寫時複製技術

2.AOF持久化記錄伺服器執行的所有寫操作命令,並在伺服器啟動時,通過重新執行這些命令來還原資料集,它可以實現每次操作都持久化。
AOF檔案中的命令全部以redis協議的格式來儲存,新命令會被追加到檔案的末尾。 redis還可以在後臺對AOF檔案進行重寫(rewrite),使得AOF檔案的體積不會超出儲存資料集狀態所需的實際大小。redis還可以同時使用AOF持久化和RDB持久化。在這種情況下,當redis重啟時,它會優先使用AOF檔案來還原資料集, 因為AOF檔案儲存的資料集通常比RDB檔案所儲存的資料集更完整。也可以關閉持久化功能,讓資料只在伺服器執行時存在。

RDB方法在redis異常死掉時,最近的資料會丟失(丟失資料的多少視你save策略的配置),所以這是它最大的缺點,當業務量很大時,丟失的資料是很多的。
Append-only方法可以做到全部資料不丟失,但redis的效能就要差些。AOF就可以做到全程持久化,只需要在配置檔案中開啟(預設是no),appendonly yes開啟AOF之後,redis每執行一個修改資料的命令,都會把它新增到aof檔案中,當redis重啟時,將會讀取AOF檔案進行“重放”以恢復到redis關閉前的最後時刻。

redis啟動裝載:
AOF優先於RDB
RDB效能優於AOF,因為裡面沒有重複
Redis一次性將資料載入到記憶體中,一次性預熱

LOG Rewriting(重寫)隨著修改資料的執行AOF檔案會越來越大,其中很多內容記錄某一個key的變化情況。因此redis有了一種比較有意思的特性:在後臺重建AOF檔案,而不會影響client端操作。在任何時候執行bgrewriteaof命令,都會把當前記憶體中最短序列的命令寫到磁碟,這些命令可以完全構建當前的資料情況,而不會存在多餘的變化情況(比如狀態變化,計數器變化等),縮小的AOF檔案的大小。所以當使用AOF時,redis推薦同時使用bgrewriteaofAOF 重寫和 RDB 建立快照一樣,都巧妙地利用了寫時複製機制。

為了壓縮AOF的持久化檔案,Redis提供了bgrewriteaof命令。
收到此命令後Redis將使用與快照類似的方式將記憶體中的資料以命令的方式儲存到臨時檔案中,最後替換原來的檔案,以此來實現控制AOF檔案的增長。
由於是模擬快照的過程,因此在重寫AOF檔案時並沒有讀取舊的AOF檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的AOF檔案。

AOF檔案重新整理的方式,有三種,參考配置引數appendfsync :
    appendfsync always:每提交一個修改命令都呼叫fsync重新整理到AOF檔案,非常非常慢,但也非常安全;
    appendfsync everysec:每秒鐘都呼叫fsync重新整理到AOF檔案,很快,但可能會丟失一秒以內的資料;
    appendfsync no:依靠OS進行重新整理,redis不主動重新整理AOF,這樣最快,但安全性就差。預設並推薦每秒重新整理,這樣在速度和安全上都做到了兼顧。

redis預設的持久化方式是RDB,資料寫入到dump檔案中。如果要啟用AOF持久化,就在redis.conf檔案中配置如下:
    appendonly yes       #啟用AOF持久化方式
    appendfilename "appendonly.aof"      #AOF檔案的名稱,預設為appendonly.aof
    # appendfsync always       #每次收到寫命令就立即強制寫入磁碟,是最有保證的完全的持久化,但速度也是最慢的,一般不推薦使用。
   appendfsync everysec       #每秒鐘強制寫入磁碟一次,在效能和持久化方面做了很好的折中,這種fsync策略可以兼顧速度和安全性,是受推薦的方式。
   # appendfsync no       #完全依賴OS的寫入,一般為30秒左右一次,效能最好但是持久化最沒有保證,不被推薦。

可能由於系統原因導致了AOF損壞,redis無法再載入這個出錯的AOF檔案,可以按照下面步驟來修復:
    1)首先做一個AOF檔案的備份,複製到其他地方;
    2)修復原始AOF檔案,執行命令redis-check-aof –fix ;
    3)可以通過diff –u命令來檢視修復前後檔案不一致的地方;
    4)重啟redis服務。

LOG Rewrite的工作原理:
同樣用到了copy-on-write:首先redis會fork一個子程式;子程式將最新的AOF寫入一個臨時檔案;父程式增量的把記憶體中的最新執行的修改寫入(這時仍寫入舊的AOF,rewrite如果失敗也是安全的);當子程式完成rewrite臨時檔案後,父程式會收到一個訊號,並把之前記憶體中增量的修改寫入臨時檔案末尾;這時redis將舊AOF檔案重新命名,臨時檔案重新命名,開始向新的AOF中寫入。

為以防萬一(機器壞掉或磁碟壞掉),最好定期把使用filesnapshotting 或 Append-only 生成的*rdb *.aof檔案備份到遠端機器上,然後可以用crontab定時(比如每半小時)scp一次。如果沒有使用redis的主從功能 ,半小時備份一次應該是可以了;並且如果應用資料量不大的話,可以單機部署,做主從有點浪費。具體還是要根據應用而定。

接著具體解說下這兩種持久化:

如果的記憶體中的資料量非常大的時候,rdb持久化的臨時檔案就會非常大,幾乎是原檔案的1倍,效能有所降低。
如果當寫操作要立刻持久化的時候,可以執行命令:save
save是全阻塞的,bgsave是非同步的。

snapshot快照首先將資料寫入臨時檔案,當成功結束後,將臨時檔案重名為dump.rdb

使用RDB恢復資料: 
自動的持久化資料儲存到dump.rdb後。實際只要重啟redis服務即可完成(啟動redis的server時會從dump.rdb中先同步資料)

客戶端使用命令進行持久化save儲存:
# redis-cli -h ip -p port save
# redis-cli -h ip -p port bgsave
一個是在前臺進行儲存,一個是在後臺進行儲存。我的client就在server這臺伺服器上,所以不需要連其他機器,直接./redis-cli bgsave。
由於redis是用一個主執行緒來處理所有 client的請求,這種方式會阻塞所有client請求。所以不推薦使用。另一點需要注意的是,每次快照持久
化都是將記憶體資料完整寫入到磁碟一次,並不是增量的只同步髒資料。如果資料量大的話,而且寫操作比較多,必然會引起大量的磁碟io操作,可能會嚴重影響效能

如果aof或rdb檔案語法有誤,可以使用下面兩條命令來修復。
1)aof修復命令:
# redis-check-aof --fix appendonlly.aof
2)rdb修復命令:
# redis-check-rdb--fix dump.rdb

aof是採用檔案追加方式,將所有的寫操作儲存在aof檔案中,當檔案越來越大時,有可能存在相同的寫操作,這些相同的操作可以將他濃縮為一條操作,這樣可以減少aof檔案的容量。

redis對aof新增了一種重寫機制,當aof檔案大小超過所設定的閾值時,redis會啟動aof檔案的內容壓縮,只保留可以恢復資料的最小指令集,可以使用命令bgrewriteaof。

RDB和AOF各自的優缺點
1)RDB持久化優點
RDB 是一個非常緊湊(compact)的檔案,它儲存了Redis在某個時間點上的資料集。 這種檔案非常適合用於進行備份的,比如說,可以在最近的24小時內,每小時備份一次RDB檔案,並且在每個月的每一天,也備份一個 RDB 檔案。這樣的話,即使遇上問題,也可以隨時將資料集還原到不同的版本。RDB 非常適用於災難恢復(disaster recovery):它只有一個檔案,並且內容都非常緊湊,可以(在加密後)將它傳送到別的資料中心,或者亞馬遜 S3 中。RDB可以最大化 Redis 的效能:父程式在儲存RDB檔案時唯一要做的就是fork出一個子程式,然後這個子程式就會處理接下來的所有儲存工作,父程式無須執行任何磁碟 I/O 操作。RDB在恢復大資料集時的速度比AOF的恢復速度要快。
    RDB持久化缺點
如果需要儘量避免在伺服器故障時丟失資料,那麼RDB不適合這種情況。 雖然Redis允許設定不同的儲存點(save point)來控制儲存RDB檔案的頻率,但是因為RDB檔案需要儲存整個資料集的狀態,所以它並不是一個輕鬆的操作。因此你可能會至少5分鐘才儲存一次RDB檔案。在這種情況下, 一旦發生故障停機,就可能會丟失好幾分鐘的資料。每次儲存RDB的時候,Redis都要 fork() 出一個子程式,並由子程式來進行實際的持久化工作。在資料集比較龐大時, fork() 可能會非常耗時,造成伺服器在某某毫秒內停止處理客戶端; 如果資料集非常巨大,並且 CPU 時間非常緊張的話,那麼這種停止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也需要進行 fork() ,但無論 AOF 重寫的執行間隔有多長,資料的耐久性都不會有任何損失。

2)AOF持久化優點
使用AOF持久化會讓Redis變得非常耐久(much more durable):你可以設定不同的fsync 策略,比如無fsync ,每秒鐘一次 fsync ,或者每次執行寫入命令時fsync 。AOF的預設策略為每秒鐘fsync 一次,在這種配置下,Redis 仍然可以保持良好的效能,並且就算髮生故障停機,也最多隻會丟失一秒鐘的資料( fsync 會在後臺執行緒執行,所以主執行緒可以繼續努力地處理命令請求)。AOF 檔案是一個只進行追加操作的日誌檔案(append only log), 因此對 AOF 檔案的寫入不需要進行 seek , 即使日誌因為某些原因而包含了未寫入完整的命令(比如寫入時磁碟已滿,寫入中途停機,等等), redis-check-aof 工具也可以輕易地修復這種問題。
Redis可以在AOF檔案體積變得過大時,自動地在後臺對AOF進行重寫:重寫後的新AOF檔案包含了恢復當前資料集所需的最小命令集合。整個重寫操作是絕對安全的,因為Redis在建立新AOF檔案的過程中,會繼續將命令追加到現有的 AOF 檔案裡面,即使重寫過程中發生停機,現有的 AOF 檔案也不會丟失。 而一旦新 AOF 檔案建立完畢,Redis 就會從舊 AOF 檔案切換到新 AOF 檔案,並開始對新 AOF 檔案進行追加操作。AOF 檔案有序地儲存了對資料庫執行的所有寫入操作, 這些寫入操作以Redis協議的格式儲存, 因此AOF檔案的內容非常容易被人讀懂, 對檔案進行分析(parse)也很輕鬆。 匯出(export) AOF 檔案也非常簡單: 舉個例子, 如果你不小心執行了 FLUSHALL 命令, 但只要 AOF 檔案未被重寫, 那麼只要停止伺服器,移除AOF檔案末尾的FLUSHALL命令, 並重啟Redis ,就可以將資料集恢復到 FLUSHALL 執行之前的狀態。
   AOF持久化缺點
對於相同的資料集來說,AOF檔案的體積通常要大於RDB檔案的體積。根據所使用的fsync策略,AOF的速度可能會慢於RDB 。在一般情況下,每秒 fsync 的效能依然非常高,而關閉fsync可以讓AOF的速度和 RDB 一樣快, 即使在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。AOF 在過去曾經發生過這樣的 bug : 因為個別命令的原因,導致 AOF 檔案在重新載入時,無法將資料集恢復成儲存時的原樣。 (舉個例子,阻塞命令BRPOPLPUSH就曾經引起過這樣的 bug 。)測試套件裡為這種情況新增了測試:它們會自動生成隨機的、複雜的資料集,並通過重新載入這些資料來確保一切正常。 雖然這種 bug 在 AOF 檔案中並不常見, 但是對比來說, RDB 幾乎是不可能出現這種 bug 的。

RDB持久化和AOF持久化,應該用哪一個?
一般來說,如果想達到足以媲美PostgreSQL的資料安全性,應該同時使用兩種持久化功能。
如果非常關心資料,但仍然可以承受數分鐘以內的資料丟失, 那麼可以只使用RDB持久化。
不推薦只使用AOF持久化:因為定時生成RDB快照(snapshot)非常便於進行資料庫備份,並且RDB恢復資料集的速度也要比 AOF 恢復的速度要快,除此之外,使用RDB還可以避免之前提到的AOF程式的bug。

快照
在預設情況下,Redis將資料庫快照儲存在名字為dump.rdb的二進位制檔案中。可以對Redis 進行設定, 讓它在“ N 秒內資料集至少有M個改動”這一條件被滿足時,自動儲存一次資料集。也可以通過呼叫 SAVE 或者 BGSAVE , 手動讓 Redis 進行資料集儲存操作。比如說, 以下設定會讓 Redis 在滿足“ 60 秒內有至少有1000個鍵被改動”這一條件時,自動儲存一次資料集:
save 60 1000
這種持久化方式被稱為快照(snapshot)。

快照的運作方式:
當 Redis 需要儲存 dump.rdb 檔案時, 伺服器執行以下操作:
Redis 呼叫 fork() ,同時擁有父程式和子程式。
子程式將資料集寫入到一個臨時 RDB 檔案中。
當子程式完成對新 RDB 檔案的寫入時,Redis 用新 RDB 檔案替換原來的 RDB 檔案,並刪除舊的 RDB 檔案。
這種工作方式使得 Redis 可以從寫時複製(copy-on-write)機制中獲益。
只進行追加操作的檔案(append-only file,AOF)
快照功能並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那麼伺服器將丟失最近寫入、且仍未儲存到快照中的那些資料。儘管對於某些程式來說, 資料的耐久性並不是最重要的考慮因素, 但是對於那些追求完全耐久能力(full durability)的程式來說, 快照功能就不太適用了。
從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。
你可以通過修改配置檔案來開啟 AOF 功能:
appendonly yes
從現在開始, 每當 Redis 執行一個改變資料集的命令時(比如 SET), 這個命令就會被追加到 AOF 檔案的末尾。
這樣的話, 當 Redis 重新啟時, 程式就可以通過重新執行 AOF 檔案中的命令來達到重建資料集的目的。

下面是redis預設的快照設定(要想關閉save快照功能,即註釋掉這三個預設的save設定即可):
save 900 1      #當有一條Keys資料被改變時,900秒重新整理到Disk一次
save 300 10    #當有10條Keys資料被改變時,300秒重新整理到Disk一次
save 60 10000    #當有10000條Keys資料被改變時,60秒重新整理到Disk一次
Redis的RDB檔案不會壞掉,因為其寫操作是在一個新程式中進行的。
當生成一個新的RDB檔案時,Redis生成的子程式會先將資料寫到一個臨時檔案中,然後通過原子性rename系統呼叫將臨時檔案重新命名為RDB檔案。
這樣在任何時候出現故障,Redis的RDB檔案都總是可用的。
同時,Redis的RDB檔案也是Redis主從同步內部實現中的一環。
第一次Slave向Master同步的實現是:
Slave向Master發出同步請求,Master先dump出rdb檔案,然後將rdb檔案全量傳輸給slave,然後Master把快取的命令轉發給Slave,初次同步完成。
第二次以及以後的同步實現是:
Master將變數的快照直接實時依次傳送給各個Slave。
但不管什麼原因導致Slave和Master斷開重連都會重複以上兩個步驟的過程。
Redis的主從複製是建立在記憶體快照的持久化基礎上的,只要有Slave就一定會有記憶體快照發生。
可以很明顯的看到,RDB有它的不足,就是一旦資料庫出現問題,那麼我們的RDB檔案中儲存的資料並不是全新的。
從上次RDB檔案生成到Redis停機這段時間的資料全部丟掉了。

AOF重寫:
因為 AOF 的運作方式是不斷地將命令追加到檔案的末尾, 所以隨著寫入命令的不斷增加, AOF 檔案的體積也會變得越來越大。舉個例子, 如果你對一個計數器呼叫了 100 次 INCR , 那麼僅僅是為了儲存這個計數器的當前值, AOF 檔案就需要使用 100 條記錄(entry)。然而在實際上, 只使用一條 SET 命令已經足以儲存計數器的當前值了, 其餘 99 條記錄實際上都是多餘的。為了處理這種情況, Redis 支援一種有趣的特性: 可以在不打斷服務客戶端的情況下, 對AOF檔案進行重建(rebuild)。執行 BGREWRITEAOF 命令, Redis將生成一個新的AOF檔案,這個檔案包含重建當前資料集所需的最少命令。

RDB和AOF之間的相互作用:
在版本號大於等於 2.4 的 Redis 中, BGSAVE 執行的過程中, 不可以執行 BGREWRITEAOF 。 反過來說, 在 BGREWRITEAOF 執行的過程中, 也不可以執行 BGSAVE 。
這可以防止兩個 Redis 後臺程式同時對磁碟進行大量的 I/O 操作。
如果 BGSAVE 正在執行, 並且使用者顯示地呼叫 BGREWRITEAOF 命令, 那麼伺服器將向使用者回覆一個 OK 狀態, 並告知使用者, BGREWRITEAOF 已經被預定執行: 一旦 BGSAVE 執行完畢, BGREWRITEAOF 就會正式開始。當 Redis 啟動時, 如果 RDB 持久化和 AOF 持久化都被開啟了, 那麼程式會優先使用 AOF 檔案來恢復資料集, 因為 AOF 檔案所儲存的資料通常是最完整的。

備份Redis 資料:
Redis對於資料備份是非常友好的,因為你可以在伺服器執行的時候對 RDB 檔案進行復制: RDB 檔案一旦被建立, 就不會進行任何修改。 當伺服器要建立一個新的 RDB 檔案時, 它先將檔案的內容儲存在一個臨時檔案裡面, 當臨時檔案寫入完畢時, 程式才使用 原子地用臨時檔案替換原來的 RDB 檔案。這也就是說, 無論何時, 複製 RDB 檔案都是絕對安全的。

----------------------------------------------------------------------------------------------------------------------------------------------
公司線上redis主從環境下的持久化策略調整:
描述:
之前線上專案使用redis,部署了redis主從環境。redis的主從複製功能非常強大,一個master可以擁有多個slave,而一個slave又可以擁有多個slave,如此下去,形成了強大的多級伺服器叢集架構。由於主redis採用了AOF和save快照的持久化,長時間下去,aof檔案不斷增大,磁碟空間使用率逐漸暴增。
考慮到效能問題,需要對redis持久化做些調整,調整如下:
   1)主庫不開啟AOF持久化,並關閉save快照功能(即註釋預設的三個save設定),只在每晚12點定時手動做一次bgsave快照,並將快照檔案轉移到異地。即主庫上不產生appendonly.aof持久化檔案,做的快照資料放在.rdb檔案裡(如dump.rdb,由於是壓縮配置(rdbcompression yes表示快照檔案要壓縮),所以快照檔案要比aof檔案小),然後將這個快照檔案dump.rdb轉移到其他的伺服器上,防止主伺服器當機造成的損失!
   2)從庫開啟AOF持久化並1秒落地,同樣不做快照save。並在每晚12點做一次bgrewriteaof壓縮appendonly.aof持久化檔案,壓縮前先對aof檔案進行備份。
--------------------------------------------------------------------------------------------------------------------------------------------
按照這種方法進行redis持久化調整,由於線上redis的主庫之前採用了AOF和save快照的持久化,之後將這兩種都關閉,從庫採用AOF持久化。出現了下面的現象:
就是主庫關閉AOF和save快照後,主redis上的appendonly.aof持久化檔案在一段時間內還在刷,在增大,這是正常的,由於之前開啟的緣故,刷過一段時間,主redis的appendonly.aof持久化檔案就不刷了,只有從redis的appendonly.aof持久化檔案在刷了
--------------------------------------------------------------------------------------------------------------------------------------------

主從redis部署的主要目的:資料持久化,災難恢復,冗餘。主庫不落地,減少消耗。
1)主庫不做AOF,不做快照,允許從庫訪問即可。
2)從庫開啟AOF,不做save
3)備份策略:
主庫每晚12點整給每個例項手動做一次bgsave快照,並將快照檔案備份到遠端節點上。
從庫每晚12點整對AOF檔案打包備份(tar),打包備份後做一次AOF檔案壓縮(bgrewriteaof)。每天的資料起始點是前一天晚上rewriteaof後的資料。

主庫伺服器指令碼:
即主庫快照之後,將快照檔案轉移到異地即從庫機器192.168.1.121/135上面。

[root@192-168-1-132 redis]# cat redis_bgsave.sh
#!/bin/bash
CURHOUR=`date +%Y%m%d_%H`
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 bgsave
sleep 10
rsync -av /data/redis/dump.rdb root@192.168.1.121:/data/backup/192.168.1.132-save/$CURHOUR/
rsync -av /data/redis/dump.rdb root@192.168.1.135:/data/backup/192.168.1.132-save/$CURHOUR/
sleep 10
date >> /data/logs/bgsave.log

從庫伺服器指令碼:

[root@cdn redis]# cat redis_backup.sh
#!/bin/bash

CURDATE=`date +%Y%m%d`
CURHOUR=`date +%Y%m%d_%H`
CURTIME=`date +%Y%m%d_%H%M%S`
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
REDISNAME=appendonly.7000
DDIR=/data/backup/redis/$CURHOUR
mkdir -p ${DDIR}
RDIR=/data/redis
cd ${RDIR}
tar -zcf $DDIR/${REDISNAME}_${CURTIME}.tar.gz appendonly.7000.aof
if [ $? != 0 ]; then
  echo "tar error $REDISNAME.aof" >> $LOGFILE
fi
sleep 5
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 bgrewriteaof
sleep 5

###  delete old backup data dir  ###
#/bin/rm -rf `date -d -30day + "%Y%m%d"`
find /data/backup/redis/ -mtime +30 | xargs rm -rf
echo "Backup $REDISNAME ok at $CURTIME !" >> $LOGFILE

[root@cdn redis]# crontab -e
59 23 * * * /bin/bash /data/redis/redis_backup.sh >/dev/null 2>&1

[root@cdn redis]# cd /data/backup/redis/20161207_13
[root@cdn 20161207_13]# ls
appendonly.7000_20161207_133131.tar.gz

-------------再看一例----------------------------------------------------------------------------------------------------------------------
公司線上一個專案資料儲存採用MySQL,共分為10個庫,分佈在4臺機器上,每個庫資料量約為10G,各機器均採用RAID5加速磁碟訪問;
當同時線上人數達高峰期(10w),DB磁碟IO壓力巨大,導致訪問巨慢,,線上人數就很難上不去了。

針對上面描述情況,使用redis後可有效解決這一瓶頸,因為Redis資料讀寫都是直接操作內。

解決方案:
將部分資料壓縮匯入到redis後,總資料量約30G(轉換成redis資料型別資料量),一主一從模型,共兩組。
一臺機器記憶體32G,開10個例項,共20個例項,多例項方便做持久化。

同樣適用於上面的redis持久化策略調整方案(思路和上面一致)

主從庫配置:
主庫:關閉save開展,aof預設不開啟,允許從庫訪問。主庫設定了密碼訪問requirepass My#redis
從庫:需增加配置:開啟AOF持久化,關閉save快照,設定密碼;
從庫10個例項的配置檔案分別為:slave6001.conf ~ slave6010.conf
slave6001.conf配置內容如下(其他例項拷貝這個,修改埠等其他資訊即可)

daemonize yes
pidfile /var/run/slave6001.pid
port 6001
timeout 300
loglevel debug
logfile /usr/local/redis/var/debug6001.log
syslog-enabled yes
databases 16
rdbcompression yes
dbfilename slave6001.rdb
dir /data/redis-data/slave6001
slaveof 192.168.0.139 6001
masterauth My#redis
slave-serve-stale-data yes
requirepass My#redis
appendonly yes
appendfilename slave6001.aof
appendfsync everysec
no-appendfsync-on-rewrite no
vm-enabled no
vm-swap-file /tmp/redis.swap
vm-max-memory 0
vm-page-size 32
vm-pages 134217728
vm-max-threads 4
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
activerehashing yes

主庫每晚12點給每個例項手動做一次bgsave快照。主庫備份指令碼(redis_bgsave.sh)

#!/bin/bash
#date=`date +%y%m%d_%H%M%S`
REDISPASSWORD=My#redis
for PORT in `seq 6001 6010`
do
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave
sleep 10
done
date >> /usr/local/redis/var/bgsave.log

從庫每晚12點拷貝每個例項的AOF到其他目錄並對其打包,壓縮包要有異地備份,之後再壓縮AOF(bgrewriteaof)。
從庫備份AOF並bgrewriteaof指令碼(redis_backup.sh :對單個例項)

#!/bin/sh
## FD:File Dir
## RD:Runing Dir
## 第一個引數為redis例項名
if [ $# -ne 1 ]; then
echo “Usage:$0  redis_name”
exit
fi
CURDATE=`date +%Y%m%d`
CURHOUR=`date +%Y%m%d_%H`
CURTIME=`date +%Y%m%d_%H%M%S`
REDISPASSWORD=My#redis
REDISNAME=$1
PORT=`echo $REDISNAME | cut -c6-9`
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
if [ "${REDISNAME}" = "" ]; then
echo “redis name Error!”
exit 1
else
if [ ! -d "/data/redis-data/${REDISNAME}" ]; then
echo “redis name Error!”
exit 1
fi
fi
DDIR=/data/backup/redis/$CURHOUR
mkdir -p ${DDIR}
RDIR=/data/redis-data/$REDISNAME
cd ${RDIR}
tar -zcf $DDIR/${REDISNAME}_${CURTIME}.tar.gz $REDISNAME.aof
if [ $? != 0 ]; then
echo “tar error $REDISNAME.aof” >> $LOGFILE
#exit 1
fi
sleep 5
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgrewriteaof
sleep 5
###  delete old backup data dir  ###
#/bin/rm -rf `date -d -7day +”%Y%m%d”`
find /data/backup/redis/ -mtime +7 | xargs rm -rf
echo “Backup $REDISNAME ok at $CURTIME !” >> $LOGFILE

從庫對所有例項備份(/data/sh/redis_allbak.sh)

#!/bin/sh
CURDATE=`date +%Y%m%d`
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
for PORT in `seq 6001 6010`
do
/data/sh/redis_backup.sh slave${PORT} && echo “slave${PORT} ok `date +%Y%m%d_%H%M%S`” >> $LOGFILE 2>&1 || echo “slave${PORT} backup error” >> $LOGFILE 2>&1
done

操作注意事項
1)若主庫掛了,不能直接開啟主庫程式。若直接開啟主庫程式將會沖掉從庫的AOF檔案,這樣將導致只能恢復到前一天晚上12的備份。
2)程式在跑時,不能重啟網路(程式是通過網路介面的埠進行讀寫的)。網路中斷將導致中斷期間資料丟失。
3)確定配置檔案全部正確才啟動(尤其不能有資料檔名相同),否則會沖掉原來的檔案,可能造成無法恢復的損失。

災難恢復
1)主庫故障,快速恢復到最近狀態描述:主庫掛了(redis程式掛了/機器當機了),從庫正常,恢復到主庫掛掉的時間點:去從庫手動做一次快照,拷貝快照到主庫相應目錄,啟動,OK。
在從庫做一次快照,轉移快照檔案到其他目錄,將快照檔案目錄拷貝到主庫相應目錄,啟動主庫,OK!
( /data/sh/redis_bgsave_cp.sh )

#!/bin/bash
REDISPASSWORD=My#redis
for PORT in `seq 6001 6010`
do
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave
sleep 5
done
sleep 15
for PORT in `seq 6001 6010`
do
SDIR=/data/redis-data/slave${PORT}/
DDIR=/data/redis_recovery/redis-data/
mkdir -p $DDIR/redis${PORT}/
cd $SDIR
cp -rf slave${PORT}.rdb $DDIR/redis${PORT}/redis${PORT}.rdb
#sleep 1
done

在主庫將原來資料目錄重新命名。
從從庫拷貝快照檔案到主庫。
啟動主庫。

2)恢復到當天12點狀態注意備份資料(當前狀態AOF+正常退出快照)!
停止redis。
解壓AOF(/data/sh/redis_untar.sh)

#!/bin/bash
DAY=20111102
SDIR=/data/backup/redis/20161102_00/
cd $SDIR
for PORT in `seq 6001 6010`
do
tar -zxf slave${PORT}_$DAY_*.tar.gz
sleep 2
done
切割AOF(/data/sh/redis_sed.sh)
#!/bin/bash
DDIR=/data/redis_recovery/
TAG=”TAG111101_1200″
for PORT in `seq 6001 6010`
do
SDIR=/data/backup/redis/20161102_00/
SAOF=${SDIR}/slave${PORT}.aof
line=`sed -n “/$TAG/=” $SAOF`
num=$[$line + 3]
mkdir -p ${DDIR}/slave${PORT}/
sed “${num},\$d” $SAOF > ${DDIR}/slave${PORT}/slave${PORT}.aof
done

將原來資料目錄重新命名。
將切割出來的AOF目錄重新命名為配置檔案的資料目錄。(註釋主從同步配置項)。
啟動從庫。
做快照,拷貝到主庫,啟動主庫(同上面第1)步)。

3)恢復到兩天或幾天前12點狀態從庫每晚備份要備份AOF未bgrewriteaof之前的資料,可根據當天晚上12點備份,沒有bfrewriteaof之前的AOF檔案來進行恢復,方法同上面的第2)步。

相關文章