领域驱动架构 微服务
如果您是企业架构师,那么您可能听说过微服务架构并与之合作过。 尽管您过去可能将REST用作服务通信层,但越来越多的项目正在迁移到事件驱动的体系结构。 让我们深入了解这种流行的体系结构的优缺点,它所包含的一些关键设计选择以及常见的反模式。
在事件驱动的体系结构中,当服务执行其他服务可能感兴趣的某些工作时,该服务会产生事件 -已执行操作的记录。 其他服务使用这些事件,以便它们可以执行事件所需要的任何自己的任务。 与REST不同,创建请求的服务不需要知道使用请求的服务的详细信息。
这是一个简单的示例:在电子商务网站上下订单时,会生成一个“下订单”事件,然后由多个微服务使用:
活动可以通过多种方式发布。 例如,可以将它们发布到保证将事件交付给适当的使用者的队列中,也可以将它们发布到发布事件并允许访问所有感兴趣方的“发布/订阅”模型流中。 在这两种情况下, 生产者都会发布事件,而消费者会接收该事件,并做出相应的React。 请注意,在某些情况下,这两个参与者也可以称为发布者 (生产者)和订阅者 (消费者)。
事件驱动的体系结构与REST相比具有一些优势,其中包括:
当然,事件驱动的体系结构也有缺点。 通过分离在紧密耦合时可能更简单的关注点,它们很容易过度设计。 可能需要大量的前期投资; 并且通常会导致基础架构,服务合同或架构,多语言构建系统和依赖关系图的额外复杂性。
也许最大的缺点和挑战是数据和事务管理。 由于事件驱动的模型具有异步特性,因此必须仔细处理服务之间的数据不一致,版本不兼容,监视重复事件,并且通常不支持ACID事务,而要支持可能难以跟踪或调试的最终一致性 。
即使有这些缺点,对于企业级微服务系统,事件驱动的体系结构通常还是更好的选择。 优点(可伸缩,松散耦合,对开发人员友好的设计)胜过缺点。
但是,在某些情况下,REST / Web界面仍然可能更可取:
确定事件驱动的体系结构之后,就该选择事件框架了。 事件的产生和使用方式是系统中的关键因素。 存在数十种经过验证的框架和选择,选择正确的框架和选择需要时间和研究。
您的基本选择取决于消息处理或流处理。
讯息处理
在传统的消息处理中,组件创建一条消息,然后将其发送到特定的(通常是单个)目的地。 一直处于空闲和等待状态的接收组件接收消息并采取相应的措施。 通常,当消息到达时,接收组件将执行单个过程。 然后,该消息被删除。
消息处理体系结构的典型示例是消息队列。 尽管大多数较新的项目都使用流处理(如下所述),但使用消息(或事件)队列的体系结构仍然很流行。 消息队列通常使用代理的“存储和转发”系统,事件在代理之间传播,直到事件到达适当的使用者为止。 ActiveMQ和RabbitMQ是消息队列框架的两个流行示例。 这两个项目都有多年的实践证明和公认的社区。
流处理
另一方面,在流处理中,组件到达特定状态时会发出事件。 其他感兴趣的组件在事件流上侦听这些事件并做出相应的React。 事件并非针对某个特定收件人,而是可用于所有感兴趣的组件。
在流处理中,组件可以同时对多个事件做出React,并对多个流和事件应用复杂的操作。 一些流包括持久性,其中事件在流中停留的时间很长。
通过流处理,系统可以重现事件的历史记录,在事件发生后上线并对其做出React,甚至执行滑动窗口计算。 例如,它可以从每秒事件流中计算每分钟的平均CPU使用率。
Apache Kafka是最流行的流处理框架之一。 Kafka是许多项目使用的成熟且稳定的解决方案。 它可以被认为是一种工业强度的流处理解决方案。 Kafka具有庞大的用户群,有用的社区以及不断发展的工具集。
其他选择
还有其他框架提供流和消息处理的组合或它们自己的独特解决方案。 例如,来自Apache的较新产品Pulsar是一个开源的pub / sub消息传递系统,该系统同时支持流和事件队列,并且都具有极高的性能。 Pulsar具有丰富的功能-它提供多租户和地理复制功能,因此也很复杂。 有人说,Kafka的目标是高吞吐量,而Pulsar的目标是低延迟。
NATS是具有“综合”队列功能的替代发布/订阅消息系统。 NATS旨在发送频繁的小消息。 它提供高性能和低延迟。 但是,NATS认为一定程度的数据丢失是可以接受的,因此性能优先于交付保证。
选择事件框架后,还需要考虑以下其他挑战:
活动采购
很难实现松散耦合的服务,不同的数据存储和原子事务的组合。 一种可能有用的模式是事件源 。 在事件源中,永远不会直接对数据执行更新和删除; 而是将实体的状态更改保存为一系列事件。
CQRS
上面的事件源提出了另一个问题:由于需要根据一系列事件来构建状态,因此查询可能很慢且很复杂。 命令查询责任隔离( CQRS )是一种设计解决方案,要求针对插入操作和读取操作使用单独的模型。
发现事件信息
事件驱动架构中的最大挑战之一是对服务和事件进行分类。 您在哪里可以找到事件描述和详细信息? 发生事件的原因是什么? 哪个团队创建了活动? 他们正在积极地工作吗?
应对变化
事件架构会改变吗? 如何在不破坏其他服务的情况下更改事件架构? 随着服务和事件数量的增加,如何回答这些问题变得至关重要。
成为好事件消费者意味着对变化的模式进行编码。 成为一个好的事件生产者意味着要了解您的架构更改如何影响其他服务,并创建设计合理的事件,并将这些事件记录清楚。
前提部署与托管部署
无论您使用哪种事件框架,您都还需要决定在内部部署框架(消息代理操作起来并不容易,尤其是具有高可用性),还是在Heroku上使用诸如Apache Kafka之类的托管服务。
与大多数体系结构一样,事件驱动的体系结构附带了自己的一组反模式。 这里有一些需要注意的地方。
好东西太多了
请注意,不要对创建事件感到兴奋。 创建太多事件将在服务之间造成不必要的复杂性,给开发人员增加认知负担,使部署和测试更加困难,并导致事件使用者拥塞。 并非每种方法都需要成为一个事件。
一般事件
请勿以名称或目的使用通用事件。 您希望其他团队了解您的事件存在的原因,该事件的用途以及何时使用。 事件应该有特定的用途,并相应地命名。 具有通用名称的事件或带有混淆标志的通用事件会导致问题。
复杂的依赖图
当心彼此依赖的服务,并创建复杂的依赖图或反馈循环。 每个网络跃点都会为原始请求增加额外的延迟,尤其是离开数据中心的北/南网络流量。
取决于保证的订单,交货或副作用
事件是异步的; 因此,包括顺序或重复项的假设不仅会增加复杂性,而且会否定基于事件的体系结构的许多关键优势。 如果您的使用者有副作用,例如在数据库中添加值,那么您可能无法通过重播事件来恢复。
过早的优化
大多数产品从小规模开始,随着时间的推移而增长。 尽管您可能梦想着将来需要扩展到一个大型的复杂组织,但如果您的团队很小,那么事件驱动的体系结构所增加的复杂性实际上可能会使您的速度减慢。 相反,可以考虑使用简单的体系结构来设计系统,但要包括必要的关注点分离,以便您可以根据需要增长将其交换出去。
期待事件驱动的解决一切
在较低的技术水平上,不要期望事件驱动的体系结构可以解决所有问题。 尽管此体系结构肯定可以改善许多技术故障,但不能解决核心问题,例如缺乏自动化测试,不良的团队沟通或过时的开发实践。
了解事件驱动架构的利弊,以及它们最常见的设计决策和挑战是创建最佳设计的重要组成部分。
如果您想了解更多信息,请查看我们在Heroku上构建的事件驱动参考体系结构 ,该体系结构使您只需单击一下即可在Heroku上部署可运行的项目。 此参考体系结构创建了一个销售虚构咖啡产品的网上商店。
产品点击被跟踪为事件并存储在Kafka中。 然后,它们由报告仪表板使用。
该代码是开源的,因此您可以根据需要进行修改并进行自己的实验。
翻译自: https://hackernoon.com/best-practices-for-event-driven-microservice-architecture-e034p21lk
领域驱动架构 微服务