Redis 分別提供了 RDB 和 AOF 兩種持久化機(jī)制:
- RDB 將數(shù)據(jù)庫的快照(snapshot)以二進(jìn)制的方式保存到磁盤中捻爷。
- AOF 則以協(xié)議文本的方式源武,將所有對(duì)數(shù)據(jù)庫進(jìn)行過寫入的命令(及其參數(shù))記錄到 AOF 文件畸冲,以此達(dá)到記錄數(shù)據(jù)庫狀態(tài)的目的称诗。
RDB
a. 什么是RDB
和 MySQL 中的 mysqldump
差不多一個(gè)道理致讥。
b. 什么情況下會(huì)觸發(fā) RDB
第一種情況富岳,主動(dòng)執(zhí)行 save
命令
(同步,阻塞 陈瘦,就是save
命令執(zhí)行完畢后才能執(zhí)行后續(xù)的其他命令操作)
阻塞
保存 RDB 文件的策略
每次創(chuàng)建新的文件幌甘,并且替換原來舊文件(假如存在舊的文件)
第二種情況,主動(dòng)執(zhí)行 bgsave
命令 (異步痊项,非阻塞 )
- 文件策略和
save
相同
第三種情況锅风,自動(dòng)觸發(fā)
自動(dòng)觸發(fā),就是通過對(duì) Redis 的配置文件重相關(guān)選項(xiàng)的修改鞍泉,當(dāng)達(dá)到某個(gè)配置好的條件后皱埠,自動(dòng)生成 RDB 文件
,其內(nèi)部使用的是 bgsave
命令咖驮。
配置文件中相關(guān)選項(xiàng)的默認(rèn)值如下表:
配置 | seconds | changes | 含義 |
---|---|---|---|
save | 900 | 1 | 每隔 900 秒檢查一次漱逸,假如至少有 1 條數(shù)據(jù)改變,就生成新的 RDB 文件 |
save | 300 | 10 | 每隔 300 秒檢查一次游沿,假如至少有 10 條數(shù)據(jù)改變饰抒,就生成新的 RDB 文件 |
save | 60 | 10000 | 每隔 60 秒檢查一次,假如至少有 10000 條數(shù)據(jù)改變诀黍,就生成新的 RDB 文件 |
每次檢查都會(huì)建立一個(gè)新的檢查點(diǎn)袋坑,以便用于下次檢查作為參考信息。
關(guān)于 RDB 文件的配置信息
默認(rèn)文件名
dbfilename dump.rdb
默認(rèn)文件保存位置
dir ./
假如
bgsave
執(zhí)行中發(fā)生錯(cuò)誤,是否停止寫入枣宫,默認(rèn)是yes
婆誓, 表示假如出錯(cuò),就停止寫入也颤。
stop-writes-on-bgsave-error yes
是否使用壓縮|
rdbcompression yes
是否進(jìn)行數(shù)據(jù)的校驗(yàn)
rdbchecksum yes
建議的最佳配置
關(guān)閉自動(dòng)生成 RDB 文件
在配置文件中注釋掉如下內(nèi)容
#save 900 1
#save 300 10
#save 60 10000
使用不同端口號(hào)進(jìn)行區(qū)分洋幻,因?yàn)椋锌赡軙?huì)在同一臺(tái)主機(jī)上開啟多個(gè) Redis 實(shí)例翅娶。
防止多個(gè)實(shí)例產(chǎn)生的數(shù)據(jù)信息寫到一個(gè)文件中文留。
dbfilename dump-${port}.rdb
指定一個(gè)大硬盤的路徑
dir /redis_data
假如出現(xiàn)錯(cuò)誤,停止繼續(xù)寫入
stop-writes-on-bgsave-error yes
采用壓縮
rdbcompression yes
進(jìn)行校驗(yàn)
rdbchecksum yes
實(shí)驗(yàn)
進(jìn)入centos的docker容器
安裝所需包和模塊
yum install epel-release
yum install -y redis
yum install -y supervisor
查看redis安裝時(shí)所有文件
rpm -ql redis
可發(fā)現(xiàn)其中有/usr/bin/redis-server
注意:可用
/usr/bin/redis-server
命令啟動(dòng)服竭沫,但用此命令啟動(dòng)燥翅,會(huì)運(yùn)行在前臺(tái)
因?yàn)闀?huì)占用終端,所以采用下文supervisor
的方式啟動(dòng)redis服務(wù)
補(bǔ)充:可用
rpm -qc redis
查看所有的配置文件蜕提、rpm -qa redis
或rpm -qa |grep redis
查找rpm安裝所有包中過濾redis包
創(chuàng)建文件夾
mkdir /etc/redis
打開配置文件
vi /etc/6379.conf
-
注釋這三行
-
改寫這行
創(chuàng)建配置文件/etc/supervisord.d/redis.ini
vi /etc/supervisord.d/redis.ini
文件內(nèi)容詳解:
[program:qfcmdb]
;執(zhí)行的命令
command=/usr/bin/redis-server /etc/redis/6379.conf
priority=999 ; 優(yōu)先級(jí)(越小越優(yōu)先)
autostart=true ; supervisord啟動(dòng)時(shí)森书,該程序也啟動(dòng)
autorestart=true ; 異常退出時(shí),自動(dòng)啟動(dòng)
startsecs=10 ; 啟動(dòng)后持續(xù)10s后未發(fā)生異常谎势,才表示啟動(dòng)成功
startretries=3 ; 異常后凛膏,自動(dòng)重啟次數(shù)
exitcodes=0,2 ; exit異常拋出的是0、2時(shí)才認(rèn)為是異常
stopsignal=QUIT ; 殺進(jìn)程的信號(hào)
; 在程序發(fā)送stopignal后脏榆,等待操作系統(tǒng)將SIGCHLD返回給supervisord的秒數(shù)猖毫。
; 如果在supervisord從進(jìn)程接收到SIGCHLD之前經(jīng)過了這個(gè)秒數(shù),
; supervisord將嘗試用最終的SIGKILL殺死它
stopwaitsecs=1
user=root ; 設(shè)置啟動(dòng)該程序的用戶
log_stdout=true ; 如果為True姐霍,則記錄程序日志
log_stderr=false ; 如果為True鄙麦,則記錄程序錯(cuò)誤日志
logfile=/var/log/6379.log ; 程序日志路徑
logfile_maxbytes=1MB ; 日志文件最大大小
logfile_backups=3 ; 日志文件最大數(shù)量
[include]
files = relative/directory/*.ini
/etc/supervisord.d/redis.ini
[program:redis-6379]
command=/usr/bin/redis-server /etc/redis/6379.conf
priority=999
autostart=true
autorestart=true
startsecs=10
startretries=3
exitcodes=0,2
stopsignal=QUIT
stopwaitsecs=1
user=root
log_stdout=true
log_stderr=false
logfile=/var/log/6379.log
logfile_maxbytes=1MB
logfile_backups=3
查看配置文件
supervisor配置文件位置
vi /etc/supervisord.conf
/etc
下已修改的文件結(jié)構(gòu)
- supervisord.conf 文件和 supervisord.d文件夾
其中supervisord.d
文件夾中有一個(gè)自定義的任意
的.ini
的文件
(此處自定義命名為redis.ini
文件)
- redis文件夾
(其中有一個(gè)自定義
的任意的以.conf結(jié)尾
的文件典唇,此處命名為:6379.conf
文件)
啟動(dòng)supervisor
supervisord
報(bào)錯(cuò)信息
由于 已經(jīng)以/usr/bin/redis-server起了一個(gè)redis服務(wù)镊折,所以,supervisord一直無法啟動(dòng)介衔,先需要kill掉這兩個(gè)進(jìn)程恨胚,然后用supervisor重啟服務(wù)即可
-
此時(shí),再查看炎咖,可發(fā)現(xiàn)redis服務(wù)已啟動(dòng)
手動(dòng)觸發(fā)生成二進(jìn)制文件
注釋了三個(gè)save赃泡,所以需要手動(dòng)去save后觸發(fā)生成.rdb的文件
持久化存儲(chǔ)
重啟redis后,可發(fā)現(xiàn)set的name依舊存在乘盼,因此實(shí)現(xiàn)了持久化存儲(chǔ)
修改配置文件
vi /etc/redis/6379.conf
-
修改name升熊,觸發(fā)保存
- 查看配置文件中定義的保存文件
cat /var/lib/redis/appendonly-6379.aof
AOF
什么是 AOF
AOF 文件保存了 Redis 的數(shù)據(jù)庫狀態(tài), 而文件里面包含的都是符合 Redis 通訊協(xié)議格式的命令文本绸栅。
AOF 保存的模式
Redis 目前支持三種 AOF 保存模式级野,它們分別是:
-
AOF_FSYNC_NO
:不保存。 -
AOF_FSYNC_EVERYSEC
:每一秒鐘保存一次粹胯。(生產(chǎn)中一般選這種) -
AOF_FSYNC_ALWAYS
:每執(zhí)行一個(gè)命令保存一次
不保存
在這種模式下蓖柔, SAVE 只會(huì)在以下任意一種情況中被執(zhí)行:
Redis 被關(guān)閉
AOF 功能被關(guān)閉
系統(tǒng)的寫緩存被刷新(可能是緩存已經(jīng)被寫滿辰企,或者定期保存操作被執(zhí)行)
這三種情況下的 SAVE 操作都會(huì)引起 Redis 主進(jìn)程阻塞。
每執(zhí)行一個(gè)命令保存一次
在這種模式下况鸣,每次執(zhí)行完一個(gè)命令之后牢贸, WRITE 和 SAVE 都會(huì)被執(zhí)行。
另外镐捧,因?yàn)?SAVE 是由 Redis 主進(jìn)程執(zhí)行的潜索,所以在 SAVE 執(zhí)行期間,主進(jìn)程會(huì)被阻塞愤估,不能接受命令請(qǐng)求帮辟。
AOF 三種保存模式的比較
因?yàn)樽枞僮鲿?huì)讓 Redis 主進(jìn)程無法持續(xù)處理請(qǐng)求, 所以一般說來玩焰, 阻塞操作執(zhí)行得越少由驹、完成得越快, Redis 的性能就越好昔园。
模式 1 的保存操作只會(huì)在AOF 關(guān)閉或 Redis 關(guān)閉時(shí)執(zhí)行蔓榄, 或者由操作系統(tǒng)觸發(fā), 在一般情況下默刚, 這種模式只需要為寫入阻塞甥郑, 因此它的寫入性能要比后面兩種模式要高, 當(dāng)然荤西, 這種性能的提高是以降低安全性為代價(jià)的: 在這種模式下澜搅, 如果運(yùn)行的中途發(fā)生停機(jī), 那么丟失數(shù)據(jù)的數(shù)量由操作系統(tǒng)的緩存沖洗策略決定邪锌。
模式 2 在性能方面要優(yōu)于模式 3 勉躺, 并且在通常情況下, 這種模式最多丟失不多于 2 秒的數(shù)據(jù)觅丰, 所以它的安全性要高于模式 1 饵溅, 這是一種兼顧性能和安全性的保存方案。
模式 3 的安全性是最高的妇萄, 但性能也是最差的蜕企, 因?yàn)榉?wù)器必須阻塞直到命令信息被寫入并保存到磁盤之后, 才能繼續(xù)處理請(qǐng)求冠句。
綜合起來轻掩,三種 AOF 模式的操作特性可以總結(jié)如下:
模式 | WRITE 是否阻塞? | SAVE 是否阻塞懦底? | 停機(jī)時(shí)丟失的數(shù)據(jù)量 | |
---|---|---|---|---|
AOF_FSYNC_NO |
阻塞 | 阻塞 | 操作系統(tǒng)最后一次對(duì) AOF 文件觸發(fā) SAVE 操作之后的數(shù)據(jù)唇牧。 | |
AOF_FSYNC_EVERYSEC |
阻塞 | 不阻塞 | 一般情況下不超過 2 秒鐘的數(shù)據(jù)。 | |
AOF_FSYNC_ALWAYS |
阻塞 | 阻塞 | 最多只丟失一個(gè)命令的數(shù)據(jù)。 |
AOF 方式下的數(shù)據(jù)還原
Redis 讀取 AOF 文件并還原數(shù)據(jù)庫的詳細(xì)步驟如下:
創(chuàng)建一個(gè)不帶網(wǎng)絡(luò)連接的偽客戶端(fake client)奋构。
讀取 AOF 所保存的文本壳影,并根據(jù)內(nèi)容還原出命令、命令的參數(shù)以及命令的個(gè)數(shù)弥臼。
根據(jù)命令宴咧、命令的參數(shù)和命令的個(gè)數(shù),使用偽客戶端執(zhí)行該命令径缅。
執(zhí)行 2 和 3 柠并,直到 AOF 文件中的所有命令執(zhí)行完畢茸习。
完成第 4 步之后, AOF 文件所保存的數(shù)據(jù)庫就會(huì)被完整地還原出來。
注意窍侧, 因?yàn)?Redis 的命令只能在客戶端的上下文中被執(zhí)行冻璃, 而 AOF 還原時(shí)所使用的命令來自于 AOF 文件腐缤, 而不是網(wǎng)絡(luò)慢蜓, 所以程序使用了一個(gè)沒有網(wǎng)絡(luò)連接的偽客戶端來執(zhí)行命令。
當(dāng)程序讀入這個(gè) AOF 文件時(shí)鼠锈, 它首先執(zhí)行 SELECT 0 命令 —— 這個(gè) SELECT 命令是由 AOF 寫入程序自動(dòng)生成的闪檬, 它確保程序可以將數(shù)據(jù)還原到正確的數(shù)據(jù)庫上。
注意:
為了避免對(duì)數(shù)據(jù)的完整性產(chǎn)生影響购笆, 在服務(wù)器載入數(shù)據(jù)的過程中粗悯, 只有和數(shù)據(jù)庫無關(guān)的訂閱與發(fā)布功能可以正常使用, 其他命令一律返回錯(cuò)誤同欠。
AOF 的重寫機(jī)制
為什么需要重寫機(jī)制
AOF 文件通過同步 Redis 服務(wù)器所執(zhí)行的命令样傍, 從而實(shí)現(xiàn)了數(shù)據(jù)庫狀態(tài)的記錄, 但是铺遂, 這種同步方式會(huì)造成一個(gè)問題: 隨著運(yùn)行時(shí)間的流逝衫哥, AOF 文件會(huì)變得越來越大。
對(duì)同一個(gè)鍵的狀態(tài)的多次不同操作娃循,而最終得到一個(gè)結(jié)果炕檩。比如對(duì)列表的添加刪除元素斗蒋。
被頻繁操作的鍵捌斧。比如累加
重新機(jī)制是如何實(shí)現(xiàn)的
實(shí)際上, AOF 重寫并不需要對(duì)原有的 AOF 文件進(jìn)行任何寫入和讀取泉沾, 它針對(duì)的是數(shù)據(jù)庫中鍵的當(dāng)前值捞蚂,也就是源數(shù)據(jù)從目前的內(nèi)存中獲取。
考慮這樣一個(gè)情況跷究, 如果服務(wù)器對(duì)鍵 list 執(zhí)行了以下四條命令:
RPUSH list 1 2 3 4 // [1, 2, 3, 4]
RPOP list // [1, 2, 3]
LPOP list // [2, 3]
LPUSH list 1 // [1, 2, 3]
那么當(dāng)前列表鍵 list 在數(shù)據(jù)庫中的值就為 [1, 2, 3] 姓迅。
如果我們要保存這個(gè)列表的當(dāng)前狀態(tài), 并且盡量減少所使用的命令數(shù), 那么最簡單的方式不是去 AOF 文件上分析前面執(zhí)行的四條命令丁存, 而是直接讀取 list 鍵在數(shù)據(jù)庫的當(dāng)前值肩杈, 然后用一條 RPUSH 1 2 3 命令來代替前面的四條命令。
除了列表之外解寝,集合扩然、字符串、有序集聋伦、哈希表等鍵也可以用類似的方法來保存狀態(tài)夫偶。
根據(jù)鍵的類型, 使用適當(dāng)?shù)膶懭朊顏碇噩F(xiàn)鍵的當(dāng)前值觉增, 這就是 AOF 重寫的實(shí)現(xiàn)原理兵拢。
基本都步驟
for 遍歷所有數(shù)據(jù)庫:
if 如果數(shù)據(jù)庫為空:
那么跳過這個(gè)數(shù)據(jù)庫
else:
寫入 SELECT 命令,用于切換數(shù)據(jù)庫
for 選擇一個(gè)庫后逾礁,遍歷這個(gè)庫的所有鍵
if 如果鍵帶有過期時(shí)間说铃,并且已經(jīng)過期,那么跳過這個(gè)鍵
if 根據(jù)數(shù)據(jù)的類型嘹履,進(jìn)行相關(guān)操作截汪。
AOF 的重寫機(jī)制
AOF 保存的模式
Redis 目前支持三種 AOF 保存模式,它們分別是:
AOF_FSYNC_NO
:不保存植捎。
AOF_FSYNC_EVERYSEC
:每一秒鐘保存一次衙解。(生產(chǎn)中一般選這種)
AOF_FSYNC_ALWAYS
:每執(zhí)行一個(gè)命令保存一次
BGREWRITEAOF
只保存最終的name的值
AOF 重寫的實(shí)現(xiàn)方式
方式 | 區(qū)別 |
---|---|
bgrewriteaof 命令 |
不需要重啟服務(wù),不便于統(tǒng)一管理 |
配置文件實(shí)現(xiàn) | 需要重啟服務(wù)焰枢,便于進(jìn)行統(tǒng)一管理 |
bgrewriteaof
配置文件實(shí)現(xiàn)
觸發(fā)條件蚓峦,必須同時(shí)滿足如下條件
aof_current_size
和aof_base_size
可以通過命令info persistence
查看到
重寫流程圖
對(duì)于上圖有四個(gè)關(guān)鍵點(diǎn)
補(bǔ)充一下:
一: 在重寫期間,由于主進(jìn)程依然在響應(yīng)
命令济锄,為了保證最終備份的完整性
暑椰;因此它依然會(huì)
寫入舊的AOF file
中,如果重寫失敗
荐绝,能夠保證數(shù)據(jù)不丟失
一汽。當(dāng)然這個(gè)是可以通過配置
來決定在重寫期間是否
進(jìn)行主進(jìn)程普通的AOF
操作。
二: 為了把重寫期間響應(yīng)
的寫入信息也寫入到新的文件
中低滩,因此也會(huì)為子進(jìn)程保留一個(gè)buf
召夹,防止新寫的file丟失數(shù)據(jù)
。
三: 重寫是直接把當(dāng)前內(nèi)存的數(shù)據(jù)
生成對(duì)應(yīng)命令
恕沫,并不需要
讀取老的AOF文件
進(jìn)行分析监憎、命令合并。
四: AOF文件直接采用的文本協(xié)議
婶溯,主要是兼容性好鲸阔、追加方便偷霉、可讀性高可認(rèn)為修改修復(fù)。
注意:無論是RDB還是AOF都是先寫入一個(gè)臨時(shí)文件褐筛,然后通過 rename 完成文件的替換工作类少。
重寫機(jī)制操作實(shí)驗(yàn):
- 修改
/etc/redis/6379.conf
文件
// 要想使用 AOF 的全部功能,需要設(shè)置為 yes
appendonly yes
// AOF 文件名渔扎,路徑才看之前的 dir
配置項(xiàng)
appendfilename "appendonly.aof"
// 平常普通的 AOF 的策略
appendfsync everysec
// 當(dāng)執(zhí)行 AOF 重寫時(shí)瞒滴,是否繼續(xù)執(zhí)行平常普通的 AOF 操作。
// 這里設(shè)置文件 yes , 表示不執(zhí)行
// 因?yàn)榧偃缭蘧瑫r(shí)執(zhí)行妓忍,兩種操作都會(huì)對(duì)磁盤 I/O 進(jìn)行訪問,造成
// I/O 訪問量過大愧旦,產(chǎn)生性能衰減
no-appendfsync-on-rewrite yes
// AOF 文件容量的增長率
auto-aof-rewrite-percentage 100
// AOF 文件的最低容量世剖,就是當(dāng)前文件的大小大于此值時(shí),就會(huì)進(jìn)行重寫笤虫。當(dāng)然這只是其中一個(gè)條件旁瘫。
auto-aof-rewrite-min-size 64mb
- 重啟
supervisorctl restart redis-6379
-
redis-cli
查看配置文件修改后狀態(tài),并進(jìn)行簡單的數(shù)據(jù)添加操作
- 查看.aof文件
cat /var/lib/redis/appendonly-6379.aof
- 主動(dòng)觸發(fā)
BGREWRITEAOF
-
再次查看.aof文件琼蚯,與上一次比較
RDB 和 AOF
區(qū)別:
如何抉擇:
從服務(wù)器開啟 RDB
始終開啟 AOF
不要使用主機(jī)的全部內(nèi)存