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

时间:2018-05-29 15:24:05

标签: 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 个答案:

答案 0 :(得分:1)

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

  • 服务内读取端:使用Akka持久性查询直接从写入端的日志读取并构建读取端。获取新事件,跟踪偏移量(知道已经读取了哪些事件)和创建读取端表的操作发生在进程中,并且最相关的是,偏移跟踪和用户表更新发生在事务中提供effectively-once语义。服务内部读取方面的另一个优点是,只要公共REST端点提供相同的API,建模就会停留在门后,您可以自由地重构表。
  • 服务间读取端:(也称为远程读取端)备选方案意味着创建远程服务并将事件从源服务发布到代理,以便远程服务可以使用它们。这有一些警告:(1)事件现在是公开的,因此公共API不易重构,(2)发布不是事务性的,消费可能是at-least-once(你通常想要的)或at-most-once所以端到端保证不再是effectively-once,(3)其他服务可以访问该主题(这不是坏事,它只是一个额外的考虑),(4)写入端和读取端存在于不同的服务中,这有点不自然。

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

HTH,