(本文的pdf版本)
眾所周知,golang非常適合用于開發后臺應用,但也通常是各種各樣的應用層軟件 。
開發系統軟件,目前的首選還是C++, C, rust等語言 。相比應用軟件,系統軟件需要更加穩定,更加高效 。其維持自身運行的資源消耗要盡可能小,然后才可以把更多CPU、內存等資源用于業務處理上 。簡單來說,系統軟件在CPU、內存、磁盤、帶寬等計算機資源的使用上要做到平衡且極致 。
golang代碼經過寫法上的優化,是可以達到接近C的性能的 。現在早已出現了很多用golang完成的系統軟件,例如很優秀的etcd, VictoriaMetrics等 。VictoriaMetrics是Metric處理領域優秀的TSDB存儲系統,在閱讀其源碼后,結合其他一些golang代碼優化的知識,我將golang開發系統軟件的知識總結如下:
golang的第一性能殺手:GC個人認為GC掃描對象、及其GC引起的STW,是golang最大的性能殺手 。本小節討論優化golang GC的各種技巧 。
壓艙物ballast下面一段神奇的代碼,能夠減少GC的頻率,從而提升程序性能:
func main(){ ballast := make([]byte, 10*1024*1024*1024) runtime.KeepAlive(ballast) // do other things}其原理是擴大golang runtime的堆內存,使得實際分配的內存不容易超過堆內存的一定比例,進而減少GC的頻率 。GC的頻率低了,STW的次數和時間也就更少,從而程序的性能也提升了 。
具體的細節請參考文章:
- 一個神奇的golang技巧:擴大heap內存來降低gc頻率 (本人)
- Go Ballast 讓內存控制更加絲滑
也需要注意,這里有個坑:如果使用mmap去映射一個文件,則某個虛擬地址沒有對應的物理地址時,操作系統會產生缺頁終端,并轉到內核態執行,把磁盤的內容load到page cache 。如果此時磁盤IO高,可能會長時間的阻塞……進一步地,導致了golang調度器的阻塞 。對象復用對象太多會導致GC壓力,但又不可能不分配對象 。因此對象復用就是減少分配消耗和減少GC的釋放消耗的好辦法 。
下面分別通過不同的場景來討論如何復用對象 。
海量微型對象的情況假設有很多幾個字節或者幾十個字節的,數以萬計的對象 。那么最好不要一個個的new出來,會有兩個壞處:
- 對象的管理會需要額外的內存,考慮內存對齊等因素又會造成額外的內存浪費 。因此海量微型對象需要的總內存遠遠大于其自身真實使用的字節數;
- GC的壓力源于對象的個數,而不是總字節數 。海量微型對象必然增大GC壓力 。
因此,海量微型對象的場景,這樣解決:
- 分配一大塊數組,在數組中索引微型對象
- 考慮fastcache這樣的組件,通過堆外內存繞過GC
大量小型對象的情況對于大量的小型對象,sync.Pool是個好選擇 。
推薦閱讀這篇文章:《Go sync.Pool 保姆級教程》
經驗總結擴展閱讀
- 持續集成指南:GitLab 的 CI/CD 工具配置與使用
- 信用卡怎么查消費明細
- 消費貸款申請產生的費用高嗎
- oppo賬號的姓名怎么修改
- 租房可以換鎖芯嗎合法么 租房換鎖費用誰來承擔
- 特斯拉可以用家用電充電嗎
- 拆線多久可以用祛疤膏?
- 衛生間和廚房用什么瓷磚?
- 肉蓯蓉副作用是什么
- 計米器怎么設置參數
