寫在前面
學習《redis入門指南》筆記,結合實踐,只記錄重要,明確,屬於新知的相關內容。
配置叢集
1、配置叢集,叢集解決了單點故障以及單臺機器記憶體上限的問題,使用叢集時,只需要將配置檔案中的引數cluster-enabled開啟即可,叢集中至少有三個主庫才可以執行,當啟動若干個redis-server後,此時每個節點都是獨立的,想要初始化叢集,redis原始碼中提供了一個使用ruby語言編寫的工具,redis-trib.rb來輔助初始化叢集。
2、使用redis-trib.rb初始化叢集,只需要執行:
redis-trib.rb create --replicas n [ip:port ...]
create 表示初始化叢集,--replicas n表示每個主庫擁有的從庫數量,執行命令後,會輸出一系列資訊,包含節點的啟動資訊(是否啟動成功),以及主從資訊,如果覺得沒問題,輸入yes來開始建立。
3、redis-trib.rb會像客戶端一樣嘗試PING每個節點,如果PING失敗則叢集啟動失敗,之後會傳送INFO命令獲取每個節點的runid以及是否開啟了叢集;以上就緒後,會向每一個節點傳送CLUSTER MEET ip port命令,用來告訴當前節點指定ip和port上執行的節點也是叢集的一部分;接著開始分配主從資料庫,redis-trib.rb會盡量使得主從庫不在同意IP上,以保證容災能力;然後為每一個主庫分配插槽(用來分配哪些鍵由哪個庫儲存),最後向每個要成為從庫的節點傳送CLUSTER REPLICATE 主庫runid命令,來將該節點轉換成從庫並複製指定執行id的節點,至此叢集初始化完畢。
4、叢集初始化完畢後可以使用redis-cli連線任意節點即可獲取整個叢集的資訊(使用CLUSTER NODES命令),也可以嘗試使用redis-cli初始化一次叢集。
增加節點
5、向叢集中增加節點
CLUSTER MEET ip port
增加節點時,只需要使用客戶端向新增節點傳送該命令;ip 和 port 分別是叢集中已有的某個節點的ip和port。
6、新增節點你會向叢集中的節點進行握手,握手成功後新節點將被認作叢集的一員,被握手的節點會使用Gossip協議通知叢集中的其他節點關於新增節點的資訊。
插槽
7、redis使用CRC16演算法將每個鍵的有效部分計算出雜湊值對16384取餘,使得每個鍵都可以分配至16384個插槽中;鍵名的有效部分有以下規則:
a、當鍵名包含{符號,且在其後存在}符號,並且兩者之間至少有一個字元,那有效部分指的是{和}之間的內容。
b、如果不滿足上一條,整個鍵名都是有效部分。
8、在使用工具redis-trib.rb初始化叢集時,每個節點會被分配到連續的插槽,但redis並沒有這個限制,可以將任意幾個插槽交給特定的節點負責。
9、檢視插槽的分配情況
CLUSTER SLOTS
返回資訊的數量會是多條,每條資訊中包含槽的開始和結束號碼以及主從資訊。
10、分配未被分配的插槽
CLUSTER ADDSLOTS slots [slots ...]
若分配了已經分配出去的插槽,則會返回錯誤。
11、若要移動插槽給另外的節點,也可以使用redis-trib.rb工具:
redis-trib.rb reshared ip port
reshared告訴redis-trib.rb要重新分片,ip和port是叢集中任意節點的地址和埠;之後redis-trib.rb會詢問要遷移多少個插槽,要把插槽遷移到哪個節點(通過執行id確定節點)要從哪個節點移出插槽,最後輸入done即可。
12、若不借助redis-trib.rb移動插槽,可以使用如下命令:
CLUSTER SETSLOT 插槽號 NODE 新節點的執行id
但使用該命令的前提是,插槽中沒有鍵,因為該命令只會遷移插槽,不會遷移鍵,使用如下命令獲取插槽中的鍵:
CLUSTER GETKEYSINSLOT 插槽號 要返回的鍵的數量
之後對每個鍵進行遷移,命令如下:
MIGRATE 目標節點地址 目標節點埠 鍵名 資料庫號碼 超時時間 [copy] [replace]
copy選項表示不從當前庫中刪除,而是複製一份副本,replace表示如果存在相同鍵名則覆蓋,資料庫號碼始終是0。
13、以上的方法仍然會造成資料臨時丟失,redis提供瞭如下兩個命令來實現叢集不下線的情況下遷移資料:
CLUSTER SETSLOT 插槽號 MIGRATING 新節點runid
CLUSTER SETSLOT 插槽號 IMPORTING 原節點runid
redis-trib.rb工具在遷移時就會先執行上面兩條命令,用來解決臨時丟失問題,之後獲取插槽中儲存的鍵,一一遷移,最後遷移插槽。
14、執行上面的前兩個命令後,當客戶端向原節點要遷移的插槽請求一個鍵時,若該鍵未被遷移,則直接返回,若已遷移,返回ASK跳轉命令告訴客戶端新的節點,客戶端會先向新節點傳送ASKING命令,之後重新執行最初的請求鍵的命令;相反,如果客戶端向新節點請求了一個正在遷移的插槽中的鍵,如果前面執行過ASKING命令則直接返回,如果沒有執行過則返回MOVE跳轉命令,重新告訴客戶端到原節點去請求鍵。
獲取與插槽對應的節點
15、對於指定的鍵,會根據CRC16演算法分配到對應的插槽,那麼如何獲知插槽所在的節點,當客戶端請求一個不在當前節點負責的插槽中的鍵時,redis會返回MOVE重定向指令:
MOVE slot ip port
包含對應鍵所在的插槽號和該插槽所在的節點的地址和埠,客戶端收到MOVE指令後,再到對應節點請求鍵。
16、一些語言的redis庫支援MOVE請求,此時對開發者而言這是透明的,使用-c引數啟動redis-cli則會以叢集模式啟動,也支援自動重定向;為解決由於重定向導致的多次的網路請求,客戶端應快取插槽的路由資訊,以達到與單機同樣的效能。
故障恢復
17、叢集中每個幾點會每秒挑選另外五個節點,對其中最久沒有相應的節點傳送PING,如果一定時間沒有回覆,發起PING的節點就會認為其疑似下線,與哨兵的主觀下線類似。
18、一旦節點A認為B疑似下線,就會在叢集中傳遞這個訊息,當某一節點收到半數以上認為B下線的訊息,就會向叢集中傳播B已下線的訊息。
19、當叢集中有主庫下線,則會導致一部分插槽無法寫入,這時如果主庫擁有至少一個從庫,叢集就會進行故障恢復將一個從庫轉變為主庫;選擇哪個主庫,與選擇領頭哨兵的過程一致,都基於RAFT演算法。
20、如果至少負責一個插槽且沒有從庫的主庫下線,叢集預設進入下線狀態無法工作,可通過修改配置引數cluster-require-full-coverage為yes來使其在這種情況仍可以工作。
叢集的一些限制
21、當涉及多鍵命令時,如果想關鍵不在同一個節點,則會執行出錯,可以利用鍵名的有效部份這一特點,將要操作的多鍵的鍵名使用{}改造,保證其在同一節點。
22、叢集中的每個節只能使用0號資料庫。