Redis持久化
預設情況下,Redis将記憶體資料庫快照儲存在名字為dump.rdb的二進制檔案中。
你可以對Redis進行設定,讓它在“N秒内資料至少有M個改動”這一條件被滿足時,自動儲存一次資料集。
比如說,以下設定會讓Redis在滿足“60秒内有至少有1000個鍵被改動”這一條件時,自動儲存一次資料庫集。
還可以手動執行指令生成RDB快照,進入redis用戶端執行指令save和bgsave可以生成dump.rdb檔案,每次指令執行都會将所有redis記憶體快照到一個新的rdb檔案裡,并覆寫原有rdb快照檔案。
Redis借助作業系統提供的寫時複制技術(Copy-On-Write,COW),在生成快照的同時,依然可以正常處理寫指令。簡單來說,bgsave子程序是由主線程fork生成的,可以共享主線程的所有記憶體資料。bgsave子程序和bgsave子程序互相不影響。但是,如果主線程要修改一塊資料,那麼,這塊資料就會被複制一份,生成該資料的副本。然後,bgsave子程序會把這個副本資料寫入RDB檔案,而在這個過程中,主線程依然可以直接修改原來的資料。
save與bgsave
<col>
指令
save
bgsave
IO類型
同步
異步
是否阻塞redis其他指令
是
否(在生成子程序執行調用fork函數時會有短暫阻塞)
複雜度
O(n)
優點
不會消耗額外記憶體
不阻塞用戶端指令
缺點
阻塞用戶端指令
需要fork子程序,消耗記憶體
快照功能并不是非常耐久(durable):如果Redis因為某些原因而造成故障停機,那麼伺服器将丢失最近寫入、且仍未儲存到快照的那些資料。從1.1版本開始,Redis增加了一種完全耐久的持久化方式:AOF持久化,将修改的每一條指令記錄進檔案appendonly.aof(先寫入os cache,每隔一段時間fsync到磁盤)。
你可以通過修改配置檔案來打開AOF功能:
從現在開始,每當Redis執行一個改變資料集的指令時(比如SET),這個指令就會被追加到AOF檔案的末尾。
這樣的話,當Redis重新啟動時,程式就可以通過重新執行AOF檔案中的指令來達到重建資料集的目的。
你可以配置Redis多久才将資料fsync到磁盤一次。
有三個選項:
推薦的措施為everysec,可兼顧速度和安全性。
AOF檔案裡可能有太多沒用的指令,是以AOF會定期根據記憶體的最新資料生成aof檔案。
例如,執行了如下指令:
重寫AOF檔案裡變成:
如下兩個配置可以控制AOF自動重寫頻率:
當然,AOF還可以手動重寫,進入redis用戶端執行指令bgrewriteaof重寫AOF。
注意:AOF重寫redis會fork出一個子程序去做(與bgsave指令類似),不會對redis正常指令處理有太多的影響。
RDB
AOF
啟動優先級
低
高
體積
小
大
恢複速度
快
慢
資料安全性
容易丢資料
根據政策決定
生産環境都可以啟用,redis啟動時如果既有rdb檔案又有aof檔案則會優先選擇aof檔案恢複資料,因為aof一般來說資料更安全一點。
重新開機Redis時,我們很少使用RDB來恢複記憶體狀态,因為會丢失大量資料。我們通常使用AOF重放,但是重放AOF日志性能相對RDB來說要慢很多,這樣在Redis示例很大的情況下,啟動需要花費很長的時間。Redis4.0為了解決這個問題,帶來了一個新的持久化選項——混合持久化。
通過如下配置可以開啟混合持久化(必須先開啟AOF):
如果開啟了混合持久化,AOF在重寫時,不再是單純的将記憶體資料轉換為RESP指令寫入AOF檔案,而是将重寫這一刻之前的記憶體做RDB快照處理,并且将RDB快照内容和增量的AOF修改記憶體資料的指令存在一起,都寫入新的AOF檔案,新的檔案一開始不叫appendonly.aof,等到重寫完新的AOF檔案才會進行改名,覆寫原有的AOF檔案,完成新舊兩個AOF檔案的替換。
于是Redis重新開機的時候,可以先加載RDB的内容,然後再重放增量AOF日志就可以完全替代之前的AOF全量檔案重放,是以重新開機效率大幅得到提升。
寫crontab定時排程腳本,每小時都copy一份rdb或aof的備份到一個目錄中去,僅僅保留最近48小時的備份。
每天都儲存一份當日的資料備份到一個目錄中去,可以保留近1個月的備份。
每天晚上将目前機器聲的備份複制到其他機器上,以防機器損壞。
Redis主從架構
如果你為master配置了一個slave,不管這個slave是否是第一次連接配接上Master,他都會發送一個PSYNC指令給master請求複制資料。master收到PSYNC指令後,會在背景進行資料持久化通過bgsave生成最新的rdb快照檔案,持久化期間,master會繼續接收用戶端的請求,它會把這些可能修改資料集的請求緩存在記憶體中。當持久化進行完畢後,master會把這份rdb檔案資料集發送給slave,slave會把接收到的資料進行持久化生成rdb,然後再加載到記憶體中。然後,master再将之前緩存在記憶體中的指令發送給slave。
當master與slave之間的連接配接由于某些原因而斷開時,slave能夠自動重連master,如果master收到了多個slave并發連接配接請求,它隻會進行一次持久化,而不是一個連接配接一次,然後再把這一份持久化的資料發送給多個并發連接配接的salve。
如果有很多從節點,為了緩解主從複制風暴(多個從節點同時複制主節點導緻主節點壓力過大),可以做如下架構,讓部分從節點與從節點(與主節點同步)同步資料。

