自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

微服務(wù)配置中心, 這個(gè)方案 Go 里用起來不輸 SpringCloud

開發(fā) 架構(gòu)
今天給大家講了微服務(wù)配置中心的實(shí)現(xiàn)方案,先介紹了下 SpringCloudConfig 標(biāo)準(zhǔn)下的使用方案,因?yàn)镾pring生態(tài)比較完整,對這方面支持的比較好,像ETCD、Consul甚至Git什么的都支持拿來做配置中心。

微服務(wù)架構(gòu)設(shè)計(jì)模式里有一條講到,要設(shè)計(jì)可配置的服務(wù)。把服務(wù)從單體架構(gòu)細(xì)分成微服務(wù)后,所有配置屬性都集中存儲在一個(gè)位置,更易于管理。這個(gè)集中存儲管理配置的地方,就是配置中心。

使用配置中心還有一個(gè)好處就是,往往都支持應(yīng)用配置的熱更新,這樣就不需要像修改本地配置那樣進(jìn)行發(fā)版部署了。

但是這么好的事兒就沒有缺點(diǎn)了嗎?當(dāng)然有,除非有基礎(chǔ)設(shè)施支持,否則它需要額外的人力進(jìn)行設(shè)計(jì)和運(yùn)維。不過好在有各種開源框架比如 Spring Cloud Config,能使服務(wù)接入配置中心,沒有什么侵入性。至少在表面使用上感覺不到有變化。

那么在 Go 里有沒有類似的方案呢?經(jīng)過我這周的試驗(yàn)探索,還真發(fā)現(xiàn)了,這個(gè)方案落地也很簡單,今天就跟大家簡單說說。更詳細(xì)的還得是大家上手操作起來才能感受到,本方案涉及的代碼太多,可以給我的公眾號:網(wǎng)管叨bi叨,發(fā)送消息【go-config】獲取項(xiàng)目下載地址。

分享軟件開發(fā)和系統(tǒng)架構(gòu)設(shè)計(jì)基礎(chǔ)、Go 語言和Kubernetes。

有人可能會說遠(yuǎn)程配置中心,我就把配置放在 ETCD 上,項(xiàng)目啟動的時(shí)候拉下來不就行了?先別著急,咱先看看隔壁家 Spring 是怎么實(shí)現(xiàn)這個(gè)事兒,有沒有我們可以學(xué)習(xí)的地方。

Spring 的配置和配置中心

用過 Spring 的同學(xué)都接觸過,在 Java 的項(xiàng)目里都有一個(gè)resources?目錄,這個(gè)目錄里一般都會有類似名字叫application.properties 的配置文件。

圖片

配置文件

也有可能配置文件的后綴名是.yaml?,那么屬性配置的格式就是YAML格式的。

在這些配置文件里設(shè)置的屬性配置,都可以通過可以通過@Value注解注入到對象的屬性上,比如假設(shè)我們在配置文件里設(shè)定了訂單的折扣為95折的配置

order:
discount: 95

那在代碼里,我們就能像下面這樣,把屬性配置的值綁定到類實(shí)例的屬性上:

public class CoffeeOrderController {

@Value("${order.discount}")
private Integer discount;

......
}

后來,因?yàn)槲⒎?wù)流行起來了,大家又對自己的服務(wù)拆得樂此不疲,所以 Spring 家族里后來又有了 SpringCloud,像我們知道的知名廠商 Alibaba、Netflix 都按它這個(gè)標(biāo)準(zhǔn)開源自己內(nèi)部使用的組件,就有了我們天天看到的各種資料推廣文里面的 SpringCloud-Netflix,SpringCloud- Alibaba這些。

SpringCloud- Alibaba在國內(nèi)因?yàn)榘⒗锏年P(guān)系使用更廣泛一些,它里面提供的配置中心方案是一個(gè)叫 Nacos 的組件,因?yàn)橛?SpringCloudConfig 這個(gè)標(biāo)準(zhǔn)存在,不管各個(gè)廠商的遠(yuǎn)程配置中心是用什么組件,都需要實(shí)現(xiàn) SpringCloudConfig 里的標(biāo)準(zhǔn)。

