事件驱动微服务体系架构

如果您是一名企业架构师,您可能听说过微服务架构,并使用过它 。虽然您过去可能使用REST作为服务通信层,但是越来越多的项目正在转向事件驱动的体系结构 。让我们深入了解这种流行架构的优缺点、它所包含的一些关键设计选择以及常见的反模式 。
什么是事件驱动的微服务体系结构?
在事件驱动的体系结构中,当服务执行其他服务可能感兴趣的某些工作时,该服务将生成一个事件—执行操作的记录 。其他服务使用这些事件,以便它们能够执行由于该事件而需要的任何自己的任务 。与REST不同,创建请求的服务不需要知道使用请求的服务的详细信息 。
这里有一个简单的例子:当一个订单被放置在一个电子商务网站,一个单一的“订单放置”事件产生,然后被几个微服务消费:
1.order服务,它可以向数据库写入一个order记录 。
2.客户服务,它可以创建客户记录 。
3.支付服务,它可以处理支付 。
事件可以以多种方式发布 。例如,可以将它们发布到保证将事件交付给适当使用者的队列中,也可以将它们发布到发布事件并允许访问所有相关方的“发布/订阅”模型流中 。在这两种情况下,生产者发布事件,消费者接收该事件,并做出相应的反应 。注意,在某些情况下,这两个角色还可以称为发布者(生产者)和订阅者(消费者) 。
为什么使用事件驱动的体系结构
与REST相比,事件驱动架构提供了以下几个优点:
异步——基于事件的架构是异步的,没有阻塞 。这使得资源可以在他们的工作单元完成后自由地转移到下一个任务,而不用担心之前发生了什么或者接下来会发生什么 。它们还允许对事件进行排队或缓冲,从而防止使用者向生产者施加压力或阻塞它们 。
•松耦合——服务不需要(也不应该)知道或依赖于其他服务 。在使用事件时,服务独立运行,不了解其他服务,包括其实现细节和传输协议 。事件模型下的服务可以独立地、更容易地更新、测试和部署 。
•易于扩展——由于服务在事件驱动的体系结构下解耦,而且服务通常只执行一项任务,因此跟踪特定服务的瓶颈,并对该服务(且仅对该服务)进行扩展变得很容易 。
•恢复支持——带有队列的事件驱动架构可以通过“重播”过去的事件来恢复丢失的工作 。当用户需要恢复时,这对于防止数据丢失非常有用 。
当然,事件驱动的架构也有缺点 。通过分离紧密耦合时可能更简单的关注点,它们很容易过度设计;它们可能需要大量的前期投资;而且常常导致基础设施、服务契约或模式、多语言构建系统和依赖关系图的额外复杂性 。
也许最大的缺点和挑战是数据和事务管理 。由于事件驱动模型的异步性,它们必须小心处理服务之间不一致的数据、不兼容的版本、监视重复的事件,并且通常不支持ACID事务,而不支持最终的一致性,因为后者更难以跟踪或调试 。
即使有这些缺点,事件驱动的体系结构通常也是企业级微服务系统的更好选择 。主要的优点是可伸缩的、松散耦合的、开发人员操作友好的 。
何时使用REST
然而,有时REST/web接口可能仍然更可取:
•您需要一个异步请求/应答接口 。
•您需要对强事务的支持 。
•您的API对公众可用 。
•您的项目很小(REST的设置和部署要简单得多) 。
您最重要的设计选择—消息传递框架
一旦决定了事件驱动的体系结构,就该选择事件框架了 。事件生成和使用的方式是系统中的一个关键因素 。目前已有数十种经过验证的框架和选择,选择正确的框架需要时间和研究 。
分俩个大类: 消息处理或流处理 。
消息处理
在传统的消息处理中,组件创建消息,然后将其发送到特定的(通常是单个的)目的地 。一直处于空闲状态并等待的接收组件接收消息并相应地执行操作 。通常,当消息到达时,接收组件执行单个流程 。然后,删除消息 。
消息处理体系结构的一个典型例子是消息队列 。尽管大多数较新的项目使用流处理(如下所述),但是使用消息(或事件)队列的体系结构仍然很流行 。消息队列通常使用代理的“存储和转发”系统,事件在此系统中从一个代理传递到另一个代理,直到它们到达适当的使用者 。ActiveMQ和RabbitMQ是消息队列框架的两个流行示例 。这些项目都有多年的实践经验和成熟的技术社区 。
流处理
另一方面,在流内处理中,组件在达到某个状态时发出事件 。其他感兴趣的组件在事件流中侦听这些事件并作出相应的反应 。事件不针对特定的收件人,而是对所有感兴趣的组件可用 。


推荐阅读