B站配置中心架构的演进
本期作者
王宗宝
哔哩哔哩资深开发工程师
陈碧仁
哔哩哔哩资深开发工程师
1、前言
配置中心的诞生和项目架构的演进有着密切的联系。传统单体应用存在一些潜在缺陷,如随着规模的扩大,部署效率降低,团队协作效率差,系统可靠性变差,维护困难,新功能上线周期长等,所以迫切需要一种新的架构去解决这些问题,而微服务( microservices )架构正是当下一种流行的解决方案。不过,解决一个问题的同时,往往会面临很多新的问题,所以微服务化的过程中伴随着很多的挑战,其中一个挑战就是有关服务(应用)配置的。
(1)当系统从一个单体应用,被拆分成分布式系统上一个个服务节点后,配置文件也必须跟着迁移(分割),这样配置就分散了,各个服务都有自己的配置,随着项目需求的不断壮大发展,配置会越来越多,到最后繁琐的配置文件会让你越来越崩溃,稍不注意出个错配置错了就得修改配置重新打包部署,特别麻烦。
(2)在集群部署的情况下,如果新版本的配置会给系统带来很大的影响,我们往往会选择灰度发布,即先发布部分服务器,进行测试,稳定后再将配置同步到所有服务器,如果说还用传统的方式,那么我们就需要将配置文件一个个的修改然后重启服务,虽然不需要我们开发自己去做,有运维,那也挺烦人的,运维发布完了,我们还得检查他改的是不是正确,费时费力。
(3)而且在系统不断的迭代的过程中有些配置在多个服务之间都是相同或相近的,就会有很大的冗余。
所以在分布式、微服务这种大环境下,传统的项目配置方式的弊端就慢慢的凸显出来了,这个问题变得非常棘手,亟待一种管理配置、治理配置的解决方案。这时,配置中心就应运而生了。
2、配置中心v1(Config)
自2017年B站开始着手配置中心的研发工作。希望能解决配置的统一管理,配置的订阅与热更,业务的透明接入等问题。
2.1 统一管理页面
配置中心v1提供一个统一的配置管理后台,对不同环境、不同应用进行权限隔离,实现操作配置方便和安全。在功能方面提供了公共配置和配置搜索等功能。
2.2 高可用
Config 在可用性上采用 Admin 广播的形式进行集群中各个节点的数据同步;在性能上采用 MySQL 存储和磁盘存储两种存储方式,MySQL 做持久化储存,磁盘主要加快访问速度。配置读取时服务首先读取本地磁盘数据,如果未命中,则直接读取数据库并缓存到内存中。
2.3 配置订阅
配置中心v1在配置订阅时采用长轮询(long polling)方式实时监听配置变更通知,如果没有变更则30秒后返回304,如果有变更立即返回。具体流程如下:
2.4 业务透明
配置中心对外提供统一的 SDK,用户可以直接通过 SDK 接入配置中心。同时也对外提供 SDK 的订阅和读取接口,用户可以根据需求自行实现各个接口。
2.5 局限性
v1通过 Redis 记录 client 请求信息,供用户查看用户的订阅情况,由于有些业务 client 端较多,如果出现大量请求将会增大返回时间;
OpenAPI 对外开放,致使很多不在管理范围内的 SDK 不受控,对后续接口升级带来很大的阻力;
v1的配置采用广播的方式发布数据,如果有节点宕机,很难保证各个节点间数据的一致性;
配置中心v1是集中式集群,不支持多活部署,没有降级方案,可靠性低;
v1也没有对配置进行校验,经常会出现用户配置格式问题,导致版本发布后解析报错,业务服务无法启动问题。
3、配置中心v2(Paladin)
在配置中心v1使用多年情况下,随着公司的规模不断扩大,业务不断扩展,越来越多的业务形态出现,原来的配置中心已经不能很好的满足当前的业务需求,且配置中心v1版本也存在一定的局限性,所以配置中心v2便应运而生。
v2主要解决了以下几个问题:
3.1 配置生命周期的管理和配置简化
Config将配置与版本独立管理,变更发布和管理难度大,配置的生命周期很难管理,且新用户学习成本高。Paladin 将配置直接绑定到分组中,配置不在拥有独立的版本。配置的变更只有在发布后才会有变更记录,其版本的迭代和回滚以分组维度进行,不在分组版本中的配置即生命周期终止。同时也极大的简化了配置变更和发布的流程,降低了用户的使用成本。
3.2 配置隔离
在 Config 中,配置的隔离不明显,很容易因为变更一个区域的配置导致所有区域的配置全部改变。在 Paladin 中配置隔离分为租户(Tenant)隔离、命名空间(Namespace)隔离和分组(Group)隔离。用户可以根据自己业务为维度做租户进行配置的隔离,如:直播业务,电商业务,游戏业务等等均可以作为独立的租户。命名空间的隔离是在租户隔离的基础上业务根据不同环境,区域和功能做第二级别隔离,用户只需保证同租户下命名空间全局唯一即可保证配置隔离,如:电商业务:测试环境-上海区域-支付功能。分组隔离是在租户和命名空间基础上做的第三级隔离,用户可以根据自己的需求使用不同的分组,分组之间的自定义配置是相互独立相互隔离的,不会因为改动一个配置而导致其他分组配置的变化。如下图,Tenant为默认public,Namespace为Env,Zone和App的组合,Group即为分组;业务可以据此做不同隔离。
3.3 增量发布与读取
对于大多数情况下应用的配置变更都是部分文件的变更,以及大文件变更和多客户端订阅,如果全量推送会占用大量的带宽。Paladin 中采用了版本信息与配置信息独立存储的方式进行,版本信息 Message 中保存该版本的所有配置文件信息列表,其中配置文件信息包括配置的ID,变更状态,配置内容的校验信息(Checksum)以及配置信息的存储Key(KeyLink)。配置发布时 Portal 将变更的配置与最近一次发布生效的配置 merge,做到增量发布。SDK 可以根据各个配置文件的变更状态信息或者根据本地缓存对比最新的 Checksum 判断配置是否需要更新,做到读增量。
3.4 提高QPS和推送延迟
Paladin 采用缓存的方式提高QPS和推送延迟。如下图,缓存层分为两个部分,一部分为存储配置内容的 LRU 缓存,主要是用来加速配置的读取。另一部是通知的缓存,为了提高通知性能,Paladin 不在使用 Redis 做推送缓存,而是采用的是 HashMap 的形式做缓存,将各个 Namespace 下的配置存储到同一个 Key 下,如果更新将会通知该租户和命名空间下的所有分组,服务根据订阅的 Labels 判断是否通知 Client,这样极大的提高了通知的效率和扩展性。
3.5 同集群中各个节点数据一致性
Paladin 不在像v1一样使用广播的形式进行数据同步,而是采用Raft协议[1,2]保证集群中各节点数据的一致性和集群的高可用行。保证一半以上节点正常情况下数据读写正常。如下图复制状态机体系结构
3.6 高可用
为了实现多活部署,Paladin 在模块设计方面:
(1)将基础数据层(Node)独立成服,并将其与数据库以及其他基础组建解耦,全量保存所有用户配置(一定的历史版本),对外仅提供 Clients 的配置获取和变更监听。
(2)将 Portal 定位为业务逻辑层,保存有配置的历史数据,用户信息,权限等。同时也统一对接公司内部的其他三方系统,提供了配置管理需要的所有元信息;
(3)Admin 组件仅封装核心配置的修改、发布等接口以及权限管理的支持,提供了统一对外的 OpenAPIs。
数据同步方面:Paladin 采用单数据库中心,多集群部署的方案。持久化数据保存在数据库中,在配置发布时 Portal 将同步发布数据到各个Node集群中,保证各个集群数据同步。通过 anycast 保证各个机房的服务就近读取该机房的配置中心配置。在某机房配置中心宕机后可以切换到其他机房读取相应的配置,保证容灾降级。
这样可以保证:
(1)如果 Admin 故障,前端只需连接到其他的 Admin 服务即可保证业务继续。
(2)如果 Portal 故障,Admin 可以重新连接其他的 Portal 服务也可以对外服务。
(3)如果某台 Node 故障,每个节点都有完整的配置副本,客户端重新连接到该区域其他节点即可。
(4)如果某个 Node 集群故障,服务将会自动降级到其他的配置中心集群读取配置。
3.7 客户端订阅连接复用
在新的业务使用中,会遇到用户单个服务监听多个分组或者多个应用的情况。所以 SDK 支持连接复用有助于简化用户操作。同时为了避免像v1一样出现 SDK 不可控的情况,Paladin 团队将维护所有语言的 SDK,对于不支持的语言 Paladin 提供物理机的 Agent 和 K8s的 Sidecar 等方式将配置写入服务自定义目录下。这样可以有效的控制 SDK 的版本以及后续 Paladin 的迭代升级。
4、功能特性
在借鉴 Config 的反馈之后,Paladin 提供更多的功能和特性以满足新的业务需求,包括:
4.1 无感知接入
Paladin 提供了应用配置,这也是配置中心针对B站业务形态做的无感知接入。应用在满足相应条件的情况下,业务可以在 PaaS 平台直接创建和部署自己的业务,无须关心配置中心的存在,方便业务的使用。Paladin 是怎么做到的?配置中心的应用配置规定了一套使用标准,而 PaaS 平台按照该标准将相应的应用参数直接注入应用容器的环境变量中,业务在使用相应的默认配置参数时即无须关心配置中心和 PaaS 的联动做到开箱即使用。
4.2 平台空间
Paladin 支持平台空间能力,允许不同平台利用配置中心高可用、高容灾能力以及稳定的配置下发通道,构建相应的平台空间。平台空间不能直接被普通业务直接感知,以一种类似于可扩展插件的方式提供。现在 B 站新一代的 ABTest 平台以及服务治理平台均已接入。我们以 ABTest 平台为例,业务可以根据自己的产品试验需求,在 ABTest 平台配置 A/B 测试配置,并在该平台进行配置发布,业务即可在其 ABTest 的平台空间获取到 A/B 配置,可以有效的降低业务对不同平台的感知和接入复杂度。
4.3 Keyspace配置
配置中心针对中间件如网关等,会涉及到各式各样的应用,如果每一个应用在使用网关等中间件时都需要配置或者针对相应的SDK做大量的配置,将会极大的增加了业务的接入复杂度,同时如果中间件升级也需要所有接入业务做相应的大的变更,增大的非必须的成本。Paladin 针对该问题推出了 Keyspace 配置。该配置不在涉及到应用问题,可以集成到中间件的SDK中,业务应用只需引用相应的SDK既可以接入。同时中间件也可以根据不同需求或者功能对指定的配置做变更,作用与指定的业务。这将极大的降低接入和迭代的困难。
4.4 配置格式校验
Paladin支持如xml,toml,yaml,json等10余种格式极其校验。配置解析时如果配置格式错误将会导致客户端解析失败,所以配置中心会配置进行格式校验,可以有效的防止因人为操作导致的配置问题。
4.5 权限管理
配置的变更是会直接影响应用服务,对于重要的服务因配置的变更可能会带来不可估量的后果。Paladin 在权限管理方面支持用户权限管理,OpenAPI 权限管理,同时还支持变更通知与发布审核通知。
4.6 版本控制与回滚
当用户需要对配置进行复盘时可以通过版本历史和版本对比查看各个历史上各个版本的配置,并能通过对比功能查看各个版本直接的差异。如果配置变更未达到预期也可以通过回滚操作将配置回滚到指定版本。
4.7 染色发布
Paladin 提供染色发布的能力,当配置变更影响较大时,用户可以通过染色发布在部分实例上发布最新配置测试是否符合预期。如果符合则全量所有实例,如果不符合则可以直接取消染色回归到之前的配置。配置中心的染色发布和公司服务治理平台进行了完全打通,支持了相关多泳道能力的建设。如配置中心和 PaaS 平台的联动,做到发布染色服务读取染色配置等一整套流程。
4.8 增量发布与读取
Paladin 提供对配置的增量读,一个配置版本的可能含有多个未变化配置,客户端只需要加载变化的配置。
4.9 模版配置
Paladin 还支持模板配置,对于中间件或者其他公共服务的 SDK 需要的配置格式是固定的,绝大部分的Value也是固定的,这个时候中间件可以创建相应的模板,其他使用该中间件应用只需引用该模板从而可以降低因各个用户的理解不同导致的配置问题。
4.10 复制与导入
Paladin 对不同区域的之间的配置可以使用导入或者复制功能直接操作,可以有效防止因人为操作问题导致的配置出错。
4.11 命令行运维工具
为了更好的提供运维服务,Paladin 可以在仅有 Node 组件的情况下运维操作,即有助于运维,也可以在 Admin 和 Portal 均不能有效提供服务的情况下做紧急操作。
5、性能
作为基础服务,Paladin 的性能也是考察服务的关键点。配置中心本身是一个多读的服务,在服务器48核2.8GHZ,单节点30万条配置的情况下,可以同时连接6.5万个客户端,平均推送耗时在40毫秒以下。在同样服务器和配置的前提下,有一万个客户端同时监听一个配置文件的变更,所需的推送时间也在600毫秒以内。
6、展望
配置中心是微服务基础架构中不可或缺的核心组件,未来我们将继续研究配置中心的应用模式与场景。Paladin 在功能上基本覆盖了配置的大部分使用方式,后续我们将进一步优化用户的使用体验,抽象出 feature/vars 等场景化能力,并对大模型的数据的分发性能进行进一步的优化,以及结合公司的容器平台研究适配 K8s 替代相应的 ETCD 提高相应的性能方面做努力。现代微服务架构和云原生环境,对应用配置管理提出了更高的要求。配置驱动资源正在成为云计算的一个重要技术趋势,云计算相关的所有资源都可以通过配置去驱动[3],未来也将研究如何在云服务平台上与其他服务整合。
参考文献
[1]https://github.com/hashicorp/raft
[2]https://pages.cs.wisc.edu/~remzi/Classes/739/Spring2004/Papers/raft.pdf
[3]https://aws.amazon.com/cn/blogs/china/technical-selection-and-landing-practice-for-building-a-cloud-native-configuration-center
以上是今天的分享内容,如果你有什么想法或疑问,欢迎大家在留言区与我们互动,如果喜欢本期内容的话,欢迎点个“在看”吧!
往期精彩指路