将Lagom写/读端分开为单独的服务?

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

添加啁啾和检索实时啁啾流将添加到同一服务中 . 这似乎是常见的做法:

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进程)的主题,目的是将读取与写入分离 . 也就是说,即使读取端(消费者)暂时不可用(即,啁啾由Kafka临时存储到磁盘,一旦再次可用,由读取端处理),写入将返回成功 .

将写入端与读取端分离为单独的服务并将它们完全在不同的端口上运行是不合逻辑的?或者这种方法有共同的陷阱吗?

回答(1)

2 years ago

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

  • 服务内读取端:使用Akka持久性查询直接从写入端的日志读取并构建读取端 . 获取新事件,跟踪偏移量(知道已经读取了哪些事件)和创建读取端表的操作发生在进程中,并且最相关的是,偏移跟踪和用户表更新发生在事务中提供 effectively-once 语义 . 服务内部读取方面的另一个优点是,只要公共REST endpoints 提供相同的API,建模就会停留在门后,您可以自由地重构表 .

  • 服务间读取端:(也称为远程读取端)备选方案意味着创建远程服务并将事件从源服务发布到代理,以便远程服务可以使用它们 . 这有一些警告:(1)事件现在是公开的,因此公共API不容易重构,(2)发布不是事务性的,消费可能是 at-least-once (你通常想要的)或 at-most-once 所以结束 - 到端保证不再是 effectively-once ,(3)其他服务可以访问该主题(这不仅仅是一个额外的考虑因素),(4)写入端和读取端存在于不同的服务中,这有点不自然 .

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

HTH,