审校 | 重楼
许多组织在其发展过程中达到了这样一个阶段,即曾经为他们提供良好服务的单一应用程序开始阻碍他们的发展。也许业务需要现有架构无法支持的新功能,或者需要更灵活的方法来存储和访问应用程序的数据。团队成长、相互冲突的性能需求和新的竞争性技术也会对单一的代码库构成挑战。采用事件驱动的微服务架构可以帮助企业应对这些挑战。
微服务通过将这些应用程序划分为专门构建的小型服务,克服了单一应用程序的局限性,这些服务可以根据它们要解决的业务问题进行定制。它们为企业提供了选择自己认为合适的编程语言、框架和数据库的自由。微服务可以根据自己的需要重新建模、管理和存储数据,从而为企业提供了完全控制如何最好地解决业务问题的能力。
在事件驱动的微服务架构中,系统通过产生和消费事件进行通信。这些事件驱动的服务从输入事件流(例如Apache Kafka主题)中消费事件,并应用其特定的业务逻辑,发出自己的输出事件,为请求响应访问提供数据,与第三方API通信,或执行其他所需的操作。
考虑事件驱动的微服务是否适合自己?
如果用户正在考虑一个事件驱动的微服务架构,第一步是确保它是自己所需要的。与许多技术决策一样,也存在权衡。单一应用程序通常与其数据存储紧密耦合,为其他内部功能提供快速的数据访问。但它们根据内部数据模型提供数据,根据底层技术提供性能和访问。例如,键值存储会导致糟糕的关系数据库,两者都不能很好地替代存储松散结构的文档。
如果用户发现自己正在编写(或使用)批量导出数据API,那么可能已经为事件驱动微服务做好了准备,这是最常见的迹象之一。类似地,如果用户正在编写定期轮询作业,以便将数据从一个数据库提取到另一个数据库中。这些是临时数据通信层的示例。用户实际上并不需要与该数据相关联的单体的业务功能,只是需要这些数据,然后可能用于继续编写自己的新业务功能。
从历史上看,在从联机事务处理(OLTP)系统提取数据以进行联机分析处理(OLAP)时,通常会发现这种模式。但是,随着数据、性能需求和业务需求的大量增长,这些相同的提取和加载模式现在普遍适用于任何只需要公共业务数据来完成其功能的操作系统。事件驱动的微服务提供了一种以不可变事件日志的形式访问历史数据和新数据的方法。
当用户需要以一致的方式向多个部门和团队提供对同一组数据的访问时,事件驱动的微服务也是一个很好的解决方案。例如,如果销售数据被打包为事件流,分析团队可以简单地订阅它,并确信他们使用的是与执行团队看到的完全相同的销售数据。事件流为数据通信层提供了基础,消除了点对点、特设、专用连接的纠结网络,并用一组易于使用的流代替它们。
利用现代云服务
用户创建的每个新服务(微型或其他)都需要部署管道、容器管理、监控和扩展服务。与单个单一服务相比,数十个微服务需要更多的开销和管理。这种开销被称为“微服务税”。简化和自动化操作将有助于降低成本,但这在历史上需要大量投资才能实现。
如今,用户可以更多地依赖托管云服务来减少微服务税。在这个时代,在Kubernetes上部署、管理、监控和扩展Dockerized服务是非常常见和容易的。同样,通过云服务(如Confluent Cloud)创建和管理Kafka主题比以往任何时候都更容易。
密切关注“托管”和“完全托管”服务之间的区别。选择完全托管的服务可以让用户继续实际运行业务,将所有维护、监视、扩展和安全需求外包给其服务提供商。依靠云服务,可以对微服务进行原型化和实验,而无需预先支付任何“微服务税”。用户可以简单地尝试它们,并采用对其最有帮助的部分和技术。
从小处着手,在现有系统的基础上构建
迁移到微服务架构不应该是一个反复更换的过程。首先,确定满足实际业务需求的特定用例。例如,用户可能需要从一个数据库中的四个不同关系表中获取和重新建模数据,以支持新的基于文档的搜索功能。如何将现有的非流数据源集成到事件驱动的架构中?
Kafka Connect是将数据库表引导到自己的事件流中的绝佳选择。用户可以连接到大量的本地数据库和云数据库、快照历史数据、过滤数据、屏蔽列等等。用户的源数据库仍然独立于Kafka Connect,让其在不影响现有系统的情况下增量地获取重要的业务数据。
用户可以增量地构建微服务,同时根据需要维护原始的单片应用程序。这不是一个“非此即彼”的问题,而是以对业务有意义的速度公开用户需要的额外数据和功能。
构建与业务需求一致的微服务
设计微服务来解决特定的、密切相关的业务问题,因为类似的问题往往需要类似的数据。将微服务与业务问题结合起来意味着除非业务发生变化,否则用户的微服务不太可能需要改变。例如,一家电子商务企业可以有一个处理支付的微服务,另一个处理库存管理的微服务,还有一个处理运输的微服务。对交付工作流所做的任何更改只会影响交付微服务。
将微服务边界与业务用例保持一致,可以减少意外或偶然更改的风险,因为功能被封装在一个服务中。在更复杂的用例中,业务工作流跨越多个微服务并不罕见,不过为了保持一致性,任何原子操作都应该保留在单个服务中。
尽量减少微服务的数量
微服务不需要很小。事实上,人们可能会发现,将微服务简单地看作是针对业务问题子集的专用服务是很有帮助的。许多人陷入的主要陷阱之一是为每一个功能构建微服务,最终往往会有数百或数千个服务!事件驱动微服务架构的目标不是构建尽可能多的服务,而是使用合适的工具来实现专用的解决方案。
在添加业务功能时,需要先查看是否可以合理地将其与现有服务集成。如果能够以一种似乎是对现有服务的合理扩展的方式添加功能,那么这样做可能比构建一个新的、可能不必要的服务更有意义。例如,扩展的库存管理功能应该在库存管理微服务中,而不是在另一个类似但不同的微服务中。
并不是所有模块从一开始就必须是微服务。一个合理的设计选择是使用具有健康API边界和关注点分离的模块化整体框架对解决方案实现原型化。用户可以将整个原型单体视为单个(大型)微服务,根据需要从事件流中读取和写入。一旦用户的业务用例变得更加明确,就可以根据需要将选择的模块拆分为自己的微服务。只在必要的时候引入新的微服务,不要忘记少即是多,尤其是刚开始的时候。
使用目录来跟踪事件流和服务
当用户创建更多的微服务和事件流时,将需要一些方法来管理、发现和跟踪使用情况和元数据。目录有两个主要功能:
(1)发现谁拥有事件流,它包含什么数据,以及它使用什么模式和结构。
(2)发现哪些微服务已经存在,谁拥有它们,它们负责哪些事件流和API。
在开始时,可以使用共享电子表格这样简单的东西对元数据进行编目。随着业务的增长,确实需要转向专用的元数据服务。Apache Atlas是一种常见的开源选择,不过更简单的答案是向云计算服务提供商寻求解决方案(例如Confluent cloud的Stream Catalog)。
创建由认可的工具、语言和框架组成的工具箱
事件驱动微服务的优点之一是,它为更广泛的技术选择打开了大门,包括各种编程语言、框架、数据库和工具。这对于创新和可访问性来说是件好事,但如果开发者使用太多不同的技术,特别是鲜为人知的或流行的选择,就会成为一个问题。
要解决这个问题,需要将关键利益相关者召集在一起,并决定将支持的技术工具箱。这不应该过度的限制,但是用户不希望不必要地支持工具和技术,因为这会增加成本、复杂性和管理开销。应用程序模板、代码生成器、事件生成器、测试框架、监视框架和编程语言只是用户可以在工具箱中找到的一些示例。
如果开发人员想要脱离工具箱,需要确保他们有充分的理由这样做,例如,为了实现某些他们无法通过其他方式创建的所需业务功能。在这种情况下,使用他们的经验作为扩展工具箱以包含新选项的案例研究。但是要小心,因为每个新添加的内容都需要努力支持。
作为一般规则,用户的目标应该是使开发人员尽可能容易地构建和维护其所需的微服务。用户甚至可以创建一个快速启动函数,生成一个带有服务骨架的GitHub回购,构建测试框架,等等。
充分利用集成和单元测试
事件驱动的微服务非常适合完全集成和单元测试。作为事件驱动微服务的主要输入形式,可以很容易地组合事件以涵盖广泛的输入和极端情况。事件模式约束了需要测试的值的范围,并为组合输入测试流提供了必要的结构。
用户通常可以通过加载带有特定事件的输入来“黑盒测试”其微服务,看看会产生什么结果。对于Kafka特定的事件,Kafka有一个内置的、基于Java的内存测试代理。通过启动代理,用户能够以编程方式生成事件并评估生成的结果。
对于基于容器的微服务集成测试,用户可以启动自己的容器化并行Kafka实例,或者直接插入云集群。制作并消费事件,然后在最后剥离所有内容。
对于单元测试,微服务类似于大多数其他应用程序架构。使用单元测试和测试所有函数,以确保输出与预期输出匹配。单元测试对于确保应用程序在第一次部署时就能正常工作,以及防止任何意外的机会至关重要。
事件流满足不同的需求
事件驱动的通信并不新鲜,但是大多数现代组织的需求已经发生了变化。数据集已经变得越来越大,单一的整体结构已经不足以处理现代组织的所有复杂和多样化的需求。事件驱动的微服务提供了一种强大而灵活的方式来满足当今的需求。事件流构成了数据通信的基础,为其他服务提供了可靠的事实来源,供它们在认为合适的情况下消费和使用。
与此同时,微服务为使用正确的工具解决业务问题提供了灵活性和选择。如今的现代云服务意味着用户在平台上花费的时间要少得多,而在问题上花费的时间要多得多。希望以上内容为人们提供了在组织中开始使用这个令人难以置信的强大和灵活的模型所需的基础知识。
原文How to get started with event-driven microservices,作者:Adam Bellemare