redis——持久化

因為redis是內存數據庫,他把數據都存在內存里,所以要想辦法實現持久化功能。

RDB

RDB持久化可以手動執行,也可以配置定期執行,可以把某個時間的數據狀態保存到RDB文件中,反之,我們可以用RDB文件還原數據庫狀態。

? ? 生成

有兩個命令可以生成RDB文件:

  • SAVE?命令由服務器進程直接執行保存操作,所以該命令會阻塞服務器,服務器不能接受其他指令。
  • BGSAVE?命令由子進程執行保存操作,所以該命令不會阻塞服務器,服務器可以接受其他指令。。

禁止BGSAVE和SAVE同時執行,也就是說執行其中一個就會拒絕另一個,這是為了避免父進程和子進程同時執行兩個rdbsave,防止產生競爭條件。

? ? 載入

? ? RDB載入工作是服務器啟動時自動執行的。

? ? 自動保存

用戶可以通過save選項設置多個保存條件,服務器狀態中會保存所有用?save?選項設置的保存條件,當任意一個保存條件被滿足時,服務器會自動執行?BGSAVE?命令。

比如

save 900 1

save 300 10

滿足:服務器在900秒之內被修改至少一次或者300秒內修改至少十次。就會執行BGSAVE。

?

當服務器啟動時,用戶可以通過指定配置文件或者傳入啟動參數來設置save選項,服務器會把條件放到一個結構體里,結構體有一個數組,保存了所有條件。

?

serverCron函數默認100毫秒檢查一次,他會遍歷數組依次檢查,符合條件就會執行BGSAVE。

? ? RDB文件結構

一個完整 RDB 文件所包含的各個部分:

REDIS,長度5字節, 保存著?"REDIS"?五個字符。 通過這五個字符, 可以在載入文件時, 快速檢查載入文件是否 RDB 文件。

db_version?,長度?4?字節, 它的值是一個字符串表示的整數, 這個整數記錄了 RDB 文件的版本號

databases?部分包含著零個或任意多個數據庫, 以及各個數據庫中的鍵值對數據

EOF?常量的長度為?1?字節, 這個常量標志著 RDB 文件正文內容的結束

check_sum?是一個?8?字節長的無符號整數, 保存著一個校驗和,以此來檢查 RDB 文件是否出錯或損壞

我并不想深入探究databases的組成。就是知道

  • RDB 文件是一個經過壓縮的二進制文件,由多個部分組成。
  • 對于不同類型的鍵值對, RDB 文件會使用不同的方式來保存它們。

即可。

?

AOF

AOF持久化是通過保存服務器執行的命令來記錄狀態的。還原的時候再執行一遍即可。

功能的實現可以分為命令追加、文件寫入、文件同步三個步驟。

?

當 AOF 持久化功能處于打開狀態時, 服務器在執行完一個寫命令之后, 會以協議格式將被執行的寫命令追加到服務器狀態的?aof_buf?緩沖區的末尾:

struct redisServer {// ...// AOF 緩沖區sds aof_buf;// ...
};

Redis 服務器進程就是一個事件循環

循環中的文件事件負責接收客戶端的命令請求, 以及向客戶端發送命令回復,

而時間事件則負責執行像?serverCron?函數這樣需要定時運行的函數。

因為服務器在處理文件事件時可能會執行寫命令, 使得一些內容被追加到?aof_buf?緩沖區里面, 所以在服務器每次結束一個事件循環之前, 它都會調用?flushAppendOnlyFile?函數, 考慮是否需要將?aof_buf?緩沖區中的內容寫入和保存到 AOF 文件里面, 這個過程可以用偽代碼表示:

def eventLoop():while True:# 處理文件事件,接收命令請求以及發送命令回復# 處理命令請求時可能會有新內容被追加到 aof_buf 緩沖區中processFileEvents()# 處理時間事件processTimeEvents()# 考慮是否要將 aof_buf 中的內容寫入和保存到 AOF 文件里面flushAppendOnlyFile()

