将 Lagom 的写入/读取端分离到单独的服务中?

Separate Lagom write / read sides into separate services?

我看过几个演示,包括 Chirper 演示应用程序: https://github.com/lagom/lagom-java-sbt-chirper-example

添加 chirp 和检索实时 chirp 流已添加到同一服务中。这似乎是常见的做法:

public interface ChirpService extends Service {

  ServiceCall<Chirp, NotUsed> addChirp(String userId);

  ServiceCall<LiveChirpsRequest, Source<Chirp, ?>> getLiveChirps();

  ServiceCall<HistoricalChirpsRequest, Source<Chirp, ?>> getHistoricalChirps();

  @Override
  default Descriptor descriptor() {
    // @formatter:off
    return named("chirpservice").withCalls(
        pathCall("/api/chirps/live/:userId", this::addChirp),
        namedCall("/api/chirps/live", this::getLiveChirps),
        namedCall("/api/chirps/history", this::getHistoricalChirps)
      ).withAutoAcl(true);
    // @formatter:on
  }
}

我的问题围绕着您可以将 addChirp 消息提交到消息代理(Kafka 进程)的主题,目的是将读取与写入分离。也就是说,写入将 return 成功,即使读取端(消费者)暂时不可用(即,chirp 由 Kafka 临时存储到磁盘,一旦可用就由读取端处理再次)。

将写入端和读取端分离成单独的服务,然后 运行 它们完全位于不同的端口上,这不是合乎逻辑的吗?还是这种方法有常见的缺陷?

在 Lagom 中写 read-side 时,您有两个选择:

  • Intra-service read-side:使用Akka Persistence Query直接从write-side的Journal中读取并构建一个read-side。获取新事件、跟踪偏移量(以了解已经读取了哪些事件)和创建读取端 tables 的操作发生在进程中,最相关的是偏移量跟踪和用户-table 更新发生在交易中提供 effectively-once 语义。服务内读取端的另一个优点是建模留在门后,只要 public REST 端点提供相同的 API.[=,您就可以自由重构 tables 27=]
  • 服务间读取端:(也称为远程读取端)替代方案意味着创建远程服务并将事件从源服务发布到代理中,以便远程服务可以使用它们。这有一些注意事项:(1) 事件现在是 public,因此 public API 不那么容易重构,(2) 发布不是事务性的,消费可能是 at-least-once (你通常想要的)或 at-most-once 所以端到端的保证不再是 effectively-once,(3)主题可以被其他服务访问(这不错,这只是一个额外的考虑),(4)写端和读端在不同的服务中,这有点不自然。

online-auction-java 演示应用程序中有一个远程读取端的演示:search-service 是一个远程读取端,它使用来自许多主题的事件,将信息整合到一个 elasticsearch 索引中。在这种情况下,使用远程读取端很有意义,因为:(a) 我们正在使用特定的存储技术(弹性搜索),以及 (b) 我们正在合并来自两个不同上游服务的流。

HTH,