微服务架构相比单体架构而言的长处,能够列举出很多:服务个体更小,更内聚,业务职责更清晰,可复用性更强,能够独立部署公布等等;从软件开发的角度,灵活性和效率都会有很大的晋升……
然而,微服务架构实质上是分布式系统架构,各个服务须要配合协同来实现产品的需要,业务数据的扩散使得服务之间须要通过集成来实现协同工作,那么问题来了,集成要采纳什么形式?要以什么样的准则进行?如何设计能力尽量保障不同服务之间数据的一致性?
一、凌乱的实现
微服务架构下举荐应用 REST 作为服务间同步通信的形式,对于非实时需要,能够基于事件来实现异步合作。这个准则非常简单,也非常容易实现,然而仅遵循这个准则却很难让咱们沿着微服务的路线走上来。一些号称微服务架构的零碎,最后服务拆分并无太大问题,但随着逻辑的一直扩大,跨服务数据交换场景的减少,这个简略的准则就很难指引日常的决策,甚至引发了一些新的问题,举几个例子:
1)服务循环依赖
在一些场景下服务 A 依赖服务 B,会调用服务 B 的 API,而在另外一些场景下,服务 B 也须要服务 A 的数据,也会通过调用服务 A 的 API 来实现。单从实现层面来看,按需获取数据,实现很不便,能够实现业务要达成的成果;但从久远来看,两个服务的耦合越来越紧,将来新增需要的实现老本会越来越高,成为技术债。
2)第三方系统集成实现到业务服务中
在一些业务场景下,以后产品须要的业务数据须要从几个第三方零碎获取并进行整合甚至通过一些计算后能力应用,之前的一些我的项目在初期实现时,数据从第三方零碎获取后,通过解决间接写入业务数据库,就把集成的代码间接写到业务服务中,看起来并没有太大的问题,只有代码上做好隔离就好了。但实际上,前期产生了一些辣手的问题让咱们不得不作出扭转:
- 一些定时触发的集成工作,每次只会在一个服务实例上运行,在运行期间可能会有大量的数据读取、计算、更新、插入等操作,会短时大量占用以后服务实例的资源,重大的状况下以后服务实例甚至无奈失常对外提供服务。
- 类似的集成以同样的形式集成到业务服务中,比方不同品牌的产品库存会从多个第三方零碎获取,业务服务变的臃肿。
- 集成方的一些变动间接影响到业务服务,比方 API 的降级,这种扭转必须要从新降级部署业务服务能力实现。
3)集成接口不幂等
无论在第三方系统集成和外部服务的调用过程中,接口不幂等都会造成数据不统一的问题。最典型的场景是服务 A 调用服务 B 的接口更新或写入数据,服务 B 解决胜利,但因为网络起因,服务 A 没有收到服务 B 的响应,服务 A 重试调用接口,此时,服务 B 因为接口不幂等返回异样的响应,导致业务流程无奈继续下去
现实是饱满的,事实是骨感的,大多数的我的项目开始于满怀激情的整洁架构的幻想,而开发工作并不像设想的那么顺利,随同着我的项目人员更替、交付压力大、人员能力有余等等,架构开始逐步走向大家不冀望的方向,技术债台高筑,攻城狮们疲于奔命的追赶进度的同时,只能望债台兴叹。
二、集成的准则
当问题产生时,架构师们都能第一工夫站进去说这个设计太烂了,怎么能做成这样;事后诸葛是咱们积攒教训的重要伎俩,从高筑的技术债台,从疲于救火的线上问题,从接了新需要确找不到正当计划……咱们始终在总结经验,为了防止再次摔倒在同一个中央,有哪些架构设计准则能够后行呢?
1)单向依赖
微服务拆分之初都定义了各个服务的上下游关系,咱们能够定义上下游服务的依赖关系如下:
- 上游服务能够间接依赖上游服务,上游服务能够通过上游服务提供的 API 同步对上游服务的数据进行读写。
- 上游服务不依赖上游服务,上游服务数据状态变动如果会对上游服务产生影响,能够通过公布畛域事件,由上游零碎监听事件作出对应的操作。
2)服务间仅冗余援用信息
微服务的各个领域实体之间存在着各式各样的关系,当畛域实体 A 依赖畛域实体 B 的信息时,通常须要在畛域实体 A 中保留一部分畛域实体 B 的正本信息,那这份正本信息中该蕴含哪些信息呢?
举个例子,畛域实体 A 是订单,畛域实体 B 是客户,客户端每次查问订单信息时,都要求同时查出客户的姓名、性别和手机号码,将这 3 个要害信息冗余在订单的服务中就能够轻松满足需要了,所有听起来是那么的美妙。
然而,这 3 个要害信息如果是能够变动的,那么问题就来了,如果畛域实体 B 中的信息更新了,畛域实体 A 中的信息要不要更新,如果不更新会造成数据不统一,如果更新无端减少了复杂度,而很有可能因而而产生循环依赖。
因而,在无奈确定数据变动的精确状况时,在正本中只保留援用信息最保险,须要残缺信息时能够通过援用查问相干信息。
3)为第三方零碎构建外观服务
面对第三方系统集成,在系统集成过程中要思考的更周全,个别状况下,咱们无法控制第三方零碎,一旦集成呈现问题,须要沟通解决方案,排期开发,联调测试等等,修复周期很长。
另一个问题是第三方零碎通常采纳的技术栈或集成形式可能和咱们的零碎齐全不同。比方它可能是个十分老旧的零碎,提供的接口是基于 XML 的 SOAP;再比方它可能无奈提供 API,只能通过导出文件到某个 SFTP 或发送邮件的形式进行集成……
为了让第三方系统集成产生尽量小的影响,咱们偏向于构建外观服务来暗藏第三方零碎实现的细节,通过外观服务对第三方零碎的性能进行包装,提供和以后零碎更加统一的集成形式。咱们能够把外观服务和第三方零碎看做是一个整体,那么第三方零碎的集成对于以后零碎内的服务来说,服务间的集成就能够和外部服务一样解决。而对于第三方系统集成相干的细节内容被隔离在外观服务中,第三方系统集成的变动,只须要批改外观服务就能够了。
4)集成接口实现要思考幂等性
这个准则非常简单,但实现过程中非常容易被疏忽,如果不在设计好的测试用例中,测试过程中也很难发现问题;少数状况下是到了线上,用户应用的实在场景才会发现问题,这时曾经产生了业务影响。
因而在波及集成的接口中,要特地关注,业务上是否要求接口的幂等性,接口不幂等的状况下业务是否可能失常的流转。
5)契约测试
服务提供的接口通常不只有一个消费者,不同消费者关怀的信息往往可能也不一样,随着服务数量的减少,在没有契约测试的状况下,很有可能产生因为一个需要批改了以后服务接口的实现,而影响其余已有性能。而往往这个问题直到全面回归的时候能力齐全发现,甚至可能产生因改变范畴很小,回归不够,在上线前也难以发现。
契约测试能够很好的解决这个问题,一方面测试前置,尽早提供反馈,另一方面也起到了架构守护的作用。
小结
系统集成是分布式系统中肯定谈判及的问题,而且是个大问题,因为它间接影响到以后零碎的架构,一个微不足道的改变很可能就毁坏了整个零碎架构的准则,长此以往准则便形同虚设。
微服务架构也不例外,在短少架构束缚的状况下,只图一时之快的实现往往会断送了微服务的劣势,一个个渺小的不合理改变会逐步将整个架构大厦捣毁,所谓千里之堤,溃于蚁穴就是这个情理。
因而,在微服务架构设计之初,咱们就要在团队内建设一些准则,明确零碎间集成须要恪守的一些标准,并且在实际过程中定期 review,必要时能够采纳一些架构守护的辅助工具,来爱护架构的衰弱度。
起源:码猿外
作者:麻广广
申明:文章取得作者受权在 IDCF 社区公众号(devopshub)转发。优质内容共享给思否平台的技术伙伴,如原作者有其余思考请分割小编删除,致谢。
IDCF DevOps 黑客马拉松,2021 年度城市公开赛,11 月 20-21 日,深圳站,企业组队参赛 & 集体参赛均可,一年等一回,错过等一年,连忙上车~ 公众号回复“黑马”退出