• nacos配置中心docker部署、配置及 goLang 集成使用


    为什么需要配置中心

    平时我们写一个demo的时候,或者说一个单体的应用,都会有一个配置文件,不管是 json文件或者yaml文件,里面包含了redis,mysql,es等信息,如果我们修改了配置文件,往往我们需要重启,为了避免重启,后来引入了viper,可以实现热更新。但并不是所有的项目都支持viper。 如果是一个分布式系统,肯定是有很多服务模块做支撑的,而且服务是可伸缩的,可能有几十台服务,也可能有几百台服务。如果每个服务模块下面都有自己的配置文件,那么如果mysql更新了端口号,运维人员就得一个一个文件的改。而且还可能不小心出错了。

    所以综上,对于服务的配置,大概有这么三个痛点

    • 修改配置项后需要重启服务,对于生产环境来说,这是不能接受的。
    • 运维人员需要到各个项目下修改配置文件。效率低,不安全。
    • 一般公司中都有开发环境、测试环境、预生产环境以及生产环境。不同环境下的配置如何隔离?

    为了解决上面的问题,配置中心应运而生。那么什么是配置中心呢?

    配置中心

    • 配置统一管理 配置项的修改编辑统一在配置中心页面进行,还包括统一的配置版本管理、环境隔离、灰度发布以及热发布,在不重启应用的情况下使得修改的配置可以生效起作用。
    • 权限统一控制 主要控制其配置的读取权限以及修改权限,通过统一的权限管理提升运维效率。
    • 操作统一审计 记录用户操作修改配置的历史信息,这样在出现问题的时候可以进行复盘回查,同时进行操作审计。

    配置中心的选型

    目前最主流的分布式配置中心主要是有spring cloud config apollo和nacos,spring cloud属于java的spring体系,我们就考虑apollo和nacos。apollo与nacos 都为目前比较流行且维护活跃的2个配置中心。apollo是协程开源,nacos是阿里开源

    • apollo大而全,功能完善。nacos小而全,可以对比成diango和flask的区别
    • 部署nacos更加简单。
    • nacos不止支持配置中心还支持服务注册和发现。
    • 都支持各种语言,不过apollo是第三方支持的,nacos是官方支持各种语言,所以我们也选用nacos作为配置中心

    Nacos

    • 安装 为了方便,我们直接使用docker开启Nacos服务
    1. docker run -d --name nacos -p 8848:8848 --privileged=true -e JVM_XMS=256m -e JVM_XMX=256m -e MODE=standalone nacos/nacos-server:latest
    • -d 后台启动
    • --name 为容器指定名称
    • -p指定端口号
    • –privileged=true : 扩大容器内的权限,将容器内的权限变为root权限
    • -e JVM_XMS=256m : 为jvm启动时分配的内存
    • -e JVM_XMX=256m : 为jvm运行过程中分配的最大内存
    • -e MODE=standalone : 使用 standalone模式(单机模式),MODE值有cluster(集群)模式/standalone模式两种,MODE必须大写

    控制台

    • 启动后访问http://127.0.0.1:8848/nacos/

    组 配置集 命名空间

    我们新建一个配置看一下

    命名空间

    • 我们可以通过命名空间区分不同的微服务

    • 我们通过命名空间可以实现服务的隔离,但是我们怎么把开发、测试和生成环境的配置也隔离起来呢。这就用到了组

    dataid

    • 一般来说,一个配置文件,对应一个dataid,单并不是说dataid必须是唯一的,我们只要保证Namespace+Group+DataId组合是唯一的即可

    通过api访问nacos

    相关参考

    • nacos作为配置中心,我们最长用的就是下面几个功能

    • 此处我们举一个例子,获取user的dev的配置文件,其中dataId对应的就是dataId,group是分组,tenant是命名空间的id
    1. $ curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=user-dev&group=dev&tenant=311387f1-790b-4045-8787-571addb6c9fd'
    2. database:
    3. driver: mysql
    4. host: 192.168.2.251
    5. port: 13309
    6. username: test
    7. dbname: cnk_user
    8. password: user
    • 更新文件
    1. $ curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=user-dev&group=dev&tenant=311387f1-790b-4045-8787-571addb6c9fd&content=test'
    2. true

    在这里插入图片描述

    在Go中的集成

    • 我们在go中怎么使用呢?我们看一下简单的代码
    1. package main
    2. import (
    3. "fmt"
    4. "github.com/nacos-group/nacos-sdk-go/clients"
    5. "github.com/nacos-group/nacos-sdk-go/common/constant"
    6. "github.com/nacos-group/nacos-sdk-go/vo"
    7. )
    8. func main() {
    9. ch:=make(chan int)
    10. ch<-1
    11. }
    12. func init() {
    13. sc := []constant.ServerConfig{{
    14. IpAddr: "127.0.0.1",
    15. Port: 8848,
    16. }}
    17. cc := constant.ClientConfig{
    18. NamespaceId: "311387f1-790b-4045-8787-571addb6c9fd", // 如果需要支持多namespace,我们可以场景多个client,它们有不同的NamespaceId。当namespace是public时,此处填空字符串。
    19. TimeoutMs: 5000,
    20. NotLoadCacheAtStart: true,
    21. LogDir: "log",
    22. CacheDir: "cache",
    23. LogLevel: "debug",
    24. }
    25. configClient, err := clients.CreateConfigClient(map[string]interface{}{
    26. "serverConfigs": sc,
    27. "clientConfig": cc,
    28. })
    29. if err != nil {
    30. fmt.Println(err.Error())
    31. }
    32. content, err := configClient.GetConfig(vo.ConfigParam{
    33. DataId: "user-dev",
    34. Group: "dev",
    35. })
    36. if err != nil {
    37. fmt.Println(err.Error())
    38. }
    39. fmt.Println(content) //字符串 - yaml
    40. err = configClient.ListenConfig(vo.ConfigParam{
    41. DataId: "user-dev",
    42. Group: "dev",
    43. OnChange: func(namespace, group, dataId, data string) {
    44. fmt.Println("配置文件发生了变化...")
    45. fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
    46. },
    47. })
    48. }
    • 我们通过api去修改配置文件
    1. $ curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=user-dev&group=dev&tenant=311387f1-790b-4045-8787-571addb6c9fd&content=test1111'
    2. true
    • 看到修改的文件已经被监控到了

    • 那么我们怎么解析和修改yaml文件呢?比如我们现在有这样一个配置

    • 我们先把它解析成一个结构体,再进行解析
    1. package main
    2. import (
    3. "fmt"
    4. "github.com/nacos-group/nacos-sdk-go/clients"
    5. "github.com/nacos-group/nacos-sdk-go/common/constant"
    6. "github.com/nacos-group/nacos-sdk-go/vo"
    7. "gopkg.in/yaml.v2"
    8. )
    9. func main() {
    10. ch := make(chan int)
    11. ch <- 1
    12. }
    13. type DatabaseNew struct {
    14. Driver string `yaml:"driver"`
    15. Host string `yaml:"host"`
    16. Port int `yaml:"port"`
    17. Username string `yaml:"username"`
    18. Dbname string `yaml:"dbname"`
    19. Password string `yaml:"password"`
    20. }
    21. type ConfigNew struct {
    22. Database DatabaseNew//数据库的配置
    23. }
    24. var GlobalConfig ConfigNew
    25. func init() {
    26. sc := []constant.ServerConfig{{
    27. IpAddr: "127.0.0.1",
    28. Port: 8848,
    29. }}
    30. cc := constant.ClientConfig{
    31. NamespaceId: "311387f1-790b-4045-8787-571addb6c9fd", // 如果需要支持多namespace,我们可以场景多个client,它们有不同的NamespaceId。当namespace是public时,此处填空字符串。
    32. TimeoutMs: 5000,
    33. NotLoadCacheAtStart: true,
    34. LogDir: "log",
    35. CacheDir: "cache",
    36. LogLevel: "debug",
    37. }
    38. configClient, err := clients.CreateConfigClient(map[string]interface{}{
    39. "serverConfigs": sc,
    40. "clientConfig": cc,
    41. })
    42. if err != nil {
    43. fmt.Println(err.Error())
    44. }
    45. content, err := configClient.GetConfig(vo.ConfigParam{
    46. DataId: "user",
    47. Group: "prod",
    48. })
    49. SetConfig(content)
    50. if err != nil {
    51. fmt.Println(err.Error())
    52. }
    53. err = configClient.ListenConfig(vo.ConfigParam{
    54. DataId: "user",
    55. Group: "prod",
    56. OnChange: func(namespace, group, dataId, data string) {
    57. fmt.Println("配置文件发生了变化...")
    58. fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
    59. SetConfig(data)
    60. },
    61. })
    62. }
    63. func SetConfig(content string) {
    64. fmt.Println(content)
    65. err := yaml.Unmarshal([]byte(content), &GlobalConfig)
    66. if err != nil {
    67. fmt.Println(err)
    68. }
    69. fmt.Printf("%+v", GlobalConfig)
    70. }

    我们通过控制台面板修改配置

  • 相关阅读:
    Android MediaCodec 框架 基于codec2
    C语言题收录(四)
    LQ0240 括号问题【程序填空】
    weblogic乱码报错解决思路
    网络协议深度解析:SSL、 TLS、HTTP和 DNS(C/C++代码实现)
    LeetCode 318 周赛
    Linux 命令:PS(进程状态)
    编译原理—运行环境、局部存储分配、活动记录、全局栈式存储分配、非局部名字的访问、参数传递
    389.找不同
    geant4创建自己的physicslist(以电磁物理为例)
  • 原文地址:https://blog.csdn.net/JineD/article/details/134247240