天天看點

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

5 用戶端路由

5.1 moved重定向

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

每個節點通信共享Redis Cluster中槽和叢集中對應節點的關系。

  1. 用戶端向Redis Cluster的任一節點發送指令
  2. 接收指令的節點再計算自己的槽和對應節點
    • 如果儲存資料的槽被配置設定給目前節點,則去槽中執行指令,并把指令執行結果傳回給用戶端
看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

如果儲存資料的槽不在目前節點的管理範圍内,則向用戶端傳回moved重定向異常

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作
  1. 用戶端接收到節點傳回的結果,如果是moved異常,則從moved異常中擷取目标節點的資訊
  2. 用戶端向目标節點發送指令,擷取指令執行結果

用戶端不會自動找到目标節點執行指令,需要二次執行

5.2 ask重定向

由于叢集伸縮時,需要資料遷移。

  • 當用戶端通路某key,節點告訴用戶端key在源節點,再去源節點通路時,卻發現key已遷移到目标節點,就會傳回ask。
  • 看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作
  1. 用戶端向目标節點發送指令,目标節點中的槽已經遷移到其它節點
  2. 目标節點會傳回ask轉向給用戶端
  3. 用戶端向新節點發送Asking指令
  4. 再向新節點發送指令
  5. 新節點執行指令,把指令執行結果傳回給用戶端

為什麼不能簡單使用MOVED重定向?

雖然MOVED意味着我們認為哈希槽由另一個節點永久提供,并且應該對指定節點嘗試下一個查詢,是以ASK意味着僅将下一個查詢發送到指定節點。

之是以需要這樣做,是因為下一個關于哈希槽的查詢可能是關于仍在A中的鍵的,是以我們始終希望用戶端嘗試A,然後在需要時嘗試B。由于隻有16384個可用的哈希槽中有一個發生,是以群集上的性能下降是可以接受的。

5.3 moved V.S ask

都是用戶端重定向:

  • moved:槽已經确定轉移
  • ask:槽還在遷移中

5.4 智能用戶端

目标

追求性能

設計思路

  • 從叢集中選一個可運作節點,使用

    Cluster slots

    初始化槽和節點映射
  • 将Cluster slots的結果映射在本地,為每個節點建立JedisPool,然後就可以進行資料讀寫操作

注意事項

  • 每個JedisPool中緩存了slot和節點node的關系
  • key和slot的關系:對key進行CRC16規則進行hash後與16383取餘得到的結果就是槽
  • JedisCluster啟動時,已經知道key,slot和node之間的關系,可以找到目标節點
  • JedisCluster對目标節點發送指令,目标節點直接響應給JedisCluster
  • 如果JedisCluster與目标節點連接配接出錯,則JedisCluster會知道連接配接的節點是一個錯誤的節點
  • 此時JedisCluster會随機節點發送指令,随機節點傳回moved異常給JedisCluster
  • JedisCluster會重新初始化slot與node節點的緩存關系,然後向新的目标節點發送指令,目标指令執行指令并向JedisCluster響應
  • 如果指令發送次數超過5次,則抛出異常"Too many cluster redirection!"
  • 基本圖示
  • 看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作
  • 全面圖示
  • 看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

6 批量操作

mget、mset須在同一槽。

Redis Cluster 不同于 Redis 單節點,甚至和一個 Sentinel 監控的主從模式也不一樣。主要因為叢集自動分片,将一個key 映射到16384槽之一,這些槽分布在多節點。是以操作多 key 的指令必須保證所有的key都映射同一槽,避免跨槽執行錯誤。

一個單獨的叢集節點,隻服務一組專用的keys,請求一個指令到一個Server,隻能得到該Server上擁有keys的對應結果。

一個非常簡單的例子是執行KEYS指令,當釋出該指令到叢集中某節點時,隻能得到該節點上擁有key,并非叢集中所有key。要得到叢集中所有key,必須從叢集的所有主節點上擷取所有key。

對于分散在redis叢集中不同節點的資料,如何比較高效地批量擷取資料呢?

6.1 串行mget

定義for循環,周遊所有key,分别去所有的Redis節點中擷取值并進行彙總,簡單,但效率不高,需n次網絡時間。

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

6.2 串行I/O

優化串行的mget,在用戶端本地做内聚,對每個key hash,然後取餘,知道key對應槽

本地已緩存了槽與節點的對應關系,然後對key按節點進行分組,成立子集,然後使用pipeline把指令發送到對應的node,需要nodes次網絡時間,大大減少了網絡時間開銷。

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

6.3 并行I/O

優化串行IO,分組key後,根據節點數量啟動對應的線程數,根據多線程模式并行向node節點請求資料,隻需1次網絡時間

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

6.4 hash_tag

不做任何改變,hash後就比較均勻地散在每個節點上

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

是否能像單機,一次IO将所有key取出呢?hash-tag提供了這樣功能:若将上述key改為如下,即大括号括起來相同的内容,保證所有的key隻向一個node請求資料,這樣執行類似mget指令隻需要去一個節點擷取資料即可,效率更高。

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

6.5 選型對比

看完這篇Redis-Cluster,穩拿30W年薪大廠offer(中)5 用戶端路由6 批量操作

第一種方式,使用多線程解決批量問題,減少帶寬時延,提高效率,這種做法就如上面所說簡單便捷(我們目前批量操作類型比較多),有效。但問題比較明顯。批量操作數量不大即可滿足。

搜狐的cachecloud采用第二點,先将key擷取槽點,然後分node pipeline操作。這種做法相對比第一種做法較優。

繼續閱讀