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

          Go 調(diào)試分析的高階技巧

          共 9298字,需瀏覽 19分鐘

           ·

          2020-07-31 18:21

          大綱

          • Golang tools

            • nm

            • compile

            • objdump

            • pprof

            • trace

          • 單元測(cè)試

            • 執(zhí)行單元測(cè)試

            • 統(tǒng)計(jì)代碼覆蓋率

          • 程序 Debug

            • dlv 調(diào)試用法

            • gdb 調(diào)試

          • 小技巧

            • 不知道怎么斷點(diǎn)函數(shù)?

            • 不知道調(diào)用上下文?

            • 不知道怎么開(kāi)啟 pprof ?

            • 為什么有時(shí)候單點(diǎn)調(diào)試的時(shí)候,總是非預(yù)期的執(zhí)行代碼?

          • 總結(jié)

          golang 高階調(diào)試

          本文專(zhuān)注 golang debug 的一些技巧應(yīng)用,以及相關(guān)工具的實(shí)用用法,再也不用怕 golang 怎么調(diào)試。golang 作為一門(mén)現(xiàn)代化語(yǔ)音,出生的時(shí)候就自帶完整的 debug 手段:

          • golang tools 是直接集成在語(yǔ)言工具里,支持內(nèi)存分析,cpu分析,阻塞鎖分析等;
          • delve,gdb 作為最常用的 debug 工具,讓你能夠更深入的進(jìn)入程序調(diào)試;
            • delve 當(dāng)前是最友好的 golang 調(diào)試程序,ide 調(diào)試其實(shí)也是調(diào)用 dlv 而已,比如 goland;
          • 單元測(cè)試的設(shè)計(jì)深入到語(yǔ)言設(shè)計(jì)級(jí)別,可以非常方便執(zhí)行單元測(cè)試并且生成代碼覆蓋率;

          Golang tools

          golang 從語(yǔ)言原生層面就集成了大量的實(shí)用工具,這些都是 Robert Griesemer, Rob Pike, Ken Thompson 這幾位大神經(jīng)驗(yàn)沉淀下的精華。你安裝好 golang 之后,執(zhí)行 go tool 就能看到內(nèi)置支持的所有工具了。

          root@ubuntu:~# go tooladdr2lineasmbuildidcgocompilecoverdistdocfixlinknmobjdumppackpproftest2jsontracevet

          我這里專(zhuān)注挑選幾個(gè) debug 常用的:

          • nm:查看符號(hào)表(等同于系統(tǒng) nm 命令)
          • objdump:反匯編工具,分析二進(jìn)制文件(等同于系統(tǒng) objdump 命令)
          • pprof:指標(biāo),性能分析工具
          • cover:生成代碼覆蓋率
          • trace:采樣一段時(shí)間,指標(biāo)跟蹤分析工具
          • compile:代碼匯編

          nm

          查看符號(hào)表的命令,等同于系統(tǒng)的 nm 命令,非常有用。在斷點(diǎn)的時(shí)候,如果你不知道斷點(diǎn)的函數(shù)符號(hào),那么用這個(gè)命令查一下就知道了(命令處理的是二進(jìn)制程序文件)。

          # exmple 為你編譯的二進(jìn)制文件go tool nm ./example

          第一列是地址,第二列是類(lèi)型,第三列是符號(hào):


          compile

          匯編某個(gè)文件

          go tool compile -N -l -S example.go

          你就能看到你 golang 語(yǔ)言對(duì)應(yīng)的匯編代碼了(注意了,命令處理的是 golang 代碼文本),酷。

          objdump

          反匯編二進(jìn)制的工具,等同于系統(tǒng) objdump(注意了,命令解析的是二進(jìn)制格式的程序文件)。

          go tool objdump example.ogo tool objdump -s DoFunc example.o? // 反匯編具體函數(shù)

          匯編代碼這個(gè)東西在 90% 的場(chǎng)景可能都用不上,但是如果你處理過(guò) c 的程序,在某些特殊場(chǎng)景,通過(guò)反匯編一段邏輯來(lái)推斷應(yīng)用程序行為將是你唯一的出路。因?yàn)榫€上的代碼一般都是會(huì)開(kāi)啟編譯優(yōu)化,所以這里會(huì)導(dǎo)致你的代碼對(duì)不上。再者,線上不可能讓你隨意 attach 進(jìn)程,很多時(shí)候都是出 core 了,你就只有一個(gè) core 文件去排查。

          pprof

          pprof 支持四種類(lèi)型的分析:

          • CPU :CPU 分析,采樣消耗 cpu 的調(diào)用,這個(gè)一般用來(lái)定位排查程序里耗費(fèi)計(jì)算資源的地方;
          • Memroy :內(nèi)存分析,一般用來(lái)排查內(nèi)存占用,內(nèi)存泄露等問(wèn)題;
          • Block :阻塞分析,會(huì)采樣程序里阻塞的調(diào)用情況;
          • Mutex :互斥鎖分析,采樣互斥鎖的競(jìng)爭(zhēng)情況;

          我們這里詳細(xì)以?xún)?nèi)存占用分析舉例(其他的類(lèi)似),pprof 這個(gè)是內(nèi)存分析神器。基本上,golang 有了這個(gè)東西,99% 的內(nèi)存問(wèn)題(比如內(nèi)存泄露,內(nèi)存占用過(guò)大等等)都是可以非常快的定位出來(lái)的。首先,對(duì)于 golang 的內(nèi)存分析(或者其他的鎖消耗,cpu 消耗)我們明確幾個(gè)重要的點(diǎn):

          • golang 內(nèi)存 pprof 是采樣的,每 512KB 采樣一次;
          • golang 的內(nèi)存采樣的是堆棧路徑,而不是類(lèi)型信息;
          • golang 的內(nèi)存采樣入口一定是通過(guò)mProf_MallocmProf_Free 這兩個(gè)函數(shù)。所以,如果是 cgo 分配的內(nèi)存,那么是沒(méi)有機(jī)會(huì)調(diào)用到這兩個(gè)函數(shù)的,所以如果是 cgo 導(dǎo)致的內(nèi)存問(wèn)題,go tool pprof 是分析不出來(lái)的;

          詳細(xì)原理,可以復(fù)習(xí)另一篇文章:內(nèi)存分析;

          分析的形式有兩種:

          1. 如果是 net/http/pporf 方式開(kāi)啟的,那么可以直接在控制臺(tái)上輸入,瀏覽器就能看;
          2. 另一種方式是先把信息 dump 到本地文件,然后用 go tool 去分析(我們以這個(gè)舉例,因?yàn)檫@種方式才是生產(chǎn)環(huán)境通用的方式)
          # 查看累計(jì)分配占用go tool pprof -alloc_space ./29075_20190523_154406_heap# 查看當(dāng)前的分配占用go tool pprof -inuse_space ./29075_20190523_154406_allocs

          你也可以不指定類(lèi)型,直接 go tool pprof ./xxx ,進(jìn)入分析之后,調(diào)用 o 選項(xiàng),指定類(lèi)型:

          我寫(xiě)了一個(gè) demo 程序,然后 dump 出了一份 heap 的 pprof 采樣文件,我們先通過(guò)這個(gè) pprof 得出一些結(jié)論,最后我再貼出源代碼,再品一品。

          go tool pprof ./29075_20190523_154406_heap(pprof) o              ...            sample_index              = inuse_space          //: [alloc_objects | alloc_space | inuse_objects | inuse_space]...       (pprof) alloc_space(pprof) topShowing nodes accounting for 290MB, 100% of 290MB total      flat  flat%   sum%        cum   cum%     140MB 48.28% 48.28%      140MB 48.28%  main.funcA (inline)     100MB 34.48% 82.76%      190MB 65.52%  main.funcB (inline)      50MB 17.24%   100%      140MB 48.28%  main.funcC (inline)         0     0%   100%      290MB   100%  main.main         0     0%   100%      290MB   100%  runtime.main

          這個(gè) top 信息表明了這么幾點(diǎn)信息:

          • main.funcA ?這個(gè)函數(shù)現(xiàn)場(chǎng)分配了 140M 的內(nèi)存,main.funcB 這個(gè)函數(shù)現(xiàn)場(chǎng)分配了 100M 內(nèi)存,main.funcC 現(xiàn)場(chǎng)分配了 50M 內(nèi)存;
            • 現(xiàn)場(chǎng)的意思:純粹自己函數(shù)直接分配的,而不是調(diào)用別的函數(shù)分配的;
            • 這些信息通過(guò) flat 得知;
          • main.funcA ?分配的 140M 內(nèi)存純粹是自己分配的,沒(méi)有調(diào)用別的函數(shù)分配過(guò)內(nèi)存;
            • 這個(gè)信息通過(guò) main.funcA flat 和 cum 都為 140 M 得出;
          • main.funcB ?自己分配了 100MB,并且還調(diào)用了別的函數(shù),別的函數(shù)里面涉及了 90M 的內(nèi)存分配;
            • 這個(gè)信息通過(guò) main.funcB flat 和 cum 分別為 100 M,190M 得出;
          • main.funcC ?自己分配了 50MB,并且還調(diào)用了別的函數(shù),別的函數(shù)里面涉及了 90M 的內(nèi)存分配;
            • 這個(gè)信息通過(guò) main.funcC flat 和 cum 分別為 50 M,140 M 得出;
          • main.main :所有分配內(nèi)存的函數(shù)調(diào)用都是走這個(gè)函數(shù)出去的。main 函數(shù)本身沒(méi)有函數(shù)分配,但是他調(diào)用的函數(shù)分配了 290M;

          demo 的源代碼:

          package main
          import ( "net/http" _ "net/http/pprof")
          func funcA() []byte { a := make([]byte, 10*1024*1024) return a}
          func funcB() ([]byte, []byte) { a := make([]byte, 10*1024*1024) b := funcA() return a, b}
          func funcC() ([]byte, []byte, []byte) { a := make([]byte, 10*1024*1024) b, c := funcB() return a, b, c}
          func main() { for i := 0; i < 5; i++ { funcA() funcB() funcC() }
          http.ListenAndServe("0.0.0.0:9999", nil)}

          dump 命令

          curl -sS 'http://127.0.0.1:9999/debug/pprof/heap?seconds=5' -o heap.pporf

          對(duì)照著代碼,再品一品。采樣原理之前已經(jīng)詳細(xì)分析過(guò)了,flat,cum 這兩個(gè)字段的含義?這個(gè)可以復(fù)習(xí)下:golang 內(nèi)存管理分析

          trace

          程序 trace 調(diào)試

          go tool trace -http=":6060" ./ssd_336959_20190704_105540_trace

          trace 這個(gè)命令允許你跟蹤采集一段時(shí)間的信息,然后 dump 成文件,最后調(diào)用 go tool trace 分析 dump 文件,并且以 web 的形式打開(kāi)。

          單元測(cè)試

          單元測(cè)試的重要性就不再論述。golang 里面 _test.go 結(jié)尾的文件認(rèn)為是測(cè)試文件,golang 作為現(xiàn)代化的語(yǔ)言,語(yǔ)言工具層面支持單元測(cè)試。

          執(zhí)行單元測(cè)試

          執(zhí)行單元測(cè)試有兩種方式:

          • go test 直接運(yùn)行,這個(gè)是最簡(jiǎn)單的;
          • 先編譯測(cè)試文件,再運(yùn)行。這種方式更靈活;

          go test 運(yùn)行

          // 直接在你項(xiàng)目目錄里運(yùn)行 go test .go test .// 指定運(yùn)行函數(shù)go test -run=TestPutAndGetKeyValue// 打印詳細(xì)信息go test -v

          編譯,運(yùn)行

          本質(zhì)上,golang 跑單測(cè)是先編譯 *_test.go 文件,編譯成二進(jìn)制后,再運(yùn)行這個(gè)二進(jìn)制文件。你執(zhí)行 go test 的時(shí)候,工具幫你做好了,這些動(dòng)作其實(shí)也是可以拆開(kāi)來(lái)自己做的。

          編譯生成單元測(cè)試可執(zhí)行文件:

          // 先編譯出 .test 文件$ go test -c?
          // 指定跑某一個(gè)文件$ ./raftexample.test -test.timeout=10m0s -test.v=true -test.run=TestPutAndGetKeyValue

          這種方式通常會(huì)出現(xiàn)在以下幾種場(chǎng)景:

          1. 這臺(tái)機(jī)器上編譯,另一個(gè)地方跑單測(cè);
          2. debug 單測(cè)程序;

          統(tǒng)計(jì)代碼覆蓋率

          golang 的代碼覆蓋率是基于單測(cè)的,由單測(cè)作為出發(fā)點(diǎn),來(lái)看你的業(yè)務(wù)代碼覆蓋率。

          操作很簡(jiǎn)單:

          1. 加一個(gè) -coverprofile 的參數(shù),聲明在跑單測(cè)的時(shí)候,記錄代碼覆蓋率;
          2. 使用 go tool cover 命令分析,得出覆蓋率報(bào)告;
          go test -coverprofile=coverage.outgo tool cover -func=coverage.out

          類(lèi)似如下:

          root@ubuntu:~/opensource/readcode-etcd-master/src/go.etcd.io/etcd/contrib/raftexample# go tool cover -func=coverage.outgo.etcd.io/etcd/v3/contrib/raftexample/httpapi.go:33:	ServeHTTP		25.0%go.etcd.io/etcd/v3/contrib/raftexample/httpapi.go:108:	serveHttpKVAPI		0.0%go.etcd.io/etcd/v3/contrib/raftexample/kvstore.go:41:	newKVStore		100.0%go.etcd.io/etcd/v3/contrib/raftexample/kvstore.go:50:	Lookup			100.0%go.etcd.io/etcd/v3/contrib/raftexample/kvstore.go:57:	Propose			75.0%go.etcd.io/etcd/v3/contrib/raftexample/kvstore.go:71:	readCommits		55.0%go.etcd.io/etcd/v3/contrib/raftexample/kvstore.go:107:	getSnapshot		100.0%go.etcd.io/etcd/v3/contrib/raftexample/kvstore.go:113:	recoverFromSnapshot	85.7%go.etcd.io/etcd/v3/contrib/raftexample/listener.go:30:	newStoppableListener	75.0%go.etcd.io/etcd/v3/contrib/raftexample/listener.go:38:	Accept			92.9%go.etcd.io/etcd/v3/contrib/raftexample/main.go:24:	main			0.0%total:							(statements)		57.1%

          這樣的話,你就知道每個(gè)函數(shù)的代碼覆蓋率。實(shí)踐證明,無(wú)數(shù)的程序 bug 都是出現(xiàn)在平時(shí)沒(méi)有覆蓋到的程序邏輯上。所以,保證你的代碼都被測(cè)試覆蓋過(guò)是保證項(xiàng)目質(zhì)量的有效手段,golang 的 go test 幫你做到這一點(diǎn)。

          程序 Debug

          程序的調(diào)試主要由兩個(gè)工具:

          1. dlv
          2. gdb

          這里推薦 dlv,因?yàn)?gdb 功能實(shí)在是有限,gdb 不理解 golang 的業(yè)務(wù)類(lèi)型和協(xié)程。但是 gdb 有一個(gè)功能是無(wú)法替代的,就是 gcore 的功能。

          dlv 調(diào)試用法

          調(diào)試二進(jìn)制

          dlv exec  [flags]

          舉例:

          dlv exec ./example

          dlv?調(diào)試二進(jìn)制,并帶參數(shù)

          dlv exec ./example -- --audit=./d

          調(diào)試進(jìn)程

          dlv attach ${pid} [executable] [flags]

          進(jìn)程號(hào)是必選的。

          舉例:

          dlv attach 12808 ./example

          調(diào)試 core 文件

          dlv 調(diào)試core文件;并且標(biāo)準(zhǔn)輸出導(dǎo)出到文件

          dlv core   [flags]
          dlv core ./example core.277282

          調(diào)試常用語(yǔ)法

          系統(tǒng)整理

          程序運(yùn)行

          1. call :call 函數(shù)(注意了,這個(gè)會(huì)導(dǎo)致整個(gè)程序運(yùn)行的)
          2. continue :往下運(yùn)行
          3. next :?jiǎn)尾秸{(diào)試
          4. restart :重啟
          5. step :?jiǎn)尾秸{(diào)試,某個(gè)函數(shù)
          6. step-instruction :?jiǎn)尾秸{(diào)試某個(gè)匯編指令
          7. stepout :從當(dāng)前函數(shù)跳出

          斷點(diǎn)相關(guān)

          1. break (alias: b) :設(shè)置斷點(diǎn)
          2. breakpoints (alias: bp) ?:打印所有的斷點(diǎn)信息
          3. clear :清理斷點(diǎn)
          4. clearall :清理所有的斷點(diǎn)
          5. condition (alias: cond) ?:設(shè)置條件斷點(diǎn)
          6. on :設(shè)置一段命令,當(dāng)斷點(diǎn)命中的時(shí)候
          7. trace (alias: t) :設(shè)置一個(gè)跟蹤點(diǎn),這個(gè)跟蹤點(diǎn)也是一個(gè)斷點(diǎn),只不過(guò)運(yùn)行到的時(shí)候不會(huì)斷住程序,只是打印一行信息,這個(gè)命令在某些場(chǎng)景是很有用的,比如你斷住程序就會(huì)影響邏輯(業(yè)務(wù)有超時(shí)),而你僅僅是想打印某個(gè)變量而已,那么用這種類(lèi)型的斷點(diǎn)就行;;

          信息打印

          1. args : 打印程序的傳參
          2. examinemem (alias: x) ?:這個(gè)是神器,解析內(nèi)存用的,和 gdb 的 x 命令一樣;
          3. locals :打印本地變量?
          4. print (alias: p) :打印一個(gè)表達(dá)式,或者變量?
          5. regs :打印寄存器的信息?
          6. set :set 賦值?
          7. vars :打印全局變量(包變量)?
          8. whatis :打印類(lèi)型信息

          協(xié)程相關(guān)

          1. goroutine (alias: gr) :打印某個(gè)特定協(xié)程的信息?

          2. goroutines (alias: grs) ?:列舉所有的協(xié)程?

          3. thread (alias: tr) :切換到某個(gè)線程?

          4. threads :打印所有的線程信息

          棧相關(guān)

          1. deferred :在 defer 函數(shù)上下文里執(zhí)行命令?

          2. down :上堆棧?

          3. frame :跳到某個(gè)具體的堆棧?

          4. stack (alias: bt) ?:打印堆棧信息?

          5. up :下堆棧

          其他命令

          1. config :配置變更?
          2. disassemble (alias: disass) :反匯編?
          3. edit (alias: ed) :略?
          4. exit (alias: quit | q) :略?
          5. funcs :打印所有函數(shù)符號(hào)?
          6. libraries :打印所有加載的動(dòng)態(tài)庫(kù)?
          7. list (alias: ls | l) :顯示源碼?
          8. source :加載命令?
          9. sources :打印源碼?
          10. types :打印所有類(lèi)型信息

          以上就是完整的 dlv 的支持的命令,從這個(gè)來(lái)看,是完全滿(mǎn)足我們的調(diào)試需求的(有的只適用于開(kāi)發(fā)調(diào)試環(huán)節(jié),比如線上的程序不可能讓你隨意單步調(diào)試的,有的使用于線上生產(chǎn)環(huán)節(jié))。

          應(yīng)用舉例

          打印全局變量

          (dlv) vars

          這個(gè)非常有用,幫助你看一些全局變量。

          條件斷點(diǎn)

          # 先斷點(diǎn)(dlv) b?
          # 查看斷點(diǎn)信息(dlv) bp
          # 然后定制條件(dlv) condition 2 i==2 && j==7 && z==32

          查看堆棧

          # 展示所有堆棧(dlv) goroutines# 所有堆棧展開(kāi)(dlv) goroutines -t

          解析內(nèi)存

          (dlv) x -fmt hex -len 20 0xc00008af38

          x 命令和 gdb 的 x 是一樣的。

          gdb 調(diào)試

          gdb 對(duì) golang 的調(diào)試支持是通過(guò)一個(gè) python 腳本文件 src/runtime/runtime-gdb.py 來(lái)擴(kuò)展的,所以功能非常有限。gdb 只能做到最基本的變量打印,卻理解不了 golang 的一些特殊類(lèi)型,比如 channel,map,slice 等,gdb 原生是無(wú)法調(diào)適 goroutine 協(xié)程的,因?yàn)檫@個(gè)是用戶(hù)態(tài)的調(diào)度單位,gdb 只能理解線程。所以只能通過(guò) python 腳本的擴(kuò)展,把協(xié)程結(jié)構(gòu)按照鏈表輸出出來(lái),支持的命令:



          gdb當(dāng)前只支持6個(gè)命令:

          3個(gè) cmd 命令

          1. info goroutines;打印所有的goroutines
          2. goroutine ${id} bt;打印一個(gè)goroutine的堆棧
          3. iface;打印靜態(tài)或者動(dòng)態(tài)的接口類(lèi)型

          3個(gè)函數(shù)

          1. len;打印string,slices,map,channels 這四種類(lèi)型的長(zhǎng)度
          2. cap;打印slices,channels 這兩種類(lèi)型的cap
          3. dtype;強(qiáng)制轉(zhuǎn)換接口到動(dòng)態(tài)類(lèi)型。

          打印全局變量 (注意單引號(hào))

          (gdb) p 'runtime.firstmoduledata'

          由于 gdb 不理解 golang 的一些類(lèi)型系統(tǒng),所以調(diào)試打印的時(shí)候經(jīng)常打印不出來(lái),這個(gè)要注意下。

          打印數(shù)組變量長(zhǎng)度

          (gdb) p $len(xxx)

          所以,我一般只用 gdb 來(lái) gcore 而已。

          小技巧

          不知道怎么斷點(diǎn)函數(shù)?

          有時(shí)候不知道怎么斷點(diǎn)函數(shù):可以通過(guò)nm查詢(xún)下,然后再斷點(diǎn),就一定能斷到了。


          不知道調(diào)用上下文?

          在你的代碼里添加一行:

          debug.PrintStack()

          這樣就能當(dāng)前代碼位置的堆棧給打印出來(lái),這樣你就直到怎么函數(shù)的調(diào)用路徑了。

          不知道怎么開(kāi)啟 pprof ?

          pprof 功能有兩種開(kāi)啟方式,對(duì)應(yīng)兩種包:

          • net/http/pprof :使用在 web 服務(wù)器的場(chǎng)景;
          • runtime/pprof ?:使用在非服務(wù)器應(yīng)用程序的場(chǎng)景;

          這兩個(gè)本質(zhì)上是一致的,net/http/pporf 也只是在 runtime/pprof 上的一層 web 封裝。

          net/http/pprof 方式

          import _ "net/http/pprof"

          runtime/pprof 方式

          這種通常用于程序調(diào)優(yōu)的場(chǎng)景,程序只是一個(gè)應(yīng)用程序,跑一次就結(jié)束,你想找到瓶頸點(diǎn),那么通常會(huì)使用到這個(gè)方式。

            // cpu pprof 文件路徑    f, err := os.Create("cpufile.pprof")  if err != nil {    log.Fatal(err)  }    // 開(kāi)啟 cpu pprof  pprof.StartCPUProfile(f)  defer pprof.StopCPUProfile()

          為什么有時(shí)候單點(diǎn)調(diào)試的時(shí)候,總是非預(yù)期的執(zhí)行代碼?

          這種情況一般是被編譯器優(yōu)化了,比如函數(shù)內(nèi)聯(lián)了,編譯出的二進(jìn)制刪減了無(wú)效邏輯、無(wú)效參數(shù)。這種情況就會(huì)導(dǎo)致你 dlv 單步調(diào)試的時(shí)候,總是非預(yù)期的執(zhí)行,或者打印某些變量打印不出來(lái)。這種情況解決方法就是:禁止編譯優(yōu)化。

          go build -gcflags "-N -l"

          總結(jié)

          該篇文章系統(tǒng)的分享了 golang 程序調(diào)試的技巧和用法:

          1. 語(yǔ)言工具包里內(nèi)置 tool 工具,支持匯編,反匯編,pprof 分析,符號(hào)表查詢(xún)等實(shí)用功能;
          2. 語(yǔ)言工具包集成單元測(cè)試,代碼覆蓋率依賴(lài)于單元測(cè)試的觸發(fā);
          3. 常用 dlv/gdb 這兩個(gè)工具作為大殺器,可以分析二進(jìn)制,進(jìn)程,core 文件;
          4. 有疑問(wèn)可以私信交流(我好像沒(méi)有留言功能),之后會(huì)有個(gè)專(zhuān)輯分享一些線上問(wèn)題排查的實(shí)際案例;




          推薦閱讀



          學(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)注


          瀏覽 76
          點(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>
                  极品久久久久 | 中国学生妹做爱视频 | 国家一级黄色片 | 亲子乱aⅴ一区二区三区的 | 欧美美女后进式插逼视频 |