Redis學習(二):Redis 持久化

1. Redis持久化的取捨和選擇

1. 什麼是持久化

  • redis全部數據保持在內存中,對數據的更新將異步地保存到磁盤上。

2. 持久化方式

  • 快照
    • MySQL Dump
    • Redis RDB
  • 寫日誌
    • MySQL Binlog
    • Hbase HLog
    • Redis AOF

2. RDB

1. 什麼是RDB

RDB

2. 觸發機制 - 主要三種方式

1. save(同步)java

  • 客戶端向redis發送一條save命令,redis會幫咱們生成RDB文件。
  • 問題:因爲是同步命令,執行save的時候,假如咱們的save很是慢(數據量多),會形成redis的阻塞。
  • 文件策略:如存在老的RDB文件,新替代老。
  • 複雜度:O(N)。

2. bgsave(異步)linux

  • 客戶端執行bgsave命令,它使用了linux的fork()函數,生成了主進程的一個redis子進程,讓子進程完成RDB的生成。RDB生成以後,會告訴主進程RDB生成成功。
  • 若是fork執行很是慢(大多數狀況下很是快),依然會阻塞redis。
  • redis會正常響應客戶端,由於createRDB這樣重的操做是讓子進程進行操做的。
  • 文件策略和複雜度與save相同。
命令   save   bgsave
IO類型   同步   異步
阻塞   是   是(阻塞發生在fork)
複雜度   O(N)   O(N)
優勢   不會消耗額外內存   不阻塞客戶端命令
缺點   阻塞客戶端命令   須要fork,消耗內存

3. 自動ios

  • redis提供了save配置來進行自動持久化
配置   seconds   changes
save   900   1
save   300   10
save   60   10000
  • 在60秒改變了10000條數據,在300秒改變了10條數據,在900秒改變了一條數據,進行自動持久化。RDB文件生成是內部調用bgsave。
  • 具體配置能夠修改。
  • 沒法控制生成RDB頻率。

4. 配置redis

  • 咱們來看一下redis默認配置文件中給出的配置
  • save:自動持久化
  • dbfilename:RDB名字
  • dir:RDB等日誌文件存放位置
  • stop-writes-on-bgsave-error:bgsave發生錯誤時是否中止寫入
  • rdbcompression:RDB文件是否採用壓縮的格式
  • rdbchecksum:是否對RDB文件進行校驗和
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir ./
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
複製代碼

5. 最佳配置緩存

  • 關閉自動持久化
  • dbfilename:使用端口號進行文件區別
  • dir:根據redis數量進行分盤
dbfilename dump-${port}.rdb
dir /bigdistpath
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
複製代碼

3. 觸發機制 - 不容忽略方式

1. 全量複製安全

2. debug reloadbash

3. shutdown微信

4. 試驗

  • 修改配置文件以便遠程鏈接
    • bind 0.0.0.0
    • protected-mode no
  • 使用jedis隨便添加些數據
127.0.0.1:6379> dbsize
(integer) 1000000

127.0.0.1:6379> info memory
# Memory
used_memory:105221280
used_memory_human:100.35M
複製代碼
  • 咱們提早在另外一個窗口準備好執行命令
127.0.0.1:6379> set hello word
OK
127.0.0.1:6379> get hello 
複製代碼
  • 在第一個窗口執行save,接着執行get hello,發現被阻塞
127.0.0.1:6379> save
OK
(4.77s)

127.0.0.1:6379> get hello
"word"
(2.22s)
複製代碼
  • 咱們還能夠去data目錄(配置文件指定)下看到生成的RDB文件
[root@localhost redis]# cd data/
[root@localhost data]# ll
總用量 52428
-rw-r--r--. 1 root root     7365 12月 21 14:29 6379.log
-rw-r--r--. 1 root root     4809 12月 20 23:40 6382.log
-rw-r--r--. 1 root root 53666783 12月 21 14:29 dump-6379.rdb
複製代碼
  • 接下來咱們驗證一下bgsive
127.0.0.1:6379> bgsave
Background saving started
複製代碼
  • 使用命令發現調用子進程,同時get hello沒有阻塞
