1. 程式人生 > 其它 >【五】golang實戰之配置中心

【五】golang實戰之配置中心

為什麼需要配置中心

  1. 新增配置
    1. 你現在的使用者服務有10個部署例項,那麼新增配置項你得去十個地方修改配置檔案還得重新啟動等
    2. 即使go的viper能完成修改配置檔案自動生效,那麼你得考慮其他語言是否也能做到這點,其他的服務是否也一定會使用viper
  2. 修改配置
    1. 大量的服務可能會使用同一個配置,比如我要更好jwt的secrect,這麼多例項需要統一更新
  3. 開發,測試,uat以及生產環境如何隔離

配置中心可以幫助我們解決以上問題,不需要手動更改每個例項的配置檔案,並且能夠快速方便的讀取到配置檔案線上更新。

安裝

docker run --name nacos-standalone -e MODE=standalone -e JVM_XMS=512m -e JVM_XMX=512m -e JVM_XMN=256m -p 8848:8848 -d nacos/nacos-server:latest

訪問需要http://192.168.0.102:8848/nacos/index.html,不能不帶後面的nacos/index.html,賬號和密碼為nacos和nacos

配置

按服務建立名稱空間

選擇好名稱空間後,建立配置檔案

將自己的配置按圖示填寫

同理把user-api的也釋出了

讀取配置

user-service

改造之前的配置結構體,新增json的tag,方便後面的解析

type DBConfig struct {
	Username          string `mapstructure:"username" json:"username"`
	Password          string `mapstructure:"password" json:"password"`
	Host              string `mapstructure:"host" json:"host"`
	Port              int    `mapstructure:"port" json:"port"`
	Dbname            string `mapstructure:"dbname" json:"dbname"`
	DefaultStringSize int    `mapstructure:"defaultStringSize" json:"defaultStringSize"`
	MaxIdleConn       int    `mapstructure:"maxIdleConn" json:"maxIdleConn"`
	MaxOpenConn       int    `mapstructure:"maxOpenConn" json:"maxOpenConn"`
}

type LogConfig struct {
	LogPath    string `mapstructure:"logPath" json:"logPath"`
	MaxSize    int    `mapstructure:"maxSize" json:"maxSize"`
	MaxBackups int    `mapstructure:"maxBackups" json:"maxBackups"`
	MaxAge     int    `mapstructure:"maxAge" json:"maxAge"`
	Level      string `mapstructure:"level" json:"level"`
}

type ServiceConfig struct {
	Host string `mapstructure:"host" json:"host"`
	Port int    `mapstructure:"port" json:"port"`
	Name string `mapstructure:"name" json:"name"`
	Id   string `mapstructure:"id" json:"id"`
	Tags string `mapstructure:"tags" json:"tags"`
}

type ConsulConfig struct {
	Host string `mapstructure:"host" json:"host"`
	Port int    `mapstructure:"port" json:"port"`
}

type NacosConfig struct {
	Host      string `mapstructure:"host"`
	Port      int    `mapstructure:"port"`
	User      string `mapstructure:"user"`
	Password  string `mapstructure:"password"`
	DataId    string `mapstructure:"dataId"`
	Namespace string `mapstructure:"namespace"`
	Group     string `mapstructure:"group"`
	Timeout   int    `mapstructure:"timeout"`
	LogLevel  string `mapstructure:"logLevel"`
	LogPath   string `mapstructure:"logPath"`
	CachePath string `mapstructure:"cachePath"`
}

單獨定義一個nacos的配置檔案

var (
	DB          *gorm.DB
	Config      *ServerTO
	NacosConfig *models.NacosConfig
)

type ServerTO struct {
	DBConfig *models.DBConfig      `mapstructure:"db" json:"db"`
	Log      *models.LogConfig     `mapstructure:"log" json:"log"`
	Service  *models.ServiceConfig `mapstructure:"service" json:"service"`
	Consul   *models.ConsulConfig  `mapstructure:"consul" json:"consul"`
}

