redis演练(5) redis持久化
何謂持久化,就是媳婦讓你,持久一些。
說白了持久化:就是將內存中的數據保存到磁盤上的過程(數據庫也算磁盤的特殊表現),以保證宕機或斷電后,可以繼續訪問。java中常見的持久化框架,如Hibernate,ibatis,jdbc都是持久化實現方式的一種,當然普通文件保存功能也算。
拿memcached來說,memcached保存的信息,沒有進行持久化,所以只能存活一個進程生命期,下次重新啟動,數據全部丟失。這算memcached的一個缺點吧。redis提供了持久化支持,而且提供了2種持久化方案。
《redis演練系列》,立足于案例展示,通過形象,對比,圖示的方式,達到知識梳理過程。
本章的主要梗概。
-
redis兩種持久化方案對比
-
redis兩種持久化方案參數說明
-
演練RDB的觸發時機
-
演練AOF
-
RDB VS AOF
1.redis兩種持久化方案對比
redis提供了兩種持久化的方式,分別是RDB(Redis DataBase)和AOF(Append Only File)。RDB,AOF就相當于redis持久界的2個親兄弟,相互配合,相互提攜。當然也會爭搶些資源。
RDB,簡而言之,就是在不同的時間點,將redis存儲的數據生成快照并存儲到磁盤等介質上;
AOF,則是換了一個角度來實現持久化,那就是將redis執行過的所有寫指令記錄下來,在下次redis重新啟動時,只要把這些寫指令從前到后再重復執行一遍,就可以實現數據恢復了。
RDB將服務器包含的所有數據庫數據以二進制文件的形式保存到硬盤里面。
下圖,是具體操作步驟。具體詳情參見【http://www.cnblogs.com/luogankun/p/3986403.html】
AOF,英文是Append Only File,即只允許追加不允許改寫的文件。AOF方式是將執行過的寫指令記錄下來,在數據恢復時按照從前到后的順序再將指令都執行一遍,就這么簡單。有點數據庫軟件聯機日志的影子。
兩者對比
redis兩種持久化方案參數說明
涉及到文件保存,一般要考慮以下幾個問題,不僅僅限于redis。
-
保存時機:什么時候觸發。取決于數據一致性和效率的平衡
-
保存目標對象:日志,二進制...
-
保存目錄:本地目錄,還是共享目錄
-
是否壓縮:節省空間
-
是否校驗:考慮安全
-
保存失敗處理機制:異常報告
-
開啟線程數:決定速度,但會影響其他功能
-
保存文件限制:超過大小,不允許;和不允許上傳*.exe文件等
帶著這些問題,去扣相關的RDB參數,和AOF參數,問題就簡單多了。
| RDB | # 存 DB 到磁盤: # #?? 格式:save <間隔時間(秒)> <寫入次數> # #?? 根據給定的時間間隔和寫入次數將數據保存到磁盤 # #?? 下面的例子的意思是: #?? 900 秒后如果至少有 1 個 key 的值變化,則保存 #?? 300 秒后如果至少有 10 個 key 的值變化,則保存 #?? 60 秒后如果至少有 10000 個 key 的值變化,則保存 # #?? 注意:你可以注釋掉所有的 save 行來停用保存功能。 #?? 也可以直接一個空字符串來實現停用: #?? save "" save 900 1 save 300 10 save 60 10000 # 默認情況下,如果 redis 最后一次的后臺保存失敗,redis 將停止接受寫操作, # 這樣以一種強硬的方式讓用戶知道數據不能正確的持久化到磁盤, # 否則就會沒人注意到災難的發生。 # # 如果后臺保存進程重新啟動工作了,redis 也將自動的允許寫操作。 # # 然而你要是安裝了靠譜的監控,你可能不希望 redis 這樣做,那你就改成 no 好了。 stop-writes-on-bgsave-error yes # 是否在 dump .rdb 數據庫的時候使用 LZF 壓縮字符串 # 默認都設為 yes # 如果你希望保存子進程節省點 cpu ,你就設置它為 no , # 不過這個數據集可能就會比較大 rdbcompression yes # 是否校驗rdb文件 rdbchecksum yes # 設置 dump 的文件位置 dbfilename dump.rdb # 工作目錄 # 例如上面的 dbfilename 只指定了文件名, # 但是它會寫入到這個目錄下。這個配置項一定是個目錄,而不能是文件名。 dir ./ |
| AOF | ??? #默認情況下Redis會異步的將數據導出到磁盤上。這種模式對許多應用程序已經足夠了, ? ??? #但是如果斷電或者redis進程出問題就會導致一段時間內的更新數據丟失(取決與配置項) ? ??? # ? ??? #這種只增文件是可選的能夠提供更好的體驗的數據持久化策略。 ? ??? #舉個例子,如果使用默認的配置數據fsync策略,在服務器意外斷電的情況下redis只會丟失一秒中內的更新數據, ? ??? #或者當redis進程出問題但操作系統運轉正常時,redis只會丟失一個數據更新操作。 ? ??? # ? ??? #AOF 和 RDB 持久化方式可以同時啟動并且無沖突。 ? ??? #如果AOF開啟,啟動redis時會加載aof文件,這些文件能夠提供更好的保證。 ? ??? #請在 http://redis.io/topics/persistence 獲取更多數據持久化信息。 ? ???? ? ??? appendonly no ? ???? ? ??? # 只增文件的文件名稱。(默認是appendonly.aof) ? ??? # appendfilename appendonly.aof ? ???? ? ??? #調用fsync()函數會通知操作系統真正將數據寫入磁盤,而不是等待緩沖區中有更多數據。 ? ??? #有些操作系統會將數據輸出到磁盤,有些操作系統只是ASAP。 ? ??? # ? ??? #redis支持三種不同的方式: ? ??? # ? ??? #no:不調用,之等待操作系統來清空緩沖區當操作系統要輸出數據時。很快。 ? ??? # always: 每次更新數據都寫入僅增日志文件。慢,但是最安全。 ? ??? # everysec: 每秒調用一次。折中。 ? ??? # ? ??? #默認是每秒中一次,因為它往往是在速度和數據安全兩者之間的折中選擇。 ? ??? #如果你可以接受讓操作系統去自動清空緩存,你可以將這項配置降低到'no'(如果你可以接受一段時間的數據丟失,默認的rdb就足夠了), ? ??? #這完全取決與你。如果你想要一個更好的體驗或者從相反的角度,使用'always',這樣會很慢,但是比'everysec'安全些。 ? ??? # ? ??? #請在下面的文章中獲取更多細節知識: ? ??? #? http://antirez.com/post/redis-persistence-demystified.html ? ??? # ? ??? #如果你不是很清楚這三項之間的區別,或者不知道哪種適合你的機器,就是用默認吧。 ? ???? ? ??? # appendfsync always ? ??? appendfsync everysec??? ??? # appendfsync no?? ??? #當AOF策略設置為'always'或者'everysec'的時候,后臺的保存進程會進行很多磁盤I/O操作, ? ??? #在某些linux結構中redis會在調用sync()方法時阻塞很長時間。記住,現在還沒辦法解決這個問題,即使在不同進程中進行調用也會block。 ? ??? # ? ??? #使用如下配置可能會緩解這個問題,這樣會在存儲大數據或者BIGREWRITEAOF的時候不會在主進程中調用fsync()方法。 ? ??? # ? ??? # 這表示,如果另外一個子進程在進行保存操作,redis的表現如同配置為‘appendfsync no’。 ? ??? #在實際應用中,這表示在最壞的情景下(使用linux默認配置)可能會丟失30秒日志。 ? ??? #? ? ??? #如果你有特殊的情況可以配置為'yes'。但是配置為'no'是最為安全的選擇。 ? ??? no-appendfsync-on-rewrite no ? ???? ? ???? ? ??? #自動重寫只增文件。 ? ??? #redis可以自動盲從的調用‘BGREWRITEAOF’來重寫日志文件,如果日志文件增長了指定的百分比。 ? ??? #? ? ??? #它是這樣工作的:每次rewrite后redis會記錄日志文件的大小。(如果重啟后沒有重寫后的大小,就默認用日志文件大小) ? ??? # ? ??? # 這個基準日志大小和當前日志大小做比較。如果當前大小比指定的百分比,重寫機制就會被觸發。 ? ??? #同時,你也要制定一個重寫下線,用來避免增長百分比夠了,但是日志文件還很小的情況。 ? ??? # ? ??? #指定百分比為0可以注掉自動重寫日志文件功能。 ??????? ??? auto-aof-rewrite-percentage 100 ? ??? auto-aof-rewrite-min-size 64mb #redis在啟動的時候可以加載被截斷的AOF文件,默認啟用; ?? (3.0以后才支持) aof-load-truncated yes?? ??? |
2.演練RDB的觸發時機
#?? 900 秒后如果至少有 1 個 key 的值變化,則保存
#?? 300 秒后如果至少有 10 個 key 的值變化,則保存
#?? 60 秒后如果至少有 10000 個 key 的值變化,則保存
#?? 注意:你可以注釋掉所有的 save 行來停用保存功能。
#?? 也可以直接一個空字符串來實現停用:
#?? save ""
save 900 1
save 300 10
save 60 10000
采用默認的RDB配置
redis.conf
| 1 2 3 4 5 6 7 | save?900?1 save?300?10 save?60?10000 stop-writes-on-bgsave-error?yes rdbcompression?yes dbfilename?dump.rdb dir?./ |
2.1演練“重啟redis,鍵值丟失”
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 192.168.163.156:6379>?flushdb OK 192.168.163.156:6379>?set?blog?"blog.51cto.com" OK #為鍵賦值 192.168.163.156:6379>?get?blog "blog.51cto.com" 192.168.163.156:6379>?exit [root@hadoop2?redis]#?ps?-ef?|grep?redis root??????2546?????1??0?07:42??????????00:00:05?/usr/local/redis/bin/redis-server?192.168.163.156:6379??????? root??????3235??2517??0?08:54?pts/0????00:00:00?grep?redis [root@hadoop2?redis]#?kill?-9?2546 #重啟redis [root@hadoop2?redis]#?bin/redis-server??redis.conf? [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 #?blog鍵值丟失 192.168.163.156:6379>?get?blog (nil) |
這個結果,是不是非常出人意外。看來“江湖上都傳言,redis斷電鍵值不丟失”有點問題。
其實,沒問題。是上面的演練存在不足,數據量沒有達到觸發時機要求。繼續。
2.2演練“重啟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 26 27 28 29 | [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 192.168.163.156:6379>?set?blog?"blog.51cto.com" OK #借助自帶測試工具,發送1w請求,觸發RDB保存 [root@hadoop2?redis]#?bin/redis-benchmark??-r?10000?-h?192.168.163.156 ======?PING_INLINE?====== ??100000?requests?completed?in?0.83?seconds ??50?parallel?clients ??3?bytes?payload ??keep?alive:?1 99.77%?<=?1?milliseconds ... #?確認??鍵值還存在 [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 192.168.163.156:6379>?get?blog "blog.51cto.com" 192.168.163.156:6379>?exit #關閉?redis服務 [root@hadoop2?redis]#?ps?-ef?|grep?redis root??????3241?????1??3?08:54??????????00:00:19?bin/redis-server?192.168.163.156:6379 root??????3351??2517??0?09:05?pts/0????00:00:00?grep?redis [root@hadoop2?redis]#?kill?-9?3241 #重啟redis服務 [root@hadoop2?redis]#?bin/redis-server??redis.conf? #確認重啟后,blog鍵值依然存在 [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 192.168.163.156:6379>?get?blog "blog.51cto.com" |
看來“江湖上都傳言,redis斷電鍵值不丟失”,是有前提條件的。
3.演練AOF
?修改redis.conf 開啟AOF 關閉RDB
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | save?900?1 save?300?10 save?60?10000 save?"" stop-writes-on-bgsave-error?yes rdbcompression?yes dbfilename?dump.rdb dir?./ appendonly?yes appendfilename?"appendonly.aof" appendfsync?everysec no-appendfsync-on-rewrite?no auto-aof-rewrite-percentage?100 auto-aof-rewrite-min-size?16mb aof-load-truncated?yes |
3.1演練重啟redis,鍵值是否丟失
| 1 2 3 4 5 6 7 8 9 10 | 192.168.163.156:6379>?set?blog?"blog.51cto.com" OK 192.168.163.156:6379>?exit [root@hadoop2?redis]#?pkill?redis #重啟 [root@hadoop2?redis]#?bin/redis-server??redis.conf? [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 #鍵值未丟失 192.168.163.156:6379>?get?blog "blog.51cto.com" |
結論:托AOF的福,鍵值沒有丟失,和RDB不同。原因是兩者的觸發時機不同。
這時候,確認下生產AOF文件
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #僅僅存了一條記錄 [root@hadoop2?redis]#?ll -rw-r--r--.?1?root?root????67?9月???3?10:31?appendonly.aof #查看日志內容(為文本文件) [root@hadoop2?redis]#?cat?appendonly.aof? *2 $6 SELECT $1 0 *3 $3 set $4 blog $14 blog.51cto.com |
3.2演練重啟AOF重寫效果
通過查看日志內容,可以確認存放的是操作命令日志。這勢必導致文件大小增長過快,這和RDB文件不同。RDB存儲的是二進制文件,而且是某時刻的快照,存儲的本身就是面向內存結果。稍后會提供例子演示下RDB的內容。
準備測試數據
| 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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | [root@hadoop2?redis]#?bin/redis-cli??-h??192.168.163.156 #順序操作鍵值多次 192.168.163.156:6379>?set?year?2001 OK 192.168.163.156:6379>?incr?year (integer)?2002 192.168.163.156:6379>?incr?year (integer)?2003 192.168.163.156:6379>?incr?year (integer)?2004 192.168.163.156:6379>?incr?year (integer)?2005 192.168.163.156:6379>?incr?year (integer)?2006 192.168.163.156:6379>?incr?year (integer)?2007 192.168.163.156:6379>?incr?year (integer)?2008 192.168.163.156:6379>?incr?year (integer)?2009 192.168.163.156:6379>?incr?year (integer)?2010 192.168.163.156:6379>?get?year "2010" #?get沒有輸出到AOF日志 [root@hadoop2?redis]#?cat?appendonly.aof? *2 $6 SELECT $1 0 *3 $3 set $4 blog $14 blog.51cto.com *2 $6 SELECT $1 0 *3 $3 set $4 year $4 2001 *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year *2 $4 incr $4 year #接下來,借助benchmark工具,批量插入數據,觸發AOF文件重寫 [root@hadoop2?redis]#?bin/redis-benchmark??-r?20000?-h?192.168.163.156 #appendonly.aof文件變化過程(11M->27M?-->32M->33M->42M->8.5M. ... [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?11M?9月???3?11:03?appendonly.aof -rw-r--r--.?1?root?root?27M?9月???3?11:03?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?32M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?33M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?36M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?42M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?44M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?8.5M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?11M?9月???3?11:04?appendonly.aof [root@hadoop2?redis]#?ll?appendonly.aof??-h -rw-r--r--.?1?root?root?15M?9月???3?11:04?appendonly.aof |
從42M 突然變成了8.5M,明顯發生了AOF重寫操作。
以year為目標,確認下AOF重寫發生了什么。
重寫前后,發現將多次操作的結果,轉換為一個等價的命令,大大降低了存儲空間。
1.我們也可以使用bgrewriteaof來手動觸發AOF的自動重寫。
2 .調用 BGSAVE 能手動觸發快照保存,保存快照。
但線上環境要注意,阻塞情況。
4.AOF VS RDB.
兩種持久化方式,不是水火不容,而是相互扶持,相融以沫。
官方文檔,建議兩者同時開啟
同時開啟兩種持久化(redis.conf)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | save?900?1 save?300?10 save?60?10000 stop-writes-on-bgsave-error?yes rdbcompression?yes dbfilename?dump.rdb dir?./ appendonly?yes appendfilename?"appendonly.aof" appendfsync?everysec no-appendfsync-on-rewrite?no auto-aof-rewrite-percentage?100 auto-aof-rewrite-min-size?16mb aof-load-truncated?yes |
4.1比較2種方式的文件存儲
| 1 2 3 4 5 6 7 8 9 10 | 1.刪除rdb,aof文件 2.重啟redis-server #3.批量發送1w條請求 [root@hadoop2?redis]#?bin/redis-benchmark??-r?10000?-h?192.168.163.156 #4.?比較2個文件大小 [root@hadoop2?redis]#?ll?-h 總用量?29M -rw-r--r--.?1?root?root??192?9月???3?10:58?1 -rw-r--r--.?1?root?root??28M?9月???3?11:26?appendonly.aof -rw-r--r--.?1?root?root?457K?9月???3?11:26?dump.rdb |
4.2 演練aof文件損壞
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | [root@hadoop2?redis]#?bin/redis-server??redis.conf? [root@hadoop2?redis]#?bin/redis-cli??-h?192.168.163.156 192.168.163.156:6379>?set?blog?"blog.51cto.com" OK 192.168.163.156:6379>?set?subject?"redis" OK 192.168.163.156:6379>?set?year?2016 OK 192.168.163.156:6379>?keys?* 1)?"year" 2)?"subject" 3)?"blog" |
手動修改下appendonly.aof 文件
使用redis-check-aof 驗證下,果然不出所料“文件有問題”
| 1 2 3 4 5 6 | [root@hadoop2?redis]#?bin/redis-check-aof? Usage:?bin/redis-check-aof?[--fix]?<file.aof> [root@hadoop2?redis]#?bin/redis-check-aof??appendonly.aof? 0x???????????????0:?Expected?\r\n,?got:?0a00 AOF?analyzed:?size=112,?ok_up_to=0,?diff=112 AOF?is?not?valid |
...查看啟動日志(WARRING 暫時先放著)
| 1 2 3 4 | 4690:M?03?Sep?11:42:12.213?#?WARNING:?The?TCP?backlog?setting?of?511?cannot?be?enforced?because?/proc/sys/net/core/somaxconn?is?set?to?the?lower?value?of?128. 4690:M?03?Sep?11:42:12.213?#?Server?started,?Redis?version?3.2.3 4690:M?03?Sep?11:42:12.213?#?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. 4690:M?03?Sep?11:42:12.214?#?Bad?file?format?reading?the?append?only?file:?make?a?backup?of?your?AOF?file,?then?use?./redis-check-aof?--fix?<filename> |
客戶端連接失敗
[root@hadoop2 redis]# bin/redis-cli? -h 192.168.163.156
Could not connect to Redis at 192.168.163.156:6379: Connection refused
修復aof文件
[root@hadoop2 redis]# bin/redis-check-aof?
Usage: bin/redis-check-aof [--fix] <file.aof>
[root@hadoop2 redis]# bin/redis-check-aof --fix appendonly.aof?
0x?????????????? 0: Expected \r\n, got: 0a00
AOF analyzed: size=112, ok_up_to=0, diff=112
This will shrink the AOF from 112 bytes, with 112 bytes, to 0 bytes
Continue? [y/N]: y
Successfully truncated AOF
#修復的結果是清空了AOF文件。
重啟成功了,但遺憾的是數據全丟失了。
bin/redis-server? redis.conf?
[root@hadoop2 redis]# cat appendonly.aof?
bin/redis-cli? -h? 192.168.163.156
192.168.163.156:6379> keys *
(empty list or set)
當然,演示AOF文件出問題,這是個比較嚴重的問題。可見備份的重要性。
AOF方式的另一個好處,我們通過一個“場景再現”來說明。某同學在操作redis時,不小心執行了FLUSHALL,導致redis內存中的數據全部被清空了,這是很悲劇的事情。不過這也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件還沒有被重寫(rewrite),我們就可以用最快的速度暫停redis并編輯AOF文件,將最后一行的FLUSHALL命令刪除,然后重啟redis,就可以恢復redis的所有數據到FLUSHALL之前的狀態了。是不是很神奇,這就是AOF持久化方式的好處之一。但是如果AOF文件已經被重寫了,那就無法通過這種方法來恢復數據了。
前人,曾靜曰過的。難道有問題。于是我重新實驗了下。
這次我加快了速度,立刻關閉redis服務,以及使用vi命令直接修改aof文件。結果卻是可以將數據恢復。
這個演示不補貼了。
本文轉自 randy_shandong 51CTO博客,原文鏈接:http://blog.51cto.com/dba10g/1845885,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的redis演练(5) redis持久化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: netty 5 alph1源码分析(服务
- 下一篇: Java过滤HTML标签工具类