?【關閉文件、AOF 刷盤、釋放內存這三個任務都有各自的任務隊列】所以不是單線程
Redis有兩種持久化方案:
-
RDB持久化
-
AOF持久化
-
基于Redis集群解決單機Redis存在的問題
【Redis是單進程的】
【也有人做分布式section】
【主從集群中多個從就是做負載均衡的】
單機的Redis存在四大問題:
RDB持久化
【執行 bgsave 過程中,Redis 依然可以繼續處理操作命令的,也就是數據是能被修改的,關鍵的技術就在于寫時復制技術(Copy-On-Write, COW)。】
RDB全稱Redis Database Backup file(Redis數據備份文件),也被叫做Redis數據快照。簡單來說就是把內存中的所有數據都記錄到磁盤中。當Redis實例故障重啟后,從磁盤讀取快照文件,恢復數據。快照文件稱為RDB文件,默認是保存在當前運行目錄。【全量拷貝】
1.執行時機
RDB持久化在四種情況下會執行:
-
執行save命令
-
執行bgsave命令
-
Redis停機時
-
觸發RDB條件時
1)save命令
執行下面的命令,可以立即執行一次RDB:
redis-cli中執行save
save命令會導致主進程執行RDB,這個過程中其它所有命令都會被阻塞。只有在數據遷移時可能用到。
2)bgsave命令
下面的命令可以異步執行RDB:
bgsave
這個命令執行后會開啟獨立進程完成RDB,主進程可以持續處理用戶請求,不受影響。
3)停機時
Redis停機時會執行一次save命令,實現RDB持久化。
4)觸發RDB條件
Redis內部有觸發RDB的機制,可以在redis.conf文件中找到,格式如下:
?# 900秒內,如果至少有1個key被修改,則執行bgsave , 如果是save "" 則表示禁用RDBsave 900 1 ?save 300 10 ?save 60 10000
RDB的其它配置也可以在redis.conf文件中設置:
?# 是否壓縮 ,建議不開啟,壓縮也會消耗cpu,磁盤的話不值錢rdbcompression yes?# RDB文件名稱dbfilename dump.rdb ??# 文件保存的路徑目錄dir ./
2.RDB原理
bgsave開始時會fork主進程得到子進程【此時主進程是阻塞的,所以要加快fork的速度】,子進程共享主進程的內存數據。完成fork后讀取內存數據并寫入 RDB 文件。
fork采用的是copy-on-write(寫時復制技術):內存大時還是很耗時,還需要大量磁盤IO,對性能影響大。
-
當主進程執行讀操作時,訪問共享內存;
-
當主進程執行寫操作時,則會拷貝一份數據(數據副本),執行寫操作。fork會把共享內存標記為read-only,以后主進程讀操作時也往副本,頁表變了。
【所有進程都沒法操作物理內存,所以由操作系統給每個進程分配一個虛擬內存,操作系統還會維護虛擬內存和物理內存之間的映射關系表(頁表),從而實現讀寫。fork的過程就是對頁表做拷貝】
【redis一般預留空間,防止被副本翻倍消耗完】
3.小結
RDB方式bgsave的基本流程?
-
fork主進程得到一個子進程,共享內存空間
-
子進程讀取內存數據并寫入新的RDB文件
-
用新RDB文件替換舊的RDB文件
RDB會在什么時候執行?save 60 1000代表什么含義?
-
默認是服務停止時
-
代表60秒內至少執行1000次修改則觸發RDB
-
宕機數據會丟失
RDB的缺點?
-
RDB執行間隔時間長,兩次RDB之間寫入數據有丟失的風險
-
fork子進程、壓縮、寫出RDB文件都比較耗時
AOF持久化
【大大提高數據的安全性,彌補RDB】
1.AOF原理
AOF全稱為Append Only File(追加文件)。Redis處理的每一個寫命令都會記錄在AOF文件,可以看做是命令日志文件。【不像RDB每次都從頭開始寫文件,累加】
【先寫到Redis,再把命令寫到AOF文件,將來恢復只需要重新執行命令】
2.AOF配置
AOF默認是關閉的,需要修改redis.conf配置文件來開啟AOF:
?# 是否開啟AOF功能,默認是noappendonly yes# AOF文件的名稱appendfilename "appendonly.aof"
AOF的命令記錄的頻率也可以通過redis.conf文件來配:
?# 表示每執行一次寫命令,立即記錄到AOF文件,先操作內存再寫到磁盤(性能最差)appendfsync always # 寫命令執行完先放入AOF緩沖區,然后表示每隔1秒將緩沖區數據寫到AOF文件,是默認方案appendfsync everysec # 寫命令執行完先放入AOF緩沖區,由操作系統決定何時將緩沖區內容寫回磁盤appendfsync no
三種刷盤策略對比:
3.AOF文件重寫
【AOF執行rewrite的緩沖區。無法設置容量上限】
因為是記錄命令,AOF文件會比RDB文件大的多。而且AOF會記錄對同一個key的多次寫操作,但只有最后一次寫操作才有意義。通過執行bgrewriteaof命令(后臺子進程 bgrewriteaof來完成),可以讓AOF文件執行重寫功能,用最少的命令達到相同效果。
【子進程帶有主進程的數據副本,這里使用子進程而不是線程,防止共享數據更改(只讀)(主進程修改了會發生「寫時復制」,所以用副本保證數據安全)時使用鎖降低性能】
【aof文件壓縮后看不懂,此時再加命令會接著寫,不過不會反壓縮回來】
set num 123 和 set num 666
都是對num的操作,第二次會覆蓋第一次的值,因此第一個命令記錄下來沒有意義。【讀取當前數據庫中的所有鍵值對,然后將每一個鍵值對用一條命令記錄到「新的 AOF 文件」】
所以重寫命令后,AOF文件內容就是:mset name jack num 666
Redis也會在觸發閾值時自動去重寫AOF文件。閾值也可以在redis.conf中配置:
?# AOF文件比上次文件 增長超過多少百分比則觸發重寫auto-aof-rewrite-percentage 100# AOF文件體積最小多大以上才觸發重寫 auto-aof-rewrite-min-size 64mb
RDB與AOF對比
RDB和AOF各有自己的優缺點,如果對數據安全性要求較高,在實際開發中往往會結合兩者來使用。
【一般兩者一起用】
【RDB相當于備份,異地容災,機房毀了,aof也廢了】
【aof寫磁盤多,好在是異步的】
混合
前部分是rdb,當同步過程新來的就會進行aof降低數據丟失率。
-
兼容性差,如果開啟混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。
混合持久化是在AOF持久化的基礎上,定期進行RDB持久化。具體實現方式是在AOF重寫時,將RDB文件以二進制壓縮格式寫入到AOF文件的開頭,之后的數據再以AOF格式追加到文件的末尾。這樣,在Redis重啟時,可以優先加載RDB部分的數據,快速恢復大部分數據,然后再通過AOF部分的命令來更新內存中的數據,以保證數據的完整性。
總結
Redis的持久化雖然可以保證數據安全,但也會帶來很多額外的開銷,因此持久化請遵循下列建議:
-
用來做緩存的Redis實例盡量不要開啟持久化功能【提高查詢效率的不需要持久化,查詢時再寫一遍就好。對于安全性要求高的,比如分布式鎖、庫存、驗訂單的流水需要持久化(可以專門放在一個redis實例)】
-
建議關閉RDB持久化功能,使用AOF持久化【可以混合。rdb會丟失數據】
-
利用腳本定期在slave節點做RDB,實現數據備份
-
設置合理的rewrite閾值,避免頻繁的bgrewrite
-
配置no-appendfsync-on-rewrite = yes,禁止在rewrite期間做aof,避免因AOF引起的阻塞【主從同步時還是要fork(大量磁盤IO),rewrite也有磁盤IO且時間長,aof刷盤也需要讀寫磁盤。rewrite占用磁盤高會影響aof刷盤】fsync刷盤
-
部署有關建議:
-
Redis實例的物理機要預留足夠內存,應對fork和rewrite【fork可能翻倍,寫時復制】
-
單個Redis實例內存上限不要太大,例如4G或8G。可以加快fork的速度、減少主從同步、數據遷移壓力
-
不要與CPU密集型應用部署在一起【fork等CPU要求高。es也高】
-
不要與高硬盤負載應用一起部署。例如:數據庫、消息隊列
-