18、分布式配置中心nacos

一、为什么需要分布式配置中心

在这里插入图片描述


二、配置中心选型

  • 目前主流的分布式配置中心:spring cloud config、apollo和nacos;spring cloud config属于java的spring体系,我们就考虑apollo和nacos
  • apollo和nacos:apollo是携程开源、nacos是阿里开源
    • a、apollo大而全,功能完善;nacos小而全,可以对比成django和flask的区别
    • b、部署nacos更加简单
    • c、nacos不止支持配置中心还支持服务注册和发现
    • d、都支持各种语言,不过apollo是第三方支持的,nacos是官方支持各种语言
  • nacos官网https://nacos.io/zh-cn/
  • apollo的git地址https://github.com/apolloconfig/apollo
  • apollo和nacos功能对比
功能点apollonacos
开源时间2016.52018.6
配置实时推送支持(http长轮询)支持(http长轮询)
配置回滚支持支持
灰度发布支持待支持
权限管理支持支持
多集群支持支持
监听查询支持支持
多语言主流语言主流语言(官方支持)
通讯协议httphttp

三、nacos安装与访问


四、api获取nacos配置

1 - nacos配置

  • 需要新建一个命名空间users

在这里插入图片描述

  • 在users命名空间下为之前的user_web和user_srv添加配置集:因为有dev和pro,所以需要新建4个配置集

在这里插入图片描述
在这里插入图片描述

2 - go nacos

package main

import (
	"fmt"
	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"time"
)

func main() {
	sc := []constant.ServerConfig{
		{
			IpAddr: "192.168.124.51",
			Port:   8848,
		},
	}

	// 创建clientConfig
	cc := constant.ClientConfig{
		NamespaceId:         "90dec033-6f9a-4ab2-97e5-fd60de1743c9", // 如果需要支持多namespace,我们可以场景多个client,它们有不同的NamespaceId。当namespace是public时,此处填空字符串。
		TimeoutMs:           5000,
		NotLoadCacheAtStart: true,
		LogDir:              "tmp/nacos/log", //去掉tmp前面的/,这样就会默认保存到当前项目目录下
		CacheDir:            "tmp/nacos/cache",
		LogLevel:            "debug",
	}

	configClient, err := clients.CreateConfigClient(map[string]interface{}{
		"serverConfigs": sc,
		"clientConfig":  cc,
	})
	if err != nil {
		panic(err)
	}

	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: "user_web.yaml",
		Group:  "dev"})

	if err != nil {
		panic(err)
	}
	fmt.Println(content) //字符串 - yaml

	//监听配置修改
	err = configClient.ListenConfig(vo.ConfigParam{
		DataId: "user_web.yaml",
		Group:  "dev",
		OnChange: func(namespace, group, dataId, data string) {
			fmt.Println("配置文件变化")
			fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
		},
	})
	time.Sleep(3000 * time.Second)
}

在这里插入图片描述

  • CacheDir的作用
    • 配置了CacheDir的时候,本地项目下会生成CacheDir的目录
    • 假设nacos的ip地址我们配置错误,无法访问nacos;如果我们有配置CachaDir,那么就会读取本地配置信息

在这里插入图片描述


五、gin集成nacos

1 - nacos配置映射成go的struct

  • 需求分析:因为go本身集成了json,而yaml需要使用第三方库,我们直接将之前的配置修改为json
  • YAML TO JSON在线转换http://json2yaml.com/convert-yaml-to-json
    在这里插入图片描述
  • nacos中添加user_web.json配置集
    在这里插入图片描述
{
  "name": "user_web",
  "port": 8081,
  "user_srv": {
    "host": "127.0.0.1",
    "port": 50051,
    "name": "user_srv"
  },
  "jwt": {
    "key": "VYLDYq3&hGWjWqF$K1ih"
  },
  "sms": {
    "key": "",
    "secrect": ""
  },
  "redis": {
    "host": "192.168.124.51",
    "port": 6379,
    "expire": 300
  },
  "consul": {
    "host": "192.168.124.51",
    "port": 8500
  }
}

2 - user_web读取nacos的config

  • user_web/config/config.go:添加NacosConfig对象
package config

type UserSrvConfig 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"`
}

type AliSmsConfig struct {
	ApiKey     string `mapstructure:"key" json:"key"`
	ApiSecrect string `mapstructure:"secrect" json:"secrect"`
}

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

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

