redis是一個記憶體資料庫,資料儲存在記憶體中,但是我們都知道記憶體的資料變化是很快的,也容易發生丟失。幸好Redis還為我們提供了持久化的機制,分別是RDB(Redis DataBase)和AOF(Append Only File)。
持久化過程
客戶端向服務端傳送寫操作(資料在客戶端的記憶體中)。
資料庫服務端接收到寫請求的資料(資料在服務端的記憶體中)。
服務端呼叫write這個系統呼叫,將資料往磁碟上寫(資料在系統記憶體的緩衝區中)。
作業系統將緩衝區中的資料轉移到磁碟控制器上(資料在磁碟快取中)。
磁碟控制器將資料寫到磁碟的物理介質中(資料真正落到磁碟上)。
這5個過程是在理想條件下一個正常的儲存流程,但是在大多數情況下,我們的機器等等都會有各種各樣的故障,這裡劃分了兩種情況:
Redis資料庫發生故障,只要在上面的第三步執行完畢,那麼就可以持久化儲存,剩下的兩步由作業系統替我們完成。
作業系統發生故障,必須上面5步都完成才可以。
RDB機制
RDB其實就是把資料以快照的形式儲存在磁碟上。什麼是快照呢,你可以理解成把當前時刻的資料拍成一張照片儲存下來。
RDB持久化是指在指定的時間間隔內將記憶體中的資料集快照寫入磁碟。也是預設的持久化方式,這種方式是就是將記憶體中資料以快照的方式寫入到二進位制檔案中,預設的檔名為dump.rdb。
可以在配置檔案中指定檔名和檔案路徑
在我們安裝了redis之後,所有的配置都是在redis.conf檔案中,裡面儲存了RDB和AOF兩種持久化機制的各種配置。
既然RDB機制是通過把某個時刻的所有資料生成一個快照來儲存,那麼就應該有一種觸發機制,是實現這個過程。對於RDB來說,提供了三種機制:save、bgsave、自動化。我們分別來看一下
save
該命令會阻塞當前Redis伺服器,執行save命令期間,Redis不能處理其他命令,直到RDB過程完成為止。具體流程如下:
執行完成時候如果存在老的RDB檔案,就把新的替代掉舊的。我們的客戶端可能都是幾萬或者是幾十萬,這種方式顯然不可取。
bgsave
執行該命令時,Redis會在後臺非同步進行快照操作,快照同時還可以響應客戶端請求。具體流程如下:
具體操作是Redis程式執行fork操作建立子程式,RDB持久化過程由子程式負責,完成後自動結束。阻塞只發生在fork階段,一般時間很短。基本上 Redis 內部所有的RDB操作都是採用 bgsave 命令。
自動觸發
①save:這裡是用來配置觸發 Redis的 RDB 持久化條件,也就是什麼時候將記憶體中的資料儲存到硬碟。比如“save m n”。表示m秒內資料集存在n次修改時,自動觸發bgsave。
預設如下配置:
#表示900 秒內如果至少有 1 個 key 的值變化,則儲存save 900 1
#表示300 秒內如果至少有 10 個 key 的值變化,則儲存save 300 10
#表示60 秒內如果至少有 10000 個 key 的值變化,則儲存save 60 10000
不需要持久化,那麼你可以註釋掉所有的 save 行來停用儲存功能。
②stop-writes-on-bgsave-error :預設值為yes。當啟用了RDB且最後一次後臺儲存資料失敗,Redis是否停止接收資料。這會讓使用者意識到資料沒有正確持久化到磁碟上,否則沒有人會注意到災難(disaster)發生了。如果Redis重啟了,那麼又可以重新開始接收資料了
③rdbcompression ;預設值是yes。對於儲存到磁碟中的快照,可以設定是否進行壓縮儲存。
④rdbchecksum :預設值是yes。在儲存快照後,我們還可以讓redis使用CRC64演算法來進行資料校驗,但是這樣做會增加大約10%的效能消耗,如果希望獲取到最大的效能提升,可以關閉此功能。
我們可以修改這些配置來實現我們想要的效果。因為第三種方式是配置的,所以我們對前兩種進行一個對比:
RDB 的優勢和劣勢
①、優勢
(1)RDB檔案緊湊,全量備份,非常適合用於進行備份和災難恢復。
(2)生成RDB檔案的時候,redis主程式會fork()一個子程式來處理所有儲存工作,主程式不需要進行任何磁碟IO操作。
(3)RDB 在恢復大資料集時的速度比 AOF 的恢復速度要快。
②、劣勢
RDB快照是一次全量備份,儲存的是記憶體資料的二進位制序列化形式,儲存上非常緊湊。當進行快照持久化時,會開啟一個子程式專門負責快照持久化,子程式會擁有父程式的記憶體資料,父程式修改記憶體子程式不會反應出來,所以在快照持久化期間修改的資料不會被儲存,可能丟失資料。
AOF機制
全量備份總是耗時的,有時候我們提供一種更加高效的方式AOF,工作機制很簡單,redis會將每一個收到的寫命令都通過write函式追加到檔案中。通俗的理解就是日誌記錄。
1、持久化原理
他的原理看下面這張圖:
每當有一個寫命令過來時,就直接儲存在我們的AOF檔案中。
2、檔案重寫原理
AOF的方式也同時帶來了另一個問題。持久化檔案會變的越來越大。為了壓縮aof的持久化檔案。redis提供了bgrewriteaof命令。將記憶體中的資料以命令的方式儲存到臨時檔案中,同時會fork出一條新程式來將檔案重寫。
重寫aof檔案的操作,並沒有讀取舊的aof檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似。
3、AOF也有三種觸發機制
(1)每修改同步always:同步持久化 每次發生資料變更會被立即記錄到磁碟 效能較差但資料完整性比較好
(2)每秒同步everysec:非同步操作,每秒記錄 如果一秒內當機,有資料丟失
(3)不同no:從不同步
4.AOF配置
表示是否開啟AOF持久化:appendonly yes(預設no,關閉)
AOF持久化配置檔案的名稱:appendfilename “appendonly.aof”
AOF持久化策略(預設每秒):
appendfsync always (同步持久化,每次發生資料變更會被立即記錄到磁碟,效能差但資料完整性比較好)
appendfsync everysec (非同步操作,每秒記錄,如果一秒鐘內當機,有資料丟失)
appendfsync no (將快取回寫的策略交給系統,linux 預設是30秒將緩衝區的資料回寫硬碟的)
bgrewriteaof機制,在一個子程式中進行aof的重寫,從而不阻塞主程式對其餘命令的處理,同時解決了aof檔案過大問題。在執行bgrewriteaof操作和主程式寫aof檔案的操作,兩者都會操作磁碟,而bgrewriteaof往往會涉及大量磁碟操作,這樣就會造成主程式在寫aof檔案的時候出現阻塞的情形,現在no-appendfsync-on-rewrite引數出場了。如果該引數設定為no,是最安全的方式,不會丟失資料,但是要忍受阻塞的問題。如果設定為yes呢?這就相當於將appendfsync設定為no,這說明並沒有執行磁碟操作,只是寫入了緩衝區,因此這樣並不會造成阻塞(因為沒有競爭磁碟),但是如果這個時候redis掛掉,就會丟失資料
no-appendfsync-on-rewrite no
Redis會記錄上次重寫時的AOF檔案大小,預設配置時當AOF檔案大小是上次rewrite後大小的一倍且檔案大於64M時觸發
auto-aof-rewrite-percentage 100 (一倍)
auto-aof-rewrite-min-size 64mb
指redis在恢復時,會忽略最後一條可能存在問題的指令。預設值yes。即在aof寫入時,可能存在指令寫錯的問題(突然斷電,寫了一半),這種情況下,yes會log並繼續,而no會直接恢復失敗.
aof-load-truncated yes
允許使用RDB-AOF混合持久化的方式結合了兩者的優點通過aof-use-rdb-preamble配置項可以開啟混合開關
aof-use-rdb-preamble yes
RDB 的優勢和劣勢
①優點
(1)AOF可以更好的保護資料不丟失,一般AOF會每隔1秒,通過一個後臺執行緒執行一次fsync操作,最多丟失1秒鐘的資料。
(2)AOF日誌檔案沒有任何磁碟定址的開銷,寫入效能非常高,檔案不容易破損。
(3)AOF日誌檔案即使過大的時候,出現後臺重寫操作,也不會影響客戶端的讀寫。
(4)AOF日誌檔案的命令通過非常可讀的方式進行記錄,這個特性非常適合做災難性的誤刪除的緊急恢復。比如某人不小心用flushall命令清空了所有資料,只要這個時候後臺rewrite還沒有發生,那麼就可以立即拷貝AOF檔案,將最後一條flushall命令給刪了,然後再將該AOF檔案放回去,就可以通過恢復機制,自動恢復所有資料
②缺點
(1)對於同一份資料來說,AOF日誌檔案通常比RDB資料快照檔案更大
(2)AOF開啟後,支援的寫QPS會比RDB支援的寫QPS低,因為AOF一般會配置成每秒fsync一次日誌檔案,當然,每秒一次fsync,效能也還是很高的
(3)以前AOF發生過bug,就是通過AOF記錄的日誌,進行資料恢復的時候,沒有恢復一模一樣的資料出來。
RDB和AOF到底該如何選擇
redis主從複製
和Mysql主從複製的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會產生讀壓力特別大的情況。為了分擔讀壓力,Redis支援主從複製,Redis的主從結構可以採用一主多從或者級聯結構,Redis主從複製可以根據是否是全量分為全量同步和增量同步。下圖為級聯結構。
全量同步
Redis全量複製一般發生在Slave初始化階段,這時Slave需要將Master上的所有資料都複製一份。具體步驟如下:
- 從伺服器連線主伺服器,傳送SYNC命令;
- 主伺服器接收到SYNC命名後,開始執行BGSAVE命令生成RDB檔案並使用緩衝區記錄此後執行的所有寫命令;
- 主伺服器BGSAVE執行完後,向所有從伺服器傳送快照檔案,並在傳送期間繼續記錄被執行的寫命令;
- 從伺服器收到快照檔案後丟棄所有舊資料,載入收到的快照;
- 主伺服器快照傳送完畢後開始向從伺服器傳送緩衝區中的寫命令;
- 從伺服器完成對快照的載入,開始接收命令請求,並執行來自主伺服器緩衝區的寫命令;
完成上面幾個步驟後就完成了從伺服器資料初始化的所有操作,從伺服器此時可以接收來自使用者的讀請求。
增量同步
Redis增量複製是指Slave初始化後開始正常工作時主伺服器發生的寫操作同步到從伺服器的過程。
增量複製的過程主要是主伺服器每執行一個寫命令就會向從伺服器傳送相同的寫命令,從伺服器接收並執行收到的寫命令。
Redis主從同步策略
主從剛剛連線的時候,進行全量同步;全同步結束後,進行增量同步。當然,如果有需要,slave 在任何時候都可以發起全量同步。redis 策略是,無論如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
注意點
如果多個Slave斷線了,需要重啟的時候,因為只要Slave啟動,就會傳送sync請求和主機全量同步,當多個同時出現的時候,可能會導致Master IO劇增當機。
主從複製的一些特點:
1)採用非同步複製;
2)一個主redis可以含有多個從redis;
3)每個從redis可以接收來自其他從redis伺服器的連線;
4)主從複製對於主redis伺服器來說是非阻塞的,這意味著當從伺服器在進行主從複製同步過程中,主redis仍然可以處理外界的訪問請求;
5)主從複製對於從redis伺服器來說也是非阻塞的,這意味著,即使從redis在進行主從複製過程中也可以接受外界的查詢請求,只不過這時候從redis返回的是以前老的資料,如果你不想這樣,那麼在啟動redis時,可以在配置檔案中進行設定,那麼從redis在複製同步過程中來自外界的查詢請求都會返回錯誤給客戶端;(雖然說主從複製過程中對於從redis是非阻塞的,但是當從redis從主redis同步過來最新的資料後還需要將新資料載入到記憶體中,在載入到記憶體的過程中是阻塞的,在這段時間內的請求將會被阻,但是即使對於大資料集,載入到記憶體的時間也是比較多的);
6)主從複製提高了redis服務的擴充套件性,避免單個redis伺服器的讀寫訪問壓力過大的問題,同時也可以給為資料備份及冗餘提供一種解決方案;
7)為了編碼主redis伺服器寫磁碟壓力帶來的開銷,可以配置讓主redis不在將資料持久化到磁碟,而是通過連線讓一個配置的從redis伺服器及時的將相關資料持久化到磁碟,不過這樣會存在一個問題,就是主redis伺服器一旦重啟,因為主redis伺服器資料為空,這時候通過主從同步可能導致從redis伺服器上的資料也被清空;
實踐配置redis主從複製
由於redis為單執行緒模式,所以我們可以在一個伺服器上部署多個redis服務
複製兩個配置檔案,其他6379和6380為兩個redis使用的埠號
cp redis.conf redis-6379.conf
cp redis.conf redis-6380.conf
修改redis-6380.conf中的配置項
修改監聽埠port 6380
修改pid執行檔案pidfile /var/run/redis_6380.pid
關閉rdb備份#save 900 1
#save 300 10
#save 60 10000
使用命令開啟兩個redis服務./redis-server redis-6379.conf
./redis-server redis-6380.conf
使用命令ps -ef | grep redis
檢視程式狀態,表示6379和6380的redis埠狀態已開啟
從伺服器配置
配置slaveof項,對應主伺服器的ip和埠slaveof 127.0.0.1 6379
如果主伺服器有配置密碼,需要新增masterauth + 密碼配置項masterauth xxx
配置完成後重啟redis服務
檢視6379埠的redis,使用info replication檢視資訊
設定一個鍵值測試
檢視6380埠的redis,使用info replication檢視資訊
檢視設定的鍵值
可以檢視到從伺服器已同步了主伺服器資料
本作品採用《CC 協議》,轉載必須註明作者和本文連結