func init() {
	Config = &ServerTO{
		DBConfig: &models.DBConfig{},
		Log:      &models.LogConfig{},
		Service:  &models.ServiceConfig{},
		Consul:   &models.ConsulConfig{},
	}
	NacosConfig = &models.NacosConfig{}
}

修改配置檔案

nacos:
  host: xx.xx.xx.xx
  port: xxx
  DataId: xxx
  Namespace: xxxxxxxxxxxx
  Group: xx
  Timeout: xxx
  LogLevel: xxx
  cachePath: xx/xx/xx
  logPath: xx/xx/xx

修改讀取配置檔案的函式

func InitConfig() {
	vp := viper.New()
	vp.AddConfigPath("configs/")
	vp.SetConfigName("config")
	vp.SetConfigType("yml")
	err := vp.ReadInConfig()
	if err != nil {
		panic(any(fmt.Sprintf("Read config failed:%v", err)))
	}
	err = vp.UnmarshalKey("nacos", &global.NacosConfig)
	if err != nil {
		panic(any(fmt.Sprintf("Read nacos failed:%v", err)))
	}
	sc := []constant.ServerConfig{
		{
			IpAddr:      global.NacosConfig.Host,
			Port:        uint64(global.NacosConfig.Port),
			ContextPath: "/nacos",
		},
	}
	cc := constant.ClientConfig{
		NamespaceId:         global.NacosConfig.Namespace,
		TimeoutMs:           uint64(global.NacosConfig.Timeout),
		NotLoadCacheAtStart: true,
		LogDir:              global.NacosConfig.LogPath,
		CacheDir:            global.NacosConfig.CachePath,
		LogLevel:            global.NacosConfig.LogLevel,
	}
	configClient, err := clients.CreateConfigClient(map[string]interface{}{
		"serverConfigs": sc, "clientConfig": cc,
	})
	if err != nil {
		panic(any(err))
	}
	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: global.NacosConfig.DataId,
		Group:  global.NacosConfig.Group,
	})
	if err != nil {
		panic(any(err))
	}
	err = json.Unmarshal([]byte(content), &global.Config)
	if err != nil {
		panic(any(fmt.Sprintf("Read config failed:%v", err)))
	}
}

另外,需要將nacos中的配置檔案由yaml轉為json,可以通過https://www.json2yaml.com/convert-yaml-to-json進行轉換。修改完畢之後如下所示

user-api

修改global檔案,除nacos之外的配置結構體新增json的tag

package global

import user "imooc/mxshop-api/api/user/v0"

var (
	Config     *ServerConfig
	Nacos      *NacosConfig
	UserClient user.UserServiceClient
)

type LogConfig struct {
	LogPath    string `mapstructure:"logPath" json:"logPath"`
	MaxSize    int    `mapstructure:"maxSize" json:"maxSize"`
	MaxBackups int    `mapstructure:"maxBackups" json:"maxBackups"`
	MaxAge     int    `mapstructure:"maxAge" json:"maxAge"`
	Level      string `mapstructure:"level" json:"level"`
}

type ServiceConfig struct {
	Host string `mapstructure:"host" json:"host"`
	Port int    `mapstructure:"port" json:"port"`
	Name string `mapstructure:"name" json:"name"`
}

type JwtConfig struct {
	SigningKey string `mapstructure:"key" json:"key"`
	Expire     int    `mapstructure:"expire" json:"expire"`
}

type RedisConfig struct {
	Host string `mapstructure:"host" json:"host"`
	Port int    `mapstructure:"port" json:"port"`
}

type SmsConfig struct {
	Template string `mapstructure:"code" json:"code"`
	Key      string `mapstructure:"key" json:"key"`
	Secret   string `mapstructure:"secret" json:"secret"`
	Expire   int    `mapstructure:"expire" json:"expire"`
	Domain   string `mapstructure:"domain" json:"domain"`
	Region   string `mapstructure:"region" json:"region"`
	Name     string `mapstructure:"name" json:"name"`
	Version  string `mapstructure:"version" json:"version"`
}

