分佈式系統的性能優化方法

本文主要記錄在分佈式系統下優化的常用方法。

找到系統的性能瓶頸

這句話似乎是廢話, 但是確實至關重要的。因爲, 整個系統的性能瓶頸, 滿足木桶效應, 最短的那根木板決定了桶裏面能夠容納水的量。類似的, 系統的整體性能或者叫吞吐量, 取決於系統中性能最差的那個模塊或者某個部分的代碼, 可能是幾個接口。
如果我們沒有找到正確的性能瓶頸, 盲目的憑藉經驗或者感覺去定位性能瓶頸點, 很有可能忙乎了好長一陣, 但是沒有任何提升, 因爲最短板的地方沒有任何修復。

定位性能瓶頸的方法
  • pstack
    通常, 可以通過pstack查看正在運行中的進程的callstack, 如果多次都顯示在某個位置, 那麼很有可能相應的函數有問題, 可以重點分析一下。

  • 藉助工具
    不同類型的問題有不同的工具, 需要具體問題具體分析。

    類型 問題 工具
    網絡 網絡連接 ping, netstat, traceroute, tcpdump
    磁盤io 讀寫性能 iotop, iostat
    內存 內存泄漏 valgrind, purify
    內存 內存交換 free, top
  • 給系統關鍵點埋點
    有時候我們從工具無法分析出, 那個模塊有性能問題, 或者我們剛剛接受一個新系統, 代碼還不熟悉, 無法知道各個模塊的具體交互量或者數據流量, 可以順着main函數, 在各個調用函數的開頭和結尾處加上性能埋點, 帶引出某個函數執行的時間。
    這樣將系統運行起來跑一會兒, 就能看出系統的主要時間花在哪裏。

  • 查看系統日誌文件
    很多系統本身都帶有日誌可以查看, 有些還可以設定日誌的級別, 這些信息能夠幫助我們定位問題。
    如果系統有慢日誌查詢, 那就更加有幫助了。

性能問題解決

簡單的代碼優化

這個是在比較新的系統中常出現, 之前知識關注與功能, 在第一次性能優化的時候, 會發現經常很小的改動就能提升很多:

  • SQL語句導致的慢查詢;
  • 大對象的頻繁的創建, 複製等;
  • 大的集合算法導致的性能問題;
單線程的性能問題

在很多時候, 單線程意味着任務需要一個接一個的執行, 如果能夠將任務並行的分配到不同的線程來執行, 並且這些任務沒有相關性, 是能夠大幅度提升性能的, 這也是在單機系統下最常用的性能優化手段。

由鎖引起的性能問題

多線程是提升性能的利器, 但是如果線程的設計不合理的時候, 很可能會造成死鎖, 或者性能的嚴重下降。死鎖的問題相對容易發現, 因爲一旦死鎖, 系統就完全卡住了。由互斥鎖引起的性能問題, 不是很容易發現, 因爲他只是造成系統間過多的同步或者通知, 並不是太明顯。
因此設計多線程系統的時候, 一定要根據具體的業務場景, 設計合理的任務分發機制, 並且儘量減少線程之間的同步, 儘量染一個線程完成整改任務。

模塊間的通信造成的性能問題

跨機器的程序一般通過TCP或者HTTP協議來進行通信, 網絡通信有很多的因素會影響到傳輸的效率, 比如,socket的設定, 我們需要儘可能的瞭解協議本身的機制, 然後根據我們的業務特徵去選擇不同的通信方式。

數據庫引起的性能問題

一般的數據庫, 像MySQL, MongoDB, 他們本身的吞吐量是比較低的, 在對相應要求比較高的系統中, 儘可能採用redis-Mysql或者redis-MongoDB的方式來提升性能, 當然, 需要重點關注數據一致性的問題。
如果,數據量沒有非常龐大的情況, 也可以考慮redis 集羣作爲存儲, 而不是緩存, 來提升系統性能。
另外, 當前的NoSQL也出現了好多年, 爲數據庫的存儲提供了比較多的選擇, NoSQL通常去掉了RDB的很多限制條件, 性能相對於關係數據庫普遍高一些。

client-server模式, 儘量提升server端的性能

在client-server模式下, 系統的吞吐量, 很大程度上取決於server端處理的速度。 提升server的處理速度, 是一個比較直觀地想法, 通常儘可能的實現異步調用,異步調用的好處就是可以儘可能快的響應客戶端,將調用本身的時間變成異步。 但是, 可能的問題就是前段發過來的待處理消息太多, 後端來不及處理, 因此通常需要評估後端的處理能力, 進行必要的流量控制。
還有一種提升後端的處理能力, 就是後端的併發處理能力, 可能是想Nginx那樣的啓動多個進程, 併發處理不同的請求, 也可以是多線程的模式來並行處理。

緩存方式解決重複的調用

還有一種問題是需要重複地調用來獲得一些信息, 比如文件的屬性信息, 而這些信息其實變化很小, 大部分時間是相同的, 爲了獲得實時的數據, 需要一次次的頻繁調用, 這種情況下, 可以將屬性信息分成可變部分與不可變部分, 我們可以緩存不變部分, 來減少調用的次數。
緩存的使用, 分爲本地內存緩存和分佈式緩存, 比如redis。 本地緩存,速度快簡單, 但是容量有限易丟失。

總之, 性能問題, 需要因地制宜, 問題不同處理的方式也不相同。

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