国产精品免费嫩草研究院|无遮羞动漫在线观看AV|国产麻豆精品传媒AV国产在线|村在线观看|寂寞情人1正版|韩国床震韩国床震古|精品系列专区久久

用golang開發系統軟件的一些細節

(本文的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 讓內存控制更加絲滑
堆外內存眾所周知,golang中分配太多對象,會給GC造成很大壓力,從而影響程序性能 。那么,我在golang runtime的堆以外分配內存,就可以繞過GC了 。可以通過mmap系統調用來使用堆外內存,具體請見:《Go Mmap 文件內存映射簡明教程》對于堆外內存的應用,在此推薦一個非常經典的golang組件:fastcache 。具體請看這篇我對fastcache的分析文章:《介紹一個golang庫:fastcache》 。
也需要注意,這里有個坑:如果使用mmap去映射一個文件,則某個虛擬地址沒有對應的物理地址時,操作系統會產生缺頁終端,并轉到內核態執行,把磁盤的內容load到page cache 。如果此時磁盤IO高,可能會長時間的阻塞……進一步地,導致了golang調度器的阻塞 。對象復用對象太多會導致GC壓力,但又不可能不分配對象 。因此對象復用就是減少分配消耗和減少GC的釋放消耗的好辦法 。
下面分別通過不同的場景來討論如何復用對象 。
海量微型對象的情況假設有很多幾個字節或者幾十個字節的,數以萬計的對象 。那么最好不要一個個的new出來,會有兩個壞處:
  • 對象的管理會需要額外的內存,考慮內存對齊等因素又會造成額外的內存浪費 。因此海量微型對象需要的總內存遠遠大于其自身真實使用的字節數;
  • GC的壓力源于對象的個數,而不是總字節數 。海量微型對象必然增大GC壓力 。
海量微型對象的影響,請看我曾經遇到過的這個問題:《【筆記】對golang的大量小對象的管理真的是無語了……》
因此,海量微型對象的場景,這樣解決:
  • 分配一大塊數組,在數組中索引微型對象
  • 考慮fastcache這樣的組件,通過堆外內存繞過GC
當然,也有缺點:不好縮容 。
大量小型對象的情況對于大量的小型對象,sync.Pool是個好選擇 。
推薦閱讀這篇文章:《Go sync.Pool 保姆級教程》

經驗總結擴展閱讀