1. 程式人生 > >redis 學習筆記三

redis 學習筆記三

緩解 實時 代理 水平擴展 命令連接 事件 都沒有 分數 能力

一、redis 復制

數據庫復制指的是發生在不同數據庫實例之間,單向的信息傳播的行為,通常由被復制方和復制方組成,被復制方和復制方之間建立網絡連接,復制方式通常為被復制方主動將數據發送到復制方,復制方接收到數據存儲在當前實例,最終目的是為了保證雙方的數據一致、同步。

Redis復制方式:

一種是主(master)-從(slave)模式,一種是從(slave)-從(slave)模式,因此Redis的復制拓撲圖會豐富一些,可以像星型拓撲,也可以像個有向無環:

通過配置多個Redis實例獨立運行、定向復制,形成Redis集群,master負責寫、slave負責讀。

復制優點

通過配置多個Redis實例,數據備份在不同的實例上,主庫專註寫請求,從庫負責讀請求,這樣的好處主要體現在下面幾個方面:

1、高可用性

在一個Redis集群中,如果master宕機,slave可以介入並取代master的位置,因此對於整個Redis服務來說不至於提供不了服務,這樣使得整個Redis服務足夠安全。

2、高性能

在一個Redis集群中,master負責寫請求,slave負責讀請求,這麽做一方面通過將讀請求分散到其他機器從而大大減少了master服務器的壓力,另一方面slave專註於提供讀服務從而提高了響應和讀取速度。

3、水平擴展性

通過增加slave機器可以橫向(水平)擴展Redis服務的整個查詢服務的能力。

復制缺點

復制提供了高可用性的解決方案,但同時引入了分布式計算的復雜度問題,認為有兩個核心問題:

  1. 數據一致性問題,如何保證master服務器寫入的數據能夠及時同步到slave機器上。

  2. 編程復雜,如何在客戶端提供讀寫分離的實現方案,通過客戶端實現將讀寫請求分別路由到master和slave實例上。

上面兩個問題,尤其是第一個問題是Redis服務實現一直在演變,致力於解決的一個問題。

復制實時性和數據一致性矛盾

Redis提供了提高數據一致性的解決方案,一致性程度的增加雖然使得我能夠更信任數據,但是更好的一致性方案通常伴隨著性能的損失,從而減少了吞吐量和服務能力。然而我們希望系統的性能達到最優,則必須要犧牲一致性的程度,因此Redis的復制實時性和數據一致性是存在矛盾的。

Redis復制工作過程:

  1. slave向master發送sync命令。

  2. master開啟子進程來講dataset寫入rdb文件,同時將子進程完成之前接收到的寫命令緩存起來。

  3. 子進程寫完,父進程得知,開始將RDB文件發送給slave。

  4. master發送完RDB文件,將緩存的命令也發給slave。

  5. master增量的把寫命令發給slave。

二、redis集群

1、Redis Sharding集群,客戶端分片

客戶端分片是把分片的邏輯放在Redis客戶端實現,通過Redis客戶端預先定義好的路由規則,把對Key的訪問轉發到不同的Redis實例中,最後把返回結果匯集

優點:

  • 所有的邏輯都是可控的,不依賴於第三方分布式中間件。開發人員清楚怎麽實現分片、路由的規則,不用擔心踩坑。
  • 這種分片性能比代理式更好(因為少了分發環節),分發壓力在客戶端,無服務端壓力增加

缺點:

  • 靜態的分片方案,需要增加或者減少Redis實例的數量,需要手工調整分片的程序。

  • 不能平滑地水平擴容,擴容/縮容時,必須手動調整分片程序,出現故障不能自動轉移,難以運維

2、Twemproxy

優點:

  • 運維成本低。業務方不用關心後端 Redis 實例,跟操作 Redis 一樣。Proxy 的邏輯和存儲的邏輯是隔離的
  • 支持無效Redis實例的自動刪除。
  • Twemproxy與Redis實例保持連接,減少了客戶端與Redis實例的連接數。

缺點:

  • a. 代理層多了一次轉發,性能有所損耗

  • b. 進行擴容/縮容時候,部分數據可能會失效,需要手動進行遷移,對運維要求較高,而且難以做到平滑的擴縮容

  • c. 出現故障,不能自動轉移,運維性很差

3、Codis

優點:

  • 支持平滑增加(減少)Redis Server Group(Redis實例),能安全、透明地遷移數據,這也是Codis 有別於Twemproxy等靜態分布式 Redis 解決方案的地方

缺點:

  • 需要更改redis的源代碼(為了加入slot信息) 以及代理實現本身會有的問題

4、Redis Cluster

優點:

  • 無中心節點

  • 數據按照 Slot 存儲分布在多個 Redis 實例上

  • 平滑的進行擴容/縮容節點

  • 自動故障轉移(節點之間通過 Gossip 協議交換狀態信息,進行投票機制完成 Slave 到 Master 角色的提升)

  • 降低運維成本,提高了系統的可擴展性和高可用性

缺點:

  • 嚴重依賴外部 Redis-Trib
  • 缺乏監控管理
  • 需要依賴 Smart Client(連接維護, 緩存路由表, MultiOp 和 Pipeline 支持)
  • Failover 節點的檢測過慢,不如“中心節點 ZooKeeper”及時
  • Gossip 消息的開銷
  • 無法根據統計區分冷熱數據
  • Slave“冷備”,不能緩解讀壓力