flushAppendOnlyFile?函數的行為由服務器配置的?appendfsync?選項的值來決定

值為?always?時, 服務器在每個事件循環都要將?aof_buf?緩沖區中的所有內容寫入到 AOF 文件并且同步 AOF 文件, 所以?always?的效率最慢的一個, 但從安全性來說,?always?是最安全的, 因為即使出現故障停機, AOF 持久化也只會丟失一個事件循環中所產生的命令數據。

值為?everysec?時, 服務器在每個事件循環都要將?aof_buf?緩沖區中的所有內容寫入到 AOF 文件, 每隔超過一秒就要在子線程中對 AOF 文件進行一次同步: 從效率上來講,?everysec?模式足夠快, 并且就算出現故障停機, 數據庫也只丟失一秒鐘的命令數據。

值為?no?時, 服務器在每個事件循環都要將?aof_buf?緩沖區中的所有內容寫入到 AOF 文件, 至于何時對 AOF 文件進行同步, 則由操作系統控制。

因為處于?no?模式下的?flushAppendOnlyFile?調用無須執行同步操作, 所以該模式下的 AOF 文件寫入速度總是最快的, 不過因為這種模式會在系統緩存中積累一段時間的寫入數據, 所以該模式的單次同步時長通常是三種模式中時間最長的: 從平攤操作的角度來看,no?模式和?everysec?模式的效率類似, 當出現故障停機時, 使用?no?模式的服務器將丟失上次同步 AOF 文件之后的所有寫命令數據。

? ? 重寫

AOF持久化是保存了一堆命令來恢復數據庫,隨著時間流逝,存的會越來越多,如果不加以控制,文件過大可能影響服務器甚至計算機。而且文件過大,恢復時需要時間也太長。

所以redis提供了重寫功能,寫出的新文件不會包含任何浪費時間的冗余命令。

接下來,我們就介紹重寫的原理。

其實重寫不會對現有的AOF文件進行讀取分析等操作,而是通過當前服務器的狀態來實現。

 # 假設服務器對鍵list執行了以下命令s;
127.0.0.1:6379> RPUSH list "A" "B"
(integer) 2
127.0.0.1:6379> RPUSH list "C"
(integer) 3
127.0.0.1:6379> RPUSH list "D" "E"
(integer) 5
127.0.0.1:6379> LPOP list
"A"
127.0.0.1:6379> LPOP list
"B"
127.0.0.1:6379> RPUSH list "F" "G"
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "C"
2) "D"
3) "E"
4) "F"
5) "G"
127.0.0.1:6379> 

當前列表鍵list在數據庫中的值就為["C", "D", "E", "F", "G"]。要使用盡量少的命令來記錄list鍵的狀態,最簡單的方式不是去讀取和分析現有AOF文件的內容,,而是直接讀取list鍵在數據庫中的當前值,然后用一條RPUSH list "C" "D" "E" "F" "G"代替前面的6條命令。

  • 偽代碼表示如下
