Redis --> Redis架構設計

Redis架構設計

1、前言

 
  Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它能夠用做數據庫、緩存和消息中間件。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內置了 複製(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不一樣級別的 磁盤持久化(persistence), 並經過 Redis哨兵(Sentinel)和自動 分區(Cluster)提供高可用性(high availability)。
 
 

2、redis啓動流程

 
1.初始化server變量,設置redis相關的默認值
2.讀入配置文件,同時接收命令行中傳入的參數,替換服務器設置的默認值
3.初始化服務器功能模塊。在這一步初始化了包括進程信號處理、客戶端鏈表、共享對象、初始化數據、初始化網絡鏈接等
4.從RDB或AOF重載數據
5.網絡監聽服務啓動前的準備工做
6.開啓事件監聽,開始接受客戶端的請求
 
啓動的部分過程經過查看下圖,會更直觀。
 
下面是針對啓動過程當中,對各個模塊的詳細理解。(目前只分析了後臺線程系統與慢查詢日誌系統)
 

3、Redis數據持久化方案

 
  在使用redis時很多人都說一個問題,就是說redis宕機了怎麼辦?會不會數據丟失等等的問題。如今來看看Redis提供的數據持久化解決方案,並經過原理分析優缺點。最終能得出Redis適合使用的應用場景。

1.RDB持久化方案

  在Redis運行時,RDB程序將當前內存中的數據庫快照保存到磁盤中,當Redis須要重啓時,RDB程序會經過重載RDB文件來還原數據庫。從上述描述能夠看出,RDB主要包括兩個功能:關於rdb的實現能夠見src/rdb.c

a)保存(rdbSave)

  rdbSave負責將內存中的數據庫數據以RDB格式保存到磁盤中,若是RDB文件已經存在將會替換已有的RDB文件。保存RDB文件期間會阻塞主進程,這段時間期間將不能處理新的客戶端請求,直到保存完成爲止。爲避免主進程阻塞,Redis提供了rdbSaveBackground函數。在新建的子進程中調用rdbSave,保存完成後會向主進程發送信號,同時主進程能夠繼續處理新的客戶端請求。

b)讀取(rdbLoad)

  當Redis啓動時,會根據配置的持久化模式,決定是否讀取RDB文件,並將其中的對象保存到內存中。載入RDB過程當中,每載入1000個鍵就處理一次已經等待處理的客戶端請求,可是目前僅處理訂閱功能的命令(PUBLISH 、 SUBSCRIBE 、 PSUBSCRIBE 、 UNSUBSCRIBE 、 PUNSUBSCRIBE),其餘一概返回錯誤信息。由於發佈訂閱功能是不寫入數據庫的,也就是不保存在Redis數據庫的。
 
RDB的缺點:再說RDB缺點時,須要提到的是RDB有保存點的概念。在默認的redis.conf中能夠看到這樣的默認配置:
#save <seconds> <changes>
save 900 1        //若是15分鐘內,有1個鍵被修改
save 300 10       //若是6分鐘內,有10個鍵被修改
save 60 10000     //若是60秒內有10000個鍵被修改
 
意思是當知足上面任意一個條件時,將會進行快照保存。爲了保證IO讀寫性能不會成爲Redis的瓶頸,通常都會建立一個比較大的值來做爲保存點。
  1.此時若是保存點設置過大,就會致使宕機丟失的數據過多。保存點設置太小,又會形成IO瓶頸
  2.當對數據進行保存時,可能會因爲數據集過大致使操做耗時,這會致使Redis可能在短期內沒法處理客戶端請求。
 

2.AOF持久化方案

  以協議文本的方式,將全部對數據庫進行的寫入命令記錄到AOF文件,達到記錄數據庫狀態的目的。

a)保存

1.將客戶端請求的命令轉換爲網絡協議格式
2.將協議內容字符串追加到變量server.aof_buf中
3.當AOF系統達到設定的條件時,會調用aof_fsync(文件描述符號)將數據寫入磁盤
 