用戶端可以一次性發送多個請求而不用等待伺服器的響應,待所有指令都發送完後再一次性讀取服務的響應,這樣可以極大的降低多條指令執行的網絡傳輸開銷,管道執行多條指令的網絡開銷實際上隻相當于一次指令執行的網絡開銷。需要注意到是用pipiline方式打包指令發送,redis必須在處理完所有指令先前緩存起所有指令的處理結果。打包的指令越多,緩存消耗記憶體也越多。是以并不是打包的指令越多越好。
pipeline中發送的每個command都會被server立即執行,如果執行失敗,将會在此後的響應中得到資訊;也就是pipeline并不是表達“所有command都一起成功”的語義,管道中指令失敗,後面指令不會有影響,繼續執行。
Redis在2.6版本推出了腳本功能,允許開發者使用Lua語言編寫腳本傳到Redis中執行。使用腳本的好處如下:
減少網絡開銷:本來5次網絡請求的操作,可以用一個請求完成,原先5次的邏輯放在redis伺服器上完成。使用腳本,減少了網絡往返時延。類似于管道。
原子操作:Redis會将整個腳本作為一個整體執行,中間不會被其他指令插入。管道不是原子的,不過redis的批量操作指令(類似mset)是原子的。
替代redis的事務功能:redis自帶的事務功能很雞肋,報錯不支援復原,而redis的lua腳本幾乎實作了正常的事務功能,支援報錯復原操作,官方推薦如果要使用redis的事務功能可以用redis lua替代。
注意:不要在Lua腳本中出現死循環和耗時的運算,否則redis會阻塞,将不接受其他的指令,是以使用時注意不能出現死循環,耗時的運算。redis是單程序、單線程執行腳本。管道不會阻塞redis。
Redis哨兵高可用架構
sentinel哨兵是特殊的redis服務,不提供讀寫服務,主要用來監控redis執行個體節點。
哨兵架構下client端第一次從哨兵找出redis的主節點,後續就直接通路redis的主節點,不會每次都通過sentinel代理通路redis的主節點,當redis的主節點發生變化,哨兵會在第一時間感覺到,并且将新的redis主節點通知給client端(這裡redis的client端一般都實作了訂閱功能,訂閱sentinel釋出的節點變動消息)。
。