type ServerConfig struct {
	Name        string        `mapstructure:"name" json:"name"`
	Port        int           `mapstructure:"port" json:"port"`
	UserSrvInfo UserSrvConfig `mapstructure:"user_srv" json:"user_srv"`
	JWTInfo     JWTConfig     `mapstructure:"jwt" json:"jwt"`
	AliSmsInfo  AliSmsConfig  `mapstructure:"sms" json:"sms"`
	RedisInfo   RedisConfig   `mapstructure:"redis" json:"redis"`
	ConsulInfo  ConsulConfig  `mapstructure:"consul" json:"consul"`
}

type NacosConfig struct {
	Host      string `mapstructure:"host"`
	Port      uint64 `mapstructure:"port"`
	Namespace string `mapstructure:"namespace"`
	User      string `mapstructure:"user"`
	Password  string `mapstructure:"password"`
	DataId    string `mapstructure:"dataid"`
	Group     string `mapstructure:"group"`
}

  • user_web/global/global.go:添加全局NacosConfig对象
package global

import (
	ut "github.com/go-playground/universal-translator"

	"web_api/user_web/config"
	"web_api/user_web/proto"
)

var (
	Trans         ut.Translator
	ServerConfig  *config.ServerConfig = &config.ServerConfig{}
	UserSrvClient proto.UserClient

	NacosConfig *config.NacosConfig = &config.NacosConfig{}
)

  • yaml修改为nacos的配置
//config_debug.yaml
host: '192.168.124.51'
port: 8848
namespace: '90dec033-6f9a-4ab2-97e5-fd60de1743c9'
user: 'nacos'
password: 'nacos'
dataid: 'user_web.json'
group: 'dev'
//config_pro.yaml
host: '192.168.124.51'
port: 8848
namespace: '90dec033-6f9a-4ab2-97e5-fd60de1743c9'
user: 'nacos'
password: 'nacos'
dataid: 'user_web.json'
group: 'pro'
  • user_web/initialize/init_config.go
    • 读取nacos的配置
    • 通过nacos到配置中心读取并映射成ServerConfig
package initialize

import (
	"encoding/json"
	"fmt"

	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"github.com/spf13/viper"
	"go.uber.org/zap"

	"web_api/user_web/global"
)

func GetEnvInfo(env string) bool {
	viper.AutomaticEnv()
	return viper.GetBool(env)
	//刚才设置的环境变量 想要生效 我们必须得重启goland
}

func InitConfig() {
	debug := GetEnvInfo("DEV_CONFIG")
	configFilePrefix := "config"
	configFileName := fmt.Sprintf("user_web/%s_pro.yaml", configFilePrefix)
	if debug {
		configFileName = fmt.Sprintf("user_web/%s_debug.yaml", configFilePrefix)
	}

	v := viper.New()
	//文件的路径如何设置
	v.SetConfigFile(configFileName)
	if err := v.ReadInConfig(); err != nil {
		panic(err)
	}
	//这个对象如何在其他文件中使用 - 全局变量
	if err := v.Unmarshal(&global.NacosConfig); err != nil {
		panic(err)
	}
	zap.S().Infof("配置信息: %v", global.NacosConfig)

	//从nacos中读取配置信息
	sc := []constant.ServerConfig{
		{
			IpAddr: global.NacosConfig.Host,
			Port:   global.NacosConfig.Port,
		},
	}

	cc := constant.ClientConfig{
		NamespaceId:         global.NacosConfig.Namespace, // 如果需要支持多namespace,我们可以场景多个client,它们有不同的NamespaceId
		TimeoutMs:           5000,
		NotLoadCacheAtStart: true,
		LogDir:              "tmp/nacos/log",
		CacheDir:            "tmp/nacos/cache",
		LogLevel:            "debug",
	}

	configClient, err := clients.CreateConfigClient(map[string]interface{}{
		"serverConfigs": sc,
		"clientConfig":  cc,
	})
	if err != nil {
		panic(err)
	}

	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: global.NacosConfig.DataId,
		Group:  global.NacosConfig.Group})

	if err != nil {
		panic(err)
	}
	//fmt.Println(content) //字符串 - yaml
	//想要将一个json字符串转换成struct,需要去设置这个struct的tag
	err = json.Unmarshal([]byte(content), &global.ServerConfig)
	if err != nil {
		zap.S().Fatalf("读取nacos配置失败: %s", err.Error())
	}
	fmt.Println(&global.ServerConfig)
}

在这里插入图片描述


六、service集成nacos

1 - 配置nacos

在这里插入图片描述

2 - user_srv读取nacos的config

  • yaml修改为nacos的配置
