<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          優(yōu)化 Golang 服務(wù)來(lái)減少 40% 以上的 CPU

          共 4089字,需瀏覽 9分鐘

           ·

          2020-08-14 14:58

          點(diǎn)擊上方藍(lán)色“Go語(yǔ)言中文網(wǎng)”關(guān)注我們,領(lǐng)全套Go資料,每天學(xué)習(xí)?Go?語(yǔ)言

          十年前,谷歌正在面臨一個(gè)由 C++ 編譯時(shí)間過(guò)長(zhǎng)所造成的嚴(yán)重瓶頸,并且需要一個(gè)全新的方式來(lái)解決這個(gè)問(wèn)題。谷歌的工程師們通過(guò)創(chuàng)造了一種新的被稱作 Go (又名 Golang)的語(yǔ)言來(lái)應(yīng)對(duì)挑戰(zhàn)。這個(gè)新語(yǔ)言 Go 帶來(lái)了 C++ 最好的部分(最主要的是它的性能和穩(wěn)定性),又與 Python 的速度相結(jié)合,使得 Go 能夠在實(shí)現(xiàn)并發(fā)的同時(shí)快速地使用多核心。

          在 Coralogix(譯者注:一個(gè)提供全面日志分析的服務(wù)產(chǎn)品,官網(wǎng)[1]),我們?yōu)榱巳ソo我們的客戶提供關(guān)于他們?nèi)罩緦?shí)時(shí)的分析、警報(bào)和元數(shù)據(jù),要去解析他們的日志。在解析階段,我們需要非常快速地解析包含多個(gè)復(fù)雜規(guī)則的服務(wù)日志,這個(gè)目標(biāo)是促使我們決定使用 Golang 的原因之一。

          這項(xiàng)新的服務(wù)現(xiàn)在就全天候的跑在生產(chǎn)階段,盡管我們看到了非常好的結(jié)果,但是它也需要跑在高性能的機(jī)器上。這項(xiàng) Go 的服務(wù)跑在一臺(tái) AWS m4.2xlarge 實(shí)例上 ,帶有 8 CPUs 和 36 GB 的配置,每天要解析幾十億的日志。

          在這個(gè)階段一切都運(yùn)行正常,我們本可以自我感覺(jué)良好,但是那并不是我們?cè)?Coralogix 想要的表現(xiàn)。我們想要更多的特性,比如性能等等,或者使用更少的 AWS 實(shí)例。為了改進(jìn),我們首先需要理解瓶頸的本質(zhì)以及我們?nèi)绾文軌驕p少或者完全解決這些問(wèn)題。

          我們決定在我們的服務(wù)上進(jìn)行一些分析,檢查一下到底是什么造成了 CPU 的高消耗,看看我們是否能夠優(yōu)化。

          首先,我們將 Go 升級(jí)到最新的穩(wěn)定版本(這是軟件生命周期中的關(guān)鍵一步)。我們是用的 Go 1.12.4 版本,最新的是 1.13.8(目前最新版本已經(jīng) 1.14.x)。根據(jù) 文檔[2] ,Go 1.13 發(fā)行版在運(yùn)行時(shí)庫(kù)方面和一些其他主要利用內(nèi)存使用的組件方面已經(jīng)有了長(zhǎng)足的進(jìn)步??傊褂米钚碌姆€(wěn)定版本能幫助我們節(jié)省許多工作。

          因此,內(nèi)存消耗由大約 800 MB 降低到了僅 180 MB

          第二,為了更好的理解我們的流程以及弄清楚我們應(yīng)該在哪花費(fèi)時(shí)間和資源,我們開(kāi)始去進(jìn)行分析。

          分析不同的服務(wù)和程序語(yǔ)言可能看起來(lái)很復(fù)雜并且令人望而生畏,但是對(duì)于 Go 來(lái)說(shuō)它實(shí)際上十分容易,僅僅幾個(gè)命令就能夠描述清楚。Go 有一個(gè)專門的工具叫“pprof”,它通過(guò)監(jiān)聽(tīng)一個(gè)路由(默認(rèn)端口 6060)能夠應(yīng)用在你的 app 上,并且使用 Go 的包來(lái)管理 HTTP 連接:

          import?_?"net/http/pprof"

          接著在你的 main 函數(shù)中或者路由包下按照如下操作初始化:

          go?func()?{
          ?log.Println(http.ListenAndServe("localhost:6060",?nil))
          }()

          現(xiàn)在你可以啟動(dòng)你的服務(wù)并且連接到:

          http://localhost:6060/debug/pprof

          Go 官方提供的完整文檔可以 在這[3] 找到。

          pprof 的默認(rèn)配置是每 30 秒對(duì) CPU 的使用情況進(jìn)行采樣。有許多不同的選擇,也可以對(duì) CPU 的使用,堆的使用或者其他更多的使用情況進(jìn)行采樣。

          我們主要關(guān)注 CPU 使用,因此在生產(chǎn)階段采取了一個(gè) 30 秒的性能分析,并且發(fā)現(xiàn)了你在下圖所看到的情況(提醒一下:這是在我們把 Go 版本升級(jí)并且將 Go 的內(nèi)部組件降到最低之后的結(jié)果):

          Go profiling — Coralogix

          正如你所看到的,我們發(fā)現(xiàn)了許多運(yùn)行時(shí)庫(kù)的活動(dòng):GC 幾乎使用了 29% 的 CPU(還僅僅只是消耗最多的前 20 個(gè)對(duì)象)。因?yàn)?Go 的 GC 非??觳⑶易隽司薮蟮膬?yōu)化,最好的實(shí)踐就是不要去改變或者修改它。因?yàn)槲覀兊膬?nèi)存消耗非常低(與我們先前的 Go 版本相比),所以主要的懷疑對(duì)象就變成了較高的對(duì)象分配率。

          如果是那種情況的話,我們就能做兩件事情了:

          • 調(diào)整 Go GC 活動(dòng),使其適合我們的服務(wù)行為,意味著 —— 延緩它的觸發(fā)以使 GC 變的不那么頻繁。這將使我們不得不補(bǔ)償更多的內(nèi)存使用。
          • 找出我們代碼中那些分配了太多對(duì)象的函數(shù)、區(qū)段或者行。

          觀察一下我們的實(shí)例類型,很明顯我們有大量的內(nèi)存可供使用,并且我們正在被機(jī)器的 CPU 數(shù)量所限制。因此我們僅僅需要調(diào)整一下比率。因?yàn)樵?Golang 的早期有一個(gè)大多數(shù)開(kāi)發(fā)者都不關(guān)注的數(shù)據(jù),叫 GOGC。這個(gè)數(shù)值默認(rèn)是 100,簡(jiǎn)單地告訴你的系統(tǒng)什么時(shí)候觸發(fā) GC。這個(gè)默認(rèn)值使得堆的大小在到達(dá)它初始態(tài)的兩倍時(shí)觸發(fā) GC。將這個(gè)數(shù)值改成一個(gè)更大的數(shù)將會(huì)延緩 GC 的觸發(fā),降低它的頻率。我們基準(zhǔn)測(cè)試了許多不同的數(shù),最終對(duì)于我們的目標(biāo)來(lái)說(shuō)最好的性能是在使用 GOGC = 2000 的時(shí)候。

          這立刻增加了我們的內(nèi)存使用,從大約 200 MB 到 大約 2.7 GB(那還是由于我們的 Go 版本更新,在內(nèi)存消耗降低的情況下),另外也減少了我們 CPU 大約 10% 的使用。

          這個(gè)接下來(lái)的截圖就展示了這些基準(zhǔn)測(cè)試的結(jié)果:

          GOGC =2000 results — Coralogix benchmark

          前面的四個(gè) CPU 的消耗函數(shù)就是我們的服務(wù)函數(shù),這十分有意義。全部的 GC 使用現(xiàn)在大約是 13%,是先前消耗的一半還少!

          我們其實(shí)可以在這就停下來(lái)了,但是我們還是決定去揭露我們?cè)谀牟⑶覟槭裁磿?huì)分配這么多對(duì)象。很多時(shí)候,這么做有充分理由(比如在流式處理的情況下,我們?yōu)槊織l獲取的消息創(chuàng)建了許多新的對(duì)象,并且因?yàn)樗c下一條消息無(wú)關(guān),需要去移除它),但是在某些情況下有一種簡(jiǎn)單的方法可以去優(yōu)化并且動(dòng)態(tài)地減少對(duì)象的創(chuàng)建。

          首先,讓我們運(yùn)行一個(gè)和之前同樣的命令,有一點(diǎn)小的改變,采用堆調(diào)試:

          http://localhost:6060/debug/pprof/heap

          為了查詢結(jié)果文件,你可以運(yùn)行如下命令在你的代碼目錄下來(lái)分析調(diào)試結(jié)果:

          go?tool?pprof?-alloc_objects?

          我們的截圖看起來(lái)像這樣:

          除了第三行一切似乎都很合理,這是一個(gè)監(jiān)控函數(shù),在每個(gè) Carologix 規(guī)則解析階段的末尾向我們的 Promethes 調(diào)用者展示結(jié)果。為了獲取進(jìn)一步信息,我們運(yùn)行如下命令:

          list?

          例如:

          list?reportRuleExecution

          然后我們會(huì)獲得如下結(jié)果:

          WithLabelValues 的兩個(gè)調(diào)用都是為了軟件度量的 Prometheus 函數(shù)(我們將這個(gè)留給產(chǎn)品去決定是否真正需要)。而且,我們可以看到第一行創(chuàng)建了大量的對(duì)象(由這個(gè)函數(shù)所創(chuàng)建的全部對(duì)象的 10%)。我們進(jìn)一步查看發(fā)現(xiàn)它是一個(gè)對(duì)于綁定到導(dǎo)出數(shù)據(jù)的消費(fèi)者 ID 從 int 到 string 的轉(zhuǎn)換,十分重要,但是考慮到實(shí)際情況,我們數(shù)據(jù)庫(kù)中消費(fèi)者的數(shù)量十分有限,我們不應(yīng)該采用 Prometheus 的方式來(lái)接收變量作為 string 類型。因此取代了每次創(chuàng)建一個(gè)新的 string 并且在函數(shù)末尾都拋棄的這種方法(浪費(fèi)分配還有 GC 的多余工作),我們?cè)趯?duì)象的分配階段定義了 map,配對(duì)了所有從 1 到 10 萬(wàn)的數(shù)字和一個(gè)需要執(zhí)行的 “get” 方法。

          現(xiàn)在運(yùn)行一個(gè)新的性能分析會(huì)話來(lái)驗(yàn)證我們的論點(diǎn)并且它的對(duì)的(你可以看到這一部分并不會(huì)再分配對(duì)象了):

          這并不是一個(gè)顯著的改進(jìn),但是總體來(lái)說(shuō)為我們節(jié)省了另一個(gè) GC 的活動(dòng),說(shuō)的更具體一點(diǎn)就是節(jié)省了大約 1% 的 CPU。

          最終的狀態(tài)就是下面的截圖:

          最終結(jié)果

          1) 內(nèi)存使用:大約 1.3 GB -> 大約 2.7 GB

          2) CPU 使用:大約 2.55 avg 和 大約 5.05 峰值期 -> 大約 2.13 avg 和 大約 2.9 峰值期。

          在我們 Golang 優(yōu)化前的 CPU:

          在我們 Golang 優(yōu)化后的 CPU:

          總體來(lái)說(shuō),我們可以看到主要的改進(jìn)是在每秒日志處理量增加時(shí)的高峰時(shí)間。這就意味著我們的基礎(chǔ)架構(gòu)不僅不需要再為了異常值進(jìn)行調(diào)整,而且變得更加穩(wěn)定了。

          總結(jié)

          通過(guò)對(duì)我們的 Go 解析服務(wù)進(jìn)行性能測(cè)試,我們能夠查明有問(wèn)題的地方,更好的理解我們的服務(wù)并且確定在哪里(如果有的話)投資時(shí)間進(jìn)行改進(jìn)。大多數(shù)性能分析工作都會(huì)以一些基礎(chǔ)數(shù)值或配置的調(diào)整,更合適你的使用情況并且最終展現(xiàn)更好的性能而結(jié)束。


          via:https://medium.com/coralogix-engineering/optimizing-a-golang-service-to-reduce-over-40-cpu-366b67c67ef9

          作者:Eliezer Yaacov[4]譯者:sh1luo[5]校對(duì):@unknwon[6]

          本文由 GCTT[7] 原創(chuàng)編譯,Go 中文網(wǎng)[8] 榮譽(yù)推出

          參考資料

          [1]

          官網(wǎng): https://coralogix.com/

          [2]

          文檔: https://golang.org/doc/devel/release.html

          [3]

          在這: https://golang.org/pkg/net/http/pprof

          [4]

          Eliezer Yaacov: https://medium.com/@eliezerj8

          [5]

          sh1luo: https://github.com/sh1luo

          [6]

          @unknwon: https://github.com/unknwon

          [7]

          GCTT: https://github.com/studygolang/GCTT

          [8]

          Go 中文網(wǎng): https://studygolang.com/



          推薦閱讀


          學(xué)習(xí)交流 Go 語(yǔ)言,掃碼回復(fù)「進(jìn)群」即可


          站長(zhǎng) polarisxu

          自己的原創(chuàng)文章

          不限于 Go 技術(shù)

          職場(chǎng)和創(chuàng)業(yè)經(jīng)驗(yàn)


          Go語(yǔ)言中文網(wǎng)

          每天為你

          分享 Go 知識(shí)

          Go愛(ài)好者值得關(guān)注



          瀏覽 62
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  AV免费观看大全 | 免费啪啪啪网站 | 韩国1级毛片 | 一本色道久久爱牛牛 | 免费看无码人妻AⅤ片 |