首頁 > 軟體

Redis高可用之持久化

2023-04-08 06:01:52

一、高可用

什麼是高可用

在web伺服器中,高可用是指伺服器可以正常存取的時間,衡量的標準是在多長時間內可以提供正常服務(99.9%、99.99%、99.999%等等)。

但是在Redis語境中,高可用的含義似乎要寬泛一些,除了保證提供正常服務( 如主從分離、快速容災技術),還需要考慮資料容量的擴充套件、資料安全不會丟失等。

Redis的高可用

Redis中,實現高可用的技術主要包括持久化、主從複製、哨兵和cluster叢集

持久化:持久化是最簡單的高可用方法(有時甚至不被歸為高可用的手段),主要作用是資料備份,即將資料儲存在硬碟,保證資料不會因程序退出而丟失。

主從複製:主從複製是高可用Redis的基礎,哨兵和叢集都是在主從複製基礎上實現高可用的。主從複製主要實現了資料的多機備份(和同步),以及對於讀操作的負載均衡和簡單的故障恢復。

缺陷:故障恢復無法自動化,寫操作無法負載均衡,儲存能力受到單機的限制。

哨兵:在主從複製的基礎上,哨兵實現了自動化的故障恢復。(主掛了,找一個從成為新的主,哨兵節點進行監控)

缺陷:寫操作無法負載均衡,儲存能力受到單機的限制;哨兵無法對從節點進行自動故障轉移,在讀寫分離場景下,從節點故障會導致讀服務不可用,需要對從節點做額外的監控、切換操作。

Cluster叢集:通過叢集,Redis解決了寫操作無法負載均衡,以及儲存能力受到單機限制的問題,實現了較為完善的高可用方案(6臺起步,成雙成對,3主3從)

二、Redis持久化

持久化功能

Redis是記憶體資料庫,資料都是儲存在記憶體中,為了避免伺服器斷電等原因導致Redis程序異常退出後資料的永久丟失,需要定期將Redis中的資料以某種形式(資料或命令)從記憶體儲存到硬碟;當下次Redis重啟時,利用持久化檔案實現資料恢復。除此之外,為了進行災難備份,可以將持久化檔案拷貝到一個遠端位置。

災難備份:一般做異地備份,發生災難後切換節點。

Redis提供兩種方式進行持久化

  • RDB持久化:原理是將Redis在記憶體中的資料庫記錄定時儲存到磁碟上。(定時對記憶體中的資料生成快照,以檔案形式儲存在硬碟中)
  • AOF持久化(append only file):原理是將Reids 的操作紀錄檔以追加的方式寫入檔案,類似於MySQL的binlog。(類似於Mysql的二進位制紀錄檔)(以追加的方式將寫和刪的操作命令記錄到AOF檔案中)

