本文主要是介绍第五篇:稳定性之提升团队潜意识【依赖简化、谨慎变更】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
依赖简化
在分布式或微服务系统中,服务肩负不同职责,服务间必然存着依赖关系、往往系统复杂度的根源除了业务的本身复杂度,就是设计不恰当的耦合关系、或者服务划分不合理。在实际开发过程中,对单体服务进行重构的时候并不多。更多的时候,我们一开始做服务架构时便在使用微服务的架构模式。随着系统需求的渐渐复杂化,我们会发现,服务间的耦合越来越严重,甚至出现了循环依赖。这种时候我们不得不质疑自己,当初的模块是否划分的足够清晰,下面看几个列子。
依赖简介
上面三张图,描述常见的几种服务依赖关系。
图一:循环依赖
A依赖B,B依赖C,C依赖A,循环依赖会有很多危害,循环依赖让事情变得复杂,架构设计目标是简单,最大程度地减少软件不同部分之间的整体耦合。 较低的耦合意味着更高的灵活性,更好的可测试性,更好的可维护性和更好的可理解性。
循环依赖可能导致后果如下:
-
- 单个单元的测试包含所有单元的测试
- 难以对计划的变更进行影响分析。
-
- 服务相互依赖、相互影响、耦合严重
- 难以对计划的变更进行影响分析。
出现这种后果的原因如下:
-
- 数据冗余,数据冗余是导致服务循环依赖的主要原因,为了保证多个服务之间数据的一致性,某个服务对数据的修改要同步到其他服务,保证其他服务冗余字段的信息准确。
- 服务职责模糊,服务职责模糊是服务定义、职责模糊,导致上游服务和下游服务相互调用,出现这种情况,是否能够给出对应的解决方案。
-
- 对业务理解不透彻,不能针对业务对服务进行合理拆分。
图二:无环有向依赖图
A同时依赖B、C,B依赖D、C依赖E,无环有向依赖图,对于这种调用关系,很容易清晰的明白各个服务职责,职责单一、可以针对需求或问题进行影响分析,便于测试,在架构设计中,比较推荐这种调用关系,无环有向依赖图,值得注意的一点是:层级不可太多,如何层级过多,也会带来稳定性问题和性能方面的问题。
服务依赖原则
在架构设计设计中,往往可以通过架构设计原则或者方法,来避免出现循环依赖,约束服务间通信方式,还需要定期通过这些原则来审视我们的系统,找到循环依赖问题并进行优化。
服务依赖的几条规则:
- 上层服务可以调用下层服务。
- 同级服务之间不能产生依赖关系,及不能产生调用关系。
- 下层服务不能调用上层服务。
- 服务之间的调用关系只能是单向的。
- 层级最好不超过3层
- 服务间尽可能通过领域事件(异步)的方式来实现
检测&打破循环依赖
想要消灭掉循环依赖单靠设计原则是不够的,一方面可以通过服务依赖原则去约束,还需要技术手段主动帮助我们发现循环依赖问题,双管齐下才可以。试想下,我们开始微服务架构之后,我们的很多服务变成分布式的了,并且我们对服务进行了拆分,拆分之后,用户的一个请求进来,会依次经过不同的服务节点进行处理,处理完成后再返回结果给用户。那么在整个处理的链条中,如何发现循环依赖呢,可以通过调用链监控帮助我们检测发现循环依赖,从而打破循环依赖。
调用链监控
调用链监控是在微服务架构中非常重要的一环。它除了能帮助我们定位问题以外,还能帮助项目成员清晰的去了解项目部署结构,一旦服务出现几十微服务,甚至更多,相信在运行时间久了之后,项目的结构很可能就是下面图片这样了,在这种情况下,团队开发者甚至是架构师都不一定能对项目的网络结构有很清晰的了解,那就更别谈系统优化了。
调用链监控具体可以帮助我们做那些事情呢,下面就一起来具体看一下「调用链监控」的作用有哪些:
- 服务网络拓扑图
-
- 通过调用链监控中记录的链路信息,给服务生成一张网络调用的拓扑图,通过这张图,我们就可以知道服务之间的调用关系是怎样的,以及系统依赖了哪些服务。并且还可以起到监控全局服务的作用。
- 快速定位问题
-
- 在分布式系统一个请求可能会经过多个服务节点,如果有任何一个节点出现了延迟或者问题,都有可能导致最终的结果出现异常,有的时候不同的服务节点甚至是由不同的团队开发的、部署在不同的服务器上,那么在这么错综复杂的环境下,我们想要排查出是链条中的具体哪个服务节点出了问题,非常困难,那么有这么一套调用链监控系统就能让开发人员快速的定位到问题和相应模块。
- 优化系统
-
- 优化系统也是「调用链监控」很重要的一个功能。因为我们记录了请求在调用链上每一个环节的信息,我们就可以通过这个来找出系统的瓶颈,做出针对性的优化。还可以分析这个调用路径是否合理,是否调用了不必要的服务节点,是否有更近、响应更快的服务节点。通过对调用链路的分析,我们就可以找出最优质的调用路径,从而提高系统的性能。
- 团队成员自律
-
- 对团队开发人员的帮助也是非常大的。因为团队所有成员都可以通过这个调用链监控系统看到系统各个模块的状态,相当于给了开发同学一个放大镜,以前开发同学完成项目交付后,只要没有出现问题,可能不太关心系统的优化,但是有这个调用链监控系统之后,哪个模块性能高,哪个模块问题大,一眼就能分辨,通过这么一个看板,开发同学慢慢的也会对自己负责的模块有更多的责任感,也会很自觉的去优化自己的模块。这种习惯的养成,对研发团队而言,非常的重要。
调用链监控,业界也有很多主流的调用监控系统、例如:CAT、Zipkin、Pinpoint、Skywalking等等。可以下去了解下。
循环依赖检测
Java生态在这方面做的比较好,本身支持循环依赖检测、防止这类带到线上。
例如:RPC框架Dubbo在启动时检测依赖的服务是否可用,不可用时会抛出异常,防止Spring初始化完成。这种情况我们就叫做RPC服务间循环依赖。出现了循环依赖,必须有一方先启动。所以这种问题是一定需要解决的。
例如:Spring bean的循环依赖,检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明有循环依赖了。
小结
微服务架构设计提倡服务拆分、小而独立,便于业务快速迭代,故一个软件系统往往拆分很多服务,大部分业务需求需要多个服务配合才能完成,在对架构理解不是很透彻的情况下,研发工程师往往倾向于采用更容易的熵增方式实现业务功能,在这种情况下,循环依赖是一个非常容易发生的坏味道,对系统的健康具有巨大的危害。对于循环依赖,不能只靠设计原则来约束团队成员,可以通过技术手段或工具帮助我们发现系统中循环依赖问题。通过可视化的方式找到系统的循环依赖,针对此就可以对症下药,消灭坏味道。
谨慎变更
谨慎变更是告诉我们对线上的任何变更都需要慎重,慎之又慎,原因是线上90%的事故或故障都是变更引起的,变更范围包括需求变更、配置变更、代码变更、表结构变更等,对这类变更需要对其进行管理,如果把事故比作火灾,那么稳定性建设的核心就是围绕系统的风险隐患,建立“防火墙”,所以稳定性建设是持久战,“保持敬畏,坚持防范”。
互联网公司的研发模式基本小步快走,高速迭代,快速试错,及时调整,一个业务每周发布十几次的变更都是很正常的,原因是可能需求上线、bug修复、架构优化调整等等,所以变更是频繁的操作,变更的操作打破了线上原本稳定运行的状态,因为引入了新的变量,故变更是研发最高危的动作,为了应对这样的情况,一方面通过变更规范性来对变更管理,另外一方面通过技术手段对变更管理之变更三板斧。
变更规范性
变更流程规范
- 严格遵循团队内部代码合并规范性,包括Merge Request,保证上线的代码是经过严格测试和审核通过。例如本地开发环境-> 本地开发环境 -> 开发环境 -> 预发环境 -> 线上环境的发布流程,严禁未经上一个环境测试的代码提交到下一个环境。
- 耐心变更,是指发布的过程中,遵循发布流程,先灰度,在小流量,在全量发布,每发布一个阶段,应观察一段时间,确保发布的内容被验证,防止未能验证到的代码,或者可能存在风险的代码,带到线上环境。如此在故障场景下可减小故障范围。同时做好回滚措施,异常场景下可缩短故障时间。
- 发布的过程中,必须关注业务监控指标、告警等。
- 存在风险或者重大的变更必须通知受影响业务方,做好应急措施。
- 变更事项需要审核机制,确保每一次发布都被确认。
- double-check 原则
变更时间规定
- 节假日前不变更,严禁在重要活动、节假日前后发布,默认情况下,周五也不准搞事情(发布)。
- 高峰期不变更,严禁在业务流量高峰时间段发布,对于一般的变更,请在周一至周四中低峰时间段发布,对于重大变更,请在凌晨发布。
变更频率规定
- 尽可能减少重大变更发布,拆分多个小功能点,独立发布。
- 严禁多功能合并发布,包括代码搭顺风车上线,建议分开上线。
- bug修复应与产品迭代变更分开。
- 对于有一定的用户量的产品,尽可能控制发布频率。
变更三板斧
随着业务发展,系统逐渐复杂,只有变更规范性应对变更管理,往往是不够的,上述更多变更事前的规范性,尽可能把风险消灭在前期,那么也很有可能风险被带到线上,为了应对这样的情况,变更三板斧自然就出现了,变更三板斧更多是帮助我们发现问题,问题提前被验证,出现问题可回滚,可快速止损。
变更可监控
在变更的过程中,有效的监控比人工反馈或者验证响应更快,也会减少故障的持续时间进而降低影响。而没有监控的变更就像是摸象,甚至是出现系统出问题了,都需要等用户来告诉你,完善且有效的监控在变更过程的重要性,不言而喻,针对完善且有效的监控需要回答三个问题:是否有问题发生?哪里发生了问题?发生了什么问题?这三个问题是递进的关系,可以从问题倒推对监控的覆盖程度与范围,监控不单单是技术指标,更多的是结合实际业务场景去设计,才能够更加细化地感知异常。
变更可灰度
在变更的过程中,不可将变更的内容直接发布到线上环境中,有些变更的内容风险非常大,没有充足的时间,直接上线,可能是天灾,灰度发布(有名金丝雀发布)是黑与白之间,能够平滑过度的一种方式,灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。值得注意是,灰度需要有耐心,尽可能让其用户对灰度发布的内容进行验证,让用户真实的去参与实际的使用,通过监控和数据反馈,如果没有实际用户参与,灰度就失去了其意义。
假设:常见的对bug修复,可能只在预发环境测试没有问题,再次发布到小流量阶段,但是并没有经过小流量阶段验证,又再次发布到线上环境,到生成环境才发现问题,这个时候问题已被放大,所以要严格遵循变更流程。
变更可回滚
在变更的过程中,难免出现事故,出现事故该如何快速止损呢,回滚是故障恢复最好手段是各种预案,而回滚也是预案中最普遍,最有效的方式,值得注意的是回滚这个操作,强调的是何时回滚?如何能确保回滚正确性?要知道,系统并不是天然可以无缝回滚的,想要系统具备回滚的能力,需要在架构设计和实现阶段付出额外的精力的,可回滚的本质是系统的兼容性设计。
例如:常见的“只增不改不删”,一个 API 内要调整很多实现逻辑才能满足新业务的需求,此时不妨直接新增一个 API ,两个 API 保持参数一致,那么一旦新 API 有异常直接切换回旧的 API 即可。
小结
谨慎变更是为了提高系统的稳定性,也是稳定性建设尤其重要的一环,原因是线上90%的事故或故障都是变更引起的,对于谨慎变更这块,一方面通过变更规范性加文化意识宣贯引导,约束变更让变更更加的规范性,尽可能将风险提前暴露和消灭掉,另一方面通过变更三板斧对变更过程中的故障进行管理,包括变更过程的故障发现、故障预警、及时止损,减小影响范围。
关于稳定性建设之道大纲速览
目录:关于【稳定性建设之道】大纲速览_jackl-CSDN博客从理论、方法、实践多维度阐述稳定性、从全局视野出发、由内到外、从组织到文化,从风险识别到风险预防、从面向失败到主动失败多个阶段,多维度去描述如何打造一个高可用的系统。https://blog.csdn.net/liu_dudu/article/details/122333724
这篇关于第五篇:稳定性之提升团队潜意识【依赖简化、谨慎变更】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!