1. 程式人生 > 其它 >原始碼分析:go-redis 叢集客戶端 key 路由的實現

原始碼分析:go-redis 叢集客戶端 key 路由的實現

原始碼:https://github.com/go-redis/redis/tree/v8.11.4

資料結構

flowchart LR subgraph clusterClient n["nodes *clusterNodes"] s["state *clusterState"] end subgraph sCNs["clusterNodes"] n2["nodes map[string]*clusterNode"] end subgraph sCS["clusterState"] s2["slots []*clusterSlot"] gg["generation uint32"] ct["createdAt time.Time"] end subgraph sCSt["clusterSlot"] se["start, end int"] n3["nodes []*clusterNode"] end subgraph sCN["clusterNode"] c["Client *Client"] g["generation uint32"] end n --> sCNs s --> sCS s2 --> sCSt n2 --> sCN n3 --> sCN gg -.- g
  • clusterClient:叢集客戶端抽象
  • clusterNodes:維護叢集內「例項地址=>節點」的對映
  • clusterState:維護叢集內「雜湊槽=>節點」的對映,建立後不可修改,只能通過新建替換更新,每次新建 generation 自增。createdAt 為建立時間。
  • clusterSlot:一個範圍的雜湊槽以及負責這些槽的節點(第一個為主節點,其餘為從節點),start為起始雜湊槽編號,end為起結束希槽編號,nodes為負責這些槽的節點。
  • clusterNode:叢集節點抽象。client為連線此節點的客戶端,generation與clusterState的generation關聯。

演算法

flowchart TD A[執行命令] --> B{"clusterClient.state<br/>是否存在?"}; B -->|不存在| C["使用 CLUSTER SLOTS 命令 獲取「雜湊槽=>例項地址」的對映資訊"]; C --> D["根據「雜湊槽=>例項地址」的對映資訊建立clusterState, clusterState.createdAt 記錄當前時間, 設定最新的 clusterState.generation, 根據例項地址,請求clusterClient.nodes建立或獲取clusterNode; 設定clusterNode.generation為clusterState.generation, clusterSlot.nodes引用這些clusterNode"] D --> E["根據命令key計算slot編號,根據slot編號 定位 clusterSlot = clusterClient.state.slots[*]"] E --> F["使用clusterSlot.nodes[0].Client執行命令"] D -."非同步".-> G["執行一次性定時器,一段時間後檢查clusterSlot.nodes, 如果其中包含clusterNode.generation小於該 clusterState.generation,移除這些clusterNode, 關閉clusterNode.Client釋放資源"] B -->|存在| H[" "] --> E H -."如果clusterState.createdAt(建立時間) 距當前時間超過某閾值,非同步執行".-> S F --"如果返回MOVED重定向"--> I["根據重定向提供的例項地址, 請求clusterClient.nodes建立或獲取clusterNode, 使用clusterNode.Client執行命令"] I -.->|非同步執行| S subgraph S["Create/Update state"] C D G end