一、背景微服务架构广泛应用于中大型互联网公司。更复杂。集中化后,交易系统需要支持的业务条线多,系统复杂度高。原有系统虽然可以支撑业务量的持续增长,但在稳定性、吞吐量和资源利用率等方面仍有优化空间。分享目的本文从业务开发的角度介绍微服务架构下开发中遇到的相关问题(微服务架构的优缺点这里不再赘述),并以门票活动预订流程的查询引擎为例作为例子来分享微服务治理的实战希望能给遇到同样问题的同学提供一些参考思路。如下图,蓝色部分是本文的重点。图1微服务架构关注点在微服务治理之前,我们先简单了解一下微服务的历史和陷阱。2.微服务简史微服务的概念于2005年提出,2011年用于表示架构风格。定义:微服务是一种架构风格,其中一个大型复杂的软件应用程序由一个或多个微服务组成,每个微服务专注于只完成一项任务。2.1微服务与SOA的关系当你在使用SOA(Service-OrientedArchitecture)时,往往分不清微服务与什么关系。总结如下:微服务是SOA的实现。微服务是去掉ESB后的SOA微服务。一种类似于SOA但又是两种不同的架构设计风格。图2微服务与SOA的关系了解了微服务与SOA的关系后,比较功能差异:表1微服务与SOA的比较2.2携程SOA从1.0演进到2.0图3携程SOA演进携程微服务:携程SOA2.0是微服务架构,推荐单机、单应用、单服务。3、微服务的陷阱微服务会错误地关注“微”。人们会错误地认为服务越小越好。事实上,尺寸并不是首要考虑的因素。接下来,我们就来看看在开发微服务应用时容易踩到的陷阱。从下图可以看出,服务拆分的越细,调用关系就越复杂。理论上有n*(n-1)个调用链接:图4服务粒度越细,调用关系越复杂。应用粒度拆分太细容易导致以下问题:3.1重复调用调用路径C->D->E而C->E,对于E的一个请求,可能会被调用多次。图5服务E在一次请求中被重复调用3.2循环依赖一个环节出现问题,导致其他环节失效。当服务B1或B2的性能下降时,最终会影响链路A/B,严重时会导致宕机。图6循环依赖3.3链接过长。服务层次太深。过长的请求链接会导致性能下降。每层网络延迟和序列化反序列化时间都有性能损失。层级越深,下游性能越差。链接太长,很难定位问题(效率低)。当服务F出现故障时,下游A~E应用拥有者需要排查原因。图7链路越长,性能损失越大。这些问题在日常开发中很容易遇到。让我们看看如何解决这些问题。4.微服务治理从下图中我们可以看出,应用之间的调用关系复杂,存在严重的循环依赖。图8应用程序调用关系图(双黄线表示循环依赖)。循环依赖是微服务中容易被忽视的一个问题。当系统稳定时,不会有问题。由于某些原因,当系统从stable变为unstable时,循环依赖很容易导致更严重的故障。先来看一个生产案例:案例:发布过程中,下游超时,掉单。刚刚接收流量的机器会因为线程初始化、类加载锁、JIT等原因产生缓慢的请求。图9释放过程中的慢请求流量接通时,请求在刚拉进来的机器中来回调用多次,由于多个慢请求叠加,接口越来越慢,机器资源耗尽。一个接一个被拖垮,最终导致整个服务不可用,导致雪崩(如下图)。图10循环依赖导致发布过程中的应用程序雪崩。当然,如果应用间循环依赖的QPS较小,比如单机QPS小于10,少量的慢请求不会耗尽资源,一般不会造成失败,但这种“恶趣味”》会给系统埋下隐患,严重时会演变成接口级的循环依赖,导致死循环,而这个死循环在测试环境中可能找不到,因为它命中了缓存,而一些发布到生产后的缓存穿透请求会导致循环调用,直到超时;如果单机QPS超过一百,产生的慢请求会在短时间内耗尽资源,阻塞后续请求,导致性能下降和失败。故障恢复时,由于调用关系复杂,无法区分上下游关系,无法根据调用关系限流,定位困难,恢复时间长。以上案例主要是循环依赖造成的,就像一颗炸弹,给系统埋下了隐患。除了循环依赖,还有以下几类问题可以优化:1)层级太深:透传字段需要针对多个应用修改,迭代效率要求低。每一层网络延迟、序列化、反序列化都有性能损失。导致终端体验差2)重复缓存:同一个DB内不同应用重复构建缓存3)大流量:重复调用,直接调用或间接调用,端部服务压力大,离线任务峰值波动大4)否isolated:核心,非核心流量不隔离5)效率低:人均应用多/资源占用率低针对以上问题,我们制定了微服务治理目标、原则和治理策略。4.1治理目标1)稳定性:故障隔离,提高系统稳定性2)交付:独立迭代,独立扩展,快速交付水平拆分:降低耦合,独立迭代。垂直拆分:减少应用层数,提高开发效率,缩短交付周期。3)复用:同一个功能被不同系统复用,实现功能复用,减少重复开发,提高一致性。4.2治理原则1)避免跨团队维护一套代码。2)服务粒度要与团队规模相匹配,人均应用数量在3个以内。根据历史经验,如果一个人在超过3个应用之间来回切换开发,会降低开发效率,告警的日常处理会很繁琐,业务和性能优化也无法聚焦。3)应用分层:上层可以依赖任何下层(不能反向依赖)。4)层级深度:在垂直域/组中,应用层级控制在5层以内。这里的“5层”是我们根据实际业务情况确定的。如果一个垂直领域/组内的应用层级超过5层,一个需求的上下游依赖过多,会降低开发效率。4.3构建原则1)业务领域拆分:职责单一,业务建模(对人员要求高)2)数据存储:独立的数据读写API3)复用性:功能复用(比如基础数据提供能力,提供给不同的用户使用teams)可靠的核心和非核心隔离4)稳定规则和易变规则隔离5)快速失败:设置合理的熔断规则6)异步通信:将与本次请求无关的操作/调用异步化4.4治理策略1)Circular的移除依赖问题:服务B和服务C的循环依赖策略应用分层与定位:第一步是划分应用层(分层工具包括传统的三层架构、泛域分层等),应用定位是分为不同的级别。确认依赖关系:如果每层有多个应用,确认上下游关系。根据业务场景,根据父子关系、包含关系、依赖关系,确定各层的依赖关系和应用职责。图11循环依赖治理2)缩短调用链路问题:服务BCD链路过长(垂直域/组)策略域切分:将粗粒度应用按业务领域垂直划分,不同层级负责不同使系统更加独立的职责。减少透传:层层职责明确,减少不必要的透传,让开发更高效。图12缩短调用链路3)复用性问题:服务BCD重复缓存相同数据(存在一致性问题)策略Sink基础服务提供基础数据:下沉与基础服务相同的功能,例如:基础数据服务提供缓存、翻译等功能。避免不同用户重复缓存和重复访问翻译。图13重复功能下沉效果:下沉基础数据服务,统一缓存,翻译等功能提供给不同的开发组。4)流量治理a)重复调用问题:一次请求,服务C的同一个接口被重复调用策略功能内聚:将同一个功能的下游依赖放到同一个服务中调用。系统自身迭代导致的调用不合理,可以按照上面的方法进行优化。如果为了解耦而进行功能解耦,则可以根据具体情况评估影响和收益。图14函数内聚合和重复调用效果:函数内聚,多个调用合并为一个调用。b)减少调用次数问题:在一个服务中,不同接口的功能划分得太细,下游使用时,需要调用多个接口来组装结果。比如:一个请求服务B的a、b、c、d、e接口都被调用了,下游需要调用太多的小接口来实现一个功能。策略合并服务B中同一领域的功能:将相同的功能合并到一个接口中,以减少调用量。接口提供模块参数,按需调用:支持按需使用,不同业务场景不需要的功能,提供模块参数,按需传递参数。对于独立的前端页面接口,对外是透明的,内部封装了相应场景需要的模块参数,比如前端首屏请求。图15请求合并效果:聚合相同的功能,合并小接口,将多个调用合并为一个调用。c)流量隔离问题:非核心流量(例如:Job调度)大于用户流量策略流量隔离:一套代码,隔离部署,核心和非核心流量隔离。核心流量承载用户请求保证交易稳定性,非核心流量承载线下任务调度和非核心场景调用。图16流量隔离效果:总开销不变,核心链路稳定性提升,非核心链路CPU占用率提升。d)线下调度流量消峰问题:单位时间(Job)调度策略过于集中合理延长调度时间:适当延迟调度时间,降低每分钟的高峰调用量,使每分钟内的调用量更加稳定.图17离线调度流量调峰效果:总调度时间在可接受范围内,延长调度时间,减少单位时间总调用次数,减轻服务器峰值压力。问题:每秒调度(Job)不平衡,导致服务稳定性差或者需要更多的服务器资源冗余来承载请求。图18客户端调度QPS不平衡策略客户端削峰填谷:如果调度波动太大,会导致对服务器的请求受限或者服务器扩缩容。对于调度不平衡的离线任务,我们控制客户端每秒发送的请求量,使每秒请求更稳定,任务调度的总时间不变。图19客户端调度由不平衡变为平衡:分钟内总调用量保持不变,服务端调用量由波动变为稳定。5)降低人均应用数/提高CPU使用率问题人均应用太多,开发效率将CPU使用率降低到6%以下,应用数占比50%以上和总数量ofcores占30%以上策略短期:shrinkCapacity,将一侧的服务器数量减少到SRE标准的最低配置。Long-term:合并细分太细的应用,参考历史、现状和未来规划,合并细分太细且CPU使用率长??期低于6%的应用。图20应用合并五、实施效果1)循环依赖(应用分层,去除应用之间的循环依赖)去除65条循环依赖链接,消除雪崩风险,超时告警降低99%,故障排查效率提升至分钟级2)长链接(降低应用层级):调用链深度缩短40%3)复用性(下沉基础数据服务,减少重复功能)新增基础数据服务,统一缓存,解决一致性问题,缓存容量降低60%4)流量治理(下水位)重复调用:功能凝聚,消除重复调用大调用量:合并小接口,消除调用高峰;线下任务削峰填谷,降低调用峰值,核心应用调用降低73%,核心系统峰值降低50%5)开发效率(解耦&减少中间层)横向拆分独立功能,降低耦合,在独立开发的垂直领域减少3层,提高开发效率6)查询引擎性能提升65%,QPS从8w提升到24w,减少分工系统不稳定导致的服务变慢,垂直优化系统,并着重于用户端到底层的优化。7)人均应用:人均应用数控制在2个以内8)资源占用(应用Merge,增加CPU占用)40+应用的CPU占用(加权平均)从18%提升到32%之前查询引擎链接对比和治理后:图21工单事件查询引擎微服务治理前后对比六、微服务架构总结服务细分得越细,调用关系越复杂,层级越深,性能损耗越大,降低开发效率(垂直域/组),所以服务不是越小越好,而是“大小合适”。在构建微服务时,需要综合考虑业务量、团队规模、成本等因素,按照合理的原则构建合适的规模,以达到预期的目标。服务治理是一个长期的过程,设定目标并不断优化,让系统更快更稳定,为业务赋能。
