1. 程式人生 > >nkv客戶端效能調優

nkv客戶端效能調優

此文已由作者張洪簫授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。

問題描述

隨著考拉業務的增長和規模的擴大,很多的應用都開始重度依賴快取服務,也就是杭研的nkv。但是在使用過程中,發現服務端壓力並不是特別大的情況下,客戶端的rt卻很高,導致應用在到達一定併發的情況下,服務的質量下降的非常嚴重,甚至出現不可用的情況。這個在大促階段尤其嚴重,所以在杭研效能測試團隊(這裡特別感謝霞姐和小寶的大力支援)的協助下,線上下進行了壓測和問題定位。

問題發現過程

測試使用了dubbo介面呼叫形式對fee工程進行加壓,fee會在被呼叫後通過nkv客戶端訪問nkv服務端。

第一階段

在逐步加壓的過程中,發現併發到達150時,rt已經漲到50ms左右,此時使用jstack列印堆疊,發現大量的執行緒在等待訊息的返回。反觀此時服務端的情況,基本無壓力,故此時定位,瓶頸在客戶端。 review客戶端程式碼,客戶端呼叫服務端採用的是netty的非同步方式,同步介面會在呼叫netty傳送訊息後使用future來獲得響應;非同步則將future返回給應用,交由應用處理。簡單的過了一遍程式碼,並沒有發現什麼異常。 因為從哨兵監控上觀察應用並沒有異常,只是上下文切換的次數稍多,差不多有8w左右,懷疑有可能是因為執行緒數過多導致上下文切換過於頻繁導致,所以將dubbo的執行緒數從400降低到了200,再次壓測,發現在同等併發數下,rt比之前低,在40ms左右。 因為40ms並不能滿足要求,而且不過壓測機的併發數提高多少,qps最高只能在1500-1700左右徘徊,無法繼續加壓,所以只能繼續找問題。

第二階段

在之後的階段卡了很久。後來觀察到qps不高,load卻比較高,邵峰提出是否是netty的一個bug,即在併發不高的情況下,佔用大量的cpu,導致響應較慢,嘗試把netty的更換到一個較高的版本,再次嘗試,問題依然。

第三階段

百思不得其解的時候,霞姐偶然在監控堆疊的地方看到有機率出現在一個鎖的地方停留,然後回過頭仔細看了下那段程式碼,終於發現了問題。 nkv在呼叫netty傳送訊息前會做這兩個操作,第一個是將channal和seq的資訊放到一個DelayQueue中,然後再將seq和channal的對應放到一個ConcurrentHashMap裡

Alt pic


然後再收到響應後,從DelayQueue中刪除收到訊息對應的資訊,再根據seq找到channal,然後喚醒等待的執行緒。  Alt pic

 

DelayQueue在這裡主要是為了防止在某些異常情況下,導致channal未釋放,會有另一個執行緒定時掃描DelayQueue清除超時物件。 但是在大併發下,由於DelayQueue的刪除是上鎖後遍歷整個列表的,所以收到響應後的清除操作,會將網路回撥執行緒和業務的傳送執行緒阻塞,雖然很快就收到服務端的響應,但是回撥執行緒卻無法回撥,所以導致整體響應非常慢。

第四階段

找到原因後,解決方案的選擇就比較多,後來選擇的方案是將DelayQueue去掉,在呼叫傳送後,將獲取future的結果的操作放入try-finally中,釋放chnnal的操作放在finally,則同步操作時釋放肯定會被執行。非同步操作則是在網路執行緒的回撥後清除channal。 修改完成後,再次壓測,再qps接近3倍的情況下,平均rt降低到原來的1/4,基本滿足了本次調優的目標。

第五階段

調優是沒有止境的,所以再過了一遍程式碼,發現在呼叫netty傳送後,客戶端呼叫了await來等待網路的回撥,

Alt pic


但是因為nkv的rt正常情況下非常低,很多操作都是毫秒內的,但是await的單位是毫秒,這樣很有可能導致有些情況下本來需要1.1.毫秒的操作,卻變成了2ms。 所以就將await改成了awaitNanos,納秒級等待。 修改後測試,在使用batch操作時,平均rt降低1.6ms,可能有些人覺得才1.6ms,差別不大,但是在99%響應在10ms內的快取服務中,降低1.6毫秒的影響已經很大了。


總結

  • 需要好的工具,像霞姐他們的效能測試工具,這樣事半功倍

  • 往往優化的點就是備忽略的點,還是得自己review

  • 優化無止境,小的點也會有很大的影響


免費體驗雲安全(易盾)內容安全、驗證碼等服務

更多網易技術、產品、運營經驗分享請點選


相關文章:
【推薦】 限時購校驗小工具&dubbo非同步呼叫實現限
【推薦】 一個體驗好的Windows 工作列縮圖開發心得