記一次服務端系統性能優化


     首先簡單介紹一下業務場景,物聯網設備,關注公眾號,免費領取環保袋。

    12月8號,也就是昨天上午,突然接到大量客戶投訴反饋下單界面點擊下單一直在“轉圈”,最后超時。緊急排查!

    第一步查看網絡,服務器ping值正常,然后查詢服務器帶寬占用率正常。

    第二步,查看應用服務器負載,很低,基本沒問題。

    第三步,重點來了,檢查數據庫性能。

    show processlist; 發現連接數維持在97-99,懷疑,是否是受到最大連接數限制,導致新的查詢在排隊,查詢得知,最大連接數設置為800,所以排除連接數限制問題。又掃了一眼processlist列表,發現大量耗時很長的查詢,初步定位問題。把sql拎出來看一下,發現該查詢沒有建索引,系統上線時間不長,業務發展迅猛,問題一下子暴露出來,建索引完事。

    索引建完之后,再次檢查數據庫,發現有很多警告,CPU占用率一直居高不下,高峰期直接100%,這個問題就比較嚴重了。首先查看了慢查詢日志,發現慢查詢的時間閾值還停留在10秒,這肯定不行,於是設置為4秒,改為4秒之后發現,依然沒有慢查詢,再看了一下sql執行情況,高峰期,qps 為1000左右,tps大概40+,比較高了,但讀請求明顯多於寫請求。決定,再次對系統進行優化。

    1. 分析了一下sql執行日志,對一段時間內執行的sql按執行次數進行了一個排序,過了一遍所有的sql,進行了少量優化,但優化空間不大。

    2. 維護設備在線狀態的模塊,分布在各地的設備每分鍾或每30秒會發一個心跳包,心跳包用於維持設備的在線狀態,現在規定是5分鍾內沒有收到心跳包則認為設備離線,收到心跳包后每次都會去更新設備最后心跳時間字段。開始想把設備在線狀態維護完全放到redis里面,直接砍掉這部分的數據庫IO,后來分析了一下,發現業務不允許,因此查詢的時候需要按照設備在線狀態來查詢。最后解決方案,由於設備每分鍾會發送1-2次心跳包,每次都去更新數據庫,而業務允許5分鍾的掉線狀態延遲,因此,利用redis緩存過濾一下,在5分鍾內,僅僅更新一次數據庫也可以達到同樣的效果。最后看了一下優化效果,發現,好像不太理想,首先,因為該update操作本來就執行的很快,資源占用很小,基於看不出CPU占用率曲線有明顯變化。

    3. 下一步,繼續尋找優化點。接受前面優化的教訓,接下來尋找優化的點的時候,從耗時長的操作入手,這樣達到的效果應該是最好的。首先把慢查詢時間閾值改為2秒,這時,一個新的慢查詢sql出現了,就是在每次創建訂單時,需要先查詢一下該公眾號當前已經成功吸粉的數量,因為業務規定達到吸粉數量目標之后需要停止吸粉,這查詢操作進行了全表掃描,而且sql沒有可優化空間了。但這里很明顯可以通過緩存去優化,將公眾號當前已吸粉數緩存起來,當訂單完結時,對緩存執行+1操作,+1操作如果直接使用redis的incr操作,會有問題:想象一下,緩存過期,這時恰好執行了incr,由於incr當key不存在時,會創建key,並初始化為0再+1,而且該key永不過期,這樣就達不到限制吸粉數量的效果了。因此通過lua腳本來進行+1操作,只有當key存在時,才執行+1,代碼如下:

local exists = redis.call('exists', KEYS[1]); 
if (exists == 1) then 
    return redis.call('incr', KEYS[1]); 
end 
return nil;
View Code

發布之后,再次查看優化效果,震驚,CPU占用率曲線斷崖式下跌,從100%掉到了10%以下,至此,本次優化取得圓滿成功,又可以撐一段時間了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM