美团分布式服务治理框架OCTO之一:服务治理
写在前面
之前的文章介绍过美团的中间件leaf-code,今天介绍另一款非常强的中间件系统Octo,其实Octo算不上是中间件系统,应该是一整套分布式服务治理平台,美团的很多中间件能力都是通过Octo暴露出来的,比如配置中心MCC、服务注册与发现、Trace系统、日志系统、监控告警系统、负载均衡、容错降级处理、灰度发布等。
这样设计的一个好处是,RD通过一个平台就可以做所有自己需要做的事情,不像有的公司每个服务治理能力独立一个系统,搞一件事情需要去N个平台。这件事本身反映了美团的一个底层价值观,就是注重效率,有的公司谈提效,只是在嘴上。
Octo核心组件包括RPC、NS、Portal等。
Ocot诞生于2014年,随着美团发展越来越好,服务数量也越来越多,服务链路越来越复杂,保留出了很多问题,如:
研发效率低:缺乏标准的服务治理框架和组件,不少团队重复造轮子,导致研发资源浪费,治理参差不齐,整体可用性不高;
运维成本高:缺乏完善、便捷的体系化运维手段,难以进行准确的告警监控,对涉及多级链路故障定位困难;
服务运营难:服务指标数据收集困难,缺乏自动化深度分析,难以满足业务快速对指标的评估及决策的要求。
抽象归纳起来,痛点是:提升研发效率和质量,降低运营成本,对于支撑业务快速稳定发展非常重要。
由于服务治理是个大而全的事情,为降低开发成本,提升稳定性。Octo依托低耦合、模块化、单元化系统架构,满足了各种复杂业务场景需求,实现了异地多活等容灾目标。
Octo为什么做的好,很重要的一点是其设计围绕于目的本身。既然作为覆盖研发全生命周期的治理系统,Octo功能涵盖了服务定义、开发、测试、部署、运维、优化、下线服务的全生命周期,打造了一系列的组件和系统,方便研发同学专注于自身业务的全生命周期。
比如,在开发阶段提供了高性能、高可用、功能模块化的通信框架为服务之间提供接入的便利性;在测试阶段提供了SET化、泳道、服务分组等各种灰度策略,帮助业务快速无损试错;在运维阶段提供机器级别、框架级别、业务级别等层级分明的监控告警能力,帮助业务快速发现问题,定位问题;在优化阶段提供了详尽的指标自定义分析报表;
Octo架构
上面提到了Octo功能很多,细化下来,功能包括:
命名服务:服务注册/发现。
服务管理:服务状态监测;服务启动、停止;服务负载均衡。
容错处理:实时屏蔽异常的服务,自动调配请求流量。
流量分发:灰度发布、节点动态流量分配等场景。
数据可视化:服务调用统计上报分析,提供清晰的数据图表展示,直观定位服务间依赖关系。
服务分组:支持服务动态自动归组与不同场景下的自定义分组,解决在多机房场景下跨机房调用穿透、沙盒测试等问题。
服务监控报警:支持服务与接口级别多指标、多维度的监控,支持多种报警方式。
统一配置管理:支持服务配置统一管理,灵活设置不同环境间差异,支持历史版本,配置项变更后实时下发。
分布式服务跟踪:轻松诊断服务访问慢、异常抖动等问题。
过载保护:灵活定义分配给上游服务消费者的配额,当服务调用量超出最大阀值时,基于不同服务消费者进行QoS区分,触发流控进行过载保护。
服务访问控制:支持多粒度、多阶段的鉴权方式。
整体架构如下:
OCTO-RPC(开源Java/C++):分布式RPC通信框架,支持Java、C++、Node.js等多种语言。
SGAgent:部署在各服务节点,承担服务注册/发现、动态路由解析、负载均衡、配置传输、性能数据上报等功能。
Oceanus(待开源):HTTP定制化路由负载器,具体可参考《Oceanus:美团HTTP流量定制化路由的实践》一文。
OCTO-NS:包括SDK(Java/C++)、基础代理SGAgent、命名服务缓存NSC、健康检查服务Scanner等组件,提供命名服务,服务注册等信息的存储,服务状态检测的扫描等功能。
Watt(待开源):统计链路信息,计算服务各类指标作为监控报警依据。
MCC(待开源):统一配置中心,可进行服务配置的管理下发。
OCTO-Portal:服务注册、管理、诊断、配置、配额等功能的一站式管理平台。s
数据中心
前面提到了Octo是服务治理的一整套平台,通过报表页面可以看到所有请求的时延、TP99~TP999、QPS、成功率等一系列核心指标,粒度可以精确到秒、分钟、小时、天级别,检索维度可以支持按照调用端IP+服务各接口查询,也可以通过制定主机+接口查询指标。
这种维度的数据可以帮助开发人员全面掌控系统运行情况、快速定位问题,但海量的数据同样给Octo的数据中心设计带来了巨大的挑战。
原始数据架构
采集层:每个业务应用实例部署一个采集代理,代理通过将采集数据用批量 RPC 的方式发送给路由节点。
路由层:每个路由节点随机收到各服务的数据后,将同一服务的所有数据,用类似 IP 直连的方式通过 RPC 发送到计算层的同一个计算节点。同服务数据汇总到同计算节点才能进行特定服务各个维度的聚合计算。
计算层:每个计算节点采用 Akka 模型,节点同时负责分钟、小时、天粒度的数据计算集。每个计算集里面又有10个子计算 actor,每个子计算 actor 对应的是一个维度。采用“先计算指标,再存储数据”的准实时模式。
存储层:准实时数据使用 HBase 存储,元数据及较大数据采用 KV 存储(美团内部系统Cellar)及 MySQL 存储。
这个原始架构面对以下几个问题:
计算节点有状态,异常无法自动化迁移。计算层部署的每个节点平均负责200+服务的统计。一个节点 OOM 或宕机时,其管理的200个服务的数据会丢失或波动,报警等依托数据的治理功能也会异常。此外计算节点 OOM 时也不宜自动迁移受影响的服务,需人工介入处理(异常的原因可能是计算节点无法承载涌入的数据量,简单的迁移易引发“雪崩”),每周投入的运维时间近20小时。
系统不支持水平扩展。计算节点的压力由其管理的服务调用量、服务内维度复杂度等因素决定。大体量的服务需单独分配高配机器,业务数据膨胀计算节点能力不匹配时,只能替换更高性能的机器。
系统整体稳定性不高。数据传输采用 RPC,单计算节点响应慢时,易拖垮所有路由层的节点并引发系统“雪崩”。
热点及数据倾斜明显,策略管理复杂。按服务划分热点明显,存在一个服务数据量比整个计算节点200个服务总数多的情况,部分机器的 CPU 利用率不到10%,部分利用率在90%+。改变路由策略易引发新的热点机器,大体量服务数据增长时需要纵向扩容解决。旧架构是人工维护160余个大服务到计算节点的映射关系供路由层使用。
正是由于以上一些问题,导致系统会出现告警丢失、误报、数据不准、告警延迟等问题,于是着手开发了新的架构。
新架构有以下几个目标:
高吞吐、高度扩展能力。具备20倍+的水平扩展能力,支持日10万亿数据的处理能力。
数据高度精确。解决节点宕机后自愈、解决数据丢失问题。
高可靠、高可用。无计算单点,所有计算节点无状态;1/3计算节点宕机无影响;具备削峰能力。
延时低。秒级指标延迟TP99<10s;分钟指标延迟TP99<2min。
由于整个Octo服务治理系统数据体量巨大,近万亿级,实现高效、准确、快速的数据架构挑战巨大。
5. TP 数据是衡量服务最核心的指标之一,但在万亿规模下,精确的准实时多维度分布式 TP 数据是一个难题,原因详细解释下:
假设计算得出 IP1 的 TP99 是100ms、QPS 为50;IP2 的 TP99 是10ms、QPS 为50;IP3 的 TP99 是1ms,QPS为50。那么该服务整体 TP99 是(100ms x 50 + 10ms x 50 + 1ms x 50)/ (50 + 50 + 50) = 37ms吗?并非如此,该服务的真实 TP99 可能是 100ms,在没有全量样本情况下无法保证准确的TP值。
假设不需要服务全局精确的时延 TP 数据,也不可以忽略该问题。按上述方式拆分并合并后,服务按接口维度计算的 TP 数据也失去了准确性。进一步说,只要不包含 IP 查询条件的所有 TP 数据都失真了。分位数这类必须建立在全局样本之上才能有正确计算的统计值。
这套高效的数据中心系统架构需要基于实时计算或离线计算技术体系实现,参考业界主流数据处理方案,对比如下:
设计思路:
解决稳定性问题,思路是(1)将计算节点无状态化(2)基于心跳机制自动剔除异常节点并由新节点承载任务(3)消息队列削峰。 解决海量数据计算问题,思路是(1)在线&离线计算隔离,两者的公共子计算前置只计算一次(2)高并发高吞吐能力设计(3)理论无上限的水平扩展能力设计。 解决热点问题,思路是(1)优化计算量分配算法,如均衡 Hash(2)理论无上限的水平扩展能力设计。 解决水平扩展问题,思路(1)是将单节点无法承载的计算模式改为局部分布式子计算并汇总,但这种方式可能会对数据准确性造成较大影响,数据统计领域精确的分布式分位数才是最难问题,另外多维条件组织对分布式改造也相当不利。(备注:其中在1.2.3第五条有详细的解释) 解决海量数据分布式多维精确 TP 计算,采用局部分布式计算,然后基于拓扑树组织数据计算流,在前置的计算结果精度不丢失的前提下,多阶段逐级降维得到所有的计算结果。
技术方案:
数据流解析
系统根据待统计的维度构建了一棵递推拓扑树,如下图所示。其中黄色的部分代表消息队列(每个矩形代表一个 topic),绿色部分代表一个计算子集群(消费前置 topic 多个 partition,统计自己负责维度的数据指标并存储,同时聚合压缩向后继续发)。除“原始采集数据 topic 外”,其他 topic 和 consumer 所在维度对应数据的检索条件(如标红二级 topic :主机+接口,代表同时指定主机和接口的指标查询数据),红色箭头代表数据流向。
拓扑树形结构的各个子集群所对应的维度标识集合,必为其父计算集群对应维度标识集合的真子集(如下图最上面链路,“主机+接口+远程服务”3个维度一定包含“主机+接口”两个维度。“主机+接口”两个维度包含“主机”维度)。集群间数据传输,采用批量聚合压缩后在消息队列媒介上通信完成,在计算过程中实现降维。
计算模式解析
下面详细介绍数据拓扑树中分布式子集群的计算模式:
首先,维度值相同的所有数据会在本层级集群内落到同一计算节点。每个计算子集群中的各计算节点,从消息队列消费得到数据并按自身维度进行聚合(前置集群已经按当前集群维度指定分发,所以聚合率很高),得到若干计数卡表(计数卡表即指定维度的时延、错误数等指标与具体计数的映射 Map)。
其次,将聚合后的计数卡表与现有的相同维度合并计算,并在时间窗口存储指标。
若计算集群有后续的子计算集群,则基于后继集群的目标维度,根据目标维度属性做散列计算,并将相同散列码的计数卡表聚合压缩后发到后继 partition。
离线的天级计算复用了三级维度、二级维度的多项结果,各环节前面计算的结果为后面多个计算集群复用,任何一个服务的数据都是在分布式计算。此外,整个计算过程中维护着技术卡表的映射关系,对于 TP 数据来说就是精确计算的,不会失真。
整个计算过程中,前置计算结果会被多个直接及间接后续子计算复用(如三级聚合计算对二级和一级都是有效的),在很大程度上减少了计算量。
1. 高吞吐 & 扩展性关键设计
去计算热点:组织多级散列数据流,逐级降维。
降计算量:前置子计算结果复用,分布式多路归并。
将网络IO,磁盘IO:优化 PB 序列化算法,自管理 MQ 批量。
去存储热点:消除 HBase Rowkey 热点。
无锁处理:自研线程分桶的流、批处理模型,全局无锁。
全环节水平扩展:计算、传输、存储均水平扩展。
2. 系统高可靠、低运维、数据准确性高于5个9关键设计
无状态化 + 快速自愈:节点无状态化,宕机秒级感知自愈。
异常实时感知:异常节点通过心跳摘除,异常数据迁移回溯。
故障隔离容灾:各维度独立隔离故障范围;多机房容灾。
逐级降维过程中数据不失真,精确的 TP 计算模式。
3. 提升实时性关键设计
流式拓扑模型,分布式子计算结果复用,计算量逐级递减。
无锁处理:自研线程分桶的流、批处理模型,全局无锁。
异常实时监测自愈:计算节点异常时迅速 Rebalance,及时自愈。
秒级计算流独立,内存存储。
新数据中心架构收益
目前日均处理数据量超万亿,系统可支撑日10万亿+量级并具备良好的扩展能力;秒峰值可处理5亿+数据;单服务日吞吐上限提升1000倍+,单服务可以支撑5000亿数据计算。 最大时延从4小时+降低到2min-,秒级指标时延 TP99 达到 6s;平均时延从4.7分+降低到1.5分-,秒级指标平均时延6s。 上线后集群未发生雪崩,同时宕机1/3实例2秒内自动化自愈。 支持多维度的准实时精确 TP 计算,最高支持到 TP 6个9;支持所有服务所有维度统计。 千余节点集群运维投入从周20小时+降低至10分以下。
Octo系统是非常庞大与复杂的架构,可以发现整个架构中的任意几个环节都是值得大家学习与深挖的,巨大体量下的架构问题总会有很多相通的问题,解决方案也类似,只有不断揣摩、参考这种业界成熟的解决方案,我们才可以在自己系统架构设计过程中游刃有余。