Kafka的命令事件


事件通常分为以下两类:消息和命令。

  • 消息事件类似于简单的事实:用户发送他们的新地址,产品离开仓库,我们首先记录这些事实,而不立即考虑接下来会发生什么。
  • 命令事件类似于调用特定操作的命令:用户单击[BUY购买]按钮,然后系统采取该操作(例如,通过触发订单处理)。

 
如何如何使用kafka的事件流平台调用另一个应用程序中的流程?
办法:
  1. 把函数调用分离出来,变成一个服务,把事件写到事件流中,详细说明必要的行动及其参数。
  2. 然后写一个单独的服务,在调用程序之前观察该事件。

就应用逻辑而言,一个命令事件通常是以 "发射-遗忘 "的方式进行调度的(事件本身是以强有力的保证进行传递和存储的,例如精确的一次性语义)。
编写者假设事件会被正确处理,而监控和错误处理的责任则落在系统的其他地方。
这与角色模型非常相似:角色有一个收件箱,我们将消息写入该收件箱,并相信它们会在适当的时候被处理。

如果明确需要一个返回值,下游服务可以将一个结果事件写回第二个流。
命令事件与它们的返回值之间的相关性通常是通过一个相关标识符来进行的。
 
具体实现代码:
假设我们有一个[BUY]按钮,应该在我们的仓储系统中触发一个dispatchProduct(12005)函数调用。而不是直接调用该函数,我们可以将调用分割开来。我们创建一个命令流。

CREATE STREAM dispatch_products (
  order_id BIGINT KEY,
  address VARCHAR
) WITH (
  KAFKA_TOPIC = ' dispatch_products',
  VALUE_FORMAT = 'AVRO',
  PARTITIONS = 2
);

我们启动一个插入流的进程。

INSERT INTO dispatch_products ( order_id, address ) VALUES ( 12004, '1 Streetford Road' );
INSERT INTO dispatch_products ( order_id, address ) VALUES ( 12005, '2 Roadford Avenue' );
INSERT INTO dispatch_products ( order_id, address ) VALUES ( 12006, '3 Avenue Fordstreet' );

最后,我们启动第二个进程,观察事件流并调用dispatchProduct的foreach:

    ...
    Serde<GenericRecord> valueGenericAvroSerde = ...
    StreamsBuilder builder = new StreamsBuilder();

    KStream<Long, GenericRecord> dispatchStream = builder.stream(
      "dispatch_products",
      Consumed.with(Serdes.Long(), valueGenericAvroSerde)
    );

    dispatchStream.foreach((key, value) -> warehouse.dispatchProduct(key, value));

 

结论
这种方法是可行的,但它可能表明错过了改善系统整体架构的机会。

考虑一下当我们需要更多的行动时会发生什么。假设[BUY]还应该触发一个电子邮件和一个文本通知给客户。仓库软件应该完成它的工作,然后给两个新的主题写 SendEmail 和 SendText 命令吗?或者这两个新事件应该由写DispatchProduct的同一个进程来写?
一个月后,当我们需要我们的销售数字时,我们应该计算发送的产品数量,还是发送的邮件数量?我们是否应该同时计算,以验证它们是否一致?系统再增长一点,我们就得问:"那个[BUY]按钮后面有多少代码?发布周期是什么?改变它是否会成为一个障碍?" [BUY]按钮对整个公司都很重要,这也是理所当然的,但它的维护不应该让公司受制于人。

这里的根本问题是,在从一个单体内的函数调用转移到一个向特定接收者发布特定命令的系统时,我们已经解耦了函数调用,而没有解耦基础概念。当我们这样做的时候,架构就会以成长的痛苦来回应。

一个更好的解决方案是认识到我们的 "命令事件 "实际上是两个概念交织在一起。"发生了什么?"和 "谁需要知道?"

通过把这些概念分开,我们可以清理我们的架构。
我们允许一个流程专注于记录所发生的事实,而其他流程自己决定是否关心这些事实。
当[购买Buy]点击发生时,我们应该只写一个订单事件。然后仓储、通知和销售可以选择作出反应,而不需要任何协调。