基于云原生基础设施的后台架构设计思考
前言
在后台服务体系中,基础设施是运行在业务逻辑之下的计算、网络、存储资源以及通用的基础服务。如果没有完善的基础设施,业务团队只能以"小作坊"形式运作,具有较弱的服务治理能力,产生效率较低,大部分时候只是为了满足业务短期需求,如果出问题了再安排人力来优化,但是并不能很好收敛架构不完善带来的效率和质量问题,特别对于ToB的场景,质量和口碑犹其重要,不应该有持续的服务质量问题。针对如何实现一套完整的基础设施及其应具备的能力,下面做了一些思考和分析。
基础构架的设计思考
总的来说,业务所需要的基础设施能力就两个:高效开发测试和高质量的运营。具体有:
相互独立又稳定的开发测试环境。不管是新功能开发还是后期迭代优化,开发测试过程很需要的一点是能够快速运行代码并验证执行结果,这里要求基础架构有高效的部署方式和基于账号信息的流量管理功能。
丰富的公共服务组件。开发最好可专注于业务逻辑开发,而不重复造各种不可靠的轮子,这需要有稳定可靠的名字服务、日志、监控、RPC、网关能力等基础服务组件。
安全高效地灰度变更。从经验上看,大部分的线上故障都是变更导致的,所以需要一种可靠低风险的灰度方式,实现方案主要两种:a)支持多set,不同用户流量在不同set,如果出问题尽量少地影响用户。b)单set之内,支持蓝绿灰度方式,发布后的版本流量从0开始增加,无异常再增加到100%。
统一而又灵活的框架能力,有标准的灰度发布、容灾容错、日志、监控、链路追踪等运维能力,但是又不会限制只使用某个框架,同时基础组件可以根据业务需求有一定插件化定制能力。
考虑持续运营的能力,默认有监控告警、弹性伸缩、多地容灾的架构能力,开发不应该花费大量时间来排查和处理线上问题,各类组件异常有容灾备份而不影响服务质量。
如上图所示,开发和测试同学可以基于账号信息路由到自己的版本,发布变更时可以控制新版本的流量比例(基于账号hash或其他维度)
基于以上考虑,设计了下面的构架图:
在上图中的各模块的功能是:
Sidecar是跟业务逻辑(Bussiness)容器有相同网络命名空间的容器。业务容器所有访问外部的流量都经过Sidecar,作为应用层协议的传输层,Sidecar将流量转发给相应的业务容器。由Sidecar实现基础设施的能力,有名字服务、流量管理、故障注入、负载均衡、日志、监控、调用链、频控等公共能力。此外,还有名字注册与反注册功能,会监控服务状态,向Registry上报心跳和服务状态,心跳超时后Registry可自动踢除节点。
Gateway是所有外部流量的访问入口,功能与Sidecar功能基本一致,此外还有https证书管理、安全防护的能力。
Registry是整个基础架构的核心,提供名字服务能力,支持支持名字注册、获取、更新、删除,支持服务多版本及灰度规则,支持set能力,支持人工屏蔽节点,在底层数据不可用时能容灾降级(不影响数据面),同时支持增量更新方式快速同步控制面的配置,另外要求客户端(Sidecar与Gateway)也有缓存和降级方案。
公共基础服务,比如配置管理、日志、监控、调用链、测试平台、频控中心、可视化的服务管理、缓存、缓存、异步任务管理、分布式事务管理等。
底层资源管理,K8S已是业界的容器编排标准,所有业务模块及公共服务都应该支持在k8s上运行,考虑容灾,同一个服务可以部署在不同k8s集群和不同的可用区。
相关问题
1.为什么用sidecar而不是直连方式,或者是都走gateway网关?
对于直连方式,sidecar提供了与业务逻辑无关的框架能力,更好地实现基础架构运营维护。相对gateway方式,sidecar即可以解决gateway网关的中心化依赖问题,在性能上,本地sidecar增加的延时一般不超过1毫秒,而gateway在不同机房里至少增加几毫秒的延时。
2.为什么服务端不用再经过一次sidecar?
上面的架构中,所有服务入口流量都会经过一次gateway或sidecar,已基本实现完整的构架能力,唯一不足是不能在服务端实现过载保护能力,但是实践过程中,这个功能基本用不上。增加一跳也会带来不稳定性和性能损耗。
3.为什么不直接使用k8s的名字服务以及DNS能力,或者直接使用etcd/zk中间件作为名字服务?
基于DNS的名字服务有性能稳定性不高,不确定的ttl以及排障困难问题,基于k8s service无法实现客户端的节点级熔断能力,不能针对单节点人工屏蔽,不支持set、不支持降级等。
4.为什么不用流量劫持的透明代理能力
5.四层流量(如mysql/redis、私有协议等)如何管理?
可在Sidecar中配置L4层代理,基于端口号做4层转发。
基于云原生的实现思路
在2021年的今天,已经有大量的开源工具和框架去解决通用的业务问题,云原生技术日渐成熟,我们也有另一个思路去考虑基础设施的架构设计问题了。先看下使用云原生技术带来的好处:
不用重复开发通用的框架组件,直接复用开源成熟项目,节省大量开发人力。
有开源的文档和示例,使用成本低。
云原生基础架构,即考虑云上环境,也可以私有化部署,可以给企业带来灵活的部署方式,在享受云上能力的同时,也不用担心厂商绑定问题。
对于基础设施维护的同学,经验可复用,在换工作时也能快速上手。
但是也要面对这些问题:
如何使用开源软件适应不同业务的个性化需求。如果在不满足需求时二次开发,后续的bug修复等维护工作会变更很复杂。
有些复杂的软件项目使用门槛高,同样也需要一定人力维护。
针对上面两个问题,需要在选型时选择合适的开源项目,充分了解开源项目的功能与业务需求,考虑开源项目的插件化扩展能力、代码质量、文档齐全和社区的活跃度及生态完善程度。
基于上面对基础设施的思考,下面对云原生实现的选型做了分析。
名字服务
名字服务是基本设施架构中最核心模块,应该具有高性能、高可用、支持Set等能力。Consul在开源的名字服务方案影响力较高,腾讯开源的TSeer(https://github.com/Tencent/TSeer)也有不错的能力,但是文档不太全,社区活跃度比较小。
Gateway与Sidecar
Gateway和Sidecar功能基本一致,应该使用相同的流量转发程序,envoy和linkerd都是不错的选择,envoy的扩展能力和活跃度好一些,可以基于envoy做数据面的转发。这里的问题是envoy需要把所有被调服务的配置都提前下发,如果在sidecar中使用,会有大量无效配置下发,在服务数量多时,会影响系统的稳定性,这也是istio中的问题。解决方案是先通过gateway冷启动(sidecar默认转发到gateway),再异步触发配置下发到相应的sidecar。
容器管理与资源调度
容器方案与虚拟机相比,主要解决了两个问题:
服务标准化,容器将服务依赖打包到镜像中,避免后期环境问题导致各种运维问题。
高效的弹性调度,解决突发流量问题,也节省了资源成本。
在容器编排中,k8s已经成为业界标准,不过k8s更多是解决资源编排和网络问题,没有服务治 理能力,基于k8s的knative、kubevela对k8s作了一层封装,某些场景下更符合开发团队的使用需求。
K8S的网络模型是开放的,目前也有非常多的实现,考虑性能和问题定位效率,不建议使用overlay类型的实现。calico的bgp模式可以直接使用原有数据中心的网络结构,如果使用云上的k8s,一般厂商都会实现类似的网络方案,容器和vm使用同一个网络平面。
考虑容灾容错,上层服务应该可以部署在多个k8s集群中,在单集群任何类型的故障发生时,也还可以正常对外提供服务。
基础公共服务
以下基础公共服务在大多业务场景是需要用到的,但是跟具体的业务逻辑关联不大,使用公共服务方式可以较好提高业务开发效率和架构能力。
配置管理
支持权限管理、富文本编辑器、SDK、版本管理和灰度功能。携程开源的apollo相对比较成熟。
日志
日志功能分为三部分,日志采集上报、日志存储和日志展示。ELK是最成熟的方案。
监控告警
监控功能分为三部分,其中监控上报有推和拉两种模式,拉的方式上报更简单(不用上报),监控存储最好使用时序数据库,监控规则配置除了按数量或百分比之后,应该还有同比能力。
云原生的Prometheus具有不错的性能和开源生态,强大的查询语法能满足业务常见的监控配置需求。
调用链
调用链一般集成到框架中,主要用于排查超时问题和了解调用拓扑图。Jaeger和Zipkin都是非常成熟的实现方案。
其他可能用到的公共服务
测试框架:具有api测试、压测、拨测能力。
定时任务管理:因为执行不是主动触发的,异步任务是比较容易出问题的,比如在计费、定时重置等业务逻辑中,定时任务管理系统可以针对异步任务的场景默认有重试和监控告警功能。
分布式事务管理:支持事务ID生成和任务流程编排,在某个子任务失败时支持重试和回滚。
分布式频控:支持精确和高性能的频控模式。
可视化管理:支持服务的部署、分组显示和下线,显示节点列表和状态,可临时屏蔽节点流量,显示服务的监控、日志、调用链及拓扑图。
(以上暂无发现有无成熟的云原生实现)
RPC的选型思考
虽然基础架构支持多种开发框架,但是统一技术栈可以减少沟通成本和长期运营成本,在RPC选型上,目前grpc和thrift是最有影响力的两种rpc实现,两者性能差异不大,grpc的文档和生态相对好一些。考虑前后端的高效联调和交互,可以通过proto协议文件生成typescript代码,前端直接通过gateway调用后端的rpc接口,而后端可以是cpp/go/java等不同语言实现的服务端。
CI/CD的实践
CI: 将代码集成的代码库时,可以增加代码规范检查、静态代码检查、单元测试增量代码覆盖率检查、接口自动化测试(墨盒)等,只有以上步骤都通过才可以合并代码。
CD:将代码转线上运行的版本,需要有编译、版本管理、灰度发布、回滚等功能。
基础设施的维护方式
基础设施建设的最终目标是解决产品的开发运营效率和服务质量问题,从业务团队的角度上,肯定是希望与业务逻辑无关的功能由基础设施来提供,只需专注于业务逻辑的实现,而不是花时间精力了解、接入各类平台或重复造轮子。从基础设施提供方来说,不应被动地接受业务方提出来各类需求,而是对业务模型有充分了解,明确业务边界,做好产品化能力,既提供稳定可靠的公共服务来满足业务通用需求,也可以对业务个性化需求做插件化开发和独立部署。
构架扩展能力
随着业务规模的增长,对基础架构也会带来新的挑战,一般会遇到的问题:
容量瓶颈:如名字服务性能、内网ip数量等。
无法快速满足业务的个性化需求,因为平台集成的功能太多,变更升级成本会比较高。
可能会出现业务相互影响的隐患。不管是什么原因,只要是混合部署,在逻辑上都会存在个别业务使用不当或异常影响到其他业务的可能。
总结
完善的基础设施建设可以为开发和运营提高效率,较好地保障业务的服务质量以及产品口碑。以名字服务/gateway/sidecar为核心的构架是一种比较优雅实现思路,而基于云原生的基础设施相比于完全自研的方式有很多好处,在节省人力的同时也方便长期运营,上文针对云原生选型问题也做了一些总结。基础设施的维护方式要从业务需求出发,最终目标能帮助业务解决非业务逻辑相关的问题,最后针对业务规模增长的问题,提出了使用公共网段部署gateway、多业务独立部署基础服务的解决方案。
【漫谈】用户画像:方法论与工程化解决方案
乐高思维-以低成本的方式平衡标准化和个性化
产品数据分析,重点是数据还是分析?
让我知道你在看