type ConsulConfig struct {
    Host string `mapstructure:"host" json:"host"`
	Port int    `mapstructure:"port" json:"port"`
}

type ServerConfig struct {
	Log         *LogConfig     `mapstructure:"log" json:"log"`
	Service     *ServiceConfig `mapstructure:"service" json:"service"`
	UserService *ServiceConfig `mapstructure:"user-service" json:"user-service"`
	Jwt         *JwtConfig     `mapstructure:"jwt" json:"jwt"`
	Sms         *SmsConfig     `mapstructure:"sms" json:"sms"`
	Redis       *RedisConfig   `mapstructure:"redis" json:"redis"`
}

func init() {
	Config = &ServerConfig{
		Log:         &LogConfig{},
		Service:     &ServiceConfig{},
		UserService: &ServiceConfig{},
		Jwt:         &JwtConfig{},
		Sms:         &SmsConfig{},
		Redis:       &RedisConfig{},
		Consul:      &ConsulConfig{},
	}
	Nacos = &NacosConfig{}
}

修改配置檔案

nacos:
  host: xx.xx.xx.xx
  port: xxx
  DataId: xxx
  Namespace: xxxxxxxxxxxx
  Group: xx
  Timeout: xxx
  LogLevel: xxx
  cachePath: xx/xx/xx
  logPath: xx/xx/xx

修改讀取配置檔案的函式

vp := viper.New()
	vp.AddConfigPath("configs/")
	vp.SetConfigName("config")
	vp.SetConfigType("yml")
	err := vp.ReadInConfig()
	if err != nil {
		panic(any(fmt.Sprintf("Read configs failed:%v", err.Error())))
	}
	err = vp.UnmarshalKey("nacos", &global.Nacos)
	if err != nil {
		panic(any(fmt.Sprintf("Read nacos configs failed:%v", err)))
	}
	sc := []constant.ServerConfig{
		{
			IpAddr:      global.Nacos.Host,
			Port:        uint64(global.Nacos.Port),
			ContextPath: "/nacos",
		},
	}
	cc := constant.ClientConfig{
		NamespaceId:         global.Nacos.Namespace,
		TimeoutMs:           uint64(global.Nacos.Timeout),
		NotLoadCacheAtStart: true,
		LogDir:              global.Nacos.LogPath,
		CacheDir:            global.Nacos.CachePath,
		LogLevel:            global.Nacos.LogLevel,
	}
	configClient, err := clients.CreateConfigClient(map[string]interface{}{
		"serverConfigs": sc, "clientConfig": cc,
	})
	if err != nil {
		panic(any(err))
	}
	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: global.Nacos.DataId,
		Group:  global.Nacos.Group,
	})
	if err != nil {
		panic(any(err))
	}
	err = json.Unmarshal([]byte(content), &global.Config)
	if err != nil {
		panic(any(fmt.Sprintf("Read config failed:%v", err)))
	}

修改main函式

	host, port, err := utils.FilterServiceByName(global.Config.UserService.Name)
	if err != nil {
		zap.S().Fatalw("FilterServiceByName", "name", global.Config.UserService.Name, "err", err)
		return
	}
	zap.S().Infof("init user-service at %s:%d", host, port)
	userConn := initialize.InitUserConnection(host, port)
	defer func() {
		if err := userConn.Close(); err != nil {
			panic(err.(any))
		}
	}()
	global.UserClient = user.NewUserServiceClient(userConn)
	zap.S().Info("user-api running...")

	addr := fmt.Sprintf("%s:%d", global.Config.Service.Host, global.Config.Service.Port)

將涉及到的配置修改的地方一一修改,然後將nacos中的配置格式更改為json格式後,即可啟動

至此,配置中心已經完成