redis演練(5) redis持久化

何謂持久化,就是媳婦讓你,持久一些。
html

說白了持久化:就是將內存中的數據保存到磁盤上的過程(數據庫也算磁盤的特殊表現),以保證宕機或斷電後,能夠繼續訪問。java中常見的持久化框架,如Hibernate,ibatis,jdbc都是持久化實現方式的一種,固然普通文件保存功能也算。java

拿memcached來講,memcached保存的信息,沒有進行持久化,因此只能存活一個進程生命期,下次從新啓動,數據所有丟失。這算memcached的一個缺點吧。redis提供了持久化支持,並且提供了2種持久化方案。linux

《redis演練系列》,立足於案例展現,經過形象,對比,圖示的方式,達到知識梳理過程。redis

本章的主要梗概。數據庫

  • redis兩種持久化方案對比緩存

  • redis兩種持久化方案參數說明
    安全

  • 演練RDB的觸發時機bash

  • 演練AOF服務器

  • RDB VS AOFapp

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】


221732277642628.png

AOF,英文是Append Only File,即只容許追加不容許改寫的文件。AOF方式是將執行過的寫指令記錄下來,在數據恢復時按照從前到後的順序再將指令都執行一遍,就這麼簡單。有點數據庫軟件聯機日誌的影子。

二者對比

221833475454922.png

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

save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./

2.1演練「重啓redis,鍵值丟失」

[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,鍵值不丟失」

[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

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,鍵值是否丟失

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文件

#僅僅存了一條記錄
[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的內容。

準備測試數據

[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重寫發生了什麼。

wKiom1fKP_uyEDCCAAAdXFCG35Q953.png

重寫先後,發現將屢次操做的結果,轉換爲一個等價的命令,大大下降了存儲空間。

1.咱們也可使用bgrewriteaof來手動觸發AOF的自動重寫。

2 .調用 BGSAVE 能手動觸發快照保存,保存快照。

但線上環境要注意,阻塞狀況。


4.AOF VS RDB.

兩種持久化方式,不是水火不容,而是相互扶持,相融以沫。

官方文檔,建議二者同時開啓

同時開啓兩種持久化(redis.conf)

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.刪除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文件損壞

[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 文件

wKiom1fKRZDSLFBqAAAydEx5rcU042.png

使用redis-check-aof 驗證下,果真不出所料「文件有問題」

[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 暫時先放着)

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文件。結果倒是能夠將數據恢復。

這個演示不補貼了。


正是有了持久化,才使redis向「存儲」靠近了一大步,數據可靠性提供了保證。

友情提示,演練文章,最好配合官方理論說明性文檔一同觀看,效果顯著。

相關文章
相關標籤/搜索