實際項目中該如何選型呢?

方案 1 使用nginx開發(OpenResty方式)

原因如下

a. 單 Master 多 Work 模式,每個 Work 跟 Redis 一樣都是單進程單線程模式,並且都是基

於 Epoll 事件驅動的模式。

b. Nginx 采用了異步非阻塞的方式來處理請求,高效的異步框架。

c. 內存占用少,有自己的一套內存池管理方式,。將大量小內存的申請聚集到一塊,能夠比

Malloc 更快。減少內存碎片,防止內存泄漏。減少內存管理復雜度。

d. 為了提高 Nginx 的訪問速度,Nginx 使用了自己的一套連接池。

e. 最重要的是支持自定義模塊開發。

f. 業界內,對於 Nginx,Redis 的口碑可稱得上兩大神器。性能也就不用說了。

方案 2 codis (豌豆莢采用的基於代理的redis集群方案)

參考codis官方文檔https://github.com/CodisLabs/codis

Codis是一整套緩存解決方案,包含高可用、數據分片、監控、動態擴態 etc.。

走的是 Apps->代理->redis cluster,一定規模後基本都采用這種方式。

方案3 自己獨立開發redis智能客戶端

主要實現redis slots管理,failover,一致性hash功能。

三、sentinel

Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis做Master-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現自動進行主備切換,而Redis-sentinel本身也是一個獨立運行的進程,它能監控多個master-slave集群,發現master宕機後能進行自懂切換。

它的主要功能有以下幾點

  • 不時地監控redis是否按照預期良好地運行;

  • 如果發現某個redis節點運行出現狀況,能夠通知另外一個進程(例如它的客戶端);

  • 能夠進行自動切換。當一個master節點不可用時,能夠選舉出master的多個slave(如果有超過一個slave的話)中的一個來作為新的master,其它的slave節點會將它所追隨的master的地址改為被提升為master的slave的新地址。

Sentinel支持集群

很顯然,只使用單個sentinel進程來監控redis集群是不可靠的,當sentinel進程宕掉後(sentinel本身也有單點問題,single-point-of-failure)整個集群系統將無法按照預期的方式運行。所以有必要將sentinel集群,這樣有幾個好處:

  • 即使有一些sentinel進程宕掉了,依然可以進行redis集群的主備切換;
  • 如果只有一個sentinel進程,如果這個進程運行出錯,或者是網絡堵塞,那麽將無法實現redis集群的主備切換(單點問題);
  • 如果有多個sentinel,redis的客戶端可以隨意地連接任意一個sentinel來獲得關於redis集群中的信息。

Redis Sentinel節點推薦3個以上。相比keepalived+redis實現高可用更靠譜,且keepalived+redis還不能管理多個實例

原理:

①sentinel集群通過給定的配置文件發現master,啟動時會監控master。通過向master發送info信息獲得該服務器下面的所有從服務器。
②sentinel集群通過命令連接向被監視的主從服務器發送hello信息(每秒一次),該信息包括sentinel本身的ip、端口、id等內容,以此來向其他sentinel宣告自己的存在。
③sentinel集群通過訂閱連接接收其他sentinel發送的hello信息,以此來發現監視同一個主服務器的其他sentinel;集群之間會互相創建命令連接用於通信,因為已經有主從服務器作為發送和接收hello信息的中介,sentinel之間不會創建訂閱連接。
④sentinel集群使用ping命令來檢測實例的狀態,如果在指定的時間內(down-after-milliseconds)沒有回復或則返回錯誤的回復,那麽該實例被判為下線。
⑤當failover主備切換被觸發後,failover並不會馬上進行,還需要sentinel中的大多數sentinel授權後才可以進行failover,即進行failover的sentinel會去獲得指定quorum個的sentinel的授權,成功後進入ODOWN狀態。如在5個sentinel中配置了2個quorum,等到2個sentinel認為master死了就執行failover。
⑥sentinel向選為master的slave發送SLAVEOF NO ONE命令,選擇slave的條件是sentinel首先會根據slaves的優先級來進行排序,優先級越小排名越靠前。如果優先級相同,則查看復制的下標,哪個從master接收的復制數據多,哪個就靠前。如果優先級和下標都相同,就選擇進程ID較小的。
⑦sentinel被授權後,它將會獲得宕掉的master的一份最新配置版本號(config-epoch),當failover執行結束以後,這個版本號將會被用於最新的配置,通過廣播形式通知其它sentinel,其它的sentinel則更新對應master的配置。

①到③是自動發現機制:

  • 10秒一次的頻率,向被監視的master發送info命令,根據回復獲取master當前信息。
  • 1秒一次的頻率,向所有redis服務器、包含sentinel在內發送PING命令,通過回復判斷服務器是否在線。
  • 2秒一次的頻率,通過向所有被監視的master,slave服務器發送當前sentinel,master信息的消息。

④是檢測機制,⑤和⑥是failover機制,⑦是更新配置機制。

註意:因為redis采用的是異步復制,沒有辦法避免數據的丟失。但可以通過以下配置來使得數據不會丟失:min-slaves-to-write 1 、 min-slaves-max-lag 10。一個redis無論是master還是slave,都必須在配置中指定一個slave優先級。要註意到master也是有可能通過failover變成slave的。如果一個redis的slave優先級配置為0,那麽它將永遠不會被選為master,但是它依然會從master哪裏復制數據。

redis 學習筆記三