携程微服务体系下的服务治理之道和优化实践

网站建设4年前发布
24 0 0

微服务架构在中大型互联网公司中被广泛应用,随着业务的发展,应用数越来越多、调用关系也越来越复杂。中台化后,交易系统要支持业务线多,系统复杂性高,原系统虽然能支撑业务量的持续增长,但在稳定性、吞吐力和资源利用率上面,还存在优化空间。,本文站在业务开发角度介绍开发在微服务架构下遇到的相关问题(微服务架构的优缺点这里不再赘述),以门票活动预订流程查询引擎为例,分享微服务治理的实战经验,希望能给遇到同样问题的同学提供一些借鉴思路。,如下图所示,蓝色部分为本文的重点,20230306152812d91e871010e199891272028e6a823db22a065d394,图1 微服务架构关注点,在微服务治理之前,我们先简单了解一下微服务历史和陷阱。,微服务概念在2005年被提出,2011年用来代表架构风格。,定义:微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成,每个微服务仅关注于完成一件任务。,大家在使用SOA (Service-Oriented Architecture)的时候往往分不清和微服务有什么关系,总结如下:,20230306153031e21d2e198bdcaf787fe21734db9f8756bcf58e233,图2 微服务与SOA的关系,了解微服务与SOA关系后,再对比一下功能差异:,20230306153032e7df6d35576816328db3640d1da9c3461569b6122,表1 微服务与SOA对比,202303061528151333d8966ce34da57287573637299975b4b7e8907,图3 携程SOA演进,携程微服务:携程SOA2.0是微服务架构,推荐单机、单应用、单服务。,微服务这个话术会将关注点错误的聚焦在“微”上,大家会误以为服务越小越好,实际上大小并不是第一考虑因素。接下来我们来看看开发微服务应用的时候容易踩到的陷阱。,下图可以看出,服务拆分越细,调用关系越复杂。,调用链路理论上有 n * (n-1) 条:,20230306153035377711065431ec15453976d0fca942469defd5711,图4 服务粒度越细调用关系越复杂,应用粒度拆分过细容易带来以下几个问题:,调用路径 C - >D ->E 和 C ->E, 对于E的一次请求,可能会被调用了多次。,202303061528159120c2d196346100d458393792556a33bc9fb5730,图5 一次请求中服务E被重复调用,一条链路出问题,导致其他链路故障。当服务B1或B2 性能变差时,最终导致链路A/B都会被影响,严重情况下导致宕机。,20230306153142e6919df575a7001841b668ba88773ad1f01126726,图6 循环依赖,服务层级过深,一次请求链路太长会导致性能下降,每层网络延时和序列化反序列化时间都有性能损失,层级越深,下游性能越差。,链路太长,定位问题困难(效率低),当服务F出现故障时,下游A~E 应用 owner 需要排查原因。,202303061532414719b7948ce3f65ba28981a3135db91fb2b3ec107,图7 链路越长,性能损失越大,以上这些问题,在日常开发中容易遇到,下面我们看看怎么解决这些问题。,从下图中可以看到应用之间调用关系复杂,并且有严重的循环依赖问题。,20230306153038a49a06f19f9439d40fc940010f52dc0cd2f7d2658,图8 应用调用关系图(双黄线表示循环依赖),循环依赖是微服务里面容易忽视的问题,系统稳定的情况下不会出现问题,由于某些原因,当系统从稳定变成非稳定状态时,循环依赖容易导致更严重的故障。我们先看1个生产案例:,案例:发布过程中下游超时,订单下跌,刚接入流量的机器因线程初始化、类加载锁、JIT等会产生慢请求。,2023030615303832a1ea0257d43e9c1c57726e6662f9cada7239214,
,图9 发布过程中的慢请求,当流量接入时,请求在刚拉入的机器中多次来回调用,因多次慢请求叠加,导致接口越来越慢,机器资源耗尽,一台一台被拖垮,最终整个服务不可用,产生雪崩(如下图)。,20230306152816c42a9e05233f1e9479a18858df838f9800783f353,图10 发布过程中循环依赖导致应用雪崩,当然如果应用间循环依赖QPS很小,例如单机QPS在10以内,少量慢请求无法将资源耗尽,一般不导致故障,但是这种“坏味道”会给系统埋下隐患,严重的时候会演变为接口级的循环依赖,导致死循环,并且这种死循环可能在测试环境由于命中缓存没有被发现,发布到生产后有些缓存穿透的请求就会导致循环调用,直到超时;如果单机QPS上百,产生的慢请求短时间内耗尽资源,阻塞后续请求,导致性能下降,产生故障。,故障恢复期间,由于调用关系复杂,分不清上下游关系,无法根据调用关系来限流,导致定位困难,恢复时间长。,上述案例主要是由循环依赖引起,像一颗炸弹,为系统埋下隐患。,除了循环依赖,还有下面几类问题可以优化:,1)层级太深:,2)重复缓存:同一个DB不同应用重复构建缓存,3)流量大:,4)未隔离:​核心、非核心流量未隔离,5)效能低:人均应用多/资源使用率低,针对上面的几类问题,我们制定了微服务治理目标、原则和治理策略。,1)稳定:故障隔离,提升系统稳定性,2)交付:独立迭代、独立扩展、快速交付,横向拆分:减少耦合,独立迭代。,纵向拆分:减少应用层级,提高开发效率,缩短交付周期。,3)重用:相同功能复用,不同系统重复功能复用,减少重复开发,提升一致性。,1)避免跨团队维护一套代码。,2)服务粒度要与团队规模匹配,人均应用数在3个以内。,根据历史经验,一个人在超过3个应用之间来回切换开发,开发效率会降低,日常处理告警繁琐,业务和性能优化也无法聚焦。,3)应用分层:上一层可以依赖任意下一层级(不可反向依赖)。,4)层级深度:垂直域/小组内,应用层级控制在5层以内。,这里的“5层”是我们根据实际业务实际情况来定的。一个垂直域/小组内应用层级超过5层,一个需求上下游依赖太多,开发效率会降低。,1)业务领域拆分:单一职责,业务建模(对人员要求高),2)数据存储:独立的数据读写API,3)复用性:功能复用(比如基础数据提供能力,提供给不同小组使用),​​4)稳定规则与易变动规则隔离,5)快速失败:设置合理的熔断规则,6)异步通信:将与此次请求无关的操作/调用异步化,1)去除循环依赖,问题:服务B和服务C 循环依赖,策略,2023030615281738b0ae21959da026ae94032d5af2002f6f2beb542,图11 循环依赖治理,2)缩短调用链路,问题:服务BCD 链路太长(垂直域/小组内),策略,20230306152817320884a8137b983089b1450aea015c6c624c11314,图12 缩短调用链路,3)复用性,问题:服务BCD 对相同数据重复缓存(存在一致性问题),策略,下沉基础服务,提供基础数据:将相同的功能下沉为基础服务,例如:基础数据服务提供缓存,翻译等功能。避免不同的使用方重复缓存,重复接入翻译。,2023030615281851a96ec666c9d47375897078438651b0938c60318,图13 重复功能下沉,效果:​下沉基础数据服务,统一缓存,翻译等功能,提供给不同的开发组使用。​,4)流量治理,a)   重复调用,问题:一次请求,服务C同一个接口被重复调用,策略,功能内聚:将同一个功能对下游的依赖放到同一个服务内调用。由于系统自身迭代导致的不合理调用,可以按照上述方法优化。如果为了解耦将功能拆开,可以根据实际情况评估影响和收益。,202303061528181954c9d230179372cce813f28d79b4b7940e99165,图14 功能内聚合并重复调用,效果:功能内聚,多次调用合并为一次调用。,b)   降低调用量,问题:一个服务中,不同的接口功能拆分太细,下游使用的时候都需要调用多个接口组装结果。例如:一次请求服务B的a、b、c、d、e接口都被调用,下游为实现一个功能,需要调用太多小接口。,策略,2023030615303816d6e7e350153baea7c0650726011bdb3aa1b9696,图15 请求合并,效果:聚合相同功能,合并小接口,多次调用合并为一次调用。,c)   流量隔离,问题:非核心流量(例如:Job调度)大于用户流量,策略,流量隔离:一套代码,隔离部署,将核心和非核心流量隔离。核心流量承载用户请求,保证交易的稳定性,非核心流量承载离线任务调度和非核心场景调用。,20230306152819b75fd7a2481b4884015712cf3dcdf49dff833f639,图16 流量隔离,效果:总成本不变,核心链路稳定性得到提升,非核心链路CPU使用率得到提升。,d)   离线调度流量消峰,问题:单位时间内调度过于集中(Job),策略,合理的延长调度时间:适当延迟调度时间,降低每分钟的调用峰值,让每分钟内调用量更加平稳。,20230306152821925ca2609eb57710a1e399ae0d3edb14aec66c384,图17 离线调度流量消峰,效果:调度总时间在可接受范围内,调度时间拉长,单位时间内调用总量降低,降低服务端峰值压力。,问题:每秒内调度不均衡(Job),导致服务稳定性差或为了能承载请求需要冗余更多服务器资源。,2023030615282147a486172084b8c7b856350211ea53d9649055797,图18 客户端调度QPS不均衡,策略,客户端削峰填谷:调度波动太大,会导致请求到了服务端被限流或者服务端扩缩容。对于调度不均衡的离线任务,我们在客户端控制每秒内发送的请求量,让每秒内请求更加平稳,任务调度总时间不变。,20230306152821256ef3a395b205ad503030a0ff91d81ef87dcd158,图19 客户端调度从不均衡变为均衡,效果:分钟内总的调用量不变,服务端调用量从波动变为平稳。,5)降低人均应用数/提升CPU使用率,问题,策略,20230306152821f3f453251a25f7137739588870e80ff90b7473285,图20 应用合并,1)循环依赖(应用分层,解除应用间循环依赖),​2)链路长(减少应用层级):调用链深度缩短 40%,3)复用性(下沉基础数据服务,减少重复功能),​4)流量治理(降低水位线),5)开发效率(解耦&减少中间层),​6)查询引擎性能提升65%,QPS从8w提升至24w,​7)人均应用:人均应用数控制在2个以内,8)资源使用率(应用合并,提升CPU使用率),20230306153039d56d2a822101cc84ad9704f718cbff4341bbf0165,图21 门票活动查询引擎微服务治理前后对比,微服务架构下服务拆分越细,调用关系越复杂,层级越深,性能损耗越大,开发效率越低(垂直域/小组内),所以服务不是越小越好,而是“合适的大小”。,在构建微服务的时候,要根据业务体量、团队规模、成本等因素综合考虑,按照合理的原则,构建出适合的大小,以达到预期的目标。,服务治理是一个长期的过程,制定目标持续优化,让系统更快更稳定,为业务赋能。

© 版权声明

相关文章