redis持久化策略梳理及主从环境下的策略调整记录
轉載自?https://www.cnblogs.com/kevingrace/p/6266319.html
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推薦同時使用bgrewriteaof。AOF 重寫和 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的主從功能 ,半小時備份一次應該是可以了;并且如果應用數據量不大的話,可以單機部署,做主從有點浪費。具體還是要根據應用而定。
接著具體解說下這兩種持久化:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 如果的內存中的數據量非常大的時候,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的二進制文件中??梢詫edis 進行設置, 讓它在“ 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上面。
| 1 2 3 4 5 6 7 8 9 | [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 |
從庫服務器腳本:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [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配置內容如下(其他實例拷貝這個,修改端口等其他信息即可)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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)
| 1 2 3 4 5 6 7 8 9 | #!/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 :對單個實例)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/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)
| 1 2 3 4 5 6 7 | #!/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 )
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/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)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/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)步。
***************當你發現自己的才華撐不起野心時,就請安靜下來學習吧***************
總結
以上是生活随笔為你收集整理的redis持久化策略梳理及主从环境下的策略调整记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RabbitMQ学习之消息可靠性及特性
- 下一篇: SpringBoot切换Tomcat容器