當前位置:首頁 > 公眾號精選 > 架構(gòu)師社區(qū)
[導讀]作者:vivo互聯(lián)網(wǎng)數(shù)據(jù)庫團隊—YuanJianwei一、背景在現(xiàn)網(wǎng)環(huán)境,一些使用Redis集群的業(yè)務(wù)隨著業(yè)務(wù)量的上漲,往往需要進行節(jié)點擴容操作。之前有了解到運維同學對一些節(jié)點數(shù)比較大的Redis集群進行擴容操作后,業(yè)務(wù)側(cè)反映集群性能下降,具體表現(xiàn)在訪問時延增長明顯。某些業(yè)務(wù)對R...

作者:vivo互聯(lián)網(wǎng)數(shù)據(jù)庫團隊—Yuan Jianwei

一、背景


在現(xiàn)網(wǎng)環(huán)境,一些使用Redis集群的業(yè)務(wù)隨著業(yè)務(wù)量的上漲,往往需要進行節(jié)點擴容操作。


之前有了解到運維同學對一些節(jié)點數(shù)比較大的Redis集群進行擴容操作后,業(yè)務(wù)側(cè)反映集群性能下降,具體表現(xiàn)在訪問時延增長明顯。


某些業(yè)務(wù)對Redis集群訪問時延比較敏感,例如現(xiàn)網(wǎng)環(huán)境對模型實時讀取,或者一些業(yè)務(wù)依賴讀取Redis集群的同步流程,會影響業(yè)務(wù)的實時流程時延。業(yè)務(wù)側(cè)可能無法接受。


為了找到這個問題的根因,我們對某一次的Redis集群遷移操作后的集群性能下降問題進行排查。


1.1 問題描述


這一次具體的Redis集群問題的場景是:某一個Redis集群進行過擴容操作。業(yè)務(wù)側(cè)使用Hiredis-vip進行Redis集群訪問,進行MGET操作。


業(yè)務(wù)側(cè)感知到訪問Redis集群的時延變高。


1.2 現(xiàn)網(wǎng)環(huán)境說明


  • 目前現(xiàn)網(wǎng)環(huán)境部署的Redis版本多數(shù)是3.x或者4.x版本;

  • 業(yè)務(wù)訪問Redis集群的客戶端品類繁多,較多的使用Jedis。本次問題排查的業(yè)務(wù)使用客戶端Hiredis-vip進行訪問;

  • Redis集群的節(jié)點數(shù)比較大,規(guī)模是100 ;

  • 集群之前存在擴容操作。


1.3 觀察現(xiàn)象


因為時延變高,我們從幾個方面進行排查:

  • 帶寬是否打滿;

  • CPU是否占用過高;

  • OPS是否很高;


通過簡單的監(jiān)控排查,帶寬負載不高。但是發(fā)現(xiàn)CPU表現(xiàn)異常:


Redis大集群擴容性能優(yōu)化實踐


1.3.1 對比ops和CPU負載


觀察業(yè)務(wù)反饋使用的MGET和CPU負載,我們找到了對應(yīng)的監(jiān)控曲線。


從時間上分析,MGET和CPU負載高并沒有直接關(guān)聯(lián)。業(yè)務(wù)側(cè)反饋的是MGET的時延普遍增高。此處看到MGET的OPS和CPU負載是錯峰的。


Redis大集群擴容性能優(yōu)化實踐


此處可以暫時確定業(yè)務(wù)請求和CPU負載暫時沒有直接關(guān)系,但是從曲線上可以看出:在同一個時間軸上,業(yè)務(wù)請求和cpu負載存在錯峰的情況,兩者間應(yīng)該有間接關(guān)系。


1.3.2 對比Cluster指令OPS和CPU負載


由于之前有運維側(cè)同事有反饋集群進行過擴容操作,必然存在slot的遷移。


考慮到業(yè)務(wù)的客戶端一般都會使用緩存存放Redis集群的slot拓撲信息,因此懷疑Cluster指令會和CPU負載存在一定聯(lián)系。


我們找到了當中確實有一些聯(lián)系:


Redis大集群擴容性能優(yōu)化實踐


此處可以明顯看到:某個實例在執(zhí)行Cluster指令的時候,CPU的使用會明顯上漲。


根據(jù)上述現(xiàn)象,大致可以進行一個簡單的聚焦:

  • 業(yè)務(wù)側(cè)執(zhí)行MGET,因為一些原因執(zhí)行了Cluster指令;

  • Cluster指令因為一些原因?qū)е翪PU占用較高影響其他操作;

  • 懷疑Cluster指令是性能瓶頸。


同時,引申幾個需要關(guān)注的問題:

  • 為什么會有較多的Cluster指令被執(zhí)行?

  • 為什么Cluster指令執(zhí)行的時候CPU資源比較高?

  • 為什么節(jié)點規(guī)模大的集群遷移slot操作容易“中招”?


二、問題排查


2.1 Redis熱點排查


我們對一臺現(xiàn)場出現(xiàn)了CPU負載高的Redis實例使用perf top進行簡單的分析:


Redis大集群擴容性能優(yōu)化實踐


從上圖可以看出來,函數(shù)(ClusterReplyMultiBulkSlots)占用的CPU資源高達 51.84%,存在異常


2.1.1 ClusterReplyMultiBulkSlots實現(xiàn)原理


我們對clusterReplyMultiBulkSlots函數(shù)進行分析:

void clusterReplyMultiBulkSlots(client *c) { /* Format: 1) 1) start slot * 2) end slot * 3) 1) master IP * 2) master port * 3) node ID * 4) 1) replica IP * 2) replica port * 3) node ID * ... continued until done */ int num_masters = 0; void *slot_replylen = addDeferredMultiBulkLength(c); dictEntry *de; dictIterator *di = dictGetSafeIterator(server.cluster->nodes); while((de = dictNext(di)) != NULL) { /*注意:此處是對當前Redis節(jié)點記錄的集群所有主節(jié)點都進行了遍歷*/ clusterNode *node = dictGetVal(de); int j = 0, start = -1; /* Skip slaves (that are iterated when producing the output of their * master) and masters not serving any slot. */ /*跳過備節(jié)點。備節(jié)點的信息會從主節(jié)點側(cè)獲取。*/ if (!nodeIsMaster(node) || node->numslots == 0) continue; for (j = 0; j < CLUSTER_SLOTS; j ) { /*注意:此處是對當前節(jié)點中記錄的所有slot進行了遍歷*/ int bit, i; /*確認當前節(jié)點是不是占有循環(huán)終端的slot*/ if ((bit = clusterNodeGetSlotBit(node,j)) != 0) { if (start == -1) start = j; } /*簡單分析,此處的邏輯大概就是找出連續(xù)的區(qū)間,是的話放到返回中;不是的話繼續(xù)往下遞歸slot。 如果是開始的話,開始一個連續(xù)區(qū)間,直到和當前的不連續(xù)。*/ if (start != -1
本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉
關(guān)閉