什么是配置
应用程序在启动和运行的时候往往读取一些配置数据,配置程序基本伴随着应用程序的整个声明周期.
比如:数据库的连接参数,启动参数等.
配置的特点
- 独立于程度的只读变量
- 伴随应用的整个生命周期
- 配置可以有多种加载配置方式
- 配置文件
- 环境变量
- 配置需要治理
同一份程序在不同的环境(开发,测试,仿真,生产),经常需要不同的配置,所以需要完善的环境,集群配置管理
什么是配置中心
当系统从一个单体服务拆分成若干个服务节点后,也就是咱们所说的:分布式服务,配置文件也必须跟着迁移,
这样配置也就太分散了,不仅如此,分散中还包含冗余.每个微服务都需要一份配置文件.
配置中心将配置从各应用剥离出来,对配置进行统一管理,应用自身不需要自己再去管理配置
配置中心的服务流程
- 用户在配置中心发布,更新配置信息.
- 服务A和服务B及时得到配置更新通知,从配置中心获取配置.
- 总的来说,配置中心就是一种统一管理各种应用配置的基础服务组件.
为什么需要配置中心
随着分布式微服务的发展,服务节点越来越多,配置问题逐渐显现出来.
- 随着程序功能的日益复杂,程序的配置也越来越复杂,各种配置,服务器之间的地址.
- 大量模块使用各自的配置,会导致运维管理繁琐,各个节点配置不一致等问题.
- 对配置的期望也越来越高,配置修改后,实时生效,灰度发布,版本管理,环境区分等
在这样的大环境下,传统的通过修改配置文件,数据库等方式已经越来越无法满足开发人员对配置管理的需求.
配置中心要满足如下特性
- 配置项容易修改和读取
- 远程管理配置的功能
- 支持对配置的修改内容的监视,把控风险.
- 可以查看配置的修改记录
- 不同环境下,应用配置之间的隔离性.
开源的配置中心
- disconf(百度)--官方已经不维护
- Spring Cloud Config
Spring Cloud开源组件,可以和Spring Cloud无缝整合,但需以来git或者svn
- Apollo
携程开源配置中心,具备规范的权限,流程治理等特性
- Nacos
阿里开源配置中心,其中包含注册中心和配置中心.
下面只说nacos和apollo
Nacos
- 动态服务配置可以让你以中心化,外部化和动态化的方式管理所有环境的应用配置和服务配置.
- 动态部署消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和便捷.
- 配置中心化管理,让实现无状态服务变得更加简单,让服务按需弹性扩展变得更容易.
- 提供了简洁易用的ui界面,帮助管理所有的服务和应用配置.
- 还提供了包括版本跟踪,灰度发布,一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性.帮助你更安全的在生产环境中管理配置变更和降低配置变更带来的风险.
架构
Nacos配置中心分为server和client,server采用javab编写,为client提供服务配置.
Client可以用多种语言实现,Nacos提供Sdk和OpenApi,如果没有SDK也可用OpenApi手写服务注册与发现和配置拉取的逻辑.
- 用户通过控制台集中对多个服务的配置进行管理配置
- 各个服务统一从Nacos server集群中获取各自的配置,并监听配置的变化.
Nacos的安装部署
- docker-compose安装
- 微服务引擎 阿里云服务
- 安装界面
- 配置管理页面
- 编辑配置页面
- 权限控制
- 命名空间,可根据命名空间,区分:测试,灰度,生产
- 集群节点管理:分布式部署,高可用
- golang 配置读取以及动态更新
// @Author: chimojiacai
// @Description: nacos 配种中心
// @File: nacos
// @Date: 2021/8/15 21:18
package config
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"
)
func NewNacosConfig() string {
clientConfig := constant.ClientConfig{
TimeoutMs: 10 * 1000, //http请求超时时间,单位毫秒
ListenInterval: 30 * 1000, //监听间隔时间,单位毫秒(仅在ConfigClient中有效)
BeatInterval: 5 * 1000, //心跳间隔时间,单位毫秒(仅在ServiceClient中有效)
NamespaceId: "", //nacos命名空间
Endpoint: "", //获取nacos节点ip的服务地址
CacheDir: "", //缓存目录
LogDir: "", //日志目录
UpdateThreadNum: 20, //更新服务的线程数
NotLoadCacheAtStart: true, //在启动时不读取本地缓存数据,true--不读取,false--读取
UpdateCacheWhenEmpty: true, //当服务列表为空时是否更新本地缓存,true--更新,false--不更新
}
// 至少一个(集群可以多个)
serverConfigs := []constant.ServerConfig{
{
IpAddr: "127.0.0.1", // nacos节点配置
ContextPath: "/nacos", // contextPath
Port: 8848, // 端口号
},
}
// 创建动态配置客户端的另一种方式 (推荐)
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
if err != nil {
panic(err)
return ""
}
// 监控配置更新
err = configClient.ListenConfig(vo.ConfigParam{
DataId: "ceshi",
Group: "DEFAULT_GROUP",
OnChange: func(namespace, group, dataId, data string) {
// 合并配置
buffer := bytes.NewBuffer([]byte(data))
err2 := viper.MergeConfig(buffer)
fmt.Println(err2) // 这里可以发送邮件
fmt.Println(viper.GetString("app_name"))
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:\n" + data)
},
})
if err != nil {
panic(err)
return ""
}
// 获取配置
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: "ceshi",
Group: "DEFAULT_GROUP",
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
},
})
if err != nil || content == "" {
panic(err)
return ""
}
fmt.Println("content:" + content)
return content
}
- 总结
- Nacos使用简单、部署方便、性能较高,能够实现基本的配置管理,提供的控制台也非常简洁。
- 权限方面控制粒度较粗,且没有审核机制
Apollo
简介
Apollo:分布式配置中心,能够集中化管理应用的不同环境,不同集群的配置,配置修改后能实时推送到应用端,并且具备规范的权限,流程治理等特性,适用于微服务配置管理场景.
Apollo包括服务端和客户端两部分.
特性
- 统一管理不同环境,不同集群配置
- 配置修改实时生效(热更新)
用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序
- 版本发布管理
配置发布都有版本概念,从而可以方便地支持配置的回滚
- 测试,灰度,生产等多环境配置
支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例
- 权限管理,发布审核,操作审计(比nacos好).
应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。
所有的操作都有审计日志,可以方便的追踪问题
- 客户端配置信息监控
可以在界面上方便地看到配置在被哪些实例使用
提供开发平台api和sdk(第三方的)
-
Apollo支持4个维度管理Key-Value格式的配置:
- application (应用)
- environment (环境)
- cluster (集群)
- namespace (命名空间)
通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖
文档中心
基础模型
- 用户在配置中心对配置进行修改并发布
- 配置中心通知Apollo客户端有配置更新
- Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用
服务端设计
[站外图片上传中...(image-9d0374-1631951517555)]
- 用户在Portal操作配置发布
- Portal调用Admin Service的接口操作发布
- Admin Service发布配置后,发送ReleaseMessage给各个Config Service
- Config Service收到ReleaseMessage后,通知对应的客户端
客户端设计
[站外图片上传中...(image-73fdb5-1631951517555)]
- 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)
- 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
- 这是一个fallback机制,为了防止推送机制失效导致配置不更新
- 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified
- 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
- 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
- 客户端会把从服务端获取到的配置在本地文件系统缓存一份
- 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
- 应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知
部署文档
使用
-
首页
-
系统配置管理
-
应用配置-配置部门
-
namespace 创建-私有的才能自定义文件格式,否则默认properties格式
-
创建配置文件-点击对号保存,点击发布则更新到app里
-
历史版本回滚-可以diff
-
查看实例
-
权限管理
golang 配置读取以及动态更新
// @Author: chimojiacai
// @Description:
// @File: apollo2
// @Date: 2021/8/22 00:23
package config
import (
"bytes"
"fmt"
"github.com/shima-park/agollo"
"github.com/spf13/cast"
"github.com/spf13/viper"
)
func NewApollo2Config() {
a, err := agollo.New("127.0.0.1:81", "123456", agollo.DefaultNamespace("avtivity1.txt"),agollo.AccessKey("1ae5a4a672db4526a726355f87336f58"))
if err != nil {
panic(err)
}
fmt.Println(
// 默认读取Namespace:application下key: foo的value
a.Get("app_name"),
// 获取namespace为test.json的所有配置项
a.GetNameSpace("avtivity1.txt"),
// 当key:foo不存在时,提供一个默认值bar
a.Get("foo", agollo.WithDefault("bar")),
//// 读取Namespace为other_namespace, key: foo的value
//a.Get("foo", agollo.WithNamespace("other_namespace")),
)
errorCh := a.Start() // Start后会启动goroutine监听变化,并更新agollo对象内的配置cache
// 或者忽略错误处理直接 a.Start()
watchCh := a.Watch()
// 启动监听配置变化
go func() {
for{
select{
case err := <- errorCh:
fmt.Println(err) // 处理异常
case resp := <-watchCh:
//fmt.Println(
// "Namespace:", resp.Namespace,
// "OldValue:", resp.OldValue,
// "NewValue:", resp.NewValue,
// "Error:", resp.Error,
//)
// 合并配置
buffer := bytes.NewBuffer([]byte(cast.ToString(resp.NewValue["content"])))
err2 := viper.MergeConfig(buffer)
fmt.Println(err2) // 这里可以发送邮件
fmt.Println(viper.GetString("app_name"))
}
}
}()
}
- 总结
- Apollo在配置管理流程上比较完善,相应配置的发布审核、权限管理等、配置的继承等,但Apollo需要使用人员进行简单学习,存在学习成本。
- Appollo部署较为复杂需要3个模块同时工作,部署一套生产高可用集群至少需要7
个节点。(可使用docker解决)
nacos和apollo总结
对比项目 | nacos | apollo |
---|---|---|
配置实时推送 | 支持(1s) | 支持(1s内) |
版本管理(回滚) | 支持 | 支持 |
权限管理 | 支持(粗颗粒度) | 支持(细颗粒度) |
灰度发布 | 支持 | 支持 |
集群 | 支持 | 支持 |
监听查询 | 支持 | 支持 |
多语言 | Go,Java,Python,C++,.Net,OpenApi | Java,Python,Nodejs,OpenApi |
配置格式校验 | 支持 | 支持 |
通信协议 | http | http |
单机读(tps) | 15000 | 9000 |
单机写(tps) | 1800 | 1100 |
nacos官方支持go sdk
apollo第三方go sdk
结论
从配置中心角度来看,性能方面Nacos的读写性能最高,Apollo次之;功能方面Apollo最为完善,但Nacos具有Apollo大部分配置管理功能。Nacos的一大优势是整合了注册中心、配置中心功能,部署和操作相比 Apollo都要直观简单,因此它简化了架构复杂度,并减轻运维及部署工作。
总的来看,Apollo和Nacos生态支持都很广泛,在配置管理流程上做的都很好。Apollo相对于Nacos在配置管理做的更加全面;Nacos则使用起来相对比较简洁,在对性能要求比较高的大规模场景更适合。
对于修改配置的次数不是特别的频繁,对于配置权限的管理不是特别严格的,且对读写性能有一定要求的,可采用Nacos,反之使用Apollo。