Redis的數據操做都在內存中,redis崩掉的話,會丟失。Redis持久化就是對數據的更新異步的保存在磁盤上,以便數據恢復。java
將Redis內存中的數據,完整的生成一個快照,以二進制格式文件(後綴RDB)保存在硬盤當中。當須要進行恢復時,再從硬盤加載到內存中。python
Redis主從複製,用的也是基於RDB方式,作一個複製文件的傳輸。ios
save命令觸發方式(同步)redis
redis> save OK
save執行時,會形成Redis的阻塞。全部數據操做命令都要排隊等待它完成。
文件策略:新生成一個新的臨時文件,當save執行完後,用新的替換老的。vim
bgsave命令觸發方式(異步)緩存
redis> bgsave Background saving started
客戶端對Redis服務器下達bgsave命令時,Redis會fork出一個子進程進行RDB文件的生成。當RDB生成完畢後,子進程再反饋給主進程。fork子進程時也會阻塞,不過正常狀況下fork過程都很是快的。
文件策略:與save命令相同。
save與bgsave對比:安全
命令 | save | bgsave |
---|---|---|
IO類型 | 同步 | 異步 |
阻塞? | 是 | 是(發生在fork期間) |
複雜度 | O(n) | O(n) |
優勢 | 不消耗額外內存 | 不阻塞客戶端命令 |
缺點 | 阻塞客戶端命令 | fork消耗額外內存 |
規則自動觸發方式
某些條件達到時,自動生成RDB文件。
好比咱們配置以下:服務器
配置 | seconds | changes | 說明 |
---|---|---|---|
save | 900 | 1 | 900秒內改變1條數據,自動生成RDB文件 |
save | 300 | 10 | 300秒內改變10條數據,自動生成RDB文件 |
save | 60 | 10000 | 60秒內改變1萬條數據,自動生成RDB文件 |
以上任一條件達到時,都會觸發生成RDB文件。不過這種方式對RDB文件的生成頻率不太好控制。若是寫量大,RDB生成會很頻繁。不是一種好的方式。
修改配置文件:網絡
# 配置自動生成規則。通常不建議配置自動生成RDB文件 save 900 1 save 300 10 save 60 10000 # 指定rdb文件名 dbfilename dump-${port}.rdb # 指定rdb文件目錄 dir /opt/redis/data # bgsave發生錯誤,中止寫入 stop-writes-on-bgsave-error yes # rdb文件採用壓縮格式 rdbcompression yes # 對rdb文件進行校驗 rdbchecksum yes
save試驗app
cd redis cd config cp ../redis.conf cp redis.conf redis-6379.conf vim redis-6379.conf
修改以下配置:
daemonize yes pidfile /var/run/redis-6379.pid port 6379 logfile "6379.log" # 先關閉自動生成RDB的配置 # save 900 1 # save 300 10 # save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump-6379.rdb dir /opt/soft/redis/data
保存配置
:wq
# 重啓redis redis-server redis-6379.conf
# 客戶端鏈接 redis-cli
# 暫時尚未Redis內存數據 127.0.0.1:6379> dbsize (integer) 0
而後寫個簡單for循環程序,往Redis執行大量的寫命令,讓內存數據足夠大。
# 再看一下,這下內存數據有不少了 127.0.0.1:6379> dbsize (integer) 5000000 # 看下內存使用了904M,足夠用以演示save的阻塞了 127.0.0.1:6379> info memory used_memory: 948306016 used_memory_human: 904.38M used_memory_rss: 1031897088 used_memory_peak: 981827104 used_memory_peak_human: 936.34M used_memory_lua: 36864 mem_fragmentation_ratio: 1.09 mem_allocator: libc
# 執行save,發現等待了若干秒後,才輸出OK以及消耗時間 127.0.0.1:6379> save OK (8.94s)
/opt/soft/redis/data目錄下也會生成dump-6379.rdb文件。
bgsave試驗
驗證bgsave的非阻塞:
# 咱們再開一個新窗口,在新窗口上鍊接redis客戶端 redis-cli # 輸好如下命令,先別執行 127.0.0.1:6379> get hello
# 而後在原窗口執行bgsave 127.0.0.1:6379> bgsave Background saving started
# 立刻切回新窗口,回車執行命令,發現world即刻返回,驗證了bgsave的非阻塞 127.0.0.1:6379> get hello "world"
接下來驗證bgsave會生成子進程:
# 在新窗口先查看下redis進程,過濾掉客戶端和grep進程,發現就只有一個redis主進程 ps -ef | grep redis- | grep -v "redis-cli" | grep -v "grep" 501 36775 1 0 10:22下午 ?? 0:17 .86 redis-server *:6379
# 在原窗口再執行一次bgsave 127.0.0.1:6379> bgsave Background saving started
# 立刻切新窗口再次查看進程,發現多了個子進程redis-rdb-bgsave ps -ef | grep redis- | grep -v "redis-cli" | grep -v "grep" 501 36775 1 0 10:22下午 ?? 0:17 .91 redis-server *:6379 501 36954 1 0 10:28下午 ?? 0:02 .81 redis-rdb-bgsave *:6379 # 再看一次,子進程已經不在了。由於子進程已經完成了它生成rdb文件的工做 ps -ef | grep redis- | grep -v "redis-cli" | grep -v "grep" 501 36775 1 0 10:22下午 ?? 0:17 .91 redis-server *:6379
最後驗證文件策略:
# 在新窗口/data目錄查看文件 ls 6379.log dump-6379.log
# 在原窗口再執行一次bgsave 127.0.0.1:6379> bgsave Background saving started
# 切新窗口再次查看文件,多了個臨時的rdb文件 ls 6379.log dump-6379.rdb temp-36985.rdb # 過會兒再查看一次,臨時文件消失了 ls 6379.log dump-6379.rdb
自動生成試驗
這個不演示了,本身修改配置文件save 60 5,配置60秒更新5次就自動生成RDB文件。重啓redis後,咱們在客戶端用set命令執行5次。觀察/data下的rdb文件的時間戳是否變化了來驗證。
咱們也能夠查看下日誌文件6379.log,輸出了試驗過程的相關日誌內容。
就是寫日誌,每次執行Redis寫命令,讓命令同時記錄日誌(以AOF日誌格式)。Redis宕機時,只要進行日誌回放就能夠恢復數據。
首先Redis執行寫命令,將命令刷新到硬盤緩衝區當中。
三種策略對比
命令 | always | everysec | no |
---|---|---|---|
優勢 | 不丟失數據 | 只丟一秒數據 | 不用管,操做系統去管 |
缺點 | IO開銷大,通常的sata盤只有幾百TPS | 丟了一秒數據 | 不可控,不知道何時刷盤,也不知道會丟失多少數據 |
一般使用everysec策略,這也是AOF的默認策略。
隨着時間的推移,命令的逐步寫入。AOF文件也會逐漸變大。當咱們用AOF來恢復時會很慢,並且當文件無限增大時,對硬盤的管理,對寫入的速度也會有產生影響。Redis固然考慮到這個問題,因此就有了AOF重寫。
原生AOF:
set hello world set hello java set hello python incr counter incr counter rpush mylist a rpush mylist b rpush mylist c 過時數據
重寫後的AOF:
set hello python set incr 2 rpush mylist a b c
AOF重寫就是把過時的、沒用的、重複的以及可優化的命令,進行化簡。只取最終有價值的結果。雖然寫入操做很頻繁,但系統定義的key的量是相對有限的。
AOF重寫能夠大大壓縮最終日誌文件的大小。從而減小磁盤佔用量,加快數據恢復速度。好比咱們有個計數的服務,有不少自增的操做,好比有一個key自增到1個億,對AOF文件來講就是一億次incr。AOF重寫就只用記1條記錄。
AOF重寫配置
auto-aof-rewrite-min-size:AOF文件重寫須要的尺寸
auto-aof-rewrite-percentage:AOF文件增加率
redis提供了aof_current_size和aof_base_size,分別用來統計AOF當前尺寸(單位:字節)和AOF上次啓動和重寫的尺寸(單位:字節)。
AOF自動重寫的觸發時機,同時知足如下兩點):
修改配置文件:
# 開啓正常AOF的append刷盤操做 appendonly yes # AOF文件名 appendfilename "appendonly-6379.aof" # 每秒刷盤 appendfsync everysec # 文件目錄 dir /opt/soft/redis/data # AOF重寫增加率 auto-aof-rewrite-percentage 100 # AOF重寫最小尺寸 auto-aof-rewrite-min-size 64mb # AOF重寫期間是否暫停append操做。AOF重寫很是消耗磁盤性能,而正常的AOF過程當中也會往磁盤刷數據。 # 一般偏向考慮性能,設爲yes。萬一重寫失敗了,這期間正常AOF的數據會丟失,由於咱們選擇了重寫期間放棄了正常AOF刷盤。 no-appendfsync-on-rewrite yes
redis-cli 127.0.0.1:6379> dbsize (integer) 5000000 127.0.0.1:6379> exit
vim redis-6379.conf
appendonly yes appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes
配置修改後,要從新啓動redis。
appendonly是支持動態配置,不用重啓Redis:
127.0.0.1:6379> config get appendonly 1) "appendonly" 2) "no" 127.0.0.1:6379> config set appendonly yes OK # 從新加載配置 127.0.0.1:6379> config rewrite OK 127.0.0.1:6379> exit
先試驗下正常AOF刷盤
# 客戶端鏈接redis,執行一些命令: redis-cli 127.0.0.1:6379> set hello world OK 127.0.0.1:6379> set hello java OK 127.0.0.1:6379> set hello redis OK 127.0.0.1:6379> incr counter (integer) 1 127.0.0.1:6379> incr counter (integer) 2 127.0.0.1:6379> rpush list a (integer) 1 127.0.0.1:6379> rpush list b (integer) 2 127.0.0.1:6379> rpush list c (integer) 3 127.0.0.1:6379> exit
# 咱們查看data目錄,appendonly.aof文件已經生成了 cd /opt/soft/redis/data ll -rw-r--r-- 1 carlosfu staff 16K 10 7 22:28 6379.log -rw-r--r-- 1 carlosfu staff 243B 10 7 22:29 appendonly.aof -rw-r--r-- 1 carlosfu staff 18B 10 7 22:19 dump-6379.rdb
再試驗下AOF重寫
redis-cli 127.0.0.1:6379> bgrewriteaof Background append only file rewriteing started 127.0.0.1:6379> dbsize (integer) 3
# 咱們再查看data目錄,appendonly.aof文件變小了 cd /opt/soft/redis/data ll -rw-r--r-- 1 carlosfu staff 17K 10 7 22:33 6379.log -rw-r--r-- 1 carlosfu staff 137B 10 7 22:33 appendonly.aof -rw-r--r-- 1 carlosfu staff 18B 10 7 22:19 dump-6379.rdb
命令 | RDB | AOF | 說明 |
---|---|---|---|
啓動優先級 | 低 | 高 | RDB和AOF都開啓的狀況下,Redis重啓後,選擇AOF進行恢復。大部分狀況下它保存了比RDB更新的數據 |
體積 | 小 | 大 | RDB二進制模式存儲,並且作了壓縮。AOF雖然有AOF重寫,可是體積相對仍是大不少,畢竟它是記日誌形式 |
恢復速度 | 快 | 慢 | RDB體積小,恢復速度快。AOF體積大,恢復速度慢 |
數據安全 | 丟數據 | 根據策略決定 | RDB丟上次快照後的數據,AOF根據always、everysec、no策略決定是否丟數據 |
輕重 | 重 | 輕 | AOF是追加日誌,因此比較輕的操做。而RDB是CPU密集型操做,對磁盤,以及fork時對內存的消耗都比較大 |
fork是一個同步操做。執行bgsave和bgrewriteaof時都會執行fork操做,
改善fork
bgsave和bgrewriteaof會進行fork操做產生子進程。
CPU
內存
硬盤
優化:
AOF阻塞定位
redis日誌:
Asynchronous AOF fsync is taking to long(disk is busy?). Writing the AOF buffer whitout waiting for fsync to complete, this may slow down Redis
info persistence
能夠查看上述日誌發生的次數。
127.0.0.1:6379> info persistence ...... ...... aof_delayed_fsync: 100 ...... ......
改善方式 同子進程的硬盤優化