由於AOF持久化的實時性更好,即當程序意外退出時丟失的資料更少,因此AOF是目前主流的持久化方式,不過RDB持久化仍然有其用武之地。(RDB體積小,恢復速度更快。對效能影響較小。

RDB持久化

RDB持久化是指在指定的時間間隔內將記憶體中當前程序中的資料生成快照儲存到硬碟(因此也稱作快照持久化),用二進位制壓縮儲存,儲存的檔案字尾是rdb;當Redis重新啟動時,可以讀取快照檔案恢復資料。

 觸發條件

RDB持久化的觸發分為手動觸發和自動觸發

手動觸發

save命令和bgsave命令都可以生成RDB檔案

save命令阻塞Redis伺服器程序,直到RDB檔案建立完畢為止,在Redis伺服器阻塞期間,伺服器不能處理任何命令請求。

bgsave命令會建立一個子程序,由子程序來負責建立RDB檔案,父程序(即Redis主程序)則繼續處理請求。

bgsave命令執行過程中,只有fork子程序時會阻塞伺服器,而對於save命令,整個過程都會阻塞伺服器,因此save已基本被廢棄,線上環境要杜絕save的使用。

自動觸發

在自動觸發RDB持久化時,Redis也會選擇bgsave而不是save來進行持久化。

自動觸發最常見的情況是在組態檔中通過save m n 指定當m秒內發生n次變化時,會觸發bgsave。

vim /etc/redis/6379.conf219行以下三個save條件滿足任意一個時,都會引起bgsave的呼叫save 900 1      #當時間到900秒時,如果redis資料發生了至少1次變化,則執行bgsavesave 300 10     #當時間到300秒時,如果redis資料發生了至少10次變化,則執行bgsavesave 60 10000   #當時間到60秒時,如果redis資料發生了至少10000次變化,則執行bgsave242行開啟RDB檔案壓縮rdbcompression yes254行 指定RDB檔名dbfilename dump.rdb264行 指定RDB檔案和AOF檔案所在目錄dir /var/lib/redis/6379

由此可見RDB時效性不夠,最快也需60秒備份一次,如果50幾秒伺服器宕了,則備份失敗

其他觸發機制

除savemn以外,還有其他情況也會觸發

  • 在主從複製場景下,如果從節點執行全量複製操作,則主節點會執行bgsave命令,並將rdb檔案傳送給從節點。
  • 執行shutdown命令時,自動執行rdb持久化。

bgsave執行流程

1、Redis父程序首先判斷:當前是否在執行save,或 bgsave/ bgrewriteaof 的子程序,如果在執行則bgsave命令直接返回。

  • bgsave/bgrewriteaof 的子程序不能同時執行,主要是基於效能方面的考慮:兩個並行的子程序同時執行大量的磁碟寫操作,可能引起嚴重的效能問題。

2、父程序執行fork操作建立子程序,這個過程中父程序是阻塞的,Redis不能執行來自使用者端的任何命令。

3、父程序fork後,bgsave 命令返回"Background saving started" 資訊並不再阻塞父程序,並可以響應其他命令。

4、子程序建立RDB檔案,根據父程序記憶體快照生成臨時快照檔案,完成後對原有檔案進行原子替換。(原子替換:檔案整體替換,要麼都發生,要麼都不發生)

5、子程序傳送訊號給父程序表示完成,父程序更新統計資訊。

啟動時載入

  • RDB檔案的載入工作是在伺服器啟動時自動執行的,並沒有專門的命令。但是由於AOF的優先順序更高,因此當AOF開啟時,Redis會優先載入AOF檔案來恢復資料;只有當AOF關閉時,才會在Redis伺服器啟動時檢測RDB檔案,並自動載入。 伺服器載入RDB檔案期間處於阻塞狀態,直到載入完成為止。
  • Redis載入RDB檔案時,會對RDB檔案進行校驗,如果檔案損壞,則紀錄檔中會列印錯誤,Redis啟動失敗。

AOF持久化

  • RDB持久化是將程序資料寫入檔案,而AOF持久化,則是將Redis執行的每次寫、刪除命令記錄到單獨的紀錄檔檔案中,查詢操作不會記錄。
  • 當Redis重啟時再次執行AOF檔案中的命令來恢復資料。(重放命令進行恢復)。
  • 與RDB相比,AOF的實時性更好,因此已成為主流的持久化方案。

開啟AOF

Redis伺服器預設開啟RDB,在/etc/redis/6379.conf組態檔中

/etc/init.d/redis_6379 restart

#重啟redis

執行流程

由於需要記錄Redis的每條寫命令,因此AOF不需要觸發。

流程包括:

  • 命令追加:將Redis的寫命令追加到緩衝區aof_buf
  • 檔案寫入和檔案同步:根據不同的同步策略將aof_buf中的內容同步到硬碟
  • 檔案重寫:定期重寫AOF檔案,達到壓縮目的(將過期資料、無效命令、多條命令,進行壓縮或刪除)

命令追加

  • Redis先將寫命令追加到緩衝區,而不是直接寫入檔案,主要是為了避免每次有寫命令都直接寫入硬碟,導致硬碟IO成為Redis負載的瓶頸。
  • 命令追加的格式是Redis命令請求的協定格式,它是一種純文字格式,具有相容性好、可讀性強、容易處理、操作簡單避免二次開銷等優點。
  • 在AOF檔案中,除了用於指定資料庫的select命令(如select 0為選中0號資料庫)是由Redis新增的, 其他都是使用者端傳送來的寫命令。

檔案寫入和檔案同步

Redis提供了多種AOF快取區的同步檔案策略,策略涉及到作業系統的write函數和fsync函數,說明如下:

  • 為了提高檔案寫入效率,在現代作業系統中,當用戶呼叫write函數將資料寫入檔案時,作業系統通常會將資料暫存到一個記憶體緩衝區裡,當緩衝區被填滿或超過了指定時限後,才真正將緩衝區的資料寫入到硬碟裡。
  • 這樣的操作雖然提高了效率,但也帶來了安全問題:如果計算機停機,記憶體緩衝區中的資料會丟失。因此係統同時提供了fsync、fdatasync等同步函數,可以強制作業系統立刻將緩衝區中的資料寫入到硬碟裡,從而確保資料的安全性。

AOF快取區的同步檔案策略存在三種同步方式

  • appendfsync always:命令寫入aof_buf後立即呼叫系統fsync操作同步到AOF檔案。安全性高,效能低。
  • appendfsync no:當緩衝區被填滿或超過了指定時限後(預設30秒),才將緩衝區的資料寫入到硬碟裡。效能高,但安全性低。
  • appendfsync everysec:每秒同步一次,是效能和資料安全性的平衡,因此是Redis的預設設定。

檔案重寫

  • 隨著時間流逝,Redis伺服器執行的寫命令越來越多,AOF檔案也會越來越大;過大的AOF檔案不僅會影響伺服器的正常執行,也會導致資料恢復需要的時間過長。
  • 檔案重寫是指定期重寫AOF檔案,減小AOF檔案的體積。需要注意的是,AOF 重寫是把Redis程序內的資料轉化為寫命令,同步到新的AOF檔案;不會對舊的AOF檔案進行任何讀取、寫入操作!
  • 關於檔案重寫需要注意的另一點是:對於AOF持久化來說,檔案重寫雖然是強烈推薦的,但並不是必須的;即使沒有檔案重寫,資料也可以被持久化並在Redis啟動的時候匯入。因此在一些現實中,會關閉自動的檔案重寫,然後通過定時任務在每天的某一時刻定時執行。

檔案重寫之所以能夠壓縮AOF檔案,是因為

  • 過期的資料不再寫入檔案。
  • 無效的命令不再寫入檔案:如有些資料被重複設值(set key v1, set key v2)、 有些資料被刪除了(set myset vl, del myset)等。
  • 多條命令可以合併為一個:如sadd myset v1, sadd myset v2, sadd myset v3可以合併為sadd myset v1 v2 v3。(sadd新增集合)

rewrite之後aof檔案會儲存keys的最後狀態,清除掉之前冗餘的,來縮小這個檔案。

由此可以看出,由於重寫後AOF執行的命令減少了,檔案重寫既可以減少檔案佔用的空間,也可以加快恢復速度。

檔案重寫的觸發方式

  • 手動觸發: 直接呼叫bgrewriteaof命令,該命令的執行與bgsave有些類似:都是fork子程序進行具體的工作,且都只有在fork時阻塞。
  • 自動觸發: 通過設定auto-aof-rewrite-min-size選項和auto-aof-rewrite-percentage選項來自動執行BGREWRITEAOF。

只有當這兩個選項同時滿足,才會自動觸發AOF重寫

 auto-aof-rewrite-percentage 100    

#檔案的大小超過基準百分之多少後觸發bgrewriteaof。預設這個值設定為100,意味著當前aof是基準大小的兩倍的時候觸發bgrewriteaof。把它設定為0可以禁用自動觸發的功能。 即當前AOF檔案大小(即aof_current_size)是上次紀錄檔重寫時AOF檔案大小(aof_base_size)兩倍時,發生BGREWRITEAOF操作。 注意:例如上次檔案達到100M進行重寫,那麼這次需要達到200M時才進行重寫。檔案需要越來越大,所以一般不使用自動重寫。如果使用自動重寫,需要定期手動重寫干預一次,讓檔案要求恢復到100M。

auto-aof-rewrite-min-size 64mb    

 #當檔案大於64M時才會進行重寫  #當前aof檔案大於多少位元組後才觸發。當前AOF檔案執行BGREWRITEAOF命令的最小值,避免剛開始啟動Reids時由於檔案尺寸較小導致頻繁的BGREWRITEAOF

檔案重寫流程

(1)Redis父程序首先判斷當前是否存在正在執行bgsave/bgrewriteaof的子程序,如果存在則bgrewriteaof命令直接返回,如果存在bgsave命令則等bgsave執行完成後再執行。(正常情況下使用AOF就會使用AOF進行記錄,不會使用RDB。主從複製時會自動觸發bgsave命令)

(2)父程序執行fork操作建立子程序,這個過程中父程序是阻塞的(無法接受任何使用者端的請求)。

(3.1)父程序fork後,bgrewriteaof 命令返回"Background append only file rewrite started" 資訊並不再阻塞父程序,並可以響應其他命令。Redis的所有寫命令依然寫入AOF緩衝區,並根據appendfsync策略同步到硬碟,保證原有AOF機制的正確。

(3.2)由於fork操作使用寫時複製技術,子程序只能共用fork操作時的記憶體資料。由於父程序依然在響應命令,因此Redis使用AOF重寫緩衝區(aof_rewrite_ buf)儲存這部分資料,防止新AOF檔案生成期間丟失這部分資料。也就是說,bgrewriteaof執行期間,Redis的寫命令同時追加到aof_ buf和aof_rewirte_ buf兩個緩衝區。 (保證新寫入的資料不丟失)

(4)子程序根據記憶體快照,按照命令合併規則寫入到新的AOF檔案。

(5.1)子程序寫完新的AOF檔案後,向父程序發訊號,父程序更新統計資訊,具體可以通過info persistence檢視。

(5.2)父程序把AOF重寫緩衝區的資料寫入到新的AOF檔案,這樣就保證了新AOF檔案所儲存的資料庫狀態和伺服器當前狀態一致。

(5.3)使用新的AOF檔案替換老檔案,完成AOF重寫。(替換是原子性的)

 啟動時載入

  • 當AOF開啟時,Redis啟動時會優先載入AOF檔案來恢復資料;只有當AOF關閉時,才會載入RDB檔案恢復資料。
  • 當AOF開啟,但AOF檔案不存在時,即使RDB檔案存在也不會載入。
  • Redis載入AOF檔案時,會對AOF檔案進行校驗,如果檔案損壞,則紀錄檔中會列印錯誤,Redis啟動失敗。但如果是AOF檔案結尾不完整(機器突然宕機等容易導致檔案尾部不完整),且aof-load-truncated引數開啟,則紀錄檔中會輸出警告,Redis忽略掉AOF檔案的尾部,啟動成功。aof-load-truncated引數預設是開啟的。

三、RDB和AOF的優缺點

RDB持久化的優缺點

優點

RDB檔案緊湊,體積小,網路傳輸快,適合全量複製;恢復速度比AOF快很多。當然,與AOF相比, RDB最重要的優點之一是對效能的影響相對較小。

(體積小,恢復速度更快,對效能影響較小。)

缺點

  • RDB檔案的致命缺點在於其資料快照的持久化方式決定了必然做不到實時持久化,而在資料越來越重要的今天,資料的大量丟失很多時候是無法接受的,因此AOF持久化成為主流。
  • 此外,RDB文 件需要滿足特定格式,相容性差(如老版本的Redis不相容新版本的RDB檔案)。
  • 對於RDB持久化,一方面是bgsave在進行fork操作時Redis主程序會阻塞,另一方面,子程序向硬碟寫資料也會帶來IO壓力。

(實時性差、相容性差、在fork子程序時會阻塞父程序。)

AOF持久化優缺點

  • 與RDB持久化相對應,AOF的優點在於支援秒級持久化、實時性好、相容性好,缺點是檔案大、恢復速度慢、對效能影響大。
  • 對於AOF持久化,向硬碟寫資料的頻率大大提高(everysec策略下為秒級),IO 壓力更大,甚至可能造成AOF追加阻塞問題。
  • AOF檔案的重寫與RDB的bgsave類似,會有fork時的阻塞和子程序的 IO 壓力問題。相對來說,由於AOF向硬碟中寫資料的頻率更高,因此對Redis主程序效能的影響會更大。

四、Redis效能管理

檢視Redis記憶體使用

方式一:進入資料庫檢視

方法二:命令列檢視

記憶體碎片率

記憶體碎片率計算方式

記憶體碎片率=Redis向作業系統申請的記憶體 / Redis中的資料佔用的記憶體

mem_fragmentation_ratio = used_memory_rss / used_memory

mem_fragmentation_ratio:記憶體碎片率。

used_memory_rss:是Redis向作業系統申請的記憶體。

used_memory:是Redis中的資料佔用的記憶體。

used_memory_peak:redis記憶體使用的峰值。

記憶體碎片如何產生

  • Redis內部有自已的記憶體管理器,為了提高記憶體使用的效率,來對記憶體的申請和釋放進行管理。
  • Redis中的值刪除的時候,並沒有把記憶體直接釋放、交還給作業系統,而是交給了Redis內部有記憶體管理器。
  • Redis中申請記憶體的時候,也是先看自己的記憶體管理器中是否有足夠的記憶體可用。
  • Redis的這種機制,提高了記憶體的使用率,但是會使Redis中有部分自己沒在用,卻不釋放的記憶體,導致了記憶體碎片的發生。

跟蹤記憶體碎片率

跟蹤記憶體碎片率,對理解Redis範例的資源效能是非常重要的:

  • 記憶體碎片率在1到1.5之間是正常的,這個值表示記憶體碎片率比較低,也說明Redis 沒有發生記憶體交換。
  • 記憶體碎片率超過1.5,說明Redis消耗了實際需要的實體記憶體的150%,其中50%是記憶體碎片率。
  • 記憶體碎片率低於1的,說明Redis記憶體分配超出了實體記憶體,作業系統正在進行記憶體交換(使用虛擬記憶體,會降低效能)。需要增加可用實體記憶體或減少Redis記憶體佔用。

解決碎片率大的問題

  • 如果Redis版本是4.0以下的,需要在redis-cli 工具上輸入shutdown save命令,讓Redis資料庫執行儲存操作並關閉Redis服務,再重啟伺服器。Redis伺服器重啟後,Redis 會將沒用的記憶體歸還給作業系統,碎片率會降下來。
  • Redis4.0版本開始,可以在不重啟的情況下,線上整理記憶體碎片,將未使用的記憶體歸還給作業系統。

config set activedefrag yes    #自動碎片清理  

memory purge                        #手動碎片清理

記憶體使用率

redis範例的記憶體使用率超過可用最大記憶體,作業系統將開始進行記憶體與swap空間交換。

避免記憶體交換髮生的方法

  • 針對快取資料大小選擇安裝Redis範例
  • 儘可能的使用Hash資料結構儲存
  • 設定key的過期時間 

內回收key

記憶體清理策略,保證合理分配redis有限的記憶體資源。

當記憶體使用達到設定的最大閾值時,需選擇一種key的回收策略,預設情況下回收策略是禁止刪除(noenviction)。

修改 /etc/redis/6379.conf 檔案中maxmemory-policy屬性

回收策略

  • volatile-lru  #使用LRU演演算法從已設定過期時間的資料集合中淘汰資料 (移除最近最少使用的key,針對設定了TTL的key)  ​
  •  volatile-ttl  #從已設定過期時間的資料集合中挑選即將過期的資料淘汰 (移除最近過期的key)  ​
  • volatile-random  #從已設定過期時間的資料集合中隨機挑選資料淘汰 (在設定了TTL的key裡隨機移除)  ​  
  • allkeys-lru  #使用LRU演演算法 從所有資料集合中淘汰資料 (移除最少使用的key,針對所有的key)
  • allkeys-random  #從資料集合中任意選擇資料淘汰(隨機移除key)  ​  
  • noenviction  #禁止淘汰資料(不刪除直到寫滿時報錯)

五、Redis的優化

設定使用者端連線超時時間

使用者端最大連線數

自動碎片清理

最大記憶體閥值

key回收策略。

控制key的長度

控制元素的大小

資料結構:Redis支援多種資料結構,包括字串、雜湊表、列表、集合和有序集合。選擇正確的資料結構可以提高效能並減少記憶體使用量。

設定過期key:強制要求所有的key必須設定過期時間,以優化redis記憶體。

冷熱分離:熱key需要單獨存放並分配合理的資源,防止大流量下直接沖垮整個快取系統。

資料壓縮:可以採用snappy、gzip 等壓縮演演算法來先將資料壓縮後再存入快取中,來節約redis的記憶體空間,但這種方法會使使用者端在讀取時還需要解壓縮,在這期間會消耗更多CPU資源,你需要根據實際情況進行權衡。建議,只是在redis匱乏時的一種方案。

記憶體淘汰優化:杜絕使用預設的記憶體淘汰策略,避免在業務擴充套件下Redis的記憶體持續膨脹,需要根據你的業務設定對應記憶體淘汰策略。

過期策略優化:由於redis採用的是定期刪除+懶載入刪除策略,且這個過程在redis 6.0之前是在主執行緒上執行的,建議所有key的過期時間用亂數打散,杜絕大批次的資料同時過期,拉胯redis的效能和造成快取雪崩。強制規範。

持久化優化:Redis支援兩種持久化選項:RDB和AOF。選擇正確的持久化選項可以提高效能並確保資料安全。

架構優化:讀寫分離能最大限度提高redis的效能,其中主庫負責資料寫入,從庫負責資料讀取;分片叢集是解決超大量資料導致效能瓶頸方案,如rediscluster。以上是在大流量下提高redis效能在架構上的優化。

lazy-free:在redis4.0+中支援,開啟lazy-free機制後,由主執行緒刪除bigkey,而較耗時的記憶體釋放會在後臺執行緒中執行,不會影響到主執行緒。

叢集:使用Redis叢集:如果Redis伺服器無法滿足效能需求,可以使用Redis叢集來擴充套件Redis伺服器。Redis叢集可以將資料分片並分佈在多個Redis伺服器上,從而提高效能和可延伸性。

使用管道:Redis支援管道操作,可以將多個命令一次性傳送到Redis伺服器,從而減少網路延遲。

以上就是Redis高可用之持久化的詳細內容,更多關於Redis持久化的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com