一份大但不全的配置中心知识备忘

前言

简单记录一下关于配置中心各方面(主要是功能方面)的一些思考和备忘知识。

基本功能

作为配置中心需要具备如下基本的核心功能:

  • 配置的增删改查
  • 支持静态配置和动态配置(或者说所有配置都是动态配置,取决于用户程序中怎么去使用它)
  • 动态配置的变更推送功能

高级功能

一般还会具有下面的高级功能:

  • 权限控制
  • 相同配置项在不同环境下(不同机房、不同单元、不同集群等)配置不同的值

其他功能在下面的多个主题下中穿插说明。

面向用户的 Web 面板

现在哪个系统还没个 Web 面板呢,配置中心也不例外。 至少需要一个面向用户的 Web 面板,不然用户体验也太差了。

这个 Web 面板一般有下面的功能:

  • 帐号体系,基本的用户管理和用户权限控制、配置的访问控制
  • 用户增删改查有权限的不同服务的配置
  • 版本控制:显式配置项值的不同版本,方便实现回退功能以及查看历史值
  • 回退:把配置项的值回退到过去某个版本
  • 变更记录(变更审计):显式配置项增删改的所有变更记录,方便追溯
  • 配置项导入、导出功能
  • 变更审批功能:某些场景下修改配置项需要接入多人 double check + 审批的流程
  • 敏感配置加密功能:面板上接入第三方敏感信息加解密系统,配置中心只存储加密后的配置,配置的加解密由第三方敏感信息加解密系统来实现。

其他 Web 面板功能会在下面的主题中穿插说明。

开关

开关其实可以作为一种特殊的配置项来实现,比如业务系统中的功能/特性开关可以通过动态配置来实现, 只不过是约定了一个特定规范用于实现开关配置项(比如,值只能是 true 或 false 或者只能是 0~100, 配置项必须以 switch: 开头), 这个约定需要 SDK 和 Web 面板一起协作来完成,通过 SDK 和面板的协作对用户屏蔽这一内部实现细节(API 端需要校验值的合法性)。

开关配置既可以用来实现新功能的灰度/开启开关, 也可以用于实现系统故障场景下的功能降级/关闭开关、fallback 启用开关等各类动态切换的场景。

配置灰度

微服务场景下功能灰度是个非常重要的功能,功能灰度既可以通过金丝雀发布的方式实现,特定场景下也可以通过功能开关的方式实现。比如前面所说的开关配置,如果约定开关配置的值是 0~100.00 的话,可以通过不同的值控制功能打开的概率从而实现功能灰度。

不只是功能需要灰度,配置也需要灰度,毕竟配置的变更对系统的影响也是非常大的,不亚于功能的变更。

一般可以考虑支持如下其中一个、几个或全部的配置项变更灰度纬度:

  • 机房
  • 单元
  • 集群
  • 某些特定客户端IP/hostname
  • 一定比例的业务系统实例

稳定性

没有一个系统能够保证 100% 不出问题,配置中心也不例外。所以在设计客户端和服务端的时候需要应用一些面向失败设计的模式。

客户端

客户端一定要实现的一个功能就是:本地缓存。 用于在无法连接服务端或者服务端异常时客户端有个本地兜底,不会因为配置中心异常导致用户服务异常。

本地缓存一般包括内存缓存和本地文件缓存,可以考虑实现其中一个或两个都实现。

以及需要注意之前 调用远程服务的一些备忘录安全友好的客户端行为 中提到的那些超时、重试等注意事项,毕竟这个也是调用远程服务的一个场景。

服务端

服务端主要需要考虑如下方案:

  • 熔断: 在特定场景下通过熔断对外部依赖的请求或来自客户端的请求来保障服务端的稳定性
  • 降级: 在特定场景下通过降级某些功能或某些外部依赖来保障核心功能的稳定性
  • 限流/限速: 根据需要对用户、服务、IP 或者推送进行限流或限速, 至少要有一个宽松的默认限流策略,防止被异常的突发流量打垮系统。
  • 隔离(舱壁模式):通过隔离技术来保护大部分用户不受少部分异常用户的影响或者核心组件受次要组件故障所影响。 常见的隔离技术有线程池隔离、进程隔离(比如剥离增删改查功能和推送功能独立部署或者在流量入口处按功能划分不同节点,比如部署单独的节点只提供推送服务)、集群隔离(为特定用户群体部署专享的独立集群,防止受主集群影响)等等。
  • 日志、监控、告警:根据实际情况来记录有用的日志、指标数据、以及配置必要的告警