[root@localhost redis]# ps -ef | grep redis-
root       4987      1  1 14:21 ?        00:00:15 redis-server 0.0.0.0:6379
root       5271   3826  0 14:33 pts/0    00:00:00 redis-cli
root       5304   4987 56 14:36 ?        00:00:01 redis-rdb-bgsave 0.0.0.0:6379
root       5306   5143  0 14:36 pts/2    00:00:00 grep --color=auto redis-
複製代碼
  • 最後咱們來看一下自動持久化策略
#save 900 1
#save 300 10
save 60 5
複製代碼
  • 能夠經過flushall清空數據
127.0.0.1:6379> flushall
OK
(0.70s)
127.0.0.1:6379> dbsize
(integer) 0
複製代碼
  • 插入數據
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set c d
OK
127.0.0.1:6379> set e f
OK
127.0.0.1:6379> set g h
OK
127.0.0.1:6379> set i j
OK
127.0.0.1:6379> set m n
OK
複製代碼
  • 查看日誌,發現進行了自動持久化
[root@localhost data]# tail -f 6379.log

5475:M 21 Dec 14:45:03.075 * 5 changes in 60 seconds. Saving...
5475:M 21 Dec 14:45:03.077 * Background saving started by pid 5494
5494:C 21 Dec 14:45:05.018 * DB saved on disk
5494:C 21 Dec 14:45:05.019 * RDB: 10 MB of memory used by copy-on-write
5475:M 21 Dec 14:45:05.073 * Background saving terminated with success
複製代碼

5. 總結

  • RDB是Redis內存到硬盤的快照,用於持久化。
  • sava一般會阻塞Redis。
  • bgsava不會阻塞Redis,可是會fork新進程。
  • save自動配置知足任一就會被執行。
  • 有些觸發機制不能忽視。

3. AOF

1. RDB有什麼問題

1. 耗時,耗性能網絡

  • RDB生成過程其實就是將內存中的數據dump到硬盤當中,造成一個RDB文件。
  • 首先是比較耗時的,咱們要將全部數據進行一個dump,是一個O(N)的過程,自己的寫也會消耗不少CPU。
  • 其次是一個內存的消耗,咱們知道bgsive有一個fork的過程。
  • 還有就是IO性能的消耗。

2. 不可控,丟失數據app

配置   動做
T1   執行多個寫命令
T2   知足RDB自動建立的條件
T3   再次執行多個寫命令
T4   宕機
  • T3到T4之間的數據寫入就會丟失

2. AOF運行原理,建立

  • 客戶端寫一條數據,就在日誌追加一條寫命令

AOF

3. AOF的三種策略

  • always
    • redis在執行寫命令的時候,實際上不是直接寫在文件系統當中,而是寫在硬盤的緩衝區當中。緩衝區會根據一些策略刷新到硬盤當中。
    • always是說每條命令fsync到硬盤,這樣redis的寫入數據就會不丟失。
  • everysec
    • everysec是說每秒把緩衝區fsync到硬盤。
    • 在高寫入量時會適當保護硬盤。
    • 缺點是若是出現了故障,有可能會丟失一秒的數據。
    • 這是一個默認值。
  • no
    • OS決定fsync,由操做系統決定何時該寫入硬盤。
命令   always   everysec   no
優勢   不丟失數據   每秒一次fsync   不用管
缺點   IO開銷較大,通常的sata盤只有幾百TPS   丟一秒數據   不可控

4. AOF重寫

  • set hello world set hello java set hello hehe => set hello hehe
  • incr counter incr counter => set counter 2
  • rpush mylist a rpush mylist b rpush mylist c => rpush mylist a b c
  • 過時數據 => 重寫過程是沒有用的

把一些能夠優化的命令進行化簡,從而達到兩個目的

  • 減小硬盤佔用量
  • 加速恢復速度

5. AOF重寫實現的兩種方式

1. bgrewriteaof

  • 客戶端向redis發送一條命令bgrewriteaof,redis會返回OK並異步執行。redis接收到這個命令後會fork出一個子進程來完成AOF的重寫。
  • 這裏的AOF重寫就是將redis內存中的數據進行一次回溯,回溯成AOF文件,是從redis內存中進行一個重寫。

2. AOF重寫配置

  • 配置