def AOF_REWRITE(tmp_tile_name):f = create(tmp_tile_name)# 遍歷所有數據庫for db in redisServer.db:# 如果數據庫為空,那么跳過這個數據庫if db.is_empty(): continue# 寫入 SELECT 命令,用于切換數據庫f.write_command("SELECT " + db.number)# 遍歷所有鍵for key in db:# 如果鍵帶有過期時間,并且已經過期,那么跳過這個鍵if key.have_expire_time() and key.is_expired(): continueif key.type == String:# 用 SET key value 命令來保存字符串鍵value = get_value_from_string(key)f.write_command("SET " + key + value)elif key.type == List:# 用 RPUSH key item1 item2 ... itemN 命令來保存列表鍵item1, item2, ..., itemN = get_item_from_list(key)f.write_command("RPUSH " + key + item1 + item2 + ... + itemN)elif key.type == Set:# 用 SADD key member1 member2 ... memberN 命令來保存集合鍵member1, member2, ..., memberN = get_member_from_set(key)f.write_command("SADD " + key + member1 + member2 + ... + memberN)elif key.type == Hash:# 用 HMSET key field1 value1 field2 value2 ... fieldN valueN 命令來保存哈希鍵field1, value1, field2, value2, ..., fieldN, valueN =\get_field_and_value_from_hash(key)f.write_command("HMSET " + key + field1 + value1 + field2 + value2 +\... + fieldN + valueN)elif key.type == SortedSet:# 用 ZADD key score1 member1 score2 member2 ... scoreN memberN# 命令來保存有序集鍵score1, member1, score2, member2, ..., scoreN, memberN = \get_score_and_member_from_sorted_set(key)f.write_command("ZADD " + key + score1 + member1 + score2 + member2 +\... + scoreN + memberN)else:raise_type_error()# 如果鍵帶有過期時間,那么用 EXPIREAT key time 命令來保存鍵的過期時間if key.have_expire_time():f.write_command("EXPIREAT " + key + key.expire_time_in_unix_timestamp())# 關閉文件f.close()

? ? AOF后臺重寫


aof_rewrite函數可以創建新的AOF文件,但是這個函數會進行大量的寫入操作,所以調用這個函數的線程被長時間的阻塞,因為服務器使用單線程來處理命令請求;所以如果直接是服務器進程調用AOF_REWRITE函數的話,那么重寫AOF期間,服務器將無法處理客戶端發送來的命令請求;


Redis不希望AOF重寫會造成服務器無法處理請求,所以將AOF重寫程序放到子進程(后臺)里執行。這樣處理的好處是:?
1)子進程進行AOF重寫期間,主進程可以繼續處理命令請求;
2)子進程帶有主進程的數據副本,使用子進程而不是線程,可以避免在鎖的情況下,保證數據的安全性。

還有一個問題,可能重寫的時候又有新的命令過來,造成信息不對等,所以redis設置了一個緩沖區,重寫期間把命令放到重寫緩沖區。
?

? 總結


AOF重寫的目的是為了解決AOF文件體積膨脹的問題,使用更小的體積來保存數據庫狀態,整個重寫過程基本上不影響Redis主進程處理命令請求;
AOF重寫其實是一個有歧義的名字,實際上重寫工作是針對數據庫的當前狀態來進行的,重寫過程中不會讀寫、也不適用原來的AOF文件;
AOF可以由用戶手動觸發,也可以由服務器自動觸發。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445402.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445402.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445402.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

redis原理總結

