目录 [−]
前几天我写了篇读书笔记: 《产品级微服务的八大原则》,介绍了Uber的SRE工程师 Susan J. Fowler 的免费书: Microservices in Production,文中提出了一个微服务成功与否的唯一标准就是可用性,非常有实践意义。但是这本书偏向于从 SRE (site reliability engineer)的视角看待微服务,对于开发工程师 (SWE, software engineer)来说,更关注的是如何正确地从单体程序重构到微服务架构,或者从头设计微服务架构, 这篇读书笔记主要就是介绍这方面的实践和经验。
Oreilly 的 的这本免费小书 Microservices AntiPatterns and Pitfalls由经验丰富的 Mark Richards 编写。书中将反模式(AntiPattern)定义为"起初看起来很美好,做到最后麻烦不断的实践模式",而将陷阱(Pitfall)定义为“起初看起来就不是一个好的设计”,书中列举了微服务开发中几种常见的反模式和陷阱,这些经验非常的接地气.他还提供了视频教程。
2006年 SOA (service-oriented architecture) 狂热流行,无数的公司随着技术潮流拥抱 SOA, 不管它们是否已经完全理解了这种复杂的架构风格的长处和短处,这些公司不可避免地陷入和服务粒度、性能、数据迁移以及SOA组织改变的斗争中,很多公司不得不放弃了 SOA, 或者折衷的建立了一种混杂的架构风格。
历史的悲剧又将重演。微服务是行业当前的发展趋势。现在,微服务就像2000年中期的 SOA 一样是技术的热潮。很多公司都在朝着微服务架构的方式改变,以期获得微服务架构的好处,例如便于测试,快速,易于部署,细粒度的可扩展性,模块化和敏捷性。然而,像 SOA 一样,这些企业开发微服务的时候又陷入了服务粒度,数据迁移,组织形式改变和分布式处理的斗争中。
就像很多新技术一样, 你了解的越深,架构风格、反模式、陷阱就会出现,并且这各个过程中得到不少教训。正如上面所说,反模式就像走到一条正确的路上,走了很久才发现路错了,而陷阱则是开始没多久你就会发现路是不对的。
这本书介绍了几种常用反模式和陷阱,但是明显的是,不可能将微服务所有的反模式和陷阱在这么一本薄薄的书中全部介绍。这些常用的反模式和陷阱包括服务粒度 (沙粒陷阱), data migration (数据驱动的迁移反模式), remote access latency ("我们到了吗"陷阱), reporting (到达报告反模式), contract versioning (静态契约陷阱), service responsiveness (超时反模式)等等。
数据驱动的迁移反模式
Data-Driven Migration AntiPattern
微服务会创建大量小的、分布式的、单一用途的服务,每个服务拥有自己的数据。这种服务和数据耦合支持一个有界的上下文和一个无共享数据的架构,其中,每个服务及其对应的数据是独立一块,完全独立于所有其他服务。服务只暴露了一个明确的接口(服务契约)。有界的上下文可以允许开发者以最小的依赖快速轻松地开发,测试和部署。
采用数据驱动的迁移反模式大多是当你从一个单体(monolithic)应用程序到微服务架构迁移的时候。我们将之称为反模式原因是,它似乎是在开始创建微服务的时候看起来是一个好主意,服务和相应的数据独立成一个微服务,非常的美好,但正如书中接下来介绍的,这可能会将你引向一个错误的道路上,问题是高风险,过剩成本和额外的迁移工作。
单体应用迁移到微服务架构有两个主要目标:第一个目标是单体应用程序的功能分割成小的,单一用途的服务。第二个目标是单体应用的数据迁移到每个服务自己独占的小数据库(或独立的服务)。
整合服务、合并到更粗粒度可以提升应用的整体性能,提高应用的健壮性和可靠性。你还可以移除服务之间的依赖,可以更好的控制、测试和发布。
当然你可能会说调用多个服务可以并行的执行,提到应用的响应,比如 reactive 架构的异步编程方式, 关键还是要权衡利弊, 确保对用户的及时响应以及系统整体的可靠性。
无因的开发者陷阱
Developer Without a Cause Pitfall
名字来自詹姆斯·迪恩演的电影《无因的反叛》(Rebel Without a Cause),一个问题青年因为错误的原因做了错误的决定。
很多架构师和开发者在微服务的开发中权衡利弊, 比如服务粒度和运维工具,但是基于错误的原因,做了错误的决定。
下图就是一个场景。服务被认为粒度太细,影响性能和可靠性,所以要迁移到一个单一的粒度更粗的服务上。
如果你不考虑这种改变带来的tradeoff,可能影响是很大的。
作者指出,要深刻理解选择微服务后面的商业驱动。
随大流陷阱
Jump on the Bandwagon Pitfall
因为微服务是现在的潮流,所以你选择了微服务,还没有仔细的分析你的商业需求、商业驱动、组织架构和技术环境,这就是随大流陷阱。
微服务并不适合所有的场景。
避免这个陷阱的方式充分理解微服务的好处和短处,俗话说,知己知彼,百战不殆。
好处:
- 发布:易于发布
- 测试:易于测试
- 改变控制:更容易的改变一个服务的功能
- 模块-
- 规模可扩展
短处
- Team组织改变
- 性能
- 可靠性降低
- 运维难度加大
所以理解了微服务的优缺点,结合自己的实际情况,来决定是否要采用微服务。
其它架构模式
微服务的架构很好,但是不是唯一的架构模式,比如下面还有一些其它的架构模式:
- Service-Based Architecture
- Service-Oriented Architecture
- Layered Architecture
- Microkernel Architecture
- Space-Based Architecture
- Event-Driven Architecture
- Pipeline Architecture
当然你并不一定只使用唯一的一种架构模式,你可能在系统中混用这些架构模式。
下面有一些架构的参考资料:
- Software Architecture Fundamentals: Understanding the Basics
- Software Architecture Fundamentals: Beyond the Basics
- Software Architecture Fundamentals: Service-Based Architecture
- Software Architecture Patterns
- Microservices vs. Service-Oriented Architecture
静态契约陷阱
The Static Contract Pitfall
这一节主要讲服务的版本控制。入股服务一开始就没有考虑版本控制,服务的schema发生变化时,或者内部实现逻辑有变化时消费者和服务器之间的通讯和业务处理就会发生问题。
所以你要为你的服务设计版本号。
有两种实现方式,在header中加入版本号,或者在服务的schema中加入版本号。
我们到了吗陷阱
Are We There Yet Pitfall
这个陷阱发生在你不知道远程调用要花多长时间的情况。50秒?平均多长时间呢,长尾的延迟呢?
首先你应该测量服务的调用时间,至少能知道一个服务远程调用的大概时间。
然后你应该评估不同的服务通讯协议的性能,比如REST、JMS、AMQP等。
当然性能也不是唯一个衡量远程通讯协议的因素,比如下面一节中讲到的内容。
REST陷阱
使用REST风格非常的流行,大部分的软件框架也选择它作为通讯的方式,比如DropWizard, Spring Boot等,有兴趣的读者可以阅读我写的Java RESTful框架的性能比较。
既然大家都在用它,还怎么是个陷阱呢?
如果把REST作为唯一的通讯方式,就有可能掉入这个陷阱。比如如何处理异步通讯(http 1.1是blocking的)、如何在一个事务中管理多次服务调用?如何支持广播?
你应该考虑两种类型的消息标准作为微服务架构中的消息传递:特定平台的标准和平台无关的标准。
特定平台的标准比如 JMS for java、MSMQ for .net。平台无关的比如 AMQP。
使用消息系统的好处可以异步请求,还可以实现广播的方式,还可以实现事务请求。
作者是 Java Message Service 第二版的作者之一,所以对消息系统有自己的见解。
