<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>

          學(xué)會這幾招讓 Go 程序自己監(jiān)控自己

          共 3003字,需瀏覽 7分鐘

           ·

          2021-11-18 02:51

          談到讓Go程序監(jiān)控自己進(jìn)程的資源使用情況,那么就讓我們先來談一談有哪些指標(biāo)是需要監(jiān)控的,一般談?wù)撨M(jìn)程的指標(biāo)最常見的就是進(jìn)程的內(nèi)存占用率、CPU占用率、創(chuàng)建的線程數(shù)。因為Go語言又在線程之上自己維護(hù)了Goroutine,所以針對Go進(jìn)程的資源指標(biāo)還需要加一個創(chuàng)建的Goroutine數(shù)量。

          又因為現(xiàn)在服務(wù)很多都部署在Kubernetes集群上,一個Go進(jìn)程往往就是一個Pod,但是容器的資源是跟宿主機(jī)共享的,只是在創(chuàng)建的時候指定了其資源的使用上限,所以在獲取CPUMemory這些信息的時候還需要具體情況分開討論。

          怎么用Go獲取進(jìn)程的各項指標(biāo)

          我們先來討論普通的宿主機(jī)和虛擬機(jī)情況下怎么獲取這些指標(biāo),容器環(huán)境放在下一節(jié)來說。

          獲取Go進(jìn)程的資源使用情況使用gopstuil庫即可完成,它我們屏蔽了各個系統(tǒng)之間的差異,幫助我們方便地獲取各種系統(tǒng)和硬件信息。gopsutil將不同的功能劃分到不同的子包中,它提供的模塊主要有:

          • cpu:系統(tǒng)CPU 相關(guān)模塊;
          • disk:系統(tǒng)磁盤相關(guān)模塊;
          • docker:docker 相關(guān)模塊;
          • mem:內(nèi)存相關(guān)模塊;
          • net:網(wǎng)絡(luò)相關(guān);
          • process:進(jìn)程相關(guān)模塊;
          • winservices:Windows 服務(wù)相關(guān)模塊。

          我們這里只用到了它的process子包,獲取進(jìn)程相關(guān)的信息。

          聲明:process 模塊需要 import "github.com/shirou/gopsutil/process"后引入到項目,后面演示的代碼會用到的os等模塊會統(tǒng)一省略import相關(guān)的信息和錯誤處理,在此提前說明。

          創(chuàng)建進(jìn)程對象

          process模塊的NewProcess會返回一個持有指定PIDProcess對象,方法會檢查PID是否存在,如果不存在會返回錯誤,通過Process對象上定義的其他方法我們可以獲取關(guān)于進(jìn)程的各種信息。

          p,?_?:=?process.NewProcess(int32(os.Getpid()))

          進(jìn)程的CPU使用率

          進(jìn)程的CPU使用率需要通過計算指定時間內(nèi)的進(jìn)程的CPU使用時間變化計算出來

          cpuPercent,?err?:=?p.Percent(time.Second)

          上面返回的是占所有CPU時間的比例,如果想更直觀的看占比,可以算一下占單個核心的比例。

          cp?:=?cpuPercent?/?float64(runtime.NumCPU())

          內(nèi)存使用率、線程數(shù)和goroutine數(shù)

          這三個指標(biāo)的獲取過于簡單咱們就放在一塊說

          //?獲取進(jìn)程占用內(nèi)存的比例
          mp,?_?:=?p.MemoryPercent()
          //?創(chuàng)建的線程數(shù)
          threadCount?:=?pprof.Lookup("threadcreate").Count()
          //?Goroutine數(shù)?
          gNum?:=?runtime.NumGoroutine()

          上面獲取進(jìn)程資源占比的方法只有在虛擬機(jī)和物理機(jī)環(huán)境下才能準(zhǔn)確。類似Docker這樣的Linux容器是靠著Linux的Namespace和Cgroups技術(shù)實現(xiàn)的進(jìn)程隔離和資源限制,是不行的。

          現(xiàn)在的服務(wù)很多公司是K8s集群部署,所以如果是在Docker中獲取Go進(jìn)程的資源使用情況需要根據(jù)Cgroups分配給容器的資源上限進(jìn)行計算才準(zhǔn)確。

          容器環(huán)境下獲取進(jìn)程指標(biāo)

          Linux中,Cgroups給用戶暴露出來的操作接口是文件系統(tǒng),它以文件和目錄的方式組織在操作系統(tǒng)的/sys/fs/cgroup路徑下,在 /sys/fs/cgroup下面有很多諸cpuset、cpu、 memory這樣的子目錄,每個子目錄都代表系統(tǒng)當(dāng)前可以被Cgroups進(jìn)行限制的資源種類。

          針對我們監(jiān)控Go進(jìn)程內(nèi)存和CPU指標(biāo)的需求,我們只要知道cpu.cfs_period_us、cpu.cfs_quota_usmemory.limit_in_bytes 就行。前兩個參數(shù)需要組合使用,可以用來限制進(jìn)程在長度為cfs_period的一段時間內(nèi),只能被分配到總量為cfs_quotaCPU時間, 可以簡單的理解為容器能使用的核心數(shù) = cfs_quota / cfs_period。

          所以在容器里獲取Go進(jìn)程CPU的占比的方法,需要做一些調(diào)整,利用我們上面給出的公式計算出容器能使用的最大核心數(shù)。

          cpuPeriod,?err?:=?readUint("/sys/fs/cgroup/cpu/cpu.cfs_period_us")

          cpuQuota,?err?:=?readUint("/sys/fs/cgroup/cpu/cpu.cfs_quota_us")

          cpuNum?:=?float64(cpuQuota)?/?float64(cpuPeriod)

          然后再把通過p.Percent獲取到的進(jìn)程占用機(jī)器所有CPU時間的比例除以計算出的核心數(shù)即可算出Go進(jìn)程在容器里對CPU的占比。

          cpuPercent,?err?:=?p.Percent(time.Second)
          //?cp?:=?cpuPercent?/?float64(runtime.NumCPU())
          //?調(diào)整為
          cp?:=?cpuPercent?/?cpuNum

          而容器的能使用的最大內(nèi)存數(shù),自然就是在memory.limit_in_bytes里指定的啦,所以Go進(jìn)程在容器中占用的內(nèi)存比例需要通過下面這種方法獲取

          memLimit,?err?:=?readUint("/sys/fs/cgroup/memory/memory.limit_in_bytes")
          memInfo,?err?:=?p.MemoryInfo
          mp?:=?memInfo.RSS?*?100?/?memLimit

          上面進(jìn)程內(nèi)存信息里的RSS叫常駐內(nèi)存,是在RAM里分配給進(jìn)程,允許進(jìn)程訪問的內(nèi)存量。而讀取容器資源用的readUint,是containerd組織在cgroups實現(xiàn)里給出的方法。

          func?readUint(path?string)?(uint64,?error)?{
          ?v,?err?:=?ioutil.ReadFile(path)
          ?if?err?!=?nil?{
          ??return?0,?err
          ?}
          ?return?parseUint(strings.TrimSpace(string(v)),?10,?64)
          }

          func?parseUint(s?string,?base,?bitSize?int)?(uint64,?error)?{
          ?v,?err?:=?strconv.ParseUint(s,?base,?bitSize)
          ?if?err?!=?nil?{
          ??intValue,?intErr?:=?strconv.ParseInt(s,?base,?bitSize)
          ??//?1.?Handle?negative?values?greater?than?MinInt64?(and)
          ??//?2.?Handle?negative?values?lesser?than?MinInt64
          ??if?intErr?==?nil?&&?intValue?0?{
          ???return?0,?nil
          ??}?else?if?intErr?!=?nil?&&
          ???intErr.(*strconv.NumError).Err?==?strconv.ErrRange?&&
          ???intValue?0?{
          ???return?0,?nil
          ??}
          ??return?0,?err
          ?}
          ?return?v,?nil
          }

          我在下方參考鏈接里會給出他們源碼的鏈接。

          總結(jié)

          你可能會問,為啥讓Go程序自己監(jiān)控自己,有什么用呢?那肯定是能以這個為基點(diǎn)做一些服務(wù)治理的事情啦,具體的應(yīng)用場景以后再分享,感興趣的可以關(guān)注一波。

          參考鏈接

          • Contianerd utils: https://github.com/containerd/cgroups/blob/318312a373405e5e91134d8063d04d59768a1bff/utils.go#L243
          • What is RSS: https://stackoverflow.com/questions/7880784/what-is-rss-and-vsz-in-linux-memory-management
          - END -


          掃碼關(guān)注公眾號「網(wǎng)管叨bi叨」

          給網(wǎng)管個星標(biāo),第一時間吸我的知識???

          網(wǎng)管為大家整理了一本超實用的《Go 開發(fā)參考書》收集了70多條開發(fā)實踐。去公眾號回復(fù)【gocookbook】即刻領(lǐng)?。?/span>


          覺得有用就點(diǎn)個在看? ??????

          瀏覽 23
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  欧美精品一区二区三区成人片在线 | 一区二区三区四区五区六区七区 | 免费Aⅴ视频 | 一级性爱视频中文字幕 | 7799天天综合网 |