译者 | 李腾辉
数十年来,人们一直采用单体构架来开发应用程序,而现在越来越多的人正在转向微服务架构。微服务架构可以为我们带来更快的开发迭代速度,更高的可扩展性、可靠性,以及灵活性—使用更合适的技术栈来开发各个组件。微服务架构依赖于各个独立部署的微服务,每个微服务都有自己独特的业务逻辑和数据库,对它的测试、增强和扩缩容也与其他服务无关。然而,微服务架构也面临着许多挑战,为了解决那些最常见的问题,一些设计模式被广泛地采用和改进,本文我们将介绍其中最重要的一部分。
必备的设计模式
在微服务架构中,有超过8种必备的设计模式,根据你正在开发的应用类型不同,我们将它们分为两大类——绿地应用(Greenfield application)和棕地应用(Brownfield application)。接下来,我们将更详细地了解这些模式。
适合绿地应用的设计模式
当我们从头开始设计应用时,我们可以随心所欲地采用微服务所需的各种最新、最先进的设计模式,现在让我们来一探究竟。
API网关模式
当你将整个业务拆分为多个微服务时会遇到下述问题:
你如何处理诸如鉴权、限流、重试、负载均衡、服务发现等问题?
你如何避免由于客户端直连微服务引发的网络拓扑混乱和耦合过高的问题?
如果客户端只需要部分数据集,谁来做数据过滤和映射?
如果客户端需要调用多个微服务才能获取到完整数据,谁来做数据聚合?
为了解决这些问题,API网关应运而生,它位于客户端和微服务之间,具有反向代理、请求聚合、优雅下线、服务发现等功能,它还可以根据客户端的不同选择暴露不同的API接口。
图1 – API网关示例UI组合模式
在这种模式下,微服务由负责具体业务的不同团队开发。而某些UI页面可能需要来自多个微服务的数据,例如,购物网站包含类目、购物车、购买选项、用户评价等功能,这些数据归属于各个微服务,由不同的团队负责。如何协调这个问题呢?
UI团队可以创建一个页面框架,通过组合多个UI组件来构建完整的页面,这种框架也称为单页应用(SPA, single-page application),像AngularJS 和 ReactJS 等前端框架都支持这一功能。这种模式还带来了更好的用户体验,允许用户刷新任何指定的页面区域。
独立数据库模式
微服务需要设计得独立且松耦合,那么对应的数据库架构应该是怎样的呢?有以下一些问题需要考量:
一个具体的业务场景可能涉及到多个服务的查询、联表、持久化等数据库操作,而这些服务由不同的团队负责
在异构的微服务架构中,每个微服务可能有不同的数据存储要求,如非结构化数据(NoSQL数据库)、结构化数据(关系型数据库)、图数据(Neo4j)
考虑到可伸缩性,数据库需要有备份和分片
图2 –服务配置独立数据库示例
一个微服务事务必须限制在它自己的数据库中,其它需要该类数据的服务必须调用这个微服务的API接口。如果你使用的是关系型数据库,那么每个服务使用自己独立的库有利于保证数据的私有性。同时为了更好地隔绝数据访问,最好为每个服务分配不同的数据库账号,这样确保了开发人员不能绕过微服务的API而直接访问数据库。
独立数据库模式使得每个微服务都可以选用最合适的数据库类型,如使用Neo4j用于社交图数据,使用Elasticsearch用于文本搜索。
Saga模式
当我们为每个服务配置一个独立数据库时,在实现跨服务事务时会出现问题,因为在这种情况下,本地ACID已经无法处理,我们如何保证数据一致性呢?解决方式是使用saga模式。saga是指一系列本地事务,其中每个本地事务更新完数据库后,会发布事件以触发下一个本地事务,saga模式还要求在任何本地事务失败时进行补偿。
有两种实现saga模式的方式:
- 编排(Choreography)——去掉控制器,由每个微服务负责监听和发布事件,并在失败时启用补偿事件。
控制比编排更容易实现,在控制机制下,只有控制器需要协调所有事件,而在编排中,每个微服务都必须监听并对事件做出反应。
熔断模式
在微服务架构中,一个操作会涉及调用多个微服务,如果其中一个下游的服务出现故障,它仍会继续调用该下游服务,最终导致耗尽所有的网络资源,同时也会造成较差的用户体验。那么我们该如何处理级联故障呢?
我们从电路断路器中得到灵感,设计出熔断模式来解决这个问题。具体来说,在客户端和微服务之间,会设置一个熔断器,用于追踪失败调用的次数,如果它超过阈值,它将触发熔断并快速失败。在一段时间之后,熔断器会再允许小部分请求通过来检测服务是否正常,如正常则恢复流量,否则继续保持断路一段时间。
图3 –熔断器状态机
按业务或子域划分模式
在微服务架构中,复杂的大型应用必须做到合理划分、高内聚、低耦合,每个微服务还应该是自治的,并且足够小,可以由"批萨大小"的团队(6-8人)开发维护。那么,我们应该怎么划分服务呢?
总体来说有两种划分方式——按业务能力或者子域:
业务能力是指可以产生价值的行为,例如,在一家航空公司中,业务能力可以是预订、销售、支付、座位分配等;子域概念来自于领域驱动设计(Domain-Design Pattern, DDD),一个领域由多个子域组成,如产品目录、订单管理、配送管理等。
适合棕地应用的设计模式
由于互联网应用已经发展了数十年,大约有80%的公司的业务是基于现有的应用运作的,这些应用被称作棕地应用。将棕地应用程序迁移到微服务架构是极具挑战性的工作。让我们看看有哪些设计模式可以帮助我们更好地简化迁移的工作。
扼杀者模式
扼杀者模式,取名来自于藤蔓这种植物,它通过缠绕杀死它所依附的树木。在这种模式下,单体应用的各功能被逐步地被替换为微服务,而对于客户端来说,由于外部API保持不变,客户端感知不到任何变化,随着转换进度的推进,最终所有功能都被重构为微服务,新架构"扼杀"取代了原来的单体架构。
防腐层模式
当新应用需要与遗留应用集成时,过时的基础协议、API和数据模型是一个让人头大的难题。如果妥协沿用旧模式和旧语义,可能会限制和破坏新应用的技术设计。要如何才能避免这个问题呢?
我们需要新增一个防腐层来转换两个系统之间的通信,防腐层同时兼容新应用和旧应用的数据模型,并根据与它通信的对象决定采用哪种通信方式。这样就实现了双赢,既不用更改旧应用逻辑,也确保新应用无需在设计和技术上做妥协。
图4 –防腐层示例
总结
微服务架构为开发人员带来了很大的灵活性,但随着要管理的组件数量的增加,也带来了许多难题。在本文中,我们介绍了对于微服务应用开发来说最必不可少的几种设计模式,供读者了解和学习。
译者介绍
李腾辉,51CTO社区编辑,目前在一家东南亚互联网金融独角兽担任资深Java工程师,负责金融借贷平台架构设计及核心建设工作,对互联网金融架构、微服务体系有较深入的研究,期望在互金领域持续深耕。
原文标题:Popular Design Patterns for Microservices Architectures,作者:Rajesh Bhojwani
链接:https://dzone.com/articles/popular-design-patterns-for-microservices-architec