最直觀的好處就是,比如說我把應(yīng)用的屬性配置放到了遠(yuǎn)程的 Nacos 上,比如這樣:

圖片

遠(yuǎn)程配置中心 Nacos

但是在應(yīng)用程序我們?nèi)匀豢梢岳^續(xù)使用 @Value注解拿到放在遠(yuǎn)程配置中心的屬性值。如果本地和遠(yuǎn)程配置中心都有的話,以本地磁盤里的配置優(yōu)先。

是不是很方便?這就類似應(yīng)用里使用的是一個(gè)門面模式,下層加載使用的組件提供的driver來完成項(xiàng)目配置的載入。

那在 Go 里面有沒有類似的方案呢?有,雖然沒有 SpringCloud 這個(gè)支持的組件那么全,但是支持 ETCD 和 Consul 做配置中心,也夠用了。

Go 項(xiàng)目的配置和配置中心

聊到 Go 項(xiàng)目的配置和配置中心,我見過的幾十個(gè)項(xiàng)目里,是的,前幾年待過的兩個(gè)拿融資多的創(chuàng)業(yè)公司里,項(xiàng)目就是很多,不停地嘗試各種方向的業(yè)務(wù),不然投資人那不好說啊,咳咳。有的,做做沒有效果就放棄了 T—_—T。

說回來,咱們配置的事兒,在這幾十個(gè)項(xiàng)目里基本上分成兩大派,有用 Viper 或者另一個(gè)Yaml開源庫直接操作本地文件的。還有一派是直接讀 ETCD ,拿下來把字節(jié)流轉(zhuǎn)到本地配置對象的。

那有沒有一種方案能兼容本地配置和遠(yuǎn)程配置中心兩種模式的?

我看了一下 Viper 是支持從遠(yuǎn)程 ETCD 或者 Consul 取配置的。

但是呢,經(jīng)過我的試驗(yàn),發(fā)現(xiàn)官網(wǎng)的給的例子有BUG,從 ETCD 上根本讀不了配置,更別提熱更新了,這點(diǎn)我們先按下不表,我先給大家介紹下 Viper 的基本使用。

主要是我也沒從頭用過,以前用的項(xiàng)目架子里是別人搭好的,哈哈~,不過你們面試的時(shí)候可別這么說大實(shí)話,今天看完我的文章,至少配置中心這塊的架構(gòu)選型,我是可以吹吹的,你們呢?

怎么安裝 Viper 包什么的,我就不說了,官網(wǎng)上都有,文末會附上官網(wǎng)的鏈接,下面直接上代碼。假如,不是假如,我真在項(xiàng)目配置文件里寫了個(gè)數(shù)據(jù)庫連接信息的YAML配置。

database:
type: mysql
dsn: "user:pass@tcp(localhost:30306)/db_name?charset=utf8&parseTime=True&loc=Local"
maxopen: 100
maxidle: 10
maxlifetime: 300

然后用 Viper 怎么讀這個(gè)配置呢?這里直接在配置文件目錄下用一個(gè) Go 的 init 函數(shù),在函數(shù)里把配置用 Viper 反序列化到一個(gè)全局變量里,供項(xiàng)目使用。

type databaseConfig struct {// 配置屬性跟類型字段不同名是要加下面這個(gè)tag
Type string `mapstructure:"type"`
DSN string `mapstructure:"dsn"`
MaxOpenConn int `mapstructure:"maxopen""`
MaxIdleConn int `mapstructure:"maxidle"`
MaxLifeTime time.Duration `mapstructure:"maxlifetime"`
}
var Database *databaseConfig

func init() {
// 獲取當(dāng)前文件的路徑
_, filename, _, _ := runtime.Caller(0)
// 配置文件目錄的路徑
configBaseDir := path.Dir(filename)
vp := viper.New()
vp.AddConfigPath(configBaseDir)
vp.SetConfigType("yaml")
err := vp.ReadInConfig()
if err != nil {
panic(err)
}
vp.UnmarshalKey("database", &Database)
Database.MaxLifeTime *= time.Second
}

