redis持久化和監控
redis 主從複製
Redis主從複製的原理
當建立主從關係時,slave配置slaveof <master_host> <master_port> 。slave伺服器會向主伺服器傳送一個sync命令。master接受並fork一個程序來執行BGSAVE命令。該命令生成一個RDB檔案並且全量傳送給slave伺服器,slave伺服器接收並載入RDB檔案,同時,主伺服器將緩衝區的命令以增量的方式傳送給從伺服器,最終使從伺服器的資料狀態和主伺服器保持一致。
RDB的工作原理
當redis生成dump.rdb檔案時,工作過程如下
-
redis主程序fork一個子程序
-
fork出來的子程序將記憶體的資料集dump到臨時的RDB中
-
當子程序對臨時的RDB檔案寫入完畢,redis用新的RDB檔案代替舊的RDB檔案
AOF的工作原理
AOF :append only file。每當Redis執行一個改變資料集的命令時,這個命令都會被追加到AOF檔案的末尾。當redis重新啟動時,程式可以通過AOF檔案恢復資料
持久化檔案監控
Redis 監控最直接的方法當然就是使用系統提供的 info 命令來做了,只需要執行下面一條命令,就能獲得 Redis 系統的狀態報告。
redis-cli info
RDB檔案狀態監控
其中跟RDB檔案狀態監控相關的引數
-
rdb_changes_since_last_save 表明上次RDB儲存以後改變的key次數
-
rdb_bgsave_in_progress 表示當前是否在進行bgsave操作。是為1
-
rdb_last_save_time 上次儲存RDB檔案的時間戳
-
rdb_last_bgsave_time_sec 上次儲存的耗時
-
rdb_last_bgsave_status 上次儲存的狀態
-
rdb_current_bgsave_time_sec 目前儲存RDB檔案已花費的時間
AOF檔案狀態監控
其中跟AOF檔案狀態監控相關的引數
-
aof_enabled AOF檔案是否啟用
-
aof_rewrite_in_progress 表示當前是否在進行寫入AOF檔案操作
-
aof_rewrite_scheduled
-
aof_last_rewrite_time_sec 上次寫入的時間戳
-
aof_current_rewrite_time_sec:-1
-
aof_last_bgrewrite_status:ok 上次寫入狀態
-
aof_last_write_status:ok 上次寫入狀態
檢視rdb檔案生成耗時
在我們優化master之前,可以看看目前我們的其中一個生產環境的的redis的持久化狀態
# Persistence
loading:0
rdb_changes_since_last_save:116200
rdb_bgsave_in_progress:1
rdb_last_save_time:1448944451
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:85
rdb_current_bgsave_time_sec:33
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
通過redis-cli的info命令,可以看到 「rdb_last_bgsave_time_sec」引數的值,
這個值表示上次bgsave命令執行的時間。在磁碟IO定量的情況下,redis佔用的記憶體越大,
這個值也就越大。通常「rdb_last_bgsave_time_sec」這個時間取決於兩個因素:
-
REDIS佔用的記憶體大小
-
磁碟的寫速度。
rdb_last_bgsave_time_sec:85
這個標識表示我們上次儲存dump RDB檔案的時間。這個耗時受限於上面提到的兩個因素。
當redis處於 rdb_bgsave_in_progress狀態時,通過vmstat命令檢視效能,得到wa值偏高,也就是說CPU在等待
IO的請求完成,我們線上的一個應用redis佔用的記憶體是5G左右,也就是redis會生成大約5G左右的dump.rdb檔案
vmstat命令
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 4 0 223912 2242680 5722008 0 0 200 48648 3640 5443 1 1 63 35 0
0 3 0 222796 2242680 5722052 0 0 16 48272 2417 5019 1 1 63 35 0
0 3 0 222300 2242680 5722092 0 0 40 24612 3042 3568 1 1 63 35 0
0 3 0 220068 2242680 5722124 0 0 64 40328 4304 4737 2 1 63 34 0
0 3 0 218952 2242680 5722216 0 0 100 48648 4966 5786 1 2 63 35 0
0 3 0 215356 2242680 5722256 0 0 0 66168 3546 4382 2 1 62 35 0
通過上面的輸出,看到BGSAVE 對於IO的效能影響比較大
那麼該如何解決由RDB檔案帶來的效能上不足的問題,又能保證資料持久化的目的
通常的設計思路就是利用「Replication」機制來解決:即master不開啟RDB日誌和AOF日誌,來保證master的讀寫效能。而slave則開啟rdb和aof來進行持久化,保證資料的永續性,
建立主從複製步驟和災難恢復
我在測試機器上,開啟兩個例項,埠分別為6379和6380
master: 172.16.76.232 6379
slave: 172.16.76.232 6380
修改配置
修改master的redis.conf
關閉RDB
# save 900 1
# save 300 10
# save 60 10000
關閉AOF
appendonly no
分別啟動master和slave的redis
service redis start
修改slave配置,指向master伺服器
redis-cli > slaveof 172.16.76.232 6379
檢視slave的複製狀態
redis-cli > info replication
指令碼模擬填充資料
#!/bin/bash
ID=1
while(($ID<50001))
do
redis-cli set "my:$ID" "aaa_okthisis_Omb5EVIwBgPHgbRj64raygpeRLKaNhyB9sLF_$ID"
redis-cli set "your:$ID" "your_okthisis_Omb5EVIwBgPHgbRj64raygpeRLKaNhyB9sLF_$ID"
redis-cli set "her:$ID" "her_okthisis_Omb5EVIwBgPHgbRj64raygpeRLKaNhyB9sLF_$ID"
redis-cli set "his:$ID" "his_okthisis_Omb5EVIwBgPHgbRj64raygpeRLKaNhyB9sLF_$ID"
ID=$(($ID+1))
done
kill掉master例項模擬災難
master redis > killall -9 redis-server
SLAVE redis > SLAVEOF NO ONE
取消Slave的同步,避免主庫在未完成資料恢復前就重啟,進而直接覆蓋掉從庫上的資料,導致所有的資料丟失。
將slave上的RDB和AOF複製到master資料資料夾中
cp /data/redis_data_slave/dump.rdb /data/redis_data/
cp /data/redis_data_slave/Append.AOF /data/redis_data/
啟動master的例項
master redis > dbsize
檢視資料是否恢復
重新開啟slave複製
slave redis > slaveof 172.16.76.232 6379
故障案例報告
redis丟失資料案例
背景介紹:
我們的一臺redis伺服器,硬體配置為4核,4G記憶體。redis持久話方案是RDB。前面幾個月redis使用的
記憶體在1G左右。在一次重啟之後,redis只恢復了部分資料,這時檢視redis.log檔案。看見了如下的錯誤
[23635] 25 Jul 08:30:54.059 * 10000 changes in 60 seconds. Saving...
[23635] 25 Jul 08:30:54.059 # Can't save in background: fork: Cannot allocate memory
這時,想起了redis啟動時的警告
WARNING overcommit_memory is set to 0!
Background save may fail under low memory condition.
To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and
then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
翻譯
警告:過量使用記憶體設定為0!在低記憶體環境下,後臺儲存可能失敗。為了修正這個問題,
請在/etc/sysctl.conf 新增一項 'vm.overcommit_memory = 1' ,
然後重啟(或者執行命令'sysctl vm.overcommit_memory=1' )使其生效。
vm.overcommit_memory不同的值說明
-
0 表示檢查是否有足夠的記憶體可用,如果是,允許分配;如果記憶體不夠,拒絕該請求,並返回一個錯誤給應用程式。
-
1 允許分配超出實體記憶體加上交換記憶體的請求
-
2 核心總是返回true
redis的資料回寫機制分為兩種
-
同步回寫即SAVE命令。redis主程序直接寫資料到磁碟。當資料量大時,這個命令將阻塞,響應時間長
-
非同步回寫即BGSAVE命令。redis 主程序fork一個子程序,複製主程序的記憶體並通過子程序回寫資料到磁碟。
由於RDB檔案寫的時候fork一個子程序。相當於複製了一個記憶體映象。當時系統的記憶體是4G,而redis佔用了
近3G的記憶體,因此肯定會報記憶體無法分配。如果 「vm.overcommit_memory」設定為0,在可用記憶體不足的情況
下,就無法分配新的記憶體。如果 「vm.overcommit_memory」設定為1。 那麼redis將使用交換記憶體。
解決辦法:
-
方法一: 修改核心引數 vi /etc/sysctl。設定
vm.overcommit_memory = 1
然後執行``` sysctl -p ```
-
方法二: 使用交換記憶體並不是一個完美的方案。最好的辦法是擴大實體記憶體。
複製有可能碰到的問題
使用slaveof命令後,長時間看不到資料同步。以為複製功能失效,或配置錯了。其實,不用擔心,有兩種方法可以確定是否正在建立複製。
在建立Redis複製時,一開始可能會發現Slave長時間不開始同步資料,可能資料量太大,導致了Master正在dump資料慢,此時如果你在Master上執行「top -p $(pgrep -d, redis-server)」命令,就能看到dump的過程
方式一: 通過「top」命令
[[email protected]_u ~]# top -p $(pgrep -d, redis-server)
top - 14:06:24 up 54 days, 6:13, 1 user, load average: 1.18, 1.32, 1.20
Tasks: 2 total, 1 running, 1 sleeping, 0 stopped, 0 zombie
Cpu(s): 15.2%us, 1.7%sy, 0.6%ni, 81.9%id, 0.2%wa, 0.0%hi, 0.4%si, 0.0%st
Mem: 24542176k total, 22771848k used, 1770328k free, 2245720k buffers
Swap: 524280k total, 0k used, 524280k free, 4369452k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21619 root 20 0 5654m 5.4g 388 R 99.9 23.0 0:23.70 redis-server
1663 root 20 0 5654m 5.4g 1068 S 15.3 23.0 5042:31 redis-server
redis-server是單程序的,現在通過「top」命令檢視已經有2個程序,因為之前提到的,redis在建立複製的時,會在
主伺服器上執行 BGSAVE 命令。fork一個子程序,dump出RDB檔案。 master dump 完畢,然後再將快照檔案傳給slave。
方式二:通過「rdb_bgsave_in_progress」標識
進入master的redis-cli
redis-cli > info persistence
...
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:1
rdb_last_save_time:1448992510
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:4
rdb_current_bgsave_time_sec:1
...
如果「rdb_bgsave_in_progress」為1,那麼master正在進行bgsave命令。同時「rdb_current_bgsave_time_sec」
顯示bgsave命令已經執行的時間。由於在master伺服器上預設不開啟RDB和AOF日誌,如果「rdb_bgsave_in_progress」為1,那麼就可以肯定由於複製原因傳送一個「bgsave」指令 dump 出 RDB 檔案。
redis 記憶體達到上限
有運營的同事反應,系統在登入的情況下,操作時會無緣無故跳到登入頁面。 由於我們的系統做了分散式的
session,預設把session放到redis裡,按照以往的故障經驗。可能是redis使用了最大記憶體上限
導致了無法設定key。 登入 redis 伺服器檢視 redis.conf 檔案設定了最大8G記憶體「maxmemory 8G」
然後通過「redis-cli info memory 」 查詢到目前的記憶體使用情況 「used_memory_human:7.71G」
接著通過redis-cli工具設定值 。報錯 「OOM command not allowed when used memory 」。再次
驗證了redis伺服器已經達到了最大記憶體
解決方法:
-
關閉redis 伺服器
redis-cli shutdown
-
修改配置檔案的最大記憶體 「maxmemory」
-
啟動redis伺服器
redis-server redis.conf