日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Go編譯時(shí)寫入數(shù)據(jù)的原理

場景

公司線上運(yùn)行的Go服務(wù)存在多個(gè)版本

荔波網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。成都創(chuàng)新互聯(lián)公司從2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)公司

時(shí)間:某天凌晨

事情:線上Go服務(wù)突然間 crash

緊急處理:重啟Go服務(wù)

故障排查:查詢?nèi)罩?,找出可能出現(xiàn)的堆棧信息以及追溯源碼

問題:線上同時(shí)存在多個(gè)版本,如何知道當(dāng)前 crash 的程序?qū)儆谀膫€(gè)版本?

添加版本信息的兩種方案

方案1,手動(dòng)添加版本信息:

 
 
 
  1. package main
  2. import (
  3.     "flag"
  4.     "fmt"
  5. )
  6. // 下面三個(gè)變量,每次發(fā)版都要修改
  7. var version = "v0.0.1" // 程序版本號
  8. var gitTag = "v0.0.1" // git tag 號
  9. var dateTime = "2021-08-14 10:00:00" // 編譯生成時(shí)間
  10. func main() {
  11.     debugVerInfo := flag.Bool("ver", false, "show app version info")
  12.     flag.Parse()
  13.     if *debugVerInfo {
  14.         fmt.Println("version is:", version)
  15.         fmt.Println("dateTime is:", dateTime)
  16.         fmt.Println("gitTag is:", gitTag)
  17.         return
  18.     }
  19.     fmt.Println("do other thing")
  20. }

由于手動(dòng)在代碼中添加版本信息,所以在排查時(shí)可以查看到對應(yīng)信息。

 
 
 
  1.   code  ./client -ver  
  2. version is: v0.0.1
  3. dateTime is: 2021-08-14 10:00:00
  4. gitTag is: v0.0.1

分析:

在很多公司甚至開源項(xiàng)目都會采用該方式,在代碼中顯式地添加版本等信息。

  1. 假設(shè)不經(jīng)常發(fā)版或者發(fā)版周期比較長,則完全沒問題
  2. 假設(shè)發(fā)版頻繁,很大概率會出現(xiàn)版本信息的遺漏、錯(cuò)誤
  3. 假設(shè)版本信息忘記更改,則查詢出來的信息就是錯(cuò)的

針對以上情況,提出一個(gè)問題:Go是編譯型語言,版本等信息是否可以在編譯時(shí),自動(dòng)地打包到二進(jìn)制文件中?

方案2,自動(dòng)打包版本信息:

 
 
 
  1. package main
  2. import (
  3.     "flag"
  4.     "fmt"
  5. )
  6. var version = "v0.0.0"http:// 此處暫時(shí)只填寫大的版本號
  7. var gitTag string
  8. var dateTime string
  9. func main() {
  10.     debugVerInfo := flag.Bool("ver", false, "show app version info")
  11.     flag.Parse()
  12.     if *debugVerInfo {
  13.         fmt.Println("version is:", version)
  14.         fmt.Println("dateTime is:", dateTime)
  15.         fmt.Println("gitTag is:", gitTag)
  16.         return
  17.     }
  18.     fmt.Println("do other thing")
  19. }

 在編譯時(shí),打包版本等信息到Go的二進(jìn)制文件中:

 
 
 
  1. go build -ldflags \
  2.     "-X main.version=v0.0.1 -X main.dateTime=`date +%Y-%m-%d,%H:%M:%S` -X main.gitTag=`git tag`" \
  3.   -o client

build 通過 -ldflags 的 -X 參數(shù)可以在編譯時(shí)將值寫入變量

變量格式:包名稱.變量名稱=值

查看版本信息

 
 
 
  1.   code  ./client -ver  
  2. version is: v0.0.1
  3. dateTime is: 2021-08-14 10:00:00
  4. gitTag is: v0.0.1

優(yōu)點(diǎn):

無需代碼中顯式添加版本等信息

避免手動(dòng)添加版本信息時(shí),遺漏或者錯(cuò)誤等情況發(fā)生

可使用持續(xù)集成工具自動(dòng)把版本等信息打包到二進(jìn)制文件中

原理

二進(jìn)制文件在加載到內(nèi)存中之后,整個(gè)內(nèi)存空間會被劃分為若干段。除了代碼區(qū)、數(shù)據(jù)區(qū)、堆、棧,還有有一個(gè)段為符號表。

在編譯時(shí),把版本等信息打包到符號表中,供程序運(yùn)行時(shí)使用。

 
 
 
  1. [root@localhost demo]# readelf -s client | grep main
  2.     ......
  3.   1686: 00000000005608b0    16 OBJECT  GLOBAL DEFAULT   10 main.version
  4.   1687: 00000000005608a0    16 OBJECT  GLOBAL DEFAULT   10 main.gitTag
  5.   1688: 0000000000560890    16 OBJECT  GLOBAL DEFAULT   10 main.dateTime
  6.     ......
  7.   2320: 00000000004eb2e8     7 OBJECT  GLOBAL DEFAULT    2 main.version.str
  8.   2321: 00000000004ebba0    20 OBJECT  GLOBAL DEFAULT    2 main.dateTime.str
  9.   2322: 00000000004eb2e0     7 OBJECT  GLOBAL DEFAULT    2 main.gitTag.str

使用 readelf -s命令查看編譯好的Go二進(jìn)制文件符號表信息,可以明顯看到在編譯時(shí)寫入的三個(gè)變量。

其中,main.version、main.gitTag、main.dateTime 大小都為16,是指 在Go中的string類型結(jié)構(gòu)體大小。

 
 
 
  1. (gdb) ptype version
  2. type = struct string {
  3.     uint8 *str;
  4.     int len;
  5. }
  6. (gdb) ptype dateTime
  7. type = struct string {
  8.     uint8 *str;
  9.     int len;
  10. }
  11. (gdb) ptype gitTag
  12. type = struct string {
  13.     uint8 *str;
  14.     int len;
  15. }

不知細(xì)心的你是否發(fā)現(xiàn),在符號表顯示的變量具體值 main.version.str、main.dateTime.str、main.gitTag.str長度都比實(shí)際多一個(gè)字節(jié)。

雖然目前Go實(shí)現(xiàn)了自舉,但是編譯Go編譯器的編譯器還是用C語言寫的

C語言字符串(字節(jié)數(shù)組)是非安全類型,使用尾零來標(biāo)識字符串結(jié)束。其中,尾零也占用一個(gè)字節(jié)。

尾零是 ASCII 第一個(gè)元素 0, 即:NUL

 
 
 
  1. (gdb) p version
  2. $1 = "v0.0.1"
  3. (gdb) p dateTime
  4. $2 = "2021-08-13,23:26:44"
  5. (gdb) p gitTag
  6. $3 = "v0.0.1"

本文標(biāo)題:Go編譯時(shí)寫入數(shù)據(jù)的原理
文章地址:http://www.dlmjj.cn/article/coihgde.html