//config_debug.yaml
host: '192.168.124.51'
port: 8848
namespace: '90dec033-6f9a-4ab2-97e5-fd60de1743c9'
user: 'nacos'
password: 'nacos'
dataid: 'user_srv.json'
group: 'dev'

//config_pro.yaml
host: '192.168.124.51'
port: 8848
namespace: '90dec033-6f9a-4ab2-97e5-fd60de1743c9'
user: 'nacos'
password: 'nacos'
dataid: 'user_srv.json'
group: 'pro'
  • user_srv/config/config.go:新增NacosConfig对象
package config

type MysqlConfig struct {
	Host     string `mapstructure:"host" json:"host"`
	Port     int    `mapstructure:"port" json:"port"`
	Name     string `mapstructure:"db" json:"db"`
	User     string `mapstructure:"user" json:"user"`
	Password string `mapstructure:"password" json:"password"`
}

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

type ServerConfig struct {
	Name       string       `mapstructure:"name" json:"name"`
	MysqlInfo  MysqlConfig  `mapstructure:"mysql" json:"mysql"`
	ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`
}

type NacosConfig struct {
	Host      string `mapstructure:"host"`
	Port      uint64 `mapstructure:"port"`
	Namespace string `mapstructure:"namespace"`
	User      string `mapstructure:"user"`
	Password  string `mapstructure:"password"`
	DataId    string `mapstructure:"dataid"`
	Group     string `mapstructure:"group"`
}

  • user_srv/global/global.go:添加全局对象NacosConfig
package global

import (
	"gorm.io/gorm"
	"nd/user_srv/config"
)

var (
	DB           *gorm.DB
	ServerConfig config.ServerConfig
	NacosConfig  config.NacosConfig
)

  • user_srv/initialize/init_config.go
    • 读取nacos的配置
    • 通过nacos到配置中心读取并映射成ServerConfig
package initialize

import (
	"encoding/json"
	"fmt"
	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"github.com/spf13/viper"
	"go.uber.org/zap"

	"nd/user_srv/global"
)

func GetEnvInfo(env string) bool {
	viper.AutomaticEnv()
	return viper.GetBool(env)
	//刚才设置的环境变量 想要生效 我们必须得重启goland
}

func InitConfig() {
	//从配置文件中读取出对应的配置
	debug := GetEnvInfo("DEV_CONFIG")
	configFilePrefix := "config"
	configFileName := fmt.Sprintf("%s_pro.yaml", configFilePrefix)
	if debug {
		configFileName = fmt.Sprintf("%s_debug.yaml", configFilePrefix)
	}

	v := viper.New()
	//文件的路径如何设置
	v.SetConfigFile(configFileName)
	if err := v.ReadInConfig(); err != nil {
		panic(err)
	}
	//这个对象如何在其他文件中使用 - 全局变量
	if err := v.Unmarshal(&global.NacosConfig); err != nil {
		panic(err)
	}
	zap.S().Infof("配置信息: %v", global.NacosConfig)

	//从nacos中读取配置信息
	sc := []constant.ServerConfig{
		{
			IpAddr: global.NacosConfig.Host,
			Port:   global.NacosConfig.Port,
		},
	}

	cc := constant.ClientConfig{
		NamespaceId:         global.NacosConfig.Namespace, // 如果需要支持多namespace,我们可以场景多个client,它们有不同的NamespaceId
		TimeoutMs:           5000,
		NotLoadCacheAtStart: true,
		LogDir:              "tmp/nacos/log",
		CacheDir:            "tmp/nacos/cache",
		LogLevel:            "debug",
	}

	configClient, err := clients.CreateConfigClient(map[string]interface{}{
		"serverConfigs": sc,
		"clientConfig":  cc,
	})
	if err != nil {
		panic(err)
	}

	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: global.NacosConfig.DataId,
		Group:  global.NacosConfig.Group})

	if err != nil {
		panic(err)
	}
	//fmt.Println(content) //字符串 - yaml
	//想要将一个json字符串转换成struct,需要去设置这个struct的tag
	err = json.Unmarshal([]byte(content), &global.ServerConfig)
	if err != nil {
		zap.S().Fatalf("读取nacos配置失败: %s", err.Error())
	}
	fmt.Println(&global.ServerConfig)
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


七、完整源码

mxshop_srvsV8.0.rar

  • 附录:资源包含了YApi的json导入,nacos的配置集导入
    • user_srv/main.go:健康监查与注册对象的ip地址需要修改为本机的ip地址
      在这里插入图片描述
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无休止符

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值