Redis笔记4-持久化方案
一:快照模式
默認redis是會以快照的形式將數據持久化到磁盤的(一個二進制文件,dump.rdb,這個文件名字可以指定),在配置文件中的格式是:save N M表示在N秒之內,redis至少發生M次修改則redis抓快照到磁盤。當然我們也可以手動執行save或者bgsave(異步)做快照。
工作原理簡單介紹一下:當redis需要做持久化時,redis會fork一個子進程;子進程將數據寫到磁盤上一個臨時RDB文件中;當子進程完成寫臨時文件后,將原來的RDB替換掉,這樣的好處就是可以copy-on-write
如下圖:
上面三組命令也是非常好理解的,就是說900指的是“秒數”,1指的是“change次數”,接下來如果在“900s“內至少有1次更改,那么就執行save保存,同樣
的道理,如果300s內至少有10次change,60s內至少有1w次change,那么也會執行save操作。
以上是redis自身進行的同步操作。
下面是我們可以以手工執行save
redis提供了兩個操作命令:save,bgsave,這兩個命令都會強制將數據刷新到硬盤中,如下圖:
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 重寫的執行間隔有多長,數據的耐久性都不會有任何損失。
?
二:AOF(Append-only file)
filesnapshotting方法在redis異常死掉時,最近的數據會丟失(丟失數據的多少視你save策略的配置),所以這是它最大的缺點,當業務量很大時,丟失的數據是很多的。Append-only方法可以做到全部數據不丟失,
但redis的性能就要差些。AOF就可以做到全程持久化,只需要在配置文件中開啟(默認是no),appendonly yes開啟AOF之后,redis每執行一個修改數據的命令,都會把它添加到aof文件中,當redis重啟時,將會讀取AOF文件進行“重放”以恢復到redis關閉前的最后時刻。
AOF文件刷新的方式,有三種,參考配置參數appendfsync?:
appendfsync always每提交一個修改命令都調用fsync刷新到AOF文件,非常非常慢,但也非常安全;
appendfsync everysec每秒鐘都調用fsync刷新到AOF文件,很快,但可能會丟失一秒以內的數據;
appendfsync no依靠OS進行刷新,redis不主動刷新AOF,這樣最快,但安全性就差。默認并推薦每秒刷新,這樣在速度和安全上都做到了兼顧。
?
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 的。
?
可能由于系統原因導致了AOF損壞,redis無法再加載這個AOF,可以按照下面步驟來修復:首先做一個AOF文件的備份,復制到其他地方;修復原始AOF文件,執行:$ redis-check-aof –fix ;可以通過diff –u命令來查看修復前后文件不一致的地方;重啟redis服務。
LOG Rewrite的工作原理:同樣用到了copy-on-write:首先redis會fork一個子進程;子進程將最新的AOF寫入一個臨時文件;父進程增量的把內存中的最新執行的修改寫入(這時仍寫入舊的AOF,rewrite如果失敗也是安全的);當子進程完成rewrite臨時文件后,父進程會收到一個信號,并把之前內存中增量的修改寫入臨時文件末尾;這時redis將舊AOF文件重命名,臨時文件重命名,開始向新的AOF中寫入。
最后,為以防萬一(機器壞掉或磁盤壞掉),記得定期把使用 filesnapshotting 或 Append-only 生成的*rdb *.aof文件備份到遠程機器上。我是用crontab每半小時SCP一次。我沒有使用redis的主從功能 ,因為半小時備份一次應該是可以了,而且我覺得有如果做主從有點浪費機器。這個最終還是看應用來定了。
?
《Redis官方文檔》使用Redis作為LRU緩存
?
如果你使用redis作為緩存,當添加新數據時,若有內存大小等限制,系統默認會根據一定的規則自動清理舊數據。這種處理方式在開發社區中眾所周知,因為它也是非常流行的緩存系統 memcached 的默認處理方式。
LRU(LRU全稱是Least?Recently Used,即最近最久未使用)實際上只是Redis支持的內存回收策略中的一種,
Redis的?maxmemory 配置選項,該配置選項用來限制 Redis 的內存使用大小,同時深入研究 LRU(確切的說是近似LRU算法) 算法在 Redis 中的應用。
?
最大內存配置選項
maxmemory 配置選項使用來配置 Redis 的存儲數據所能使用的最大內存限制。可以通過在內置文件redis.conf中配置,也可在Redis運行時通過命令CONFIG SET來配置。例如,我們要配置內存上限是100M的Redis緩存,那么我們可以在 redis.conf 配置如下:
maxmemory 100mb
?
設置 maxmemory 為 0 表示沒有內存限制。在 64-bit 系統中,默認是 0 無限制,但是在 32-bit 系統中默認是 3GB。
當存儲數據達到限制時,Redis 會根據情形選擇不同策略,或者返回errors(這樣會導致浪費更多的內存),或者清除一些舊數據回收內存來添加新數據
?
回收策略
當內存達到限制時,Redis 具體的回收策略是通過 maxmemory-policy 配置項配置的。
以下的策略都是可用的:
- noenviction:不清除數據,只是返回錯誤,這樣會導致浪費掉更多的內存,對大多數寫命令(DEL 命令和其他的少數命令例外)
- allkeys-lru:從所有的數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰,以供新數據使用
- volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰,以供新數據使用
- allkeys-random:從所有數據集(server.db[i].dict)中任意選擇數據淘汰,以供新數據使用
- volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰,以供新數據使用
- volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰,以供新數據使用
當 cache 中沒有符合清除條件的 key 時,回收策略 volatile-lru, volatile-random 和volatile-ttl 將會和 策略 noeviction 一樣返回錯誤。選擇正確的回收策略是很重要的,取決于你的應用程序的訪問模式。但是,你可以在程序運行時重新配置策略,使用 INFO 輸出來監控緩存命中和錯過的次數,以調優你的設置。
?
普適經驗規則:
- 如果期望用戶請求呈現冪律分布(power-law distribution),也就是,期望一部分子集元素被訪問得遠比其他元素多時,可以使用allkeys-lru策略。在你不確定時這是一個好的選擇。
- 如果期望是循環周期的訪問,所有的鍵被連續掃描,或者期望請求符合平均分布(每個元素以相同的概率被訪問),可以使用allkeys-random策略。
- 如果你期望能讓 Redis 通過使用你創建緩存對象的時候設置的TTL值,確定哪些對象應該是較好的清除候選項,可以使用volatile-ttl策略。
當你想使用單個Redis實例來實現緩存和持久化一些鍵,allkeys-lru和volatile-random策略會很有用。但是,通常最好是運行兩個Redis實例來解決這個問題。
另外值得注意的是,為鍵設置過期時間需要消耗內存,所以使用像allkeys-lru這樣的策略會更高效,因為在內存壓力下沒有必要為鍵的回收設置過期時間。
?
回收過程
理解回收過程是運作流程非常的重要,回收過程如下:
- 一個客戶端運行一個新命令,添加了新數據。
- Redis檢查內存使用情況,如果大于maxmemory限制,根據策略來回收鍵。
- 一個新的命令被執行,如此等等。
我們添加數據時通過檢查,然后回收鍵以返回到限制以下,來連續不斷的穿越內存限制的邊界。
如果一個命令導致大量的內存被占用(比如一個很大的集合保存到一個新的鍵),那么內存限制很快就會被這個明顯的內存量所超越。
近似LRU算法
Redis的LRU算法不是一個嚴格的LRU實現。這意味著Redis不能選擇最佳候選鍵來回收,也就是最久未被訪問的那些鍵。相反,Redis 會嘗試執行一個近似的LRU算法,通過采樣一小部分鍵,然后在采樣鍵中回收最適合(擁有最久訪問時間)的那個。
然而,從Redis3.0開始,算法被改進為維護一個回收候選鍵池。這改善了算法的性能,使得更接近于真實的LRU算法的行為。Redis的LRU算法有一點很重要,你可以調整算法的精度,通過改變每次回收時檢查的采樣數量。
這個參數可以通過如下配置指令:
maxmemory-samples 5
Redis沒有使用真實的LRU實現的原因,是因為這會消耗更多的內存。然而,近似值對使用Redis的應用來說基本上也是等價的。下面的圖形對比,為Redis使用的LRU近似值和真實LRU之間的比較。
用于測試生成了上面圖像的Redis服務被填充了指定數量的鍵。鍵被從頭訪問到尾,所以第一個鍵是LRU算法的最佳候選回收鍵。然后,再新添加50%的鍵,強制一般的舊鍵被回收。
你可以從圖中看到三種不同的原點,形成三個不同的帶。
- 淺灰色帶是被回收的對象
- 灰色帶是沒有被回收的對象
- 綠色帶是被添加的對象
在理論的LRU實現中,我們期望看到的是,在舊鍵中第一半會過期。而Redis的LRU算法則只是概率性的過期這些舊鍵。 你可以看到,同樣使用5個采樣點,Redis 3.0表現得比Redis 2.8要好,Redis 2.8中最近被訪問的對象之間的對象仍然被保留。在Redis 3.0中使用10為采樣大小,近似值已經非常接近理論性能。
注意,LRU只是一個預測模型用來指定鍵在未來如何被訪問。另外,如果你的數據訪問模式非常接近冪律,大多數的訪問都將集中在一個集合中,LRU近似算法將能處理得很好。
在模擬實驗的過程中,我們發現使用冪律訪問模式,真實的LRU算法和Redis的近似算法之間的差異非常小,或者根本就沒有。然而,你可以提高采樣大小到10,這會消耗額外的CPU,來更加近似于真實的LRU算法,看看這會不會使你的緩存錯失率有差異。
使用CONFIG SET maxmemory-samples <count>命令在生產環境上試驗各種不同的采樣大小值是很簡單的。
轉載于:https://www.cnblogs.com/huangjuncong/p/8489343.html
總結
以上是生活随笔為你收集整理的Redis笔记4-持久化方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第七章课后习题
- 下一篇: 转:Linux设备驱动开发(1):内核基