除了把配置項(xiàng)反序列化到結(jié)構(gòu)體類型里,還能通過類似 Spring 里的@Value那種方式讀單個(gè)配置項(xiàng)的值。

vp.Get("database.type")

不過我更傾向于反序列化到結(jié)構(gòu)體這種方式,使用起來更方便,同時(shí)熱更新配置時(shí)這種方式也更方便些。

項(xiàng)目里實(shí)例化數(shù)據(jù)庫連接的時(shí)候,就可以像這樣,用上我們的配置啦。

// 具體完整實(shí)例代碼,實(shí)在太多
// 請給我的公眾號:網(wǎng)管叨bi叨,發(fā)送消息【go-config】來領(lǐng)取。
db, err := gorm.Open(config.Database.Type, config.Database.DSN)
if err != nil {
panic(err)
}
db.DB().SetMaxOpenConns(config.Database.MaxOpenConn)
db.DB().SetMaxIdleConns(config.Database.MaxIdleConn)
db.DB().SetConnMaxLifetime(config.Database.MaxLifeTime)
if err = db.DB().Ping(); err != nil {
panic(err)
}

下面我們接著來說,Viper 使用遠(yuǎn)程配置中心的情況。這里我給大家安利下我的 ETCD 集群 K8s 搭建教程:用Kubernetes搭建Etcd集群和WebUI,不然如果你本地沒有 ETCD 的話,不太好實(shí)踐,除非…你嚯嚯下你們公司測試環(huán)境的ETCD,嘿嘿,保命要緊,還是在自己電腦上搭建吧。

另外安利下我的 K8s 教程,上面用的Nacos也是我用 K8s 搭建的,在教程里都有,在公眾號網(wǎng)管叨bi叨回復(fù)k8s就能拿到教程,絕對實(shí)用。

下面我們給項(xiàng)目加一個(gè) redis 連接信息的配置

redis:
address: "localhost:6579"
password: "DFgsdfhshf"
dbnumber: 0
maxactive: 100
maxidle: 20

把這個(gè)配置放到遠(yuǎn)程的ETCD 配置中心里:

圖片

ETCD 中的配置

后來我按照官網(wǎng)的例子,死活讀不到我這個(gè)key 對應(yīng)的配置,在網(wǎng)上查了一下,究其原因,是因?yàn)?Viper 依賴 crypt 庫,而 crypt 截至目前還不支持新版 ETCD 的 API。

ETCD 的 KV 中可以存儲加密的數(shù)據(jù),Viper 在獲取的時(shí)候通過 crypt 自動解密,這個(gè)初衷是好的,但是公司里的配置中心基本上都是內(nèi)網(wǎng)訪問,再則加密存儲的話,我就不能像上面這樣直接在客戶端里進(jìn)行KV編輯了,有什么辦法呢?

看網(wǎng)上有技術(shù)大佬分析,可以通過重新實(shí)現(xiàn)remoteConfigFactory接口;

type remoteConfigFactory interface {
Get(rp RemoteProvider) (io.Reader, error)
Watch(rp RemoteProvider) (io.Reader, error)
WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
}

這個(gè)接口的具體實(shí)現(xiàn)我就不放上來了實(shí)在是太多,可以自己下載項(xiàng)目去看,下載鏈接獲取方式,給我的公眾號「網(wǎng)管叨bi叨」發(fā)送消息【go-config】獲取項(xiàng)目下載鏈接。

使用 Viper 讀取遠(yuǎn)程配置,還需要匿名導(dǎo)入它提供的一個(gè)庫。

_ "github.com/spf13/viper/remote"

下面演示一下使用 Viper 讀取遠(yuǎn)程配置和熱更新配置的代碼。

type RedisConfig struct {
Address string `mapstructure:"address"`
Password string `mapstructure:"password"`
DbNumber int `mapstructure:"dbnumber"`
MaxActive int `mapstructure:"maxactive"`
MaxIdle int `mapstructure:"maxidle"`
}
var Redis *RedisConfig

