Redis 故障轉移、高可用方案!
Redis 大家都不陌生,就算是沒用過,也都聽說過了。
作爲最廣泛使用的 KV 內存數據庫之一,在當今的大流量時代,單機模式略顯單薄,免不了要有一些拓展的方案。
筆者下文會對各種方案進行介紹,並且給出_場景_,_實現_ 等等概述,還會提到一些新手常見的誤區。
正文
先從基礎的拓展方式開始,這樣更便於理解較高級的模式。
ps: 本文背景是以筆者落筆時官網最新穩定版 5.0.8 爲準,雖然還沒寫完就變成了 6.0.1。
分區
概述
分區 (Partitioning) 是一種最爲簡單的拓展方式。
在我們面臨單機的存儲空間瓶頸時,第一點就能想到像傳統的關係型數據庫一樣,進行數據分區。
或者假設手中有 N 臺機器可以作爲 Redis 服務器 所有機器內存總和有 256G, 而客戶端正好也需要一個大內存的存儲空間。
我們除了可以把內存條都拆下來焊到一個機器上,也可以選擇分區使用,這樣又拓展了計算能力。
單指分區來講,即將全部數據分散在多個 Redis 實例中,每個實例不需要關聯,可以是完全獨立的。
使用方式
-
客戶端處理 和傳統的數據庫分庫分表一樣,可以從 key 入手,先進行計算,找到對應數據存儲的實例在進行操作。範圍角度,比如 orderId:1~orderId:1000 放入實例 1,orderId:1001~orderId:2000 放入實例 2... 哈希計算,就像我們的 hashmap 一樣,用 hash 函數加上位運算或者取模,高級玩法還有一致性 Hash 等操作,找到對應的實例進行操作
-
使用代理中間件 我們可以開發獨立的代理中間件,屏蔽掉處理數據分片的邏輯,獨立運行。當然也有他人已經造好的輪子,Redis 也有優秀的代理中間件,譬如 Twemproxy,或者 codis,可以結合場景選擇是否使用。
缺點
-
無緣多 key 操作,key 都不一定在一個實例上,那麼多 key 操作或者多 key 事務自然是不支持。
-
維護成本,由於每個實例在物理和邏輯上,都屬於單獨的一個節點,缺乏統一管理。
-
靈活性有限,範圍分片還好,比如 hash+MOD 這種方式,如果想動態調整 Redis 實例的數量,就要考慮大量數據遷移,這就非常麻煩了。
同爲開發者,深知我們雖然總能 “曲線救國” 的完成一些當前環境不支持的功能,但是總歸要麻煩一些。
主從
概述數據遷移
常說的主從 (Master-Slave),也就是複製 (Replication) 方式,怎麼稱呼都可以。
同上面的分區一樣,也是 Redis 高可用架構的基礎,新手可能會誤以爲這類基礎模式即是 “高可用”,這並不是十分正確的。
分區暫時能解決單點無法容納的數據量問題,但是一個 Key 還是隻在一個實例上,在大流量時代顯得不那麼可靠。
主從就是另一個緯度的拓展,節點將數據同步到從節點,就像將實例 “分身” 了一樣,可靠性又提高了不少。
[
圖畫的有些誇張了,主要還是想體現結構靈活,是一主一從,還是一主多從,還是一主多從多從... 看你心情
有了 “實例分身”,自然就可以做讀寫分離,將讀流量均攤在各個從節點。
使用方式
高手雲集的時代,聊天軟件難免要備上這麼一張表情包。
這表情包和使用方式有什麼關係呢?首先看看使用方式:
-
作爲主節點的 Redis 實例,並不要求配置任何參數,只需要正常啓動
-
作爲從節點的實例,使用配置文件或命令方式
REPLICAOF 主節點Host 主節點port
即可完成主從配置
是不是和表情包一樣,“dalao” 沒動,我去 “抱大腿”。
這樣一個主從最小配置就完成了,主從實例即可對外提供服務。
命令裏的 “主節點” 是相對的,slave 也可以抱 slave 大腿,也就是上文提到的結構靈活。
缺點
-
slave 節點都是隻讀的,如果寫流量大的場景,就有些力不從心了。那我把 slave 節點只讀關掉不就行了?當然不行,數據複製是由主到從,從節點獨有數據同步不到主節點,數據就不一致了。
-
故障轉移不友好,主節點掛掉後,寫處理就無處安放,需要手工的設定新的主節點,如使用
REPLICAOF no one
(誰大腿我都不抱了) 晉升爲主節點,再梳理其他 slave 節點的新主配置,相對來說比較麻煩。
哨兵
概述
主從的手工故障轉移,肯定讓人很難接受,自然就出現了高可用方案 - 哨兵(Sentinel)。
我們可以在主從架構不變的場景,直接加入 Redis Sentinel,對節點進行監控,來完成自動的故障發現與轉移。
並且還能夠充當配置提供者,提供主節點的信息,就算髮生了故障轉移,也能提供正確的地址。
哨兵本身也是 Redis 實例的一種,但不作爲數據存儲方使用,啓動命令也是不一樣的。
雖然圖有些複雜,看起來像要召喚光能使者。
其實實際使用起來是很便捷的。
使用方式
Sentinel 的最小配置,一行即可:
sentinel monitor <主節點別名> <主節點host> <主節點端口> <票數>
只需要配置 master 即可,然後用redis-sentinel <配置文件>
命令即可啓用。
Redis 官網提到的 “最小配置” 是如下所示,除了上面提到的一行,還有其它的一些配置:
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
這是因爲官網加了一個修飾詞,是 “典型的最小配置”,把重要參數和多主的例子都寫出來了,照顧大家 CV 大法的時候,不要忘記重要參數,其實都是有默認值的。
正如該例所示,設置主節點別名就是爲了監控多主的時候,與其額外配置項能夠與其對應, 以及 sentinel 一些命令,如SENTINEL get-master-addr-by-name
就要用到別名了。
哨兵數量建議在三個以上且爲奇數,在 Redis 官網也提到了各種情況的 “佈陣” 方式,非常值得參考。
更多
既然是高可用方案,並非有嚴格意義上的 “缺點”,還需配合使用場景進行考量。
-
故障轉移期間短暫的不可用,但其實官網的例子也給出了
parallel-syncs
參數來指定並行的同步實例數量,以免全部實例都在同步出現整體不可用的情況,相對來說要比手工的故障轉移更加方便。 -
分區邏輯需要自定義處理,雖然解決了主從下的高可用問題,但是 Sentinel 並沒有提供分區解決方案,還需開發者考慮如何建設。
-
既然是還是主從,如果異常的寫流量搞垮了主節點,那麼自動的 “故障轉移” 會不會變成自動 “災難傳遞”,即 slave 提升爲 Master 之後掛掉,又進行提升又被掛掉。不過最後這點也是筆者猜測,並沒有聽說過出現這種案例,可不必深究。
集羣
概述
Redis Cluster 是官方在 3.0 版本後推出的分佈式方案。
對開發者而言,“官方支持” 一詞是大概率非常美好的,小到 issue,大到 feature。自定義去解決問題,成本總是要高一些。
有了官方的正式集羣方案,從請求路由、故障轉移、彈性伸縮幾個緯度的使用上,將更爲容易。
Cluster 不同於哨兵,是支持分區的。有說法 Cluster 是哨兵的升級,這是不嚴謹的。
二者緯度不一樣,如果因爲 Cluster 也有故障轉移的功能,就說它是哨兵的升級款,略顯牽強。
Cluster 在分區管理上,使用了 “哈希槽”(hash slot) 這麼一個概念,一共有 16384 個槽位,每個實例負責一部分槽,通過CRC16(key)&16383
這樣的公式,計算出來 key 所對應的槽位。
雖然在節點和 key 二者中又引入了槽的概念,看起來不易理解,實際上因爲顆粒度更細了,減少了節點的擴容和收縮難度,相比傳統策略還是很有優勢。
當然,“槽”是虛擬的概念,節點自身去維護 “槽” 的關係,並不是要真正下載啓動個 “槽服務” 在跑。
使用方式
Redis 的各種玩法,都是從配置文件着手,集羣也不例外。
cluster-enabled yes
cluster-config-file "redis-node.conf"
關鍵配置簡潔明瞭,有兩步
-
開啓集羣
-
指定集羣配置文件
集羣配置文件 (cluster-config-file) 爲內部使用,可以不去指定,Redis 會幫助創建一個。啓動還是普通的方式redis-server redis.conf
首先以集羣方式啓動了 N 臺 Redis 實例,這當然還沒完事。
接下來的步驟筆者稱爲 “牽線搭橋分配槽”,聽起來還算順口。
“牽線搭橋分配槽” 的方式也在不斷升級,從直接用原始命令來處理,到使用腳本,以及現在的 Redis-cli 官方支持,使用哪種方式都可以。
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
上方的命令即是 Redis 官網給出的 redis-cli 的方式用法,一行命令完成 “三主三從” 以及自動分配槽的操作。
這樣集羣就搭建完成了,當然,使用官方提供的 check 命令檢查一下,也是有必要的。
redis-cli --cluster check 127.0.0.1:7001
更多
-
雖然是對分區良好支持,但也有一些分區的老問題,譬如:如果不在同一個 “槽” 的數據,是沒法使用類似 mset 的多鍵操作。
-
在 select 命令頁有提到, 集羣模式下只能使用一個庫,雖然平時一般也是這麼用的,但是要了解一下。
-
運維上也要謹慎,俗話說得好,“使用越簡單底層越複雜”,啓動搭建是很方便,使用時面對帶寬消耗,數據傾斜等等具體問題時,還需人工介入,或者研究合適的配置參數。
結尾
趣談
在寫 “主從” 方案的時候,發現有一個有趣的事情:
筆者開始是記得主從的關鍵命令是SLAVEOF
,後來查閱官方的時候,發現命令已經更改爲REPLICAOF
,雖然SLAVEOF
還能用。
官網的一些描述詞彙,有的地方還是 Slave,也有些是用 Replication。
好奇的筆者查了一下相關的資料,並看了些 Redis 作者 antirez 的有關此時博客,發現已經是兩年前的事情了。
其實就是 “Slave” 這個變量名給了一些人機會,藉此 “噴” 了一波作者,作者也做出了一部分妥協。
有興趣的盆友可以自己搜搜看,技術外的東西就不做評價了,看個樂呵就行。
筆者的主要目的還是:看官方文檔的時候,別讓不同的 “詞彙” 迷惑了。
來源 | https://juejin.cn/post/6844904147943161869
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/KEbBq3vkpjyc-WB_CSfdCA