吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Redis持久化機制的實現原理和使用技巧

我快閉嘴 ? 來源:稀土掘金技術社區 ? 作者:稀土掘金技術社區 ? 2022-09-13 16:42 ? 次閱讀


Redis將數據存儲在內存中,宕機或重啟都會使內存數據全部丟失, Redis的持久化機制用來保證數據不會因為故障而丟失。

Redis提供兩種持久化方式,一種為內存快照方式,生成rdb文件,rdb是某一時間點內存數據的全量備份,文件內容是存儲結構非常緊湊的二進制序列化形式;另一種是AOF日志備份方式,日志保存的是基于數據的連續增量備份,日志文件內容是服務端執行的每一條指令的記錄文本。

兩種方式各有優略,下面的章節會詳細介紹兩種持久化機制的實現原理和使用技巧。

1.內存快照

Redis進行快照數據持久化時,為了不阻塞線上業務,要能夠響應客戶端請求。快照持久化的工作是將一個時間點內存數據序列化后同步到磁盤rdb文件。備份數據如何在內存中瞬間凝固,不再改變?文件IO操做怎樣才能不拖累服務端對客戶端的正常響應?這一切都要從Copy On Write說起。

1.1 快照原理——Copy On Write

Copy On Write簡寫為COW,又叫寫時復制,是操作系統為優化使用子進程采取的一種策略。

類Unix系統創建進程的主要方式是調用glibc的函數fork,熟悉Linux的人都知道:Linux操作系統的進程都是通過init進程(pid=1)或者其子進程fork(vfork)出來的。

fork()會產生一個與父進程完全相同的子進程,有兩次返回:將子進程的pid返回給父進程,0返回給子進程。如果小于0,說明創建進程失敗!下面是一個C語言的例子:

#include
#include

intmain(){
pid_tpid;
intcount=0;
pid=fork();
if(pid0)
printf("errorinfork!");
elseif(pid==0){
printf("childprocess,processidis%d/n",getpid());
count++;
}else{
printf("parentprocess,processidis%d/n",getpid());
count++;
}
printf("counttotal:%d/n",count);
return0;
}

輸出結果為:

parentprocess,processidis23049
counttotal:1
childprocess,processidis23050
counttotal:1

當前進程調用fork(),會創建一個跟當前進程完全相同的子進程(除了pid),所以子進程同樣是會執行fork()之后的代碼。父子進程的count變量都是1,說明父子進程使用了各自獨有的棧區(count變量存放在棧區)。

我們先來看一下CPU執行程序的流程。

dd86a140-3027-11ed-ba43-dac502259ad0.jpg

CPU在加載執行程序時,首先按照虛擬地址來尋址,然后通過MMU(內存管理單元)將虛擬地址轉換為物理地址。因為只有程序的一部分加入到內存中(按頁加載),所以會出現所尋找的地址不在內存中的情況(CPU產生缺頁異常),如果在內存不足的情況下,就會通過頁面調度算法來將內存中的頁面置換出來,然后將在外存中的頁面加入到內存中,使程序繼續正常運行。

Linux操作系統的每一個進程,都會分配有虛擬地址物理地址,虛擬地址和物理地址通過MMU保持映射關系。一個進程是一個主體,它有靈魂有身體,靈魂就是其虛擬地址空間(有相應的數據結構表示),包括:正文段、數據段、堆、棧這四個部分;相應的,內核會為這四個部分分配各自的物理塊(進程的身體)即:正文段塊、數據段塊、堆塊、棧塊。

我們再來看一下fork進程時寫時復制的過程:

ddb4f612-3027-11ed-ba43-dac502259ad0.jpg

fork產生子進程時,操作系統只為新生成的子進程創建虛擬空間結構,它們復制于父進程的虛擬空間結構,但是不為這些段分配物理內存,它們共享父進程的物理空間,當父子進程中有更改相應段的行為發生時,再為子進程相應的段分配物理空間,這就是寫時復制。

1.2 快照執行流程

Redis在持久化時會調用glibc的函數fork產生一個子進程,快照持久化完全交給子進程來處理,父進程繼續處理客戶端請求。

dde9506a-3027-11ed-ba43-dac502259ad0.jpg

可以通過在Redis客戶端輸入bgsave命令來觸發快照保存操作,Redis調用bgsaveCommand函數,該函數fork一個子進程,子進程剛剛產生時,它和父進程共享內存里面的代碼段和數據段。這時將父子進程比喻成一個連體嬰兒 非常恰當,這是Linux操作系統的機制,為了節約內存資源,盡可能的將內存資源共享起來。在進程分離的一瞬間,內存的增長幾乎沒有明顯的變化。子進程因為沒有數據的變化,它能感知到的內存數據在進程產生的一瞬間就凝固了,再也不會改變。父進程可以繼續處理客戶端請求,當子進程推出后,父進程調用相關函數處理子進程的善后工作。

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

2.AOF持久化

AOF日志存儲的Redis服務器的順序指令序列,只記錄對內存進行修改的指令記錄。有了AOF文件,就可以通過一個空的Redis實例順序執行所有的指令來恢復Redis當前實例的內存數據結構的狀態,這個過程叫做重放

2.1 AOF日志文件寫入

AOF日志以文件的形式存在,寫文件通過操作系統提供的write函數執行,但是write之后的數據只是寫到了內核的一個緩沖區中,然后內核還需要異步的調用fsync函數異步的將數據刷回磁盤。fsync函數是一個阻塞并且緩慢的操作,如果機器突然宕機,AOF日志內容可能還沒來的及完全刷到磁盤,這時候就會丟失數據。Redis通過appendfsync配置控制執行fsync的頻次,具體有如下三種模式:

  • no: 永遠不調用fsync,讓操作系統決定何時同步磁盤,這樣做很不安全,但是Redis的性能最高。
  • always: 每執行一次寫入操作就執行一次fsync,雖然數據安全性高,會導致執行非常緩慢。
  • everysec: 每隔1s執行一次fsync,這個1s的周期是可以配置的,這是數據安全性和性能之間的折中方案,在保證高性能的同時,盡量使數據少丟失。推薦在生產環境中使用。

2.2 AOF執行流程

Redis收到客戶端的指令以后,首先進行參數校驗、邏輯處理,如果沒有問題,會判斷是否開啟AOF,如果開啟,則會將每條命令執行完畢后同步寫入aof_buf中,aof_buf是個全局的SDS類型的緩沖區。

de26f65e-3027-11ed-ba43-dac502259ad0.jpg

每一條命令的執行都會調用call函數,注意:Redis服務端是先執行指令再將命令寫入aof_buf。

2.3 日志瘦身——AOF重寫

Redis服務端在長期運行過程中,AOF日志會越來越長,如果實例宕機或者重啟,重放整個AOF日志會非常耗時,導致Redis長時間無法對外提供服務,所以需要對AOF日志進行瘦身,即:**AOF重寫。**

我們考慮一下AOF和RDB文件的加載過程:RDB只需要把相應的數據加載都內存并生成相應的數據結構就可以了,有些結構如intset、ziplist,保存的時候直接按照字符串保存,加載速度非常快。但是AOF日志文件的加載需要創建一個偽客戶端,順序執行一遍命令,根據Redis作者做的測試,RDB在10~20秒能加載1GB的文件,AOF的速度是RDB的一半(如果做了AOF重寫會加快)

通過Redis客戶端bgrewriteaof指令對AOF日志進行瘦身過程如下:

de4c2ea6-3027-11ed-ba43-dac502259ad0.jpg

Redis服務端調用bgrewriteaofCommand命令創建管道,創建管道對作用是AOF重寫過程中批量接收服務端累積的命令;創建完管道以后,fork進程,子進程調用rewriteAppendOnlyFile執行AOF重寫操作;父進程記錄一些統計指標后繼續進入主循環處理客戶端請求,待子進程結束以后,處理一些善后工作。瘦身工作就是子進程對所有數據庫中的鍵各自生成一條相應的執行命令,最后將重寫開始后父進程繼續執行的命令進行回放,生成一個新的AOF文件。

例如執行了下面的命令:

127.0.0.1:6379>lpushlistguozhaoran
(integer)3
127.0.0.1:6379>lpoplist
"ran"
127.0.0.1:6379>lpoplist
"zhao"
127.0.0.1:6379>lpushlistzhao
(integer)2

AOF文件會保存對list操作的4條命令,但是list現在內存中的元素是這樣的:

127.0.0.1:6379>lrangelist0-1
1)"zhao"
2)"guo"

AOF重寫以后就日志文件內容直接就變為了lpush list zhao guo。日志瘦身既可以減小文件大小,又可以提高加載速度。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

3.混合持久化

RDB和AOF實現持久化的方式各有優缺點,我們來簡單總結一下:

RDB 保存的是一個時間的快照,如果發生故障,丟失的是最后一次RDB執行時間點到故障發生的時間間隔之內產生的數據。如果Redis數據量很大,QPS很高,執行一次RDB需要的時間會相應增加,發生故障時丟失的數據也會增多。

AOF 保存的是一條條的命令,理論上可以做到發生故障時只丟失一條命令。但是由于操作系統中執行寫文件操作代價很大,Redis提供了配置參數,可以對完全性和性能取折中,設置不同的配置策略。但是重放AOF日志相對于使用RDB來說還是慢很多。

Redis4.0為了解決這個問題,帶來了一個新的持久化選項——混合持久化。混合持久化是指進行AOF重寫時子進程將當前時間點的數據快照保存為RDB文件格式,而后將父進程累積命令保存為AOF格式,最終生成的格式如下圖所示:

de5d3962-3027-11ed-ba43-dac502259ad0.jpg

將RDB文件內容和增量AOF日志文件存在一起,這里的AOF日志不再是全量日志,通常這部分AOF日志很小。于是在Redis重啟的時候,可以先加載rdb內容,然后再重放增量AOF日志,就可以完全替代之前的AOF全量文件重放,重啟效率會得到大幅度提升。

4.Redis持久化相關配置

下面總結一下Redis4.0版持久化相關的配置及其含義。

配置項 可選值 默認值 作用
save save save 900 1 save 300 10 save 60 10000 save "":禁用快照備份,默認關閉 save 900 1:在900秒內有1個key被改動,自動保存到dump.rdb文件中 save 300 10:在300秒內有10個key被改動,自動保存到dump.rdb文件中 save 60 10000:在60秒內有10000個key被改動,自動保存到dump.rdb文件中 以上3中條件任意一種被滿足就會觸發保存
stop-writes-on-bgsave-error yes/no yes 開啟該參數后,如果開啟了RDB快照(即配置了save指令),并且最近一次快照執行失敗,則Redis將停止接收寫相關的請求
rdbcompression yes/no yes 執行rdb的時候是否將string類型的數據壓縮
rdbchecksum yes/no yes 是否開啟rdb文件內容的校驗
dbfilename 文件名稱 dump.rdb rdb文件名稱
dir 文件路徑 ./ RDB和AOF文件存放路徑
appendonly yes/no no 是否開啟AOF功能
appendfilename 文件名稱 appendonly.aof AOF文件名稱
appendfsync always/everysec/no everysec fsync執行頻次,上邊有說到
no-appendfsync-on-rewrite yes/no no 開啟該參數后,如果后臺正在執行一次rdb快照或者aof重寫,則主進程不再進行fsync操作,即使將appendsync配置成always或者everysec
auto-aof-rewrite-percentage 百分比 100 和auto-aof-rewrite-min-size配和使用,下面會講解
auto-aof-rewrite-min-size 文件大小 64M 當AOF文件大于64M時,并且AOF文件當前大小比基準大小增長了100%時會觸發一次AOF重寫。
aof-load-truncated yes/no yes AOF以追加日志的方式生成,當服務端發生故障時會有命令不完整的情況。開啟該參數后,在這種情況下,AOF會截斷尾部不完整的命令繼續加載,并且在日志中給出提示。
aof-use-rdb-preamble yes/no yes 是否開啟混合持久化
aof-rewrite-incremental-fsync yes/no yes 開啟該參數后,AOF重寫時每產生32MB數據執行一次fsync

5.總結

Redis是內存數據庫,機器故障或重啟之后,內存數據全部丟失,所以需要持久化來保證數據安全。

Redis提供了快照RDB和AOF日志同步兩種方式進行數據持久化,快照RDB實現原理是Copy On Write,優點是機器加載速度快,缺點是執行緩慢,QPS高的情況下會丟失大量數據;AOF則是將命令一條條的有序存放到日志文件中,優點是盡可能少的丟失數據,缺點是日志文件重放緩慢,日志文件會很大,可以通過重寫AOF日志來實現,另外提供了這種的配置方案異步執行fsync操作。

生產環境中推薦使用混合持久化,這種方式綜合了RDB和AOF兩種方式的優點。文章最后總結了一下Redis持久化配置項。本文是筆者學習Redis持久化的總結,希望能對讀者有所幫助。



審核編輯:湯梓紅


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10902

    瀏覽量

    213007
  • 內存
    +關注

    關注

    8

    文章

    3055

    瀏覽量

    74327
  • Redis
    +關注

    關注

    0

    文章

    378

    瀏覽量

    10942

原文標題:深度剖析Redis持久化機制

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Redis堅持持久方式概述

    Redis 持久
    發表于 09-25 17:04

    如何使得redis中的數據不再有

    ,原因是redis持久功能導致的,所謂的持久就是redis在系統關閉的時候把數據存儲到硬盤
    發表于 11-05 08:50

    談談Redis怎樣配置實現主從復制?

    之前總結過redis持久機制:深度剖析Redis持久
    發表于 01-31 11:31 ?685次閱讀

    Redis持久化分為兩種:RDB和AOF

    Redis持久,一個老掉牙的問題,但是面試官就是喜歡問。這也是我們學Redis必會的一個知識點。
    的頭像 發表于 02-21 09:22 ?732次閱讀

    Redis持久機制介紹

    Redis持久機制? 為了能夠重用Redis數據,或者防止系統故障,我們需要將Redis中的數
    的頭像 發表于 10-09 11:44 ?526次閱讀
    <b class='flag-5'>Redis</b><b class='flag-5'>持久</b><b class='flag-5'>化</b><b class='flag-5'>機制</b>介紹

    Redis持久RDB方式介紹

    Redis持久 Redis是一個內存數據庫,為了保證數據的持久性,它提供了兩種持久
    的頭像 發表于 10-09 14:56 ?541次閱讀
    <b class='flag-5'>Redis</b><b class='flag-5'>持久</b><b class='flag-5'>化</b>RDB方式介紹

    redis持久方式有幾種及配置

    Redis是一種內存數據庫,為了避免數據丟失,需要將數據持久到磁盤上。Redis提供了兩種持久
    的頭像 發表于 12-04 11:09 ?692次閱讀

    redis兩種持久方式的區別

    Redis是一款高性能、開源的鍵值存儲數據庫,它支持多種數據結構,并且具有高效的內存讀寫以及持久功能。Redis持久
    的頭像 發表于 12-04 11:12 ?556次閱讀

    redis持久方式RDB和AOF的區別

    Redis 是一個高性能的鍵值對數據庫,提供了兩種持久方式:RDB 和 AOF。RDB 是將 Redis 的數據快照保存到磁盤上,而 AOF 則是將
    的頭像 發表于 12-04 16:25 ?814次閱讀

    redis持久機制和如何實現持久

    Redis是一款高性能的非關系型數據庫,其持久機制是保證數據在重啟后仍能夠保存的關鍵。Redis提供了兩種方式來
    的頭像 發表于 12-05 10:02 ?497次閱讀

    redis持久機制優缺點

    Redis是一個基于內存的高性能鍵值存儲系統,它提供了多種持久機制來保證數據的可靠性。本文將詳細介紹Redis
    的頭像 發表于 12-05 10:03 ?766次閱讀

    redis里數據什么時候持久

    Redis是一種開源的高性能、非關系型內存數據庫,它使用了鍵值對存儲數據,并且支持多種數據結構。 Redis提供了持久機制,以確保在服務器
    的頭像 發表于 12-05 10:05 ?489次閱讀

    云容器redis持久配置

    丟失。 Redis提供了不同的持久機制,可以根據需要進行配置。本文將詳細介紹云容器中Redis持久
    的頭像 發表于 12-05 10:07 ?539次閱讀

    redis持久rdb和aof一起用好處

    Redis是一個流行的內存數據庫,它通過使用不同的持久機制來確保數據的持久性。RDB和AOF是Redi
    的頭像 發表于 12-05 10:17 ?808次閱讀

    Redis使用重要的兩個機制:Reids持久和主從復制

    今天這篇文章,我們一起了解 Redis 使用中非常重要的兩個機制:Reids 持久和主從復制。 我們都知道Redis是一個內存數據庫,在學
    的頭像 發表于 12-18 10:33 ?166次閱讀
    <b class='flag-5'>Redis</b>使用重要的兩個<b class='flag-5'>機制</b>:Reids<b class='flag-5'>持久</b><b class='flag-5'>化</b>和主從復制
    百家乐最新的投注方法| 百家乐金币游戏| 澳博国际| OG百家乐大转轮| 哪家百家乐官网最好| 一二博网址| 试玩百家乐代理| 百家乐官网园有限公司| 大发888英皇国际| 百家乐小音箱| 百家乐官网平预测软件| 百家乐官网游戏真钱游戏| 娱网棋牌大厅下载| 康莱德百家乐的玩法技巧和规则| 百家乐官网园能贷款吗| 上海玩百家乐官网算不算违法 | 百家乐现场投注平台| 百家乐官网十赌九诈| 百家乐官网算牌皇冠网| 温州市百家乐鞋业有限公司| 百家乐官网发牌靴8| 真人百家乐官网大转轮| 网上百家乐官网玩法| 金龙娱乐城开户送彩金| 大发888 58| 大发888代理充值| 金钱豹百家乐的玩法技巧和规则| 太阳城百家乐祖玛| 百家乐的代理办法| 百家乐官网网址官网| 赌百家乐官网到底能赌博赢| 百家乐官网注册送彩金平台| 西昌市| 贡嘎县| 360博彩通| 蒙特卡罗娱乐场| 888真人| 大发888官网首页| 全讯网abckkk.com| 申烨太阳城三期| 大发888游戏平台dafa888gw|