Go語言:谷歌go-redis模塊面向redis cluster集羣的客戶端的主要功能點及性能

版權所有,轉載請註明原文鏈接。

谷歌的go-redis@v6.15.7對redis cluster集羣提供了支持,這也是相對於redigo的一個重要優勢,後者目前還沒有提供集羣支持。go-redis@v6.15.7的主要功能點如下:

1.客戶端緩存了每一組連續的slot所對應的起止slotID和存儲節點列表,以提高一次性訪問的成功率,避免MOVED重定向。

type clusterSlot struct {
    start, end int
    nodes      []*clusterNode
}

2.如果執行命令時服務端返回MOVED錯誤,則客戶端通過cluster slots命令重新獲取節點信息

//如果是MOVED類型錯誤,則更新節點信息
func (c *ClusterClient) checkMovedErr(
    cmd Cmder, err error, failedCmds *cmdsMap,
) bool {
    moved, ask, addr := internal.IsMovedError(err)

    if moved {
        c.state.LazyReload()
...

//向節點發送CLUSTER SLOTS命令
func (c *ClusterClient) loadState() (*clusterState, error) {
...
slots, err := node.Client.ClusterSlots().Result()
...

3. 管理一組redis.Client,每一個redis.Client獨立創建一個連接池。
4. 對key執行命令時,先計算key通過CRC16轉換後的值然後用16384取餘,從而得到一個0-16383的slotID。然後找到對應的主從節點列表,列表第一個元素是主節點。

//通過二分查找來找到slotID對應的節點列表
func (c *clusterState) slotNodes(slot int) []*clusterNode {
    i := sort.Search(len(c.slots), func(i int) bool {
        return c.slots[i].end >= slot
    })
    if i >= len(c.slots) {
        return nil
    }
    x := c.slots[i]
    if slot >= x.start && slot <= x.end {
        return x.nodes
    }
    return nil
}


5. 可以通過配置來指定只讀操作是否可以在從節點上執行,還可以進一步指定在多個從節點之間隨機選取或者按Ping時間最短來選取。其中Ping命令是另起一個go routine來計算,Ping 10次求平均。

//10次Ping求平均
func (n *clusterNode) updateLatency() {
    const probes = 10

    var latency uint32
    for i := 0; i < probes; i++ {
        start := time.Now()
        n.Client.Ping()
        probe := uint32(time.Since(start) / time.Microsecond)
        latency = (latency + probe) / 2
    }
    atomic.StoreUint32(&n.latency, latency)
}

6. 批量執行多條命令時,客戶端先計算各條命令對應的slotID,然後把slotID相同的命令放到一起發送給對應節點批量執行,不同slotID之間是並行執行的。在計算slotID時,採用的是每條命令的第一個key,也就是說含有多個key的命令有可能會導致MOVED重定向,從而影響效率。

//取第一個key計算slotID
func cmdSlot(cmd Cmder, pos int) int {
    if pos == 0 {
        return hashtag.RandomSlot()
    }
    firstKey := cmd.stringArg(pos)
    return hashtag.Slot(firstKey)
}


7. 經驗證,可以支持在客戶端redis寫操作達到1000QPS負載的情況下,動態增加節點,期間性能幾乎沒有什麼影響。(服務端5.0.8,客戶端 v6.15.7)。因爲,集羣每次只是移動16384個slot中的一個,而被移動的slot也只是造成客戶端多一次MOVED重定向,所以總體性能影響很小。

8. 經驗證,可以支持在客戶端redis寫操作達到1000QPS負載的情況下,人爲掛掉一個主節點,則集羣自動切換主從,客戶端自動更新節點信息表,期間性能幾乎沒有什麼影響,客戶端也沒有出現報錯。(服務端5.0.8,客戶端 v6.15.7)。

9. 啓動時不會建立到節點的連接,在需要執行命令時才建立連接。

 

相關文章:

《Go語言:谷歌的go-redis模塊面向redis cluster集羣的客戶端參數配置》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章