可以进一步参考 《Release It! Second Edition》阅读笔记(一)《Release It! Second Edition》阅读笔记(二) 中的内容。

治理

配置中心不仅仅只是一个存放配置的地方,同样还应该承担起配置治理和收口的职责, 同时,没有考虑各方面治理的中间件只能说是一个软件或服务,而不能说是一个成熟的产品。

下面简单记录一些常见的治理场景。

通用配置治理

所谓的通用配置指的是各个服务都会去配置的一些配置项,如果不治理的话,一方面配置项的名称会五花八门不利于用户服务的后续交接和维护,另一方面因为没有统一治理规范化,导致无法快速的根据需要调整或统计公司内部所有业务服务所使用的通用配置。

希望通过治理后能够规范化通用配置,实现统一约定通用配置项名称方便业务系统的日常维护以及赋予平台统一管控的能力。

下面举一些通用配置的例子:

  • 业务系统所使用的微服务框架本身包含了各种各样的配置,可以对这些配置项的名称和取值作统一规范化,用户按照规范在配置中心配置相应的配置,框架按照规范从配置中心去获取对应的配置。
  • 框架内置的各组件的功能特性的降级和开启开关
  • 基于框架实现的服务间调用的服务级别和接口级别的降级和开启开关
  • 服务启动时的启动参数控制、jvm 参数控制

基础服务配置治理

同样,基础服务配置治理也是为了规范化业务系统对基础服务依赖的相关配置,方便业务系统的日常维护以及赋予平台统一管控的能力。

下面举几个基础服务配置的例子:

  • 数据库连接信息和连接参数
  • 消息队列连接信息
  • 限流/限速组件的配置信息
  • 其他基础服务(redis、es、oss等基础服务)的客户端所需的配置信息

遗留配置治理

随着时间的推移,配置中心上会存在很多遗留的不再使用的旧配置,为了避免成为配置坟场,需要对配置的使用情况进行治理。

需要客户端/框架和服务端一起来实现配置使用的治理,客户端/框架中收集和上报用户系统真正在使用的配置项, 如果服务端能够感知到的话也可以在服务端主动记录。

收集到真正在使用的配置项后,需要 Web 面板配置在页面上展示配置项的使用情况,方便用户清理不再使用的配置(可以主动提示用户某些配置项很久没使用了,是否是已废弃配置,请及时清理)。

用户使用姿势治理

没有哪个系统和服务是万能的,每个服务都有它预设的使用场景限制/约定,配置中心也不例外。

所以在设计和开发配置中心的时候需要要定下它服务的场景和使用约束,提前发现或及时发现不合理的使用姿势,甚至直接拒绝不合理的使用姿势从源头就扼杀而不是等到后面再来治理。

客户端治理

还有一个就是客户端的治理。

  • 版本治理:无论是官方实现的客户端还是第三方实现的客户端,随着时间的推移都需要治理,比如统计旧版及关键版本的使用情况, 根据使用情况废弃旧版或推动旧版业务方升级改造。 所以所有客户端的请求信息中必须包含符合规范的客户端名称和版本号(比如 http 协议的话可以考虑放在 User-Agent 里),方便服务端记录和统计客户端信息
  • 实现方式治理:如果是官方实现的客户端的话,可以很好的把控客户端的实现方式,但是第三方实现的客户端可能会包含各种影响服务端稳定性的不正确实现姿势或使用姿势。一方面服务端需要防范和应对会来自客户端的异常请求,另一方面也要实现能够帮助配置中心开发人员及时或提前发现可能的或已存在的异常请求,进而调整官方客户端的实现以及协调第三方客户端改进实现,比如应用上面【稳定性-客户端】那里提到的本地缓存以及各种客户端实现注意事项。再通过上面的版本治理来推进用户升级客户端。

故障排查

配置中心作为一个所有业务系统都会使用的一个中间件,为了减轻开发的排障压力需要主动收集关键信息或提供排障工具用于快速排障或自证清白。

可以考虑收集如下信息:

  • 配置使用追踪(何时哪个客户端获取(使用)了哪个配置项)
  • 变更推送追踪(何时推送了哪个配置项的啥变更给哪个客户端)
  • 客户端异常情况(日志或打点)

并提供工具、手段或页面方便用户快速自行 debug:

  • 一份包含常见问题的答疑和 debug 步骤文档
  • 以某种方式在 Web 面板页面展示上面收集的信息
  • API 或 SDK 的错误或异常信息中包含对应问题 case 的原因说明或解决办法的文档 URL 地址
  • 提供工具用于用户在他们出现异常的机器上进行简单的自动诊断,比如自动检测与服务端的网络连接情况、分析客户端的错误日志、根据已知的各种常见问题 case 的异常原因和检查步骤自动分析并给出相应的建议
  • 提供工具分析用户的代码检测出不符合规范的代码用法给予提示、改进建议甚至是自动重新源代码