其中第三步提到的設定條件,就是AOF性能的關鍵點。目前Redis支持三種保存條件機制:
1.AOF_FSYNC_NO:不保存
  此模式下,每執行一條客戶端的命令,都會將協議字符串追加到server.aof_buf中,但不會執行寫入磁盤。
寫入只發生在:
  1.Redis被正常關閉;
  2.Aof功能關閉;
  3.系統寫緩存已滿,或後臺定時保存操做被執行
上面三種狀況都會阻塞主進程,致使客戶端請求失敗。
 
2.AOF_FSYNC_EVERYSECS:每一秒保存一次
  由後臺子進程調用寫入保存,不會阻塞主進程。若是發生宕機,那麼最大丟失數據會在2s之內的數據。 這也是默認的設置選項。
 
3.AOF_FSYNC_ALWAYS:每執行一個命令都保存一次
  這種模式下,能夠保證每一條客戶端指令都被保存,保證數據不會丟失。但缺點就是性能大大降低,由於每一次操做都是獨佔性的,須要阻塞主進程。
 

b)讀取

  AOF保存的是數據協議格式的數據,因此只要將AOF中的數據轉換爲命令,模擬客戶端從新執行一遍,就能夠還原全部數據庫狀態。
讀取的過程是:
  1.建立模擬的客戶端
  2.讀取AOF保存的文本,還原數據爲原命令和原參數。而後使用模擬的客戶端發出這個命令請求。
  3.繼續執行第二步,直到讀取完AOF文件
 
AOF須要將全部的命令都保存到磁盤,那麼這個文件會隨着時間變得愈來愈大。讀取也會變得很慢。Redis提供了AOF的重寫機制,幫助減小文件的大小。
實現的思路是:
LPUSH list 1 2 3 4 5
LPOP list
LPOP list
LPUSH list 1

最初保存到AOF文件的將會是四條指令。但通過AOF重寫後,會變成一條指令:redis

LPUSH list 1 3 4 5
同時,考慮到爲了在AOF重寫時,不影響AOF的寫入增長了AOF重寫緩存的概念。也就是說Redis在開啓AOF時,除了將命令格式數據寫入到AOF文件,同時也會寫入到AOF重寫緩存。這樣AOF的寫入、重寫就作到了隔離,保證了重寫時不會阻塞寫入。
 

c)AOF重寫流程

1.AOF重寫完成會向主進程發送一個完成的信號
2.會將AOF重寫緩存中的數據所有寫入到文件中
3.用新的AOF文件,覆蓋原有的AOF文件。
 

d)AOF缺點

1.AOF文件一般會大於相同數據集的RDB文件
2.AOF模式下性能與RDB模式下性能高低,主要取決於AOF選用的fsync模式
 
下面給出客戶端請求RedisServer時,server端持久化的部分操做圖解。

4、Redis數據庫的實現

 
  Redis是一個鍵值對數據庫,稱爲鍵空間。實現這種KV形式的存儲,Redis使用了兩種數據結構類型:一、字典,Redis字典使用的是哈希表實現,本來不許備詳細介紹Redis哈希表的實現。但發現Redis在實現哈希表時,提供了一個很好的rehash方案,這個方案思路很好,甚至能夠衍生到其餘各個應用中使用,方案的名稱叫「漸進式Rehash」。
  實現哈希表的方法大同小異,但爲什麼各個開源軟件老是去開發本身獨有的哈希數據結構呢?從研究PHP內核的哈希實現與Redis哈希實現,發現應用場景決定了必須定製才能更好的發揮性能。
a)PHP主要應用於WEB場景,在WEB場景針對單次請求數據之間是隔離的,而且哈希的數量是有限的,那麼進行一次rehash也是很快的。因此PHP內核使用阻塞形式rehash,即rehash進行中將不能對當前哈希表進行任何操做。
 
b)在來看Redis,常駐進程,接收客戶端請求處理各項事務,而且操做的數據是相關且數據量較大的,若是使用PHP內核的那種方式就會出現:對哈希表進行rehash時,此時將阻塞全部客戶端請求,併發性能會大大降低。
 
初始化字典圖解:
 
新增字典元素圖解:
 
Rehash執行流程:
 
 
相關文章
相關標籤/搜索