日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

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

新聞中心

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

場(chǎng)景

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

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

時(shí)間:某天凌晨

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

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

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

問(wè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" // 程序版本號(hào)
  8. var gitTag = "v0.0.1" // git tag 號(hào)
  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í)可以查看到對(duì)應(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

分析:

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

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

針對(duì)以上情況,提出一個(gè)問(wèn)題:Go是編譯型語(yǔ)言,版本等信息是否可以在編譯時(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í)只填寫大的版本號(hào)
  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 通過(guò) -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):

無(wú)需代碼中顯式添加版本等信息

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

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

原理

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

在編譯時(shí),把版本等信息打包到符號(hào)表中,供程序運(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)制文件符號(hào)表信息,可以明顯看到在編譯時(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),在符號(hào)表顯示的變量具體值 main.version.str、main.dateTime.str、main.gitTag.str長(zhǎng)度都比實(shí)際多一個(gè)字節(jié)。

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

C語(yǔ)言字符串(字節(jié)數(shù)組)是非安全類型,使用尾零來(lái)標(biāo)識(shí)字符串結(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"

本文題目:Go編譯時(shí)寫入數(shù)據(jù)的原理
文章來(lái)源:http://www.5511xx.com/article/coihgde.html