事件驱动型微服务是被构建用于满足特定界限上下文的小型应用程序。消费者微服务从一个或多个输入事件流中消费并处理事件,生产者微服务则往事件流中生产事件以给其他的服务消费。事件驱动型微服务是一系列输入事件流的消费者,同时也是另外一些输出事件流的生产者,这是很正常的。这些服务可能是无状态的也可能是有状态的,并且可能包含同步的“请求–响应”API。这些服务都共享从事件代理消费事件或往事件代理生产事件的通用功能。事件驱动型微服务之间的通信是完全异步的。
事件流由事件代理提供服务,本章后半部分将对此进行详细介绍。运行任何有一定规模的微服务通常需要使用发布流水线和容器管理系统,本章末尾会对此进行讨论。
构建拓扑
拓扑这个术语经常出现在事件驱动型微服务的讨论中,通常用于表示单个微服务的处理逻辑。它也可能用于表示在独立的微服务、事件流和“请求–响应”API 之间的类似图的关系。下面依次看一下拓扑的各种定义。
微服务拓扑
微服务拓扑是单个微服务内部的事件驱动拓扑。它定义了对传入事件执行的数据驱动操作,包括转换、存储和发布。展示了从两个输入事件流获取数据的单一微服务拓扑。
微服务拓扑从事件流 A 获取事件并物化到数据存储中。物化操作将在本章后面进行详细介绍。同时,微服务也从事件流 B 获取事件,然后过滤出一些事件,执行转换,再与存储的状态进行联结。结果被输出到一个新的事件流中。微服务的事件获取、处理和输出都是其拓扑的一部分。
业务拓扑
业务拓扑是实现复杂业务功能的一系列微服务、事件流和 API。它是服务的任意分组,可以表示由单个团队或部门所拥有的服务,或是那些实现复杂业务功能超集的服务。第 1 章中详细介绍的业务沟通结构组成了业务拓扑。微服务实现了业务界限上下文,而事件流提供了用于共享跨上下文领域数据的数据通信机制。
微服务拓扑详细描述了单个微服务的内部工作方式,业务拓扑详细描述了服务之间的关系。
展示了有 3 个独立微服务和事件流的业务拓扑。注意,业务拓扑并没有详细描述微服务的内部工作机制。
微服务 1 从事件流 A 中消费并转换数据,然后生成结果到事件流 B。微服务 2 和微服务 3 都从事件流 B 中消费。微服务 2 严格充当一名消费者的角色,并提供了 REST API,使得数据可以被同步访问。同时,微服务 3 根据其界限上下文需求执行自己的转换并输出到事件流 C。新的微服务和事件流可以根据需要添加到业务拓扑中,通过事件流进行异步耦合。
事件内容
事件可以是发生在业务沟通结构范围内的任何事情。收到一张发票、预订一间会议室、要一杯咖啡(是的,你可以把咖啡机连到一个事件流上)、雇用一位新员工以及完成任意的代码等,都是发生在某个业务内的事件的例子。重要的是要认识到,事件可以是任何对业务重要的“事情”。一旦开始捕获这些事件,就可以在整个组织内创建事件驱动系统来使用这些事件。
事件是关于“发生了什么”的记录,非常类似于用应用程序的信息和错误日志来记录应用程序内发生了什么的方式。但是,如第 1 章所述,与这些日志不同,事件还是事实的单一来源。因此,它们必须包含准确描述所发生事件所需的所有信息
事件的结构
事件通常用键 / 值(key/value)格式表示。值存储着事件的完整细节,键则用于标识目的、路由以及基于相同的键对事件执行的聚合操作。键并不是所有事件类型的必选字段
无键事件
无键事件用于描述一个单一的事实陈述。举例来说,一个客户与产品发生了交互,比如用户在电子书平台上打开了一本书,这就是一个事件。顾名思义,此类事件没有涉及键
实体事件实体是一个唯一的东西,并且使用唯一 ID 作为键。实体事件描述了一个实体,通常是业务上下文中的一个对象,在某个时间节点上的属性和状态。对于图书出版商来说,以 ISBN 为键的图书实体就是一个实体事件。值的字段包含了与该唯一实体相关的所有必要信息
实体事件在事件驱动架构中相当重要。它们提供了一个实体状态的连续历史,并可用于物化状态。只需要最新的实体事件来确定实体的当前状态。
键控事件
键控事件包含了一个键,但并不表示一个实体。键控事件通常用于划分事件流,以保证在单个事件流分区中的数据局部性(本章后面会进一步介绍)。举个例子,以 ISBN 为键的事件流表示有哪些用户跟图书有过交互
请注意,事件可以按键聚合,这样就可以为每个 ISBN 组成一个用户列表,从而产生以 ISBN 为键的单个实体事件。