網(wǎng)絡(luò)操作的性能優(yōu)化

先貼上優(yōu)化前后的對比圖(優(yōu)化于1月15日上線,19日上了一些細(xì)節(jié)的優(yōu)化):

  • web服務(wù)器的cpu使用


    web服務(wù)器 cpu使用
    web服務(wù)器 cpu使用
  • web服務(wù)器的load


    web服務(wù)器 load
    web服務(wù)器 load
  • rpc的連接數(shù)(主要是與redis的連接)


    rpc的連接數(shù)
    rpc的連接數(shù)
  • redis服務(wù)的cpu使用


    redis服務(wù)的cpu使用
    redis服務(wù)的cpu使用
  • redis所在機(jī)器的連接數(shù)


    redis所在機(jī)器的連接數(shù)
    redis所在機(jī)器的連接數(shù)

現(xiàn)象

  • 某產(chǎn)品由于某些因素(運營,版本更新及體驗等)使得活躍用戶及停留時間不斷提高,進(jìn)而使得服務(wù)器資源使用增長,原先設(shè)定的報警閾值頻繁被觸發(fā),具體表現(xiàn)為:
    • web機(jī)器的load與cpu使用都變高
    • 依賴的緩存服務(wù)redis連接數(shù)與cpu不斷攀升
    • rpc(用于業(yè)務(wù)分離)的連接數(shù)不斷攀升

如何解決

  • 負(fù)載均衡,增加服務(wù)器——最簡單粗暴且有效的方式
  • 找到系統(tǒng)性能瓶頸,優(yōu)化之——這是最經(jīng)濟(jì)也最有挑戰(zhàn)的事
  • ——考慮到線上服務(wù)尚未出現(xiàn)功能性問題,先嘗試第二種方式

定位

  • 參考我之前的blog,對線上各服務(wù)(均為java進(jìn)程)取jstack并用stackAnalysis工具分析其瓶頸,發(fā)現(xiàn)許多線程都停留在對redis的操作上
  • 很顯然,redis的大量請求是瓶頸

分析

  • 仔細(xì)分析stack dump中有相似stackstrace的線程,發(fā)現(xiàn)對緩存的操作有不少shit的邏輯:
    • "同樣的數(shù)據(jù)取兩次"——如:interceptor中會對同一個user對象獲取兩次

      e.g.:
      User user = userRpcServer.getUser(uid);
      // 一些業(yè)務(wù)邏輯
      boolean isForbidderUser = userRpcServer.isForbidderUser(uid);
      
      • 從上面看并沒有直接問題,但仔細(xì)分析會發(fā)現(xiàn)userRpcServer.isForbidderUser(uid)中還會調(diào)用一次getUser(id)
    • "取到了數(shù)據(jù)卻不用"——如:獲取User對象時同時獲取其帳啟余額,但只有與帳戶相關(guān)的請求才需要獲取余額,大多數(shù)接口不需要

      UserAccount userAccount = userRpcServer.getUserAccount(uid);
      UserInfo userInfo = userRpcServer.getUserInfo(uid);
      User user =  makeUser(userAccount, userInfo);
      
    • "已經(jīng)知道緩存中不存在數(shù)據(jù)了,卻還去取"——因為調(diào)用棧較長,所以隱藏的比較深,限于篇幅,暫不舉例。但也正因為隱藏的較深,才造成了資源的浪費不太輕易被發(fā)現(xiàn)。

    • "有大量用for循環(huán)對redis做網(wǎng)絡(luò)操作的邏輯"——如:根據(jù)userIds獲取users

      for(uid : uids) {
          users.add(redisServer.getUser(uid))
      }
      
      • 這樣的邏輯應(yīng)該盡量用批量操作的方式去完成
  • 分析redis slow log, 找出其中耗時和頻繁的操作(尤其是刪除操作),發(fā)現(xiàn)有一些優(yōu)化的空間——此前已做過一次slow log對應(yīng)key的優(yōu)化,所以這次在這方面沒做太多事情。

解決

  • 對應(yīng)上面分析到的問題,分別的解決方案為:
    • 同樣的數(shù)據(jù)取兩次 —— 相同的數(shù)據(jù)只取一次
    • 取到了數(shù)據(jù)卻不用 —— 不用則不取
    • 已經(jīng)知道緩存中不存在數(shù)據(jù)了,卻還去取一次 —— 有的放矢
    • 有大量用for循環(huán)對redis做網(wǎng)絡(luò)操作的邏輯 —— 盡量用批量請求
      • redis是一個集群,因此需要用ShardedJedisPipeline來做批量請求
  • 優(yōu)化之后報警短信完全消失。

優(yōu)化結(jié)果評估

  • 找到優(yōu)化方法并進(jìn)行優(yōu)化之后,分別對各個優(yōu)化做性能測試
  • 需要對每一步優(yōu)化都做性能測試,知悉各改動優(yōu)化的力度。

思考

  • 人總是:1. 犯錯;2. 選擇最合適的辦法解決當(dāng)前需求——不論是coding還是產(chǎn)品架構(gòu)或者公司運轉(zhuǎn)。
  • 錯誤總比較明顯容易解決,但隨著產(chǎn)品發(fā)展時間推移,一些曾合理的地方會變得不太合理,甚至?xí)鸬搅俗璧K作用。
  • 我們需要不斷從現(xiàn)狀中找到不合理的地方,并改進(jìn)它,而不是盲從、習(xí)慣或停留于批判。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容