日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入浅出Go Runtime

發(fā)布時間:2024/8/1 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出Go Runtime 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

以下內(nèi)容轉(zhuǎn)載自?https://mp.weixin.qq.com/s/ivO-USpxiyrL-9BzgE8Vcg

介紹

基于2019.02發(fā)布的go 1.12 linux amd64版本, 主要介紹了Runtime一些原理和實現(xiàn)的一些細節(jié), 對大家容易不容易理解或者網(wǎng)絡(luò)上很多錯誤的地方做一些梳理:

  • Golang Runtime是個什么? Golang Runtime的發(fā)展歷程, 每個版本的改進

  • Go調(diào)度: 協(xié)程結(jié)構(gòu)體, 上下文切換, 調(diào)度隊列, 大致調(diào)度流程, 同步執(zhí)行流又不阻塞線程的網(wǎng)絡(luò)實現(xiàn)等

  • Go內(nèi)存: 內(nèi)存結(jié)構(gòu), mspan結(jié)構(gòu), 全景圖及分配策略等

  • Go GC: Golang GC停頓大致的一個發(fā)展歷程, 三色標記實現(xiàn)的一些細節(jié), 寫屏障, 三色狀態(tài), 掃描及元信息, 1.12版本相對1.5版本的改進點, GC Pacer等

  • 實踐: 觀察調(diào)度, GC信息, 一些優(yōu)化的方式, 幾點問題排查的思路, 幾個有意思的問題排查

  • 總結(jié): 貫穿Runtime的思想總結(jié)

  • 這個是我今年8月份在深圳Gopher Meetup做的一個關(guān)于runtime的分享, 10月份在Go夜讀(項目地址 https://reading.developerlearning.cn) 里也分享了一次

    視頻地址: https://www.bilibili.com/video/av73297683?seid=596154768710832594

    一些問題解答: https://github.com/developer-learning/night-reading-go/issues/492

    兩個分享都是用的精簡版, 這里的把完整版的講一下, 加一些注語, 注語位于PPT頁的下面. (ppt地址 https://github.com/yifhao/share).

    為什么去了解runtime呢?

  • 可以解決一些棘手的問題: 在寫這個PPT的時候, 就有一位朋友在群里發(fā)了個pprof圖, 說同事寫的代碼有問題, CPU利用率很高., 找不出來問題在哪, 我看了下pprof圖, 說讓他找找是不是有這樣用select的, 一查的確是的. 平時也幫同事解決了一些和并發(fā), 調(diào)度, GC有關(guān)的問題

  • 好奇心: 大家寫久了go, 驚嘆于它的簡潔, 高性能外, 必然對它是怎么實現(xiàn)的有很多好奇. 協(xié)程怎么實現(xiàn), GC怎么能并發(fā), 對象在內(nèi)存里是怎么存在的? 等等

  • 技術(shù)深度的一種?

  • 本次分享基于2019.02發(fā)布的go 1.12 linux amd64版本, 主要介紹了Runtime實現(xiàn)的一點細節(jié). 水平和精力有限, 必然有問題存在, 有問題歡迎大家給我留言.

    Runtime簡介及發(fā)展

    Runtime簡介

    go的runtime代碼在go sdk的runtime目錄下.?

    主要有所述的4塊功能. 提到runtime, 大家可能會想起java, python的runtime.?

    不過go和這兩者不太一樣, java, python的runtime是虛擬機, 而go的runtime和用戶代碼一起編譯到一個可執(zhí)行文件中.?

    用戶代碼和runtime代碼除了代碼組織上有界限外, 運行的時候并沒有明顯的界限.?

    如上所示, 一些常用的關(guān)鍵字被編譯成runtime包下的一些函數(shù)調(diào)用.

    Runtime版本歷史

    左邊標粗的是一些更新比較大的版本. 右邊的GC STW僅供參考.

    調(diào)度

    調(diào)度簡述

    goroutine實現(xiàn)

    我們?nèi)タ凑{(diào)度的一個進化, 從進程到線程再到協(xié)程, 其實是一個不斷共享, 不斷減少切換成本的過程. go實現(xiàn)的協(xié)程為有棧協(xié)程, go協(xié)程的用法和線程的用法基本類似. 很多人會疑問, 協(xié)程到底是個什么東西? 用戶態(tài)的調(diào)度感覺很陌生, 很抽象, 到底是個什么東西?

    ?

    我覺得要理解調(diào)度, 要理解兩個概念: 運行和阻塞. 特別是在協(xié)程中, 這兩個概念不容易被正確理解. 我們理解概念時往往會代入自身感受, 覺得線程或協(xié)程運行就是像我們吭哧吭哧的處理事情, 線程或協(xié)程阻塞就是做事情時我們需要等待其他人, 然后就在這等著了. 要是其他人搞好了, 那我們就繼續(xù)做當前的事. 其實主體對象搞錯了. 正確的理解應該是我們處理事情時就像CPU, 而不是像線程或者協(xié)程. 假如我當前在寫某個服務(wù), 發(fā)現(xiàn)依賴別人的函數(shù)還沒有ready, 那就把寫服務(wù)這件事放一邊. 點開企業(yè)微信, 我去和產(chǎn)品溝通一些問題了. 我和產(chǎn)品溝通了一會后, 檢查一下, 發(fā)現(xiàn)別人已經(jīng)把依賴的函數(shù)提交了, 然后我就最小化企業(yè)微信, 切到IDE, 繼續(xù)寫服務(wù)A了.

    對操作系統(tǒng)有過一些了解, 知道linux下的線程其實是task_struct結(jié)構(gòu), 線程其實并不是真正運行的實體, 線程只是代表一個執(zhí)行流和其狀態(tài). 真正運行驅(qū)動流程往前的其實是CPU. CPU在時鐘的驅(qū)動下, 根據(jù)PC寄存器從程序中取指令和操作數(shù), 從RAM中取數(shù)據(jù), 進行計算, 處理, 跳轉(zhuǎn), 驅(qū)動執(zhí)行流往前. CPU并不關(guān)注處理的是線程還是協(xié)程, 只需要設(shè)置PC寄存器, 設(shè)置棧指針等(這些稱為上下文), 那么CPU就可以歡快的運行這個線程或者這個協(xié)程了.

    線程的運行, 其實是被運行. 其阻塞, 其實是切換出調(diào)度隊列, 不再去調(diào)度執(zhí)行這個執(zhí)行流. 其他執(zhí)行流滿足其條件, 便會把被移出調(diào)度隊列的執(zhí)行流重新放回調(diào)度隊列.

    協(xié)程同理, 協(xié)程其實也是一個數(shù)據(jù)結(jié)構(gòu), 記錄了要運行什么函數(shù), 運行到哪里了. go在用戶態(tài)實現(xiàn)調(diào)度, 所以go要有代表協(xié)程這種執(zhí)行流的結(jié)構(gòu)體, 也要有保存和恢復上下文的函數(shù), 運行隊列. 理解了阻塞的真正含義, 也就知道能夠比較容易理解, 為什么go的鎖, channel這些不阻塞線程. 對于實現(xiàn)的同步執(zhí)行流效果, 又不阻塞線程的網(wǎng)絡(luò), 接下來也會介紹.

    協(xié)程結(jié)構(gòu)體和切換函數(shù)

    ?

    我們go一個func時一般這樣寫

  • go func1(arg1 type1,arg2 type2){....}(a1,a2)

  • 一個協(xié)程代表了一個執(zhí)行流, 執(zhí)行流有需要執(zhí)行的函數(shù)(對應上面的func1), 有函數(shù)的入?yún)?a1, a2), 有當前執(zhí)行流的狀態(tài)和進度(對應CPU的PC寄存器和SP寄存器), 當然也需要有保存狀態(tài)的地方, 用于執(zhí)行流恢復. 真正代表協(xié)程的是runtime.g結(jié)構(gòu)體. 每個go func都會編譯成runtime.newproc函數(shù), 最終有一個runtime.g對象放入調(diào)度隊列. 上面的func1函數(shù)的指針設(shè)置在runtime.g的startfunc字段, 參數(shù)會在newproc函數(shù)里拷貝到stack中, sched用于保存協(xié)程切換時的pc位置和棧位置. 協(xié)程切換出去和恢復回來需要保存上下文, 恢復上下文, 這些由以下兩個匯編函數(shù)實現(xiàn). 以上就能實現(xiàn)協(xié)程這種執(zhí)行流, 并能進行切換和恢復. (下圖中的struct和函數(shù)都做了精簡)

    GM模型及GPM模型

    有了協(xié)程的這種執(zhí)行流形式, 那待運行的協(xié)程放在哪呢? 在Go1.0的時候:

    ?

  • 調(diào)度隊列schedt是全局的, 對該隊列的操作均需要競爭同一把鎖, 導致伸縮性不好.

  • 新生成的協(xié)程也會放入全局的隊列, 大概率是被其他m(可以理解為底層線程的一個表示)運行了, 內(nèi)存親和性不好. 當前協(xié)程A新生成了協(xié)程B, 然后協(xié)程A比較大概率會結(jié)束或者阻塞, 這樣m直接去執(zhí)行協(xié)程B, 內(nèi)存的親和性也會好很多.

  • 因為mcache與m綁定, 在一些應用中(比如文件操作或其他可能會阻塞線程的系統(tǒng)調(diào)用比較多), m的個數(shù)可能會遠超過活躍的m個數(shù), 導致比較大的內(nèi)存浪費..

  • 那是不是可以給m分配一個隊列, 把阻塞的m的mcache給執(zhí)行g(shù)o代碼的m使用? Go 1.1及以后就是這樣做的.

    ?

    在1.1中調(diào)度模型更改為GPM模型, 引入邏輯Process的概念, 表示執(zhí)行Go代碼所需要的資源, 同時也是執(zhí)行Go代碼的最大的并行度. 這個概念可能很多人不知道怎么理解. P涉及到幾點, 隊列和mcache, 還有P的個數(shù)的選取. 首先為什么把全局隊列打散, 以及mcache為什么跟隨P, 這個在GM模型那一頁就講的比較清楚了. 然后為什么P的個數(shù)默認是CPU核數(shù): Go盡量提升性能, 那么在一個n核機器上, 如何能夠最大利用CPU性能呢? 當然是同時有n個線程在并行運行中, 把CPU喂飽, 即所有核上一直都有代碼在運行. 在go里面, 一個協(xié)程運行到阻塞系統(tǒng)調(diào)用, 那么這個協(xié)程和運行它的線程m, 自然是不再需要CPU的, 也不需要分配go層面的內(nèi)存. 只有一直在并行運行的go代碼才需要這些資源, 即同時有n個go協(xié)程在并行執(zhí)行, 那么就能最大的利用CPU, 這個時候需要的P的個數(shù)就是CPU核數(shù). (注意并行和并發(fā)的區(qū)別)

    協(xié)程狀態(tài)及流轉(zhuǎn)

    協(xié)程的狀態(tài)其實和線程狀態(tài)類似,狀態(tài)轉(zhuǎn)換和發(fā)生狀態(tài)轉(zhuǎn)換的時機如圖所示. 還是需要注意: 協(xié)程只是一個執(zhí)行流, 并不是運行實體.

    調(diào)度

    并沒有一個一直在運行調(diào)度的調(diào)度器實體. 當一個協(xié)程切換出去或新生成的m, go的運行時從stw中恢復等情況時, 那么接下來就需要發(fā)生調(diào)度. go的調(diào)度是通過線程(m)執(zhí)行runtime.schedule函數(shù)來完成的.

    sysmon協(xié)程

    在linux內(nèi)核中有一些執(zhí)行定時任務(wù)的線程, 比如定時寫回臟頁的pdflush, 定期回收內(nèi)存的kswapd0, 以及每個cpu上都有一個負責負載均衡的migration線程等.?

    ?

    在go運行時中也有類似的協(xié)程, sysmon. 功能比較多: 定時從netpoll中獲取ready的協(xié)程, 進行搶占, 定時GC,打印調(diào)度信息,歸還內(nèi)存等定時任務(wù)

    ?

    協(xié)作式搶占

    go目前(1.12)還沒有實現(xiàn)非協(xié)作的搶占. 基本流程是sysmon協(xié)程標記某個協(xié)程運行過久, 需要切換出去, 該協(xié)程在運行函數(shù)時會檢查棧標記, 然后進行切換.

    同步執(zhí)行流不阻塞線程的網(wǎng)絡(luò)的實現(xiàn)

    go寫后臺最舒服的就是能夠以同步寫代碼的方式操作網(wǎng)絡(luò), 但是網(wǎng)絡(luò)操作不阻塞線程.?

    主要是結(jié)合了非阻塞的fd, epoll以及協(xié)程的切換和恢復.?

    ?

    linux提供了網(wǎng)絡(luò)fd的非阻塞模式, 對于沒有ready的非阻塞fd執(zhí)行網(wǎng)絡(luò)操作時, linux內(nèi)核不阻塞線程, 會直接返回EAGAIN, 這個時候?qū)f(xié)程狀態(tài)設(shè)置為wait, 然后m去調(diào)度其他協(xié)程.?

    ?

    go在初始化一個網(wǎng)絡(luò)fd的時候, 就會把這個fd使用epollctl加入到全局的epoll節(jié)點中. 同時放入epoll中的還有polldesc的指針.

    ?

  • func netpollopen(fd uintptr, pd *pollDesc) int32 {

  • var ev epollevent

  • ev.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLET

  • *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd

  • return-epollctl(epfd, _EPOLL_CTL_ADD, int32(fd), &ev)

  • }

  • 在sysmon中, schedule函數(shù)中, start the world中等情況下, 會執(zhí)行netpoll 調(diào)用epollwait系統(tǒng)調(diào)用.

    把ready的網(wǎng)絡(luò)事件從epoll中取出來, 每個網(wǎng)絡(luò)事件可以通過前面?zhèn)魅氲膒olldesc獲取到阻塞在其上的協(xié)程, 以此恢復協(xié)程為runnable.

    調(diào)度相關(guān)結(jié)構(gòu)體

    調(diào)度綜述

    內(nèi)存分配

    內(nèi)存分配簡介

    Go的分配采用了類似tcmalloc的結(jié)構(gòu).?

    ?

    特點: 使用一小塊一小塊的連續(xù)內(nèi)存頁, 進行分配某個范圍大小的內(nèi)存需求.?

    比如某個連續(xù)8KB專門用于分配17-24字節(jié),以此減少內(nèi)存碎片. 線程擁有一定的cache, 可用于無鎖分配.

    同時Go對于GC后回收的內(nèi)存頁, 并不是馬上歸還給操作系統(tǒng), 而是會延遲歸還, 用于滿足未來的內(nèi)存需求.

    內(nèi)存空間結(jié)構(gòu)

    在1.10以前go的堆地址空間是線性連續(xù)擴展的, 比如在1.10(linux amd64)中, 最大可擴展到512GB.?

    ?

    因為go在gc的時候會根據(jù)拿到的指針地址來判斷是否位于go的heap的, 以及找到其對應的span, 其判斷機制需要gc heap是連續(xù)的.?

    但是連續(xù)擴展有個問題, cgo中的代碼(尤其是32位系統(tǒng)上)可能會占用未來會用于go heap的內(nèi)存. 這樣在擴展go heap時, mmap出現(xiàn)不連續(xù)的地址, 導致運行時throw.?

    ?

    在1.11中, 改用了稀疏索引的方式來管理整體的內(nèi)存. 可以超過512G內(nèi)存, 也可以允許內(nèi)存空間擴展時不連續(xù).?

    在全局的mheap struct中有個arenas二階數(shù)組, 在linux amd64上,一階只有一個slot, 二階有4M個slot, 每個slot指向一個heapArena結(jié)構(gòu), 每個heapArena結(jié)構(gòu)可以管理64M內(nèi)存, 所以在新的版本中, go可以管理4M*64M=256TB內(nèi)存, 即目前64位機器中48bit的尋址總線全部256TB內(nèi)存.

    span機制

    ?

    前面提到了go的內(nèi)存分配類似于tcmalloc, 采用了span機制來減少內(nèi)存碎片.?

    每個span管理8KB整數(shù)倍的內(nèi)存, 用于分配一定范圍的內(nèi)存需求.

    內(nèi)存分配全景

    ?

    多層次的分配Cache, 每個P上有一個mcache, mcache會為每個size最多緩存一個span, 用于無鎖分配.?

    ?

    全局每個size的span都有一個mcentral, 鎖的粒度相對于全局的heap小很多, 每個mcentral可以看成是每個size的span的一個全局后備cache.?

    在gc完成后, 會把P中的span都flush到mcentral中, 用于清掃后再分配. P有需要span時, 從對應size的mcentral獲取. 獲取不到再上升到全局的heap.

    幾種特殊的分配器

    對于很小的對象分配, go做了個優(yōu)化, 把小對象合并, 以移動指針的方式分配.?

    ?

    對于棧內(nèi)存有stackcache分配, 也有多個層次的分配, 同時stack也有多個不同size.?

    用于分配stack的內(nèi)存也是位于go gc heap, 用mspan管理, 不過這個span的狀態(tài)和用于分配對象的mspan狀態(tài)不太一樣, 為mSpanManual.?

    ?

    我們可以思考一個問題, go的對象是分配在go gc heap中, 并由mcache, mspan, mcentral這些結(jié)構(gòu)管理, 那么mcache, mspan, mcentral這些結(jié)構(gòu)又是哪里管理和分配的呢??

    肯定不是自己管理自己. 這些都是由特殊的分配fixalloc分配的, 每種類型有一個fixalloc, 大致原理就是通過mmap從進程空間獲取一小塊內(nèi)存(百KB的樣子), 然后用來分配這個固定大小的結(jié)構(gòu).

    內(nèi)存分配綜合

    GC

    Golang GC簡述

    GC簡介

    GC并不是個新事物, 使得GC大放光彩的是Java語言.

    Golang GC發(fā)展

    上面是幾個比較重要的版本. 左圖是根據(jù)twitter工程師的數(shù)據(jù)繪制的(堆比較大), 從1.4的百ms級別的停頓到1.8以后的小于1ms.?

    右圖是我對線上服務(wù)(Go 1.11編譯)測試的一個結(jié)果, 是一個批量拉取數(shù)據(jù)的服務(wù), 大概3000qps, 服務(wù)中發(fā)起的rpc調(diào)用大概在2w/s. 可以看到大部分情況下GC停頓小于1ms, 偶爾超過一點點.?

    整體來說golang gc用起來是很舒心的, 幾乎不用你關(guān)心.

    三色標記

    go采用的是并發(fā)三色標記清除法.?

    圖展示的是一個簡單的原理.

    有幾個問題可以思考一下:?

    并發(fā)情況下, 會不會漏標記對象??

    對象的三色狀態(tài)存放在哪??

    如何根據(jù)一個對象來找到它引用的對象?

    寫屏障

    GC最基本的就是正確性: 不漏標記對象, 程序還在用的對象都被清除了, 那程序就錯誤了. 有一點浮動垃圾是允許的.?

    在并發(fā)情況下, 如果沒有一些措施來保障, 那可能會有什么問題呢??

    看左邊的代碼和圖示, 第2步標記完A對象, A又沒有引用對象, 那A變成黑色對象.?

    在第3步的時候, muator(程序)運行, 把對象C從B轉(zhuǎn)到了A,?

    第4步, GC繼續(xù)標記, 掃描B, 此時B沒有引用對象, 變成了黑色對象. 我們會發(fā)現(xiàn)C對象被漏標記了.

    如何解決這個問題? go使用了寫屏障, 這里的寫屏障是指由編譯器生成的一小段代碼. 在gc時對指針操作前執(zhí)行的一小段代碼, 和CPU中維護內(nèi)存一致性的寫屏障不太一樣哈. 所以有了寫屏障后, 第3步, A.obj=C時, 會把C加入寫屏障buf. 最終還是會被掃描的.

    ?

    這里感受一下寫屏障具體生成的代碼.?

    我們可以看到在寫入指針slot時, 對寫屏障是否開啟做了判斷, 如果開啟了, 會跳轉(zhuǎn)到寫屏障函數(shù), 執(zhí)行加入寫屏障buf的邏輯.?

    1.8中寫屏障由Dijkstra寫屏障改成了混合式寫屏障, 使得GC停頓達到了1ms以下.

    ?

    三色狀態(tài)

    并沒有這樣一個集合把不同狀態(tài)對象放到對應集合中. 只是一個邏輯上的意義.

    掃描和元信息

    gc拿到一個指針, 如何把這個指針指向的對象其引用的子對象都加到掃描隊列呢? 而且go還允許內(nèi)部指針, 似乎更麻煩了.?

    我們分析一下, 要知道對象引用的子對象, 從對象開始到對象結(jié)尾, 把對象那一塊內(nèi)存上是指針的放到掃描隊列就好了.?

    那我們是不是得知道對象有多大, 從哪開始到哪結(jié)束, 同時要知道內(nèi)存上的8個字節(jié), 哪里是指針, 哪里是普通的數(shù)據(jù).?

    ?

    首先go的對象是mspan管理的, 我們?nèi)绻苤缹ο髮儆谀膫€mspan, 就知道對象多大, 從哪開始, 到哪結(jié)束了.?

    前面我們講到了areans結(jié)構(gòu), 可以通過指針加上一定的偏移量, 就知道屬于哪個heap arean 64M塊. 再通過對64M求余, 結(jié)合spans數(shù)組, 即可知道屬于哪個mspan了.

    結(jié)合heapArean的bitmap和每8個字節(jié)在heapArean中的偏移, 就可知道對象每8個字節(jié)是指針還是普通數(shù)據(jù)(這里的bitmap是在分配對象時根據(jù)type信息就設(shè)置了, type信息來源于編譯器生成)

    GC流程

    1.5和1.12的GC大致流程相同.?

    上圖是golang官方的ppt里的圖, 下圖是我根據(jù)1.12源碼繪制的.?

    從最壞可能會有百ms的gc停頓到能夠穩(wěn)定在1ms以下, 這之間GC做了很多改進.?

    右邊是我根據(jù)官方issues整理的一些比較重要的改進. 1.6的分布式檢測, 1.7將棧收縮放到了并發(fā)掃描階段, 1.8的混合寫屏障, 1.12更改了mark termination檢測算法, mcache flush移除出mark termination等等...

    Golang GC Pacer

    大家對并發(fā)GC除了怎么保證不漏指針有疑問外, 可能還會疑問, 并發(fā)GC如何保證能夠跟得上應用程序的分配速度? 會不會分配太快了, GC完全跟不上, 然后OOM?

    這個就是Golang GC Pacer的作用.?

    Go的GC是一種比例GC, 下一次GC結(jié)束時的堆大小和上一次GC存活堆大小成比例. 由GOGC控制, 默認100, 即2倍的關(guān)系, 200就是3倍, 以此類推.?

    假如上一次GC完成時, 存活對象1000M, 默認GOGC 100, 那么下次GC會在比較接近但小于2000M的時候(比如1900M)開始, 爭取在堆大小達到2000M的時候結(jié)束.?

    這之間留有一定的裕度, 會計算待掃描對象大小(根據(jù)歷史數(shù)據(jù)計算)與可分配的裕度的比例, 應用程序分配內(nèi)存根據(jù)該比例進行輔助GC, 如果應用程序分配太快了, 導致credit不夠, 那么會被阻塞, 直到后臺的mark跟上來了,該比例會隨著GC進行不斷調(diào)整.?

    GC結(jié)束后, 會根據(jù)這一次GC的情況來進行負反饋計算, 計算下一次GC開始的閾值. 如何保證按時完成GC呢??

    GC完了后, 所有的mspan都需要sweep, 類似于GC的比例, 從GC結(jié)束到下一次GC開始之間有一定的堆分配裕度, 會根據(jù)還有多少的內(nèi)存需要清掃, 來計算分配內(nèi)存時需要清掃的span數(shù)這樣的一個比例.

    實踐與總結(jié)

    觀察調(diào)度

    觀察一下調(diào)度, 加一些請求.?

    我們可以看到雖然有1000個連接, 但是go只用了幾個線程就能處理了, 表明go的網(wǎng)絡(luò)的確是由epoll管理的.?

    runqueue表示的是全局隊列待運行協(xié)程數(shù)量, 后面的數(shù)字表示每個P上的待運行協(xié)程數(shù).?

    可以看到待處理的任務(wù)并沒有增加, 表示雖然請求很多, 但完全能hold住.?

    同時可以看到, 不同P上有的時候可能任務(wù)不均衡, 但是一會后, 任務(wù)又均衡了, 表示go的work stealing是有效的.

    觀察GC

    其中一些數(shù)據(jù)的含義, 在分享的時候沒有怎么解釋, 不過網(wǎng)上的解釋幾乎沒有能完全解釋正確.?

    我這里敲一下. 其實一般關(guān)注堆大小和兩個stw的wall time即可.?

    ?

    gc 8913(第8913次gc) @2163.341s(在程序運行的第2163s) 1%(gc所有work消耗的歷史累計CPU比例, 所以其實這個數(shù)據(jù)沒太大意義) 0.13(第一個stw的wall time)+14(并發(fā)mark的wall time)+0.20(第二個stw的wall time) ms clock, 1.1(第一個stw消耗的CPU時間)+21(用戶程序輔助掃描消耗的cpu時間)/22(分配用于mark的P消耗的cpu時間)/0(空閑的P用于mark的cpu時間)+1.6ms(第2個stw的cpu時間) cpu, 147(gc開始時的堆大小)->149(gc結(jié)束的堆大小)->75MB(gc結(jié)束時的存活堆大小), 151 MB goal(本次gc預計結(jié)束的堆大小), 8P(8個P)

    優(yōu)化

    個人建議, 沒事不要總想著優(yōu)化, 好好curd就好.

    ?

    當然還是有一些優(yōu)化方法的..

    一點實踐

    我們將pprof的開啟集成到模板中, 并自動選擇端口, 并集成了gops工具, 方便查詢runtime信息, 同時在瀏覽器上可直接點擊生成火焰圖, pprof圖, 非常的方便, 也不需要使用者關(guān)心.

    問題排查的一點思路

    一次有意思的問題排查

    負載, 依賴服務(wù)都很正常, CPU利用率也不高, 請求也不多, 就是有很多超時.

    ?

    該服務(wù)在線上打印了debug日志, 因為早期的服務(wù)模板開啟了gctrace, 框架把stdout重定向到一個文件了. 而輸出gctrace時本來是到console的, 輸出到文件了, 而磁盤跟不上, 導致gctrace日志被阻塞了.

    這里更正一下ppt中的內(nèi)容, 并不是因為gc沒完成而導致其他協(xié)程不能運行, 而是后續(xù)gc無法開啟, 導致實質(zhì)上的stw. 打印gc trace日志時, 已經(jīng)start the world了, 其他協(xié)程可以開始運行了. 但是在打印gctrace日志時, 還保持著開啟gc需要的鎖, 所以, 打印gc trace日志一直沒完成, 而gc又比較頻繁, 比如0.1s一次, 這樣會導致下一次gc開始時無法獲取鎖, 每一個進入gc檢查的p阻塞, 實際上就造成了stw.

    Runtime的一點個人總結(jié)

    并行, 縱向多層次, 橫向多個class, 緩存, 緩沖, 均衡.

    參考文檔

    總結(jié)

    以上是生活随笔為你收集整理的深入浅出Go Runtime的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 99热1| 4444亚洲人成无码网在线观看 | 免费欧美视频 | 国产网站av | 免费福利视频在线观看 | 伊人黄| 国产精品欧美在线 | 无码人妻精品一区二区中文 | 免费在线观看你懂的 | 麻豆精品免费视频 | 亚洲国产精品福利 | 超碰人人国产 | 国产白丝在线观看 | 亚洲色图欧美色 | 哈利波特3在线观看免费版英文版 | 免费看污的网站 | 自拍偷拍第5页 | xxxx日韩| 成人福利小视频 | 欧美一区二区三区四区视频 | 极品人妻一区二区 | 99视频这里有精品 | xx69欧美 | av影视在线| caopeng在线视频 | 99热99在线 | 狠狠丁香 | 爱情岛成人 | 日本理论片午伦夜理片在线观看 | 91精品大片| 亚洲av永久无码精品放毛片 | 李华月全部毛片 | 91久久网| 囯产精品久久久久久 | 激情小说亚洲图片 | 日韩一级黄色录像 | 男女啪啪av | 欧美一级做a爰片免费视频 成人激情在线观看 | 日日草夜夜草 | 日韩一级视频在线观看 | 欧美成人免费观看视频 | 国产精品一区二区三区四区五区 | 久久久久久麻豆 | 91微拍| 台湾佬久久 | 天天在线免费视频 | 国产成人精品白浆久久69 | 麻豆va | 国产a级免费视频 | 国产欧美激情视频 | 麻豆www. | 成人动漫在线播放 | 久久草精品 | 欧美日韩一区在线播放 | 日不卡 | 娇小萝被两个黑人用半米长 | 久久久黄色片 | 无码少妇精品一区二区免费动态 | 丁香婷婷久久 | 2019中文字幕在线免费观看 | 日本一本在线 | 四虎在线影院 | 艳妇av | 国产91久久精品一区二区 | 成人在线视频免费 | 麻豆成人精品国产免费 | 美女的诞生免费观看在线高清 | 国产一区二区三区久久 | 污版视频在线观看 | 天堂av在线免费 | 国产网址在线观看 | 在线免费观看黄色片 | 三级不卡视频 | 羞羞漫画在线播放 | 美女网站一区 | 小珊的性放荡羞辱日记 | 青青青手机视频 | 亚洲久久在线观看 | 激情欧美一区二区 | 蜜色av| 久久合合 | 91超碰在线免费观看 | 一区二区三区不卡视频在线观看 | 国产成人精品免高潮费视频 | 美女午夜激情 | 日韩国产欧美一区二区三区 | 天天射狠狠干 | 性xxxx| 免费成人美女在线观看. | 色射影院| 巨物撞击尤物少妇呻吟 | 女人性做爰24姿势视频 | 岛国激情 | 色综合狠狠爱 | 午夜激情网站 | 色桃av| 男女洗澡互摸私密部位视频 | 精品人妻无码专区在线 | 白嫩白嫩国产精品 |