數據結構(字典、鏈表、字符串) 數據結構(整數集合,壓縮列表) 數據結構(跳表介紹和手撕) LRU介紹和實現 對象(字符串對象、列表對象、哈希對象、集合對象、有序集合總結&#xff…

劍指offer(刷題51-60)--c++,Python版本

文章目錄目錄第51題:解題思路:代碼實現:cpython第52題:解題思路:代碼實現:cpython第53題:解題思路:代碼實現:cpython第54題:解題思路:代碼實現&am…

2017第一屆河北省大學生程序設計競賽題解

超級密碼 小明今年9歲了,最近迷上了設計密碼!今天,他又設計了一套他認為很復雜的密碼,并且稱之為“超級密碼”. 說實話,這套所謂的“超級密碼”其實并不難:對于一個給定的字符串,你只要提取其中…

劍指offer(刷題61-65)--c++,Python版本

文章目錄目錄第61題:解題思路:代碼實現:cpython第62題:解題思路:代碼實現:cpython第63題:解題思路:代碼實現:cpython第64題:解題思路:代碼實現&am…

2018第二屆河北省大學生程序設計競賽題解

icebound的賬單 題目描述 icebound從小就有記賬的習慣。又到了月末icebound統計資金狀況的時候。icebound每個月除了不停的揮霍以外,有時他會良心發現,勤工儉學,因此會有一些微薄的收入。然而icebound數學不好,需要你來幫助他統計…

大數的四則運算(加法、減法、乘法、除法)

大數的四則運算(加法、減法、乘法、除法) 前言: 在計算機中數字表示的范圍是有限制的,比如我們熟知的 int、float、double 等數據類型所能表示的范圍都是有限的,如果我們要對位數達到幾十位、幾百位、上千位的大整數進…

數組基操三連(1)

題目: 給定一個數組arr,求出需要排序的最短子數組長度 要求: 時間o(n),空間o(1) 思路: 有序的數組中,任意一個數字,一定小于左邊的數大于右邊的數。 我們找到的需要排序的子數組,顯然是比右邊…

IT互聯網公司的筆試的輸入輸出- c++ python

文章目錄目錄c方式1&#xff1a;方式2&#xff1a;Python方式1&#xff1a;方式2&#xff1a;方式3&#xff1a;目錄 c 方式1&#xff1a; 第一種情況&#xff1a;輸入n個數&#xff0c;存放在數組中 #include <iostream> #include <vector> using namespace st…

隨機過程1

隨機過程1概述1.參考書目2.主要內容3.概率論--基本概念回顧3.1對“不確定性”的認識3.2 應對“不確定性”應該怎么做3.3隨機變量&#xff08;Random Variable&#xff09;3.4分布函數&#xff08;Distribution Function&#xff09;3.5概率密度&#xff08;Density&#xff09;…

數組基操三連(4)

題目一 給定一個長度為N的整型數組arr&#xff0c;其中有N個互不相等的自然數1~N 請實現arr的排序 但是不要把下標0~N-1位置上的數值通過直接賦值的方式替換成1~N。 要求&#xff1a;時間復雜度為O(N)&#xff0c;額外空間復雜度為O(1)。 思路&#xff1a;從左向右檢查&…

Linux(1)-touch,mkdir,rm,mv,cp,ls,cd,cat

Linux1-實用終端命令1. touch, mkdir2. rm, mv, cp3. ls(通配符),cd(絕對/相對路徑)4. cat, more/less文件內容瀏覽文件/目錄-增刪查改, 文件內容查看.1. touch, mkdir touch新文件 &#xff1a;在當前文件夾下&#xff0c;創建文件。文件不存在則創建新文件&#xff1b;文件存…

java常用類介紹及源碼閱讀(ArrayList)

java.util 類 ArrayList<E> 繼承關系&#xff1a; java.lang.Objectjava.util.AbstractCollection<E>java.util.AbstractList<E>java.util.ArrayList<E>List 接口的動態數組的實現。 實現了所有可選列表操作&#xff0c;并允許包括 null 在內的所有…

tests1

ls,cd,tardone

數組精選題目三連(5)

子數組的最大累加和問題 輸入一個整形數組&#xff0c;求數組中連續的子數組使其和最大。比如&#xff0c;數組x 應該返回 x[2..6]的和187. 這四個代碼完成的功能都是求最大子數組&#xff08;注意用詞準確&#xff0c;子數組連續&#xff0c;子序列可以不連續&#xff09;。…

大數據學習(1)-大數據概述

文章目錄目錄大數據產生背景大數據概念大數據影響大數據應用大數據關鍵技術大數據產業大數據&#xff0c;云計算&#xff0c;物聯網關系云計算物聯網大數據&#xff0c;物聯網&#xff0c;云計算三者之間聯系目錄 大數據產生背景 三次信息化浪潮 根據IBM前首席執行官郭士納福…

java常用類介紹及源碼閱讀(LinkedList)

java.util 類 LinkedList<E> java.lang.Objectjava.util.AbstractCollection<E>java.util.AbstractList<E>java.util.AbstractSequentialList<E>java.util.LinkedList<E> List 接口的鏈接列表實現。實現所有可選的列表操作&#xff0c;并且允…