寫代碼如何合理使用和優化咱們的機器資源(CPU、內存、網絡、磁盤)

寫代碼腦子必定要繃緊一根弦,認知到咱們所在的機器資源是有限的。機器資源有哪些?CPU、內存、網絡、磁盤等,若是不作好保護控制工做,一旦某一資源滿負荷,很容易致使出現線上問題。

1 CPU 資源怎麼限制

*  
計算算法優化。若是服務須要進行大量的計算,好比推薦排序服務,那麼務必對你的計算算法進行優化,好比筆者曾經對地理空間距離計算這一重度使用的算法進行了優化,取得了較好的效果,詳見《地理空間距離計算優化》一文。
* 
鎖。對於不少服務而言,沒有那麼多耗費計算資源的算法,但 CPU 使用率也很高,這個時候須要看看鎖的使用狀況,個人建議是如無必要,儘可能不用顯式使用鎖。
* 
習慣問題。好比寫循環的時候,千萬要檢查看看是否能正確退出,有些時候一不當心,在某些條件下就成爲死循環,很著名的案例就是《多線程下HashMap的死循環問題》。好比集合遍歷時候使用性能較差的遍歷方式、String + 檢查,若是有超過多個 String 相加,是否使用 StringBuffer.append?
* 
儘可能使用線程池。經過線程池來限制線程的數目,避免線程過多形成的線程上下文切換的開銷。
* 
JVM 參數調優。JVM 參數也會影響 CPU 的使用,如《發佈或重啓線上服務時抖動問題解決方案》。

2 內存資源怎麼限制

* 
JVM 參數設置。經過 JVM 參數的設置來限制內存使用,JVM 參數調優比較靠經驗,有一篇朋友寫的好文能夠參考《Linux 與 JVM 的內存關係分析》。
* 
初始化 Java 集合類大小。使用 Java 集合類的時候儘可能初始化大小,在長鏈接服務等耗費內存資源的服務中這種優化很是重要。
* 
使用內存池/對象池
* 
使用線程池的時候必定要設置隊列的最大長度。以前看過好多起故障都是因爲隊列最大長度沒有限制最後致使內存溢出。
* 
若是數據較大避免使用本地緩存。若是數據量較大,能夠考慮放置到分佈式緩存如 Redis、Tair 等,否則 gc 均可能把本身服務卡死。
* 
對緩存數據進行壓縮。好比以前作推薦相關服務時,須要保存用戶偏好數據,若是直接保存可能有 12G,後來採用短文本壓縮算法直接壓縮到 6G,不過這時必定要考慮好壓縮解壓縮算法的 cpu 使用率、效率與壓縮率的平衡,一些壓縮率很高可是性能不好的算法,也不適合線上實時調用。有些時候直接使用 probuf 來序列化以後保存,這樣也能節省內存空間。
* 
清楚第三方軟件實現細節,精確調優。在使用第三方軟件時,只有清楚細節後才知道怎麼節約內存,這點我在實際工做中深有體會,好比以前在閱讀過lucene的源碼後發現咱們的索引文件原來是能夠壓縮的,而這在說明文檔中都找不到,具體參考《lucene索引文件大小優化小結》一文。

3 網絡資源怎麼限制

* 
減小調用的次數。常常看到有同窗在循環裏用 redis/tair 的 get,若是意識到這裏面的網絡開銷的話就應該使用批量處理;又如在推薦服務中常常遇到要去多個地方去取數據,通常採用多線程並行去取數據,這個時候不只耗費cpu資源,也耗費網絡資源,一種在實際中經常採用的方法就是先將不少數據離線存儲到一塊 ,這時候線上服務只要一個請求就能將全部數據獲取。
* 
減小傳輸的數據量。一種方法是壓縮後傳輸,還有一種就是按需傳輸,好比常常遇到的 getData(int id),若是咱們返回該 id 對應的 Data 全部信息,一來人家不須要,二來數據量傳輸太大,這個時候能夠改成 getData(int id, Listfields),使用方傳輸相應的字段過來,服務端只返回使用方須要的字段便可。

4 磁盤資源怎麼限制

打日誌要控制量,並按期清理。1)只打印關鍵的異常日誌;2)對日誌大小進行監控報警。我有一次就遇到了第三方服務掛了,而後我這邊就不斷打印調用該第三方服務異常的日誌,原本個人服務有降級方案,若是第三方服務掛了會自動使用其它服務,可是忽然收到報警說我服務掛了,登上機器一看才知道是磁盤不夠致使的崩潰;3)按期對日誌進行清理,好比用 crontab,每隔幾天對日誌進行清理;4)打印日誌到遠端,對於一些比較重要的日誌能夠直接將日誌打印到遠端HDFS文件系統裏;
備註
基礎原則……控制資源的使用
相關文章
相關標籤/搜索