一. 基礎概覽
1.1 兩種方式
Redis具有持久化功能,其會按照設定以快照或操作日誌的形式將資料持久化到硬碟。根據持久化使用技術的不同,Redis的持久化分為兩種:RDB 和 AOF。
1.2 基本原理
Redis持久化也稱為鈍化,是指將記憶體中的資料庫的狀態描述資訊儲存到磁碟中。
1.3 載入
當胸痛重新啟動時,自動載入持久化檔案,並根據檔案中資料庫狀態描述資訊將資料恢復到記憶體中,這個資料恢復過程稱為啟用。
需要注意的是,RDB是預設持久化方式,但Redis允許RDB和AOF兩種持久化技術同時開啟。兩種技術同時開啟的狀態下,系統啟動時若兩種持久化檔案同時存在,則優先載入AOF持久化檔案。
二. RDB 持久化
RDB,Redis DataBase,是指將記憶體中某一時刻的資料快照全量寫入到指定rdb檔案的持久化技術。RDB持久化預設是開啟的。當Redis啟動時會自動讀取RDB檔案,將資料從硬碟載入到記憶體,以恢復Redis資料。
2.1 持久化的執行
RDB持久化的執行有三種方式:手動save命令、手動bgsave,與自動條件觸發。
(1)手動save命令
save
透過在redis-cli客戶端中執行save命令,可立即進行一次持久化儲存。save命令在執行期間會阻塞redis-server程序,直到持久化過程完畢。而在redis-server程序阻塞期間,redis不能處理任何讀寫請求,無法對外提供服務。
(2)手動bgsave
bgsave
透過在redis-cli客戶端中執行bgsave命令,可立即進行一次持久化儲存。不同於save命令的是,正如該命令的名稱一樣,background save,後臺允許save。bgsave命令會使伺服器程序redis-server生成一個子程序,由該子程序負責完成儲存過程。在子程序進行儲存過程中,不會阻塞redis-server程序對客戶端讀寫請求的處理。
(3)自動條件觸發
自動條件觸發的本質仍是bgsave命令的執行。只不過是使用者透過在配置檔案中做相應的設定後,redis會根據設定資訊自動呼叫bgsave命令執行。
(4)檢視持久化時間
透過lastsave命令可以檢視最近一次執行持久化的時間,其返回的是一個Unix時間戳。
lastsave
2.2 RDB最佳化配置
RDB相關的配置在redis.conf檔案中的SNAPSHOTTING部分。
################################ SNAPSHOTTING ################################ # Save the DB to disk. # # save <seconds> <changes> [<seconds> <changes> ...] # # Redis will save the DB if the given number of seconds elapsed and it # surpassed the given number of write operations against the DB. # # Snapshotting can be completely disabled with a single empty string argument # as in following example: # # save "" # # Unless specified otherwise, by default Redis will save the DB: # * After 3600 seconds (an hour) if at least 1 change was performed # * After 300 seconds (5 minutes) if at least 100 changes were performed # * After 60 seconds if at least 10000 changes were performed # # You can set these explicitly by uncommenting the following line. # 下面是預設持久規則 # save 3600 1 300 100 60 10000
# 如果60s內執行了10000次的變更操作,則執行一次bgsave;如果這個條件不成立,例如,60s內就執行了9990次, 那麼就檢查300s內,是否變化了100次+,如果滿足,則bgsave
# 一次;如果還是不滿足,例如 5分鐘(300s),就執行了99次,那麼怎看上面的規則;判斷 3600s,變化次數是否不小於1次(至少一次),如果至少一次,則觸發 bgsave。
# 即:這兒定義的觸發 持久化的條件:依次判斷 【60 10000】?【300 100】? 【3600 1】? 。要求是越來越低了。
# By default Redis will stop accepting writes if RDB snapshots are enabled # (at least one save point) and the latest background save failed. # This will make the user aware (in a hard way) that data is not persisting # on disk properly, otherwise chances are that no one will notice and some # disaster will happen. # # If the background saving process will start working again Redis will # automatically allow writes again. # # However if you have setup your proper monitoring of the Redis server # and persistence, you may want to disable this feature so that Redis will # continue to work as usual even if there are problems with disk, # permissions, and so forth. stop-writes-on-bgsave-error yes ## 上面的引數 是 bgsave 遇到錯誤時,是否阻止寫入的引數
# Compress string objects using LZF when dump .rdb databases? # By default compression is enabled as it's almost always a win. # If you want to save some CPU in the saving child set it to 'no' but # the dataset will likely be bigger if you have compressible values or keys. rdbcompression yes ##是否採用壓縮的引數
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. # This makes the format more resistant to corruption but there is a performance # hit to pay (around 10%) when saving and loading RDB files, so you can disable it # for maximum performances. # # RDB files created with checksum disabled have a checksum of zero that will # tell the loading code to skip the check. rdbchecksum yes ##備份校驗的引數
# Enables or disables full sanitization【淨化;消毒;衛生處理;】 checks for ziplist and listpack etc when # loading an RDB or RESTORE payload. This reduces the chances of a assertion or # crash later on while processing commands. # Options: # no - Never perform full sanitization # yes - Always perform full sanitization # clients - Perform full sanitization only for user connections. # Excludes: RDB files, RESTORE commands received from the master # connection, and client connections which have the # skip-sanitize-payload ACL flag. # The default should be 'clients' but since it currently affects cluster # resharding via MIGRATE, it is temporarily set to 'no' by default. # # sanitize-dump-payload no # The filename where to dump the DB dbfilename dump.rdb # Remove RDB files used by replication in instances without persistence # enabled. By default this option is disabled, however there are environments # where for regulations【法規;規則;章程】 or other security concerns【憂慮;擔心】, RDB files persisted on # disk by masters in order to feed replicas, or stored on disk by replicas # in order to load them for the initial synchronization, should be deleted # ASAP【as soon as possible】. Note that this option ONLY WORKS in instances that have both AOF # and RDB persistence disabled, otherwise is completely ignored.--注意生效的前提。 # # An alternative (and sometimes better) way to obtain the same effect is # to use diskless replication on both master and replicas instances. However # in the case of replicas, diskless is not always an option. rdb-del-sync-files no # The working directory. ##這一part是說設定目錄的 # # The DB will be written inside this directory, with the filename specified # above using the 'dbfilename' configuration directive. # # The Append Only File will also be created inside this directory. ##注意:對AOF檔案(備份方式)同樣有用 # # Note that you must specify a directory here, not a file name. dir ./ ################################# REPLICATION #################################
需要說明的是,下面這語句比較考驗 英語 能力。
By default this option is disabled 【預設是關閉的】, however there are environments where for regulations or other security concerns 【但是考慮的一些要求】,
RDB files 【【【 persisted on disk by masters in order to feed replicas, or stored on disk by replicas in order to load them for the initial synchronization 這些都是定語,
是用來描述 RBD file 的 用途,在master是什麼用途,在replica上什麼用途】】】, should be deleted ASAP.
2.3 RDB檔案結構
RDB持久化檔案dump.rdb整體上有五部分構成:
(1)SOF
SOF(Start Of File)是一個常量,一個字串REDIS,僅包含這5個字元,其長度為5.用於標識RDB檔案的開始,以便在載入RDB檔案時可以迅速判斷出檔案是否是RDB檔案。
(2)rdb_version
這是一個整數,長度為4位元組,表示RDB檔案的版本號。
(3)EOF
EOF(End Of File)是一個常量,佔1個位元組,用於標識RDB資料的結束,校驗和開始。
(4)check_sum
校驗和check_sum用於判斷RDB檔案中的內容是否出現資料異常。其採用的是CRC校驗演算法。
CRC 校驗演算法:
在持久化時,先將SOF、rdb_version及記憶體資料庫中的資料快照,這三者的二進位制資料拼接起來,形成一個二進位制資料(假設稱為資料a),然後再使用這個除以校驗和check_sum,此時可獲取到一個餘數b,然後再將b 拼接到a的後面,形成了databases。----這樣說應該不對吧?應該說形成了SOF+rdb_version+databases的結構體。
再載入時,需要先使用check_sum,對RDB檔案進行資料情況判斷(是否損壞)。驗證過程為:只需將RDB檔案中除EOF與check_sum外的資料除以check_sum,只要除得到餘數不是0,就說明檔案發生了損壞。當然,如果餘數是0,也不能肯定檔案沒有損壞。
(5)databases
databases部分是RDB檔案中最重要的資料部分,其可以包含任意多個非空資料庫。而每個database又是由三部分構成:
*** SODB:是一個常量,佔1個位元組,用於標識一個資料庫的開始。
*** db_number:資料庫編號。
*** key_value_pairs:當前資料庫中的鍵值對資料。
每個key_value_pairs又由很多個用於描述鍵值對的資料構成。
*** VALUE_TYPE:是一個常量,佔1個位元組,用於標識該鍵值對中value的型別。
*** EXPIRETIME_UNIT:是一個常量,佔1個位元組,用於標識過期時間的單位是秒還是毫秒。
*** time:當前key-value的過期時間。
概況總結如下
2.4 RDB持久化過程
對於Redis預設的RDB持久化,在進行bgsave持久化時,redis-save程序會fork出一個bgsave子程序,由該子程序以非同步方式負責完成持久化。而在持久化過程中,redis-server程序不會阻塞,其會繼續接收並處理使用者的讀寫請求。
bgsave子程序詳細工作原理如下:
由於子程序可以繼承父程序的所有資源,且父程序不能拒絕子程序的繼承權。所以,bgsave子程序有權讀取到redis-server程序寫入到記憶體中的使用者資料,使得將記憶體資料持久化到dump.rdb稱為可能。
bgsave子程序在持久化時首先會將記憶體中的全量資料copy到磁碟中的一個RDB臨時檔案,copy結束後,再將該檔案rename為dump.rdb,替換掉原來的同名檔案。
不過,在進行持久化過程中,如果redis-server程序接收到了使用者寫請求,則系統會將記憶體中發生資料修改的物理塊copy出一個副本。等記憶體中的全量資料copy結束後,會再將副本中的資料copy到RDB臨時檔案。這個副本的生成是由Linux系統的寫時複製技術(Copy-On-Write)實現的。
概況總結如下
內容補充--寫時複製
寫時複製技術是LInux系統的一種程序管理技術。
原本再Unix系統中,當一個主程序透過fork()系統呼叫建立子程序後,核心程序會複製主程序的整個記憶體空間中的資料,然後分配給子程序。這中方式存在的問題由以下幾點:
(1)過程非常耗時;(2)過程降低了系統效能;(3)如果主程序修改了記憶體資料,子程序副本中的資料是沒有修改的。即出現了資料冗餘,而冗餘資料最大的問題是資料一致性無法保證。
現代的Linux則採用了更為有效的方式:寫時複製。子程序會繼承父程序的所有資源,其中就包括主程序的記憶體空間。即子程序和父程序共享記憶體。只要記憶體被共享,那麼該記憶體就是隻讀的(防寫的)。而寫時複製則是在任何一方需要寫入資料到共享記憶體時就會出現異常,此時核心程序就會將需要寫入的資料copy出一個副本寫入到另一塊非共享記憶體區塊。
在寫時複製的視角下,看bgsave,如下:
學習參閱宣告
【Redis影片從入門到高階】
【https://www.bilibili.com/video/BV1U24y1y7jF?p=11&vd_source=0e347fbc6c2b049143afaa5a15abfc1c】