需要根据日常答疑和 debug 经验丰富上面的手段和方法。

控制面板

这个控制面板是一个面向配置中心开发人员和运维人员的 Web 面板(不一定是一个面板,也可能指的是包含公司内部各基础服务系统的一组面板集合), 用于观测配置中心运行过程中的各种状态信息(观测方面的需求也可以通过接入监控系统来实现) 以及在不重启配置中心不同组件服务的前提下动态控制配置中心的各种内部功能和细节。

动态控制方面,常见的有如下需求:

  • 变更特定服务配置的访问控制信息
  • 变更对用户/客户端的限速、优先级、黑白名单等配置
  • drop 或屏蔽一些请求
  • 后端服务节点的控制,比如上下线变更
  • 内部功能的开启和关闭、配置的变更(也可以直接通过面向用户的 Web 面板控制,即配置中心本身也通过配置中心来托管配置)
  • SDK 特定功能的开启和关闭

观测方面的需求一般通过接入监控系统来实现,详见下面的监控告警主题。

监控告警

接入监控告警可以帮助配置中心开发人员和运维人员观测系统的运行状况,提前或及时发现异常情况,提高系统的稳定性以及故障处理速度。

客户端和服务端可以考虑上报/提供如下指标数据,用于监控和告警。同样只是一些简单的例子,需要考虑实际场景添加合适的指标。

服务端

  • 客户端请求情况:基本的请求信息(请求方、api、响应情况(成功、失败、响应时间等)
  • 配置变更
  • 变更推送
  • 限速、黑白名单触发
  • 其他内部关注的点

客户端

  • API 调用:api、成功、失败(失败原因)、响应时间

周边生态

目标是希望围绕配置中心形成一个生态,而不是所有需求都由配置中心来实现。

比如:

  • 微服务调用方或被调用方的限流功能,可能是由专门的组件或服务来实现限流功能, 但是每个服务的限流配置可以规范化存放在配置中心,帮助限流组件省去重复实现配置管理和变更推送的功能。
  • 基于各服务方使用配置中心实现功能开关来控制调用降级的前提,可以实现一个在不同故障场景下批量切换多个调用链上下游的降级开关,实现故障时上下游快速降级的需求(一键降级)。这个需求虽然可以在配置中心上实现,但是会给配置中心增加不必要的复杂度,可以考虑实现一个单独的系统,这个系统会调用配置中心的 api 来实现相应的开关切换,在那个系统中实现这个需求所需的各种繁琐的业务流程。
  • 其他需要实现配置管理和配置变更推送的场景,都可以把配置规范化存放在配置中心,围绕配置中心形成一个庞大的生态系统。

文档

如果没有文档的话,用户可能都不知道怎么用你的产品,你的产品做的再好也没有用。

文档主要包括面向用户的文档和面向内部开发和运维人员的文档。

面向用户的文档:

  • 使用文档,包括 Web 面板的使用文档、API 文档、SDK 使用文档、debug 工具使用文档等等
  • 答疑文档,包括常见问题解答、常见异常 debug 步骤和解决方法等等
  • 介绍文档,包括适用的场景、解决的问题、不适用的场景、使用约束等等
  • ...

面向开发和运维的文档:

  • 开发文档
  • 部署和运维文档
  • 监控和告警
  • 常见故障恢复方法和步骤
  • 常见问题 debug 步骤和解决方法(包括用户遇到的问题以及内部问题)
  • ...

其他

# TODO

总结

简单记录了一下配置中心的一些备忘知识,后面有空的时候再补充更新。

BTW,开发一个配置中心或配置管理平台的时候不一定需要实现上面的所有的内容,可以是它的超集也可以是它的子集,同时也不要想着一次性就实现最终产品,可以考虑通过小步试错,快速迭代的方式一步步的实现和落地各种功能和方案(通过一个个的阶段性迭代和目标来实现最终目的,不要想着一蹴而就或者在一个大的迭代中完成目标)。 重要的是要考虑实际场景,组织架构风格,组织或团队的短期和长期目标(<del>比如某些团队或个人会把项目作为升职加薪的跳板,这样的话就需要取舍,哪些功能/需求是可以快速做出闪亮成绩的,哪些是需要时间才能证明其价值。不是时常会听说某个公司内某个/些项目在晋升季一过就没人维护甚至直接就黄了嘛[1]</del>)。


Comments