func init() {
// 初始化 Viper 和上面例子里的一樣,這里省略
...
代碼里省略一切error處理
// 告訴Viper遠(yuǎn)程ETCD里的KV在哪里找
err := vp.AddRemoteProvider("etcd", "http://127.0.0.1:32379", "root/config/viper-test/config")
vp.SetConfigType("yaml")
err = vp.ReadInConfig()
err = vp.ReadRemoteConfig()
vp.UnmarshalKey("database", &Database)
Database.MaxLifeTime *= time.Second
vp.UnmarshalKey("redis", &Redis)
// 這里簡單輸出一下 redis 的配置,就不做其他演示了
fmt.Printf("Redis Config: %v\n", Redis)
// 監(jiān)聽KV變更,進(jìn)行熱更新
go watchRemoteConfig(vp)
}

監(jiān)聽配置變更,進(jìn)行熱更新這塊,我暫時(shí)實(shí)現(xiàn)的簡單點(diǎn),用了下輪詢,后面有好的方法了再更新。

func watchRemoteConfig(vp *viper.Viper) {
for {
time.Sleep(5 * time.Second)
err := vp.WatchRemoteConfigOnChannel()
if err != nil {
zlog.Error("Read Config Server Error", zap.Error(err))
return
}
// 監(jiān)控遠(yuǎn)程配置的變更
vp.UnmarshalKey("redis", &Redis)
fmt.Printf("Redis Config: %v\n", Redis)
}
}

這里演示的配置熱更新我就是簡單向控制臺輸出了一下 Redis 的配置,啟動后我試了一下,在ETCD里把配置修改后能直接在項(xiàng)目里變更過來,下面是我把Redis配置的端口從 6579 改成 6580 的一個(gè)演示。

圖片

配置動態(tài)更新

總結(jié)

今天給大家講了微服務(wù)配置中心的實(shí)現(xiàn)方案,先介紹了下 SpringCloudConfig 標(biāo)準(zhǔn)下的使用方案,因?yàn)镾pring生態(tài)比較完整,對這方面支持的比較好,像ETCD、Consul甚至Git什么的都支持拿來做配置中心。

Go 里邊的 Viper 庫也很強(qiáng)大,只是用 Etcd 當(dāng)配置中心的時(shí)候需要我們自己做些擴(kuò)展,雖然沒有那么開箱即用,但是研究問題動手解決的過程還是很有意思的。

對了,Viper 支持同時(shí)使用本地和遠(yuǎn)程配置,本地配置優(yōu)先級高于遠(yuǎn)程,大家不要弄混了。

這里我再給個(gè)建議像是服務(wù)器啟動參數(shù) server.port,application.name這類幾乎是項(xiàng)目創(chuàng)建完后就不會再改的配置,放在本地配置文件就好。

責(zé)任編輯:武曉燕 來源: 網(wǎng)管叨bi叨
相關(guān)推薦

2021-06-30 09:20:18

NuShell工具Linux

2021-09-18 08:52:45

人工智能

2020-01-06 13:42:29

Linux極客腳本語言

2021-01-04 09:35:55

微服務(wù)架構(gòu)配置中心

2018-04-20 07:22:59

物聯(lián)網(wǎng)互聯(lián)網(wǎng)IoT

2025-01-13 00:00:07

Go語言微服務(wù)

2021-03-10 09:54:43

RustNuShell系統(tǒng)

2020-12-08 11:20:43

Windows微軟數(shù)據(jù)

2024-12-10 08:27:28

2021-01-14 09:55:21

Java微服務(wù)Go

2024-07-04 11:33:33

2012-07-11 09:34:39

微軟云計(jì)算

2022-05-22 21:16:46

TypeScriptOmit 工具

2019-04-15 13:52:18

微服務(wù)配置中心Apollo

2020-01-22 16:29:52

機(jī)器學(xué)習(xí)人工智能計(jì)算機(jī)

2022-05-09 08:56:27

Go淺拷貝接口

2022-08-29 06:27:15

Nacos微服務(wù)

2021-03-09 09:33:42

網(wǎng)關(guān)授權(quán)微服務(wù)

2024-05-21 10:28:51

API設(shè)計(jì)架構(gòu)

2021-04-22 09:31:58

服務(wù)器微服務(wù)配置
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號