简体   繁体   English

微服务:组合来自 SAME 服务实例的数据的最佳实践?

[英]Microservices: Best Practice for combining data from Instances of SAME service?

Scenario:设想:

We have two instances of the same microservice, which receives two events (pictured as Event1 and Event2 below) from Kafka.我们有同一个微服务的两个实例,它们从 Kafka 接收两个事件(如下图所示的Event1Event2 )。 The instances need to combine the result of their own individual transformations, with that of the other, and send only 1 notification downstream.实例需要将它们自己的单独转换的结果与另一个转换的结果结合起来,并且只向下游发送 1 个通知。

I am trying to understand what is the best way to do all this.我试图了解完成这一切的最佳方法是什么。 Specifically, how to make:具体如何制作:

  • each instance of the microservice to wait for the other instance,微服务的每个实例等待另一个实例,
  • and then combine the individual transforms into one然后各个变换合并为一个
  • and then check if the other instance has already combined and sent the notification, if yes, then skip !然后检查其他实例是否已经合并并发送通知,如果是,则跳过

Below diagram to help visualize:下图帮助可视化:

在同一微服务的多个实例中组合事件数据

Consider using the temporal.io open source project to implement this.考虑使用temporal.io开源项目来实现这一点。 You can code your logic as a simple stateful class that reacts to the events.您可以将逻辑编码为对事件作出反应的简单有状态类。 The idea of Temporal is that the instance of that class is not linked to a specific instance of the service. Temporal 的想法是该类的实例不链接到服务的特定实例。 Each object is unique and identified by a business ID.每个对象都是唯一的,并由业务 ID 标识。 So all the cross-process coordination is handled by the Temporal runtime.所以所有的跨进程协调都由 Temporal 运行时处理。

Here is a sample code using Temporal Java SDK.这是使用 Temporal Java SDK 的示例代码。 Go, Typescript/Javascript, PHP, Python are also supported.还支持 Go、Typescript/Javascript、PHP、Python。

  @WorkflowInterface
  public interface CombinerWorkflow {
    @WorkflowMethod
    void combine();

    @SignalMethod
    void event1(Event1 name);

    @SignalMethod
    void event1(Event2 name);
  }

  // Define the workflow implementation which implements the getGreetings workflow method.
  public static class CombinerWorkflowImpl implements CombinerWorkflow {

    private Event1 event1;
    private Event2 event2;
    
    private Notifier notifier = Workflow.newActivityStub(Notifier.class); 
    
    @Override
    public void combine() {
      Workflow.await(()->event1 != null && event2 !=null);
      Event3 result = combine(event1, event2);
      notifier.notify(result);
    }

    @Override
    public void event1(Event1 event) {
      this.event1 = event;
    }

    @Override
    public void event1(Event2 event) {
      this.event2 = event;
    }
  }

This code looks too simple as it doesn't talk to persistence.这段代码看起来太简单了,因为它不涉及持久性。 But Temporal ensures that all the data and even threads are durably preserved as long as needed (potentially years).但是 Temporal 确保所有数据甚至线程都可以根据需要(可能是几年)持久保存。 So any infrastructure and process failures will not stop its execution.因此,任何基础设施和流程故障都不会停止其执行。

There are multiple ways to get around such kind of data sync problems.有多种方法可以解决此类数据同步问题。 But since you are using Kafka, you should be using out of box functionalities offered by Kafka.但是由于您使用的是 Kafka,因此您应该使用 Kafka 提供的开箱即用的功能。

Option 1 (Preferable)选项 1(首选)

Kafka guarantees to maintain the order of events within the same partition . Kafka 保证在同一个分区内保持事件的顺序。 Therefore if your producer could send these events to the same partition, they would be received by the same consumer in any given consumer group (in your case, same instance - or if you are using threads as consumer, same thread of same consumer).因此,如果您的生产者可以将这些事件发送到同一个分区,它们将被任何给定消费者组中的同一消费者接收(在您的情况下,相同的实例 - 或者如果您使用线程作为消费者,相同消费者的同一线程)。 With this you wouldn't need to worry about about syncing events across multiple consumers.有了这个,您就不必担心跨多个消费者同步事件。

If you are using Spring Boot, this could be easily achieved by providing partition key in kafka template .如果您使用的是 Spring Boot,这可以通过在kafka 模板中提供分区键来轻松实现。

More on this topic : How to maintain message ordering and no message duplication有关此主题的更多信息: 如何维护消息顺序和不重复消息

Option 2选项 2

Now, if you don't have control over producer, you would need to handle this at application side.现在,如果您无法控制生产者,则需要在应用程序端进行处理。 You are going to need a distributed caching support, eg redis for this.您将需要分布式缓存支持,例如 redis。 Simply maintain the boolean state ( completed: true OR false ) for these events and only when all related events are received, process the downstream logic.只需维护这些事件的布尔状态( completed: true OR false ),并且仅当收到所有相关事件时,才处理下游逻辑。

NOTE : Assuming you are using a persistence layer, combining and transforming the events should be trivial.注意:假设您使用的是持久层,组合和转换事件应该是微不足道的。 But if you are not using any persistence, then you would need to use in-memory cache for Option1.但是,如果您不使用任何持久性,那么您将需要为 Option1 使用内存缓存。 For Option2, it should be trivial because you already have the distributed cache (and can store whatever you want).对于 Option2,它应该是微不足道的,因为您已经拥有分布式缓存(并且可以存储您想要的任何内容)。

It's worth noting that you cannot guarantee all of:值得注意的是,您不能保证所有:

  • a notification which needs to be sent will be sent in some finite period of time (this is a reasonable working definition of availability in this context)需要发送的通知将在某个有限的时间段内发送(这是在这种情况下可用性的合理工作定义)
  • no notification will be sent more than once不会多次发送通知
  • either instance can fail or there are arbitrary network delays任一实例都可能失败或存在任意网络延迟

Fundamentally you will need each instance to tell the other one that it's claiming responsibility for sending the notification or ask the other instance if it's claimed that responsibility.从根本上讲,您将需要每个实例告诉另一个实例它声称对发送通知负责,或者询问另一个实例是否声称该负责。 If telling, then if it doesn't wait for acknowledgement you cannot guarantee "not more than once".如果告诉,那么如果它不等待确认,您不能保证“不超过一次”。 If you tell and wait for acknowledgement, you cannot guarantee "will be sent in a finite period".如果您告诉并等待确认,则不能保证“将在有限的时间内发送”。 If you ask, you will likewise have to decide whether or not to send in the case of no reply.如果您提出要求,您同样必须在没有回复的情况下决定是否发送。

You could have the instances use some external referee: this only punts the CAP tradeoff to that referee.您可以让实例使用一些外部裁判:这只会将 CAP 折衷推给该裁判。 If you choose a CP referee, you will be giving up on guaranteeing a notification will be sent.如果您选择 CP 裁判,您将放弃保证会发送通知。 If you choose AP, you will be giving up on guaranteeing that no notification gets sent more than once.如果您选择 AP,您将放弃保证不会多次发送通知。

You'll have to choose which of those three guarantees you want to weaken;您必须选择要削弱这三个保证中的哪一个; deciding how you weaken will guide your design.决定如何削弱将指导您的设计。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM