redis rdb aof区别_Redis(三):持久化RDB,fork.copyonwrite,AOF,RDBamp;AOF混合使用
Redis的數據全部在內存里,如果突然宕機,數據就會全部丟失,因此必須有一種機制來保證Redis的數據不會因為故障而丟失,這種機制就是Redis的持久化機制。
Redis的持久化有兩種,第一種是快照,第二種是AOF日志??煺帐且淮涡匀總浞?#xff0c;AOF日志是連續的增量備份。
第一種快照是內存數據的二進制序列化形式,在存儲上非常緊湊,而第二種AOF日志記錄的是內存數據修改的指令記錄文本。
AOF日志在長期的運行過程中會變得無比龐大,數據庫重啟時需要加載AOF日志進行指令重放,這個時間就會很漫長,所以需要定期進行AOF重寫,給AOF日志瘦身。
快照(RDB)的原理:
Redis是單線程程序,這個線程要同時負責:
1、多個客戶端socket的并發讀寫操作 2、內存數據結構的邏輯重寫在服務線上請求的同時,Redis還需要進行內存快照,內存快照要求Redis必須進行文件io操作,可是文件io操作不能使用多路復用的API。
這就意味著單線程在服務器上請求的同時,還要進行文件io操作,而文件io操作會嚴重拖累服務器的性能。
另外,為了不阻塞線上的業務,Redis需要一邊持久化,一邊相應客戶端的請求。持久化的同時,內存數據結構還在變化,比如一個大型的hash字典正在持久化的時候,這時一個請求過來把它給刪掉了,或者修改了,可是還沒持久化完畢,這怎么辦?Redis使用操作系統的多進程COW(Copy on Write)機制來實現快照持久化
Fork多進程
Redis在持久化的時候會調用glicb的函數fork產生一個子進程,快照持久化完全交給子進程來處理,父進程繼續處理客戶端業務請求。子進程剛剛產生的時候和父進程共享內存里的代碼段和數據段。
子進程做數據持久化的時候,不會修改現有內存數據結構,它只是對數據結構進行遍歷讀取,然后序列化寫到磁盤上。
但是父進程不一樣,必須持續服務客戶端的請求,然后對內存數據結構進行不斷的修改。這個時候就會使用OS的COW機制來進行數據段頁面的分離。
如上圖所示,數據段是由很多操作系統的頁面組合而成,當父進程對其中一個頁面的數據進行修改時,會將被共享的頁面復制一份分離出來,然后對復制的這個頁面進行修改。這時子進程相應的頁面是沒有變化的,還是進程產生時那一瞬間的數據。
隨著父進程修改操作的持續進行,越來越多的共享頁面被分離出來,內存就會持續增長,但是也不會超過原有數據的2倍大小。另外Redis實例里的冷數據占的比例往往是比較高的,所以很少會出現所有的頁面都被分離的情況,被分離的往往只有其中一部分頁面。每個頁面的大小只有4KB,一個Redis實例里面一般都會有成千上萬個頁面。
子進程因為數據沒有變化,它能看到的內存里的數據在進程產生的那一瞬間就凝固了,再也不會發生改變。這也是為何Redis的持久化叫做“快照”的原因了。接下來子進程就可以安心的遍歷數據,進行序列化寫到磁盤中了。
那現在就有一個問題了,父進程如果占了10G,那么子進程也占10G,redis的空間夠不夠呢?持久化的時候速度快不快呢?其實父進程和子進程只保存了物理機的內存的地址,兩份地址而已,指向的都是內存。所就不存在兩個都占10G了。而父進程和子進程是通過fork()出來的,還有就是子進程也不是一下就創建出來,其中的COW是copy on write,意思是寫的時候才復制地址。創建子進程并不發生復制,玩的是指針。
例如看一下fork :
輸入 man 2 fork 命令
然后輸入/copy
NOTES
Under Linux, fork() is implemented using copy-on-write pages, so the only
penalty that it incurs is the time and memory required to duplicate the parent’s
page tables, and to create a unique task structure for the child.
Since version 2.3.3, rather than invoking the kernel’s fork() system call, the
glibc fork() wrapper that is provided as part of the NPTL threading implementa-
tion invokes clone(2) with flags that provide the same effect as the traditional
system call. The glibc wrapper invokes any fork handlers that have been estab-
lished using pthread_atfork(3).
在Linux下,fork()是使用寫時復制的頁面實現的,因此它帶來的唯一損失是復制父頁面表和為子頁面創建唯一的任務結構所需的時間和內存。自從2.3.3版本以來,作為NPTL線程實現一部分提供的glibc fork()包裝器沒有調用內核的fork()系統調用,而是使用提供與傳統系統調用相同效果的標志調用clone(2)。glibc包裝器調用使用pthread_atfork(3)建立的任何fork處理程序。
就是父進程進行修改的時候,會新創建一個,然后指向,而子進程還是指向原來的。
fork是系統調用,copy on write是內核機制。 redis調用fork()優點是速度快,占用空間小。關機維護的時候,用save命令,其余的一般都是bgsave達到60秒了 操作數達到10000,滿足其中一個,就會寫rdb。依次類推,如果到900秒了,操作數達到1筆的時候,滿足其中一個,就會寫RDB。
Redis默認是開啟RDB的,如果想關閉,那么就把下圖中這個刪除,或者 save ""
那么持久化的RDB文件存儲在哪呢?繼續往下翻:
RDB的優缺點:
優點:1,壓縮后的二進制文件,適用于備份、全量復制,用于災難恢復
2,加載RDB恢復數據遠快于AOF方式
缺點:1,無法做到實時持久化,每次都要創建子進程,頻繁操作成本過高
2,保存后的二進制文件,存在老版本不兼容新版本rdb文件的問題
3,不支持拉鏈,只有一個dump.rdb
4,丟失數據相對較多,窗口數據容易丟失,8點做了一個rdb,假設9點又要做一個rdb,此時斷電了,那么就丟了一個小時的數據。這是全量備份技術的通用的缺點。
以上是RDB。
針對RDB不適合實時持久化,redis提供了AOF持久化方式來解決
AOF(append only file )(只會向文件追加)AOF日志存儲的是Redis服務器的順序指令序列,AOF日志只記錄對內存進行修改的指令記錄,假設AOF日志記錄了自Redis實例創建以來所有的修改性指令序列,那么就可以通過對一個空的Redis實例順序執行所有的指令--也就是“重放”,來恢復Redis當前實例的內存數據結構的狀態。
Redis會在收到客戶端修改指令后,進行參數校驗、邏輯處理,如果沒問題,就立即將該指令文本存儲到AOF日志中,也就是說,先執行指令才將日志存盤。這點不同于hbase等存儲引擎,他們都是先存儲日志再做邏輯處理的。
Redis在長期運行的過程中,AOF日志會越來越長,如果實例宕機重啟,重放整個AOF日志會非常耗時,導致Redis長時間無法對外提供服務,所以需要對AOF日志瘦身。
AOF重寫:
Redis 提供了 bgrewriteaof 指令用于對AOF日志進行瘦身,原理是開辟一個子進程對內存進行遍歷,轉換成一系列Redis的操作指令,序列化到一個新的AOF日志文件中。序列化完畢后再將操作期間發生增量AOF日志追加到這個新的AOF日志文件中,追加完畢后就立即替代舊的AOF日志文件了,瘦身工作就完成了。而重寫的意義是以后加載速度變快,減小AOF體積,比如set k1 a set k1 b set k1 c,就會在aof文件中出現這些記錄,而此時k1對應的value是C,a和b是沒用的,經過bgrewriteaof命令后,aof文件中將不再有a和b的影子,就只保留了k1 c。
fsync:
AOF日志是以文件的形式存在的,當程序對AOF日志文件進行寫操作時,實際上是將內容寫到了內核為文件描述符(File Descriptors ,簡稱fd ,很多fd就是 fds)分配到一個內存緩沖中,然后內核會異步將臟數據刷回到磁盤。這就意味著如果突然宕機,AOF日志內容可能還沒來得及完全刷到磁盤中,這個時候就會出現日志丟失,這怎么辦?不急,Linux的glibc提供了 fsync(int fd)函數可以將指定文件的內容強制從內核緩存刷到磁盤。只要Redis進程實時調用fsync函數就可以保證AOF日志不丟失。但是fsync是磁盤io操作,很慢,如果Redis執行一條指令就要 fsync 一次,那么Redis高性能的地位就不保了。所以在生產環境的服務器中,Redis通常是每隔1s左右執行一次 fsync 操作,這個1s周期是可以配置的。這是在數據安全性和性能之間做的一個折中,在保持高性能的同時,盡可能是數據少丟失。
在Redis的主節點不會進行持久化操作,因為無論是AOF還是RDB都比較耗資源,持久化操作主要在從節點進行。從節點是備份節點,沒有來自客戶端請求的壓力,它的操作系統資源往往比較充沛。但是如果出現網絡分區,從節點長期連不上主節點,就會出現數據不一致的問題,特別是在網絡分區出現的情況下,主節點一旦不小心宕機了,那么數據就會丟失,所以在生產環境下要做好實時監控工作,保證網絡暢通或者能快速修復。另外還應該再增加一個從節點以降低網絡分區的概率,只要有一個從節點數據同步正常,數據也就不會輕易丟失。
假設AOF文件是10T,那么恢復的時候不會內存溢出,因為只要寫寫寫直到AOF文件成了10T,但凡能寫到10個T,那肯定沒有內存溢出。所以恢復的時候也不會內存溢出。如果要溢出的話,那么早就溢出了,還能把AOF文件寫到10個T么?
下來說AOF的配置:
vi 6379.conf, 不是vim 用 vi 打開 上面寫錯了。
總是,每秒,從不。紅框中的,fsync上面說過了Redis4.0混合持久化:
重啟Redis時,很少使用rdb的方式恢復內存狀態,因為rdb會丟失大量數據。通常使用AOF日志重放,但是重放AOF日志相對于使用rdb來說慢很多,這樣在Redis實例很大的情況下,啟動需要花很長的時間。
Redis4.0帶來了一個新的持久化選項--混合持久化。將rdb的內容和增量的AOF日志文件存在一起。這里的AOF不再是全量的日志,而是自持久化開始到持久化結束的這段時間發生的增量AOF日志,通常這部分AOF日志很小。一定是重寫之后才開始混合,比如開啟了混合持久化后,set k1 v1 set k1 v2 等等 一定是輸入 bgrewriteaof 命令后,前面的一系列操作就變成了 RDB形式,保存在aof文件中,后續繼續set k3 v3 的時候,是以明文的形式追加到aof文件中
于是,在Redis重啟的時候,可以先加載rdb的內容,然后再重放增量AOF日志,就可以完全替代之前的AOF全量文件重放,重啟效率得到大幅提升。
下來演示一下redis持久化
下來改配置文件:來驗證rdb和aof是什么概念
vi /etc/redis/6379.conf
把daemonize yes改成daemonize no ,表示不讓redis變成后臺服務進程運行,成為前臺阻塞的運行。
打開AOF持久化,因為RDB是默認開啟的不用管
原來是no,改成yes然后把混合持久化關閉
現在準備工作已經做好了,打開了aof,打開了rdb(默認開啟),關閉了混合持久化。
我現在是在root根目錄:
然后把1號shell窗口切換到etc下的redis目錄:
然后切換到2號shell窗口:
然后切回到1號shell窗口,啟動redis
然后切回到2號shell窗口,LL看一下
然后 vi appendonly.aof,發現什么都沒有記錄
然后在3號shell打開 redis 6379 客戶端
然后設置一個kv。set k1 hello
然后切回到2號shell。LL看一下,因為不滿足rdb的那三個條件
所以可以看到還是只落了一個aof文件
打開這個aof文件看一下
*2代表:兩個元素組成 一個是 select 另一個是 0號庫
然后在3號shell 繼續輸入 set k2 xxoo
然后切換到2號shell 查看 aof文件:
然后想一下 把這兩筆數據 弄到rdb里面去。在3號shell 輸入 bgsave
然后在2號shell查看:
然后1號shell窗口 會發生
然后切換到2號shell,打開這個dump.rdb
下來看一下 aof 的重寫功能:
那么aof文件會相應的增長很多對k1的操作:
那現在k1的最終value是c,所以以上k1之前的value值都是垃圾。所以給aof文件瘦身一下:瘦身前是170字節
然后在3號shell 窗口 :輸入bgrewriteaof
然后在2號shell 看一下 目前 aof的大小 :
然后打開aof文件:
然后在1號shell 中 ctrl +c 結束:
把3號shell的客戶端 也退出去 exit,把2號的aof和rdb文件也全部刪除 rm -fr ./*
然后切到1號shell,改配置:
開啟混合持久化:
保存后,啟動redis:
然后2號shell 里還是一個空的 aof,沒毛病
然后3號shell開啟redis客戶端 :set 兩次
然后在2號shell 看一下:然并卵,不是混合持久化。
然后繼續3號shell 寫,寫完后bgrewriteaof
現在是混合持久化:所以查看2號shell:沒有增量前是103字節
打開,可以看到變成了二進制的rdb了。和以前的aof文件不一樣
然后繼續set兩條記錄 3號shell:
然后轉到2號shell:查看aof文件:變成104字節了。
我不知道為什么,我打開看不到增量的內容,可能是io的延遲吧,不知道出什么bug了。
這下能看了:
dump.rdb
appendonly.aof
appendonly yes (默認不開啟,為no)
總結
以上是生活随笔為你收集整理的redis rdb aof区别_Redis(三):持久化RDB,fork.copyonwrite,AOF,RDBamp;AOF混合使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 建行惠存通是怎么回事
- 下一篇: mysql不支持union_MySQL中