解决Redis持久化数据丢失
為什么持久化?
持久化是Redis保障高可用性的基礎(chǔ)。因為Redis是一個內(nèi)存數(shù)據(jù)庫,它的數(shù)據(jù)均保存在內(nèi)存中,如果Redis實例發(fā)生宕機(jī),在沒有數(shù)據(jù)備份前提下,你的生產(chǎn)數(shù)據(jù)將會全部丟失。這時完善的持久化機(jī)制,可以把內(nèi)存中的數(shù)據(jù)持久化到磁盤上,方便我們進(jìn)行備份數(shù)據(jù)和快速恢復(fù)數(shù)據(jù)。
但是持久化就一定能保證數(shù)據(jù)不丟失嗎?
首先我們要了解Redis為了保證高可用性,一般都是從一下幾個方面入手的:
- 數(shù)據(jù)持久化
- 主從復(fù)制
- 自動故障恢復(fù)
- Redis集群
常見的Redis持久化有兩種:(1)RDB快照持久化(2)AOF持久化,區(qū)別在于RDB持久化保存完整的數(shù)據(jù),AOF緩存的是redis指令(當(dāng)然我們該可以簡化AOF緩存的指令)。缺點也很明顯,RDB是某一時刻的數(shù)據(jù)快照,因此它的數(shù)據(jù)并不全,生成RDB文件的代價是比較大的,它會消耗大量的CPU和內(nèi)存資源。RDB持久化適用于主從全量同步數(shù)據(jù)、數(shù)據(jù)庫備份。AOF適合做增量數(shù)據(jù)的持久化。Redis啟動會優(yōu)先加載AOF文件進(jìn)行數(shù)據(jù)恢復(fù)。
AOF 持久化
什么是 AOF 持久化
AOF(Append Only File):通過保存數(shù)據(jù)庫執(zhí)行的命令來記錄數(shù)據(jù)庫的狀態(tài)。
AOF日志對數(shù)據(jù)庫命令的保存順序是,Redis 先執(zhí)行命令,把數(shù)據(jù)寫入內(nèi)存,然后才記錄日志。
為什么要后記錄日志呢
1、后寫,能夠避免記錄到錯誤的命令。因為是先執(zhí)行命令,后寫入日志,只有命令執(zhí)行成功了,命令才能被寫入到日志中。
2、避免阻塞當(dāng)前的寫操作,是在命令執(zhí)行后才記錄日志,所以不會阻塞當(dāng)前的寫操作。
AOF 的潛在風(fēng)險
-
1、如果命令執(zhí)行成功,寫入日志的時候宕機(jī)了,命令沒有寫入到日志中,這時候就有丟失數(shù)據(jù)的風(fēng)險了,因為這時候沒有寫入日志,服務(wù)斷電之后,這部分?jǐn)?shù)據(jù)就丟失了。
這種場景在別的地方也很常見,比如基于 MQ 實現(xiàn)分布式事務(wù),也會出現(xiàn)業(yè)務(wù)處理成功 + 事務(wù)消息發(fā)送失敗這種場景,RabbitMQ,RocketMQ,Kafka 事務(wù)性,消息丟失和消息重復(fù)發(fā)送的處理策略
-
2、AOF 的日志寫入也是在主線程進(jìn)行的,如果磁盤的壓力很大,寫入速度變慢了,會影響后續(xù)的操作。
這兩種情況可通過調(diào)整 AOF 文件的寫入磁盤的時機(jī)來避免
AOF 文件的寫入和同步
AOF 文件持久化的功能分成三個步驟,文件追加(append),文件寫入,文件同步(sync)。
AOF 文件在寫入磁盤之前是先寫入到 aof_buf 緩沖區(qū)中,然后通過調(diào)用 flushAppendOnlyFile 將緩沖區(qū)中的內(nèi)容保存到 AOF 文件中。
寫入的策略通過 appendfsync 來進(jìn)行配置
-
Always:同步寫回 每次寫操作命令執(zhí)行完后,同步將 AOF 日志數(shù)據(jù)寫回硬盤;
-
Everysec:每秒寫回 每次寫操作命令執(zhí)行完后,先將命令寫入到 AOF 文件的內(nèi)核緩沖區(qū),然后每隔一秒將緩沖區(qū)里的內(nèi)容寫回到硬盤;
-
No:操作系統(tǒng)控制的寫回 Redis 不在控制命令的寫會時機(jī),交由系統(tǒng)控制。每次寫操作命令執(zhí)行完成之后,命令會被放入到 AOF 文件的內(nèi)核緩沖區(qū),之后什么時候?qū)懭氲酱疟P,交由系統(tǒng)控制。
RDB 持久化
什么是 RDB 持久化
RDB(Redis database):實現(xiàn)方式是將存在 Redis 內(nèi)存中的數(shù)據(jù)寫入到 RDB 文件中保存到磁盤上從而實現(xiàn)持久化的。
和 AOF 不同的是 RDB 保存的是數(shù)據(jù)而不是操作,在進(jìn)行數(shù)據(jù)恢復(fù)的時候,直接把 RDB 的文件讀入到內(nèi)存,即可完成數(shù)據(jù)恢復(fù)。
RDB 如何做內(nèi)存快照
Redis 中對于如何備份數(shù)據(jù)到 RDB 文件中,提供了兩種方式
-
1、save: 在主線程中執(zhí)行,不過這種會阻塞 Redis 服務(wù)進(jìn)程;
-
2、bgsave: 主線程會 fork 出一個子進(jìn)程來負(fù)責(zé)處理 RDB 文件的創(chuàng)建,不會阻塞主線程的命令操作,這也是 Redis 中 RDB 文件生成的默認(rèn)配置;
對于 save 和 bgsave 這兩種快照方式,服務(wù)端是禁止這兩種方式同時執(zhí)行的,防止產(chǎn)生競爭條件。
Redis 中可以使用 save 選項,來配置服務(wù)端執(zhí)行 BGSAVE 命令的間隔時間
## Save the DB on disk:## save <seconds> <changes>## Will save the DB if both the given number of seconds and the given# number of write operations against the DB occurred.## In the example below the behaviour will be to save:# after 900 sec (15 min) if at least 1 key changed# after 300 sec (5 min) if at least 10 keys changed# after 60 sec if at least 10000 keys changed## Note: you can disable saving completely by commenting out all "save" lines.## It is also possible to remove all the previously configured save# points by adding a save directive with a single empty string argument# like in the following example:## save ""save 900 1save 300 10save 60 10000save 300 10?就是服務(wù)端在300秒,讀數(shù)據(jù)進(jìn)行了至少10次修改,就會觸發(fā)一次 BGSAVE 命令
?
單節(jié)點模式
單節(jié)點模式下只使用RDB持久化,在某一時刻redis宕機(jī),此時的數(shù)據(jù)并沒有來得及進(jìn)行rdb持久化備份,這就出現(xiàn)了數(shù)據(jù)丟失的可能。
在Redis單節(jié)點模式下,我們可以可以采用RDB+AOF結(jié)合使用防止Redis緩存數(shù)據(jù)丟失,一個進(jìn)行全量數(shù)據(jù)備份,一個進(jìn)行增量操作指令的備份。
Redis集群模式
在Redis集群主從結(jié)構(gòu)下,如果不開啟master的持久化,在master意外宕機(jī)后,由于數(shù)據(jù)全在master節(jié)點的內(nèi)存上,在master節(jié)點重啟后數(shù)據(jù)將會全部丟失。此時進(jìn)行主從數(shù)據(jù)同步操作,將會導(dǎo)致slave從節(jié)點的數(shù)據(jù)也會被master節(jié)點的空數(shù)據(jù)覆蓋清理掉。
在master-slave主從模式下master node 必須開啟持久化功能來保證數(shù)據(jù)不丟失。
但是master-node開啟持久化并不意味著數(shù)據(jù)就不會丟失。
數(shù)據(jù)異步復(fù)制時丟失
因為master-slave節(jié)點的數(shù)據(jù)同步是異步的,可能在數(shù)據(jù)同步完成前master節(jié)點發(fā)生宕機(jī),此時這部分的數(shù)據(jù)就意外丟失了。
腦裂時數(shù)據(jù)丟失
所謂腦裂,是指master節(jié)點自己突然脫離正常網(wǎng)絡(luò)(并沒有宕機(jī),還在運行中),與其他的salve節(jié)點的連接斷開,但哨兵會認(rèn)為master節(jié)點已經(jīng)宕機(jī),要從slave節(jié)點中重新選舉新的master節(jié)點,這個時候集群中實際存在兩個master節(jié)點,這就是腦裂。
雖然某一個slave節(jié)點被選舉為master節(jié)點,但是客戶端連接的master仍然是舊master節(jié)點,數(shù)據(jù)還是寫向舊master節(jié)點上,當(dāng)舊master節(jié)點再次恢復(fù)后,會作為slave節(jié)點掛在新master節(jié)點上,舊master節(jié)點中的數(shù)據(jù)會被新master節(jié)點上的數(shù)據(jù)同步清理掉。
解決方案
通過redis.conf 中配置項,設(shè)置至少有1個slave,數(shù)據(jù)復(fù)制和同步的延遲不能超過8秒,來減少異步復(fù)制和腦裂導(dǎo)致的數(shù)據(jù)丟失 :
min-slaves-to-write 1 min-slaves-max-lag 8如果所有的slave節(jié)點的數(shù)據(jù)同步延時都超過8s,master節(jié)點拒絕寫請求。
這種情況下腦裂也就最多丟失8秒的數(shù)據(jù)。
總結(jié)
以上是生活随笔為你收集整理的解决Redis持久化数据丢失的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring项目启动慢问题
- 下一篇: java毕业生设计原创网络文学管理系统计