配置名   含義
auto-aof-rewrite-min-size   AOF文件重寫須要的尺寸
auto-aof-rewrite-percentage   AOF文件增加率
  • 統計
統計名   含義
aof-current-size   AOF當前尺寸(單位:字節)
aof-base-size   AOF上次啓動和重寫的尺寸(單位:字節)
  • 自動觸發時機
    • aof-current-size > auto-aof-rewrite-min-size
    • (aof-current-size - aof-base-size) / aof-base-size > auto-aof-rewrite-percentage

6. AOF配置

  • 咱們修改一下redis默認配置文件中給出的配置
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
dir /home/redis/data
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
複製代碼
  • 進行一些簡單操做
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
複製代碼
  • 查看AOF文件是否生成
[root@localhost redis]# cd data
[root@localhost data]# ll
總用量 40
-rw-r--r--. 1 root root 21736 12月 21 16:57 6379.log
-rw-r--r--. 1 root root  4809 12月 20 23:40 6382.log
-rw-r--r--. 1 root root   277 12月 21 16:58 appendonly.aof
-rw-r--r--. 1 root root   127 12月 21 15:22 dump-6379.rdb
複製代碼
  • 查看文件內容
[root@localhost data]# more appendonly.aof 

*3
$3
set
$5
hello
$5
world
複製代碼
  • 咱們稍微看一下文件格式

    • *3表示下面這個命令有3個參數
    • $3表示下面一個數據的字節長度
  • 下面咱們來看下重寫

127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
複製代碼
  • 再次打開appendonly.aof,咱們發現只保留了set hello redis。
*3
$3
SET
$5
hello
$5
redis
複製代碼

7. RDB和AOF的抉擇

1. RDB和AOF比較

命令   RDB   AOF
啓動優先級   低   高
體積   小   大
恢復速度   快   慢
數據安全性   丟數據   根據策略決定
輕重   重   輕

2. RDB最佳策略

  • "關"
  • 集中管理
  • 主從,從開?

3. AOF最佳策略

  • "開":緩存和存儲
  • AOF重寫集中管理
  • everysec

4. 最佳策略

  • 小分片
  • 緩存或者存儲
  • 監控(硬盤,內存,負載,網絡)
  • 足夠的內存

4. 開發運維常見問題

1. fork操做

1. 同步操做

2. 與內存量息息相關:內存越大,耗時越長(與機器類型有關)

3. info:latest_fork_usec

4. 改善fork

  • 優先使用物理機或者高效支持fork操做的虛擬化技術。
  • 控制redis實例最大可用內存:maxmemory。
  • 合理配置linux內存分配策略:vm.overcommit_memory=1。
  • 下降fork頻率:例如放寬AOF重寫自動觸發時機,沒必要要的全量複製。

2. 子進程開銷和優化

1. CPU

  • 開銷:RDB和AOF文件生成,屬於CPU密集型。
  • 優化:不作CPU綁定,不和CPU密集型部署。

2. 內存

  • 開銷:fork內存開銷,copy-on-write。
  • 優化:禁止支持大的內存頁分配 : echo never > /sys/kernel/mm/transparent_hugepage/enabled。

3. 硬盤

  • 開銷:AOF和RDB文件寫入,能夠結合iostat,iotop分析。
  • 優化:
    • 不要和高硬盤負載服務部署在一塊兒:存儲服務,消息隊列等。
    • 不要進行AOF追加:no-appendfsync-on-rewrite = yes。
    • 根據寫入量決定磁盤類型:例如ssd。
    • 單機多實例持久化文件目錄能夠考慮分盤。

3. AOF追加阻塞

  • 若是使用了AOF,咱們一般會使用每秒刷盤的這樣一個策略。
  • 首先主線程去寫入AOF緩衝區,同時還有一個AOF同步線程去同步每秒刷盤的操做,同時還會記錄最近的一次同步時間。
  • 主線程還會對比和上次AOF的時間,若是距離上次同步時間超過兩秒,主線程會阻塞。
  • 解決方法主要參考上面關於硬盤的優化。

最後

你們能夠關注個人微信公衆號一塊兒學習進步。

相關文章
相關標籤/搜索