Go 專案配置檔案的定義和讀取
前言
我們在寫應用時,基本都會用到配置檔案,從各種 shell
到 nginx
等,都有自己的配置檔案。雖然這沒有太多難度,但是配置項一般相對比較繁雜,解析、校驗也會比較麻煩。本文就給大家講講我們是怎麼簡化配置檔案的定義和解析的。
場景
如果我們要寫一個 Restful API
的服務,配置項大概有如下內容:
-
Host
,偵聽的IP
,如果不填,預設用0.0.0.0
-
Port
,偵聽的埠,必填,只能是數字,大於等於80,小於65535 -
LogMode
,日誌模式,只能選file
或者console
-
Verbose
,看是否輸出詳細日誌,可選,預設為false
-
MaxConns
,允許的最大併發連線數,預設10000
-
Timeout
,超時設定,預設3s
-
CpuThreshold
,設定CPU
使用率觸發系統降載的閾值,預設900
,1000m
表示100%
之前我們用 json
做配置檔案,但是 json
有個問題,無法加註釋,所以我們後來切換到了 yaml
格式。
接下來讓我們看看藉助 go-zero
怎麼來方便的的定義和解析這樣的配置檔案~
定義配置
首先,我們需要將上述配置需求定義到 Go 結構體裡,如下:
RestfulConf struct { Host string `json:",default=0.0.0.0"` Port int `json:",range=[80,65535)"` LogMode string `json:",options=[file,console]"` Verbose bool `json:",optional"` MaxConns int `json:",default=10000"` Timeout time.Duration `json:",default=3s"` CpuThreshold int64 `json:",default=900,range=[0:1000]"` }
可以看到,我們對每個配置項都有一定的定義和限制,其中一些定義如下:
-
default
,配置沒填的話,使用該預設值,可以看到其中的3s
會自動解析成time.Duration
型別 -
optional
,此項可以不配置,沒有的話,用型別零值 -
range
,限定數字型別,需要在給定的範圍內 -
options
,限制配置的值只能是給出的這幾個之一
並且,一些屬性可以疊加使用,比如:
-
default
和range
一起使用,就可以既增加了範圍限制,又提供了預設值 -
default
和options
一起使用,就可以既增加了可選項限制,又提供了預設值
配置檔案
因為我們在定義配置的時候,給了很多的預設值,還有使用 optional
指定為可選,所以我們的配置檔案裡的配置項就相對比較少了,能用預設值的就不用寫了,如下:
# 因為很多都有預設值,所以只需要寫需要指定值和沒有預設值的 Port: 8080 LogMode: console # 可以讀取環境變數的值 MaxBytes: ${MAX_BYTES}
這裡有個注意點,如果配置項的 value
全部是數字,而你定義的配置型別是 string
,比如有人測試密碼經常用 123456
,但是密碼一般會定義為 string
,配置就要寫成如下(只是舉個例子哈,密碼一般不建議裸寫到配置檔案裡):
Password: "123456"
這裡的雙引號不能少,少了會報 type mismatch
之類的錯誤,因為 yaml
解析器會把不帶雙引號的 123456
解析成 int
。
載入配置檔案
我們有了配置定義( config.go
)和配置檔案( config.yaml
),接下來就是載入配置檔案了,載入配置檔案有三種方式:
- 必須載入成功,否則程式退出,我們一般這麼用,如果配置不對,程式就無法繼續了
// 有錯誤直接退出程式 var config RestfulConf conf.MustLoad("config.yaml", &config)
go-zero
自帶的 goctl
生成的預設程式碼也是使用 MustLoad
來載入配置檔案的
-
載入配置,並自行判斷是否有
error
// 自己判斷並處理 error var config RestfulConf // 為了更簡潔,這裡的 LoadConfig 後續會改為 Load,LoadConfig 已被標記為 Deprecated if err := conf.LoadConfig("config.yaml", &config); err != nil { log.Fatal(err) }
- 載入配置並讀取環境變數
// 自動讀取環境變數 var config RestfulConf conf.MustLoad(configFile, &config, conf.UseEnv())
這裡為啥我們需要顯式指定 conf.UseEnv()
,因為如果預設讀取的話,可能在配置裡大家寫特定字元的時候就需要 escape
了,所以預設不讀取環境變數,這個設計也歡迎大家多提提建議哈
實現原理
我們在實現類似 yaml/json
解析的時候一般會直接使用 encoding/json
或者對應的 yaml
庫,但是對於 go-zero
來說,我們需要在 unmarshal
的時候有更精確的控制,這就需要我們自己定製 yaml/json
的解析了,完整的程式碼實現在:
配置檔案程式碼: http://github.com/zeromicro/go-zero/tree/master/core/conf
yaml/json
解析程式碼: http://github.com/zeromicro/go-zero/tree/master/core/mapping
這裡也充分展示了 reflect
的用法,以及複雜場景下如何通過單元測試保證程式碼的正確性。
總結
我一直比較推薦 Fail Fast
的思想,我們在載入配置檔案的時候也是這樣,一旦有錯誤,立馬退出,這樣運維在部署服務時就會及時發現問題,因為程序壓根起不來。
go-zero
的所有服務的配置項都是通過這樣的方式來載入和自動驗證的,包括我寫的很多工具的配置也是基於此來實現的,希望能對你有所幫助!
專案地址
http://github.com/zeromicro/go-zero
http://gitee.com/kevwan/go-zero
歡迎使用 go-zero
並 star
支援我們!
微信交流群
關注『 微服務實踐 』公眾號並點選 交流群 獲取社群群二維碼。
如果你有 go-zero
的使用心得文章,或者原始碼學習筆記,歡迎通過公眾號聯絡投稿!
- 敏捷需求管理篇|如何從0-1寫好一個使用者故事
- go-zero微服務實戰系列(四、CRUD熱熱身)
- 乘風破浪,探索資料視覺化開發平臺 FlyFish 開源背後的祕密!
- 僅有 0.1M 可訓引數,AIOps 日誌異常檢測新正規化
- go-zero 微服務實戰系列(一、開篇)
- 開發者必讀:2022年移動應用出海趨勢洞察白皮書
- Zadig 面向開發者的自測聯調子環境技術方案詳解
- 碼住!基於深度學習的時間序列預測方法總結
- 運維領域告警智慧定級原理探索(含詳細實驗報告)
- jQuery 已經是時代的眼淚了嗎
- MySQL-Seconds_behind_master的精度誤差
- Go 專案配置檔案的定義和讀取
- 【架構視角】一篇文章帶你徹底吃透Spring 原 薦
- 金融級應用開發|SOFABoot 框架剖析
- Zadig 基於 OPA 實現 RBAC 和 ABAC 許可權管理技術方案詳解
- 英特爾開放 x86?事情恐怕沒這麼簡單……
- 收藏不讀系列:DSL 領域特定語言
- 一文帶你認識 SOFARegistry 之基礎架構篇
- .NET 20 週年:臨危受命阻擊 Java,見證微軟轉向開源
- Apache Druid 在 Shopee 的工程實踐