• 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)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    在这里插入图片描述

    • 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
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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"`
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 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{}
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 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'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 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)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    在这里插入图片描述


    六、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'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 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"`
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 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
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 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)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    在这里插入图片描述

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


    七、完整源码

    mxshop_srvsV8.0.rar

    • 附录:资源包含了YApi的json导入,nacos的配置集导入
      • user_srv/main.go:健康监查与注册对象的ip地址需要修改为本机的ip地址
        在这里插入图片描述
  • 相关阅读:
    学习笔记
    系统架构设计:11 论湖仓一体架构及其应用
    【Linux】Linux进程控制
    国产操作系统之银河麒麟服务器版V10安装
    STM32 HAL库 串口使用问题记录
    qtdesigner的一些实用设置
    手把手带你刷好题(牛客刷题⑤)
    SQL注入绕过安全狗的waf防火墙,这一篇就够了,8k文案超详细
    Python | 安装、环境配置及包的安装
    java ssm企业员工健康管理系统#计算机毕业设计
  • 原文地址:https://blog.csdn.net/qq23001186/article/details/126083648