前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Lagom和Java构建反应式微服务系统

使用Lagom和Java构建反应式微服务系统

作者头像
用户1263954
发布2018-01-30 15:29:20
1.9K0
发布2018-01-30 15:29:20
举报
文章被收录于专栏:IT技术精选文摘IT技术精选文摘

介绍

Lagom是一个帮助您构建反应式微服务的框架。

大多数微服务框架着重于帮助您构建脆弱的单实例微服务,根据定义,这些微服务不具可扩展性或不具有弹性。 Lagom帮助您将微服务作为系统(反应系统)进行构建,以确保您的微服务从一开始就具有弹性。

构建反应系统可能很困难,但是Lagom则将从复杂性中脱离出来。

Akka和Play在下面做了大量的工作,开发人员可以专注于一个更简单的事件驱动的编程模型,同时受益于一个消息驱动的系统。 Lagom提供了一个有意见的框架,像导轨一样加快你的旅程。 Lagom工具和API简化了包含微服务的系统的开发和部署。

反应式微服务架构:分布式系统的设计原则,JonasBonér介绍了现代系统背后的基本原理以及如何构建。

“当我们纠缠我们的系统时,我们将权力从中央管理机构转移到更小的团队,他们可以快速抓住机会,保持敏捷,因为他们能够明确界定他们控制的界限内的软件。”(JonasBonér)

反应式微服务需求

看看基于微服务的架构,您很快就意识到他们有各种需求需要满足。这包括隔离和服务自主性,但最终导致“活动宣言”(reactivemanifesto.org)定义的特征。 Lagom默认是异步的 - 它的API通过流式的一流概念进行跨服务通信。所有Lagom API都使用Akka Stream的异步IO功能进行异步流; Java API使用JDK8 CompletionStage进行异步计算。通过内置支持具有命令查询责任分离(CQRS)的事件溯源(ES),Lagom倾向于以数据持久性为基础的事件源架构。持续实体是Lagom实施事件溯源。

Lagom框架包括库和支持开发部署的开发环境:

在开发过程中,单个命令构建您的项目,并启动所有服务和支持的Lagom基础设施。修改代码时,它会重新加载。开发环境允许您在短短几分钟内提供新服务或加入现有的Lagom开发团队。

您可以使用Java或Scala创建微服务器。 Lagom为微服务之间的通信提供了一个特别无缝的体验。服务位置,通信协议和其他问题由Lagom透明处理,最大限度地提高了方便性和生产力。 Lagom支持事件溯源和CQRS(命令查询责任隔离)的持久性。

您可以在您选择的平台上部署您的微服务器。

设计您的微服务系统

首先,确定需要一个可以消费异步消息的简单微服务器。它不需要有多复杂甚至提供很多价值。简单性降低了与部署相关的风险,可以快速获胜。接下来,在架构层面,抽出可以划分的核心服务。将其分为微服务系统。当你一次攻克一个问题时,你和你的团队会随着你一样努力学习,并且会变得越来越有效。使用诸如领域驱动设计(DDD)的方法可以帮助您的组织处理企业系统中固有的复杂性。 DDD鼓励将大型模型打破为有界的上下文。每个有界的上下文定义了适用于特定团队的边界,解决了具体的使用情况,并且包括实现该上下文系统所需的数据模式和物理元素。有限的上下文允许小团队一次关注一个上下文并行工作。

服务和通信

无论您是从头开始构建新系统还是将整体分解为微服务,以下问题的答案将有助于您做出良好的选择。

这项服务只做一件事吗?

这个服务是否自主?

这项服务是否拥有自己的数据?

你应该得到隔离和自主的服务。这样的服务通过网络发送消息来相互通信(服务间)。为了实现性能和恢复能力,您通常会运行多个相同服务的实例,通常在不同的节点上,并且此类服务内部通信也会遍历网络。此外,第三方和旧系统也可能会为您的微服务系统消费或提供信息。

服务间通信

虽然类似的,服务内和服务间通信具有非常不同的需求,但您需要多个实施选项。业务间通信必须使用松散耦合的协议和消息格式来保持隔离和自主性,而服务内通信可以利用具有较少开销和更好性能的机制。

服务调用(同步或异步(流))允许服务使用已发布的API和标准协议(HTTP和WebSockets)进行通信。 Lagom服务由接口,称为服务描述符。该接口不仅定义了如何调用和实现服务,还定义了描述如何将接口映射到底层传输协议的元数据。通常,服务描述符,其实现和消费应该与正在使用的传输方式无关,无论是REST,Websockets还是其他传输。

当您使用call,namedCall或pathCall时,Lagom将尽力尝试以语义方式将其映射到REST,这意味着如果有请求消息,它将使用POST,如果没有,它将使用GET。 Lagom中的每个服务调用都有一个请求消息类型和一个响应消息类型。当不使用请求或响应消息时,可以在其位置使用akka.NotUsed。请求和响应消息类型分为两类:严格和流式传输。严格的消息是可以由简单的Java对象表示的单个消息。消息将被缓存到内存中,然后解析为例如JSON。上述服务调用使用严格的消息。

流式传输消息是Source类型的消息。 Source是一种允许异步流式传输和处理消息的Akka流API。

此服务调用具有严格的请求类型和流响应类型。这样做的一个实现可能会返回一个Source,它以指定的间隔发送输入tick消息String。

通过提供服务描述符接口的实现来实现服务,实现由该描述符指定的每个Call。

sayHello()方法是使用lambda来实现的。在这里要注意的一点是,调用sayHello()本身不会执行调用,它只返回要执行的调用。这里的优点在于,当使用诸如认证的其他交叉切割问题来组合call时,可以使用普通的基于功能的组合来轻松完成。

提供服务的实现后,我们现在可以使用Lagom框架进行注册。 Lagom建立在Play框架之上,因此使用Play的基于Guice的依赖注入支持来注册组件。要注册一个服务,你需要实现一个Guice模块。这通过在根包中创建一个名为Module的类完成。

使用流式传输消息需要使用Akka流。 tick服务调用将返回以指定间隔发送消息的源。 Akka流对这样的流有一个有用的构造函数:

前两个参数是发送消息之前的延迟以及它们应该发送的间隔。第三个参数是应该在每个刻度上发送的消息。以1000的间隔调用此服务call和一个tick的请求消息将导致返回的流每秒发送一个tick消息。

如果要从请求头读取或向响应头添加一些内容,则可以使用ServerServiceCall。如果直接实现服务调用,您可以简单地将返回类型更改为HeaderServiceCall。

将消息发送到Broker,如Apache Kafka,可以进一步解耦通信。 Lagom的Message Broker API提供至少一次的语义并使用Kafka。如果新实例开始发布信息,则其消息将添加到先前发布的事件中。如果一个新实例订阅一个主题,他们将收到所有的过去,现在和未来的事件。主题是强类型的,因此,用户和生产者都可以预先知道流通的预期数据是什么。

要将数据发布到主题,服务需要在其服务描述符中声明该主题。

用于声明主题的语法就像已经定义了服务端点的语法一样。

Descriptor.publishing方法接受主题调用序列;可以通过Service.topic静态方法定义每个主题调用。后者采用主题名称,并引用返回主题实例的方法。默认情况下,流经主题的数据将序列化为JSON。通过为服务描述符中定义的每个主题传递不同的消息序列化程序,可以使用不同的序列化格式。

Lagom产生消息的主要来源是持久性实体事件。响应于发生的事情而不是以特殊方式发布事件,最好从持久性实体获取事件流,并将其适应于发送到消息代理的消息流。这样,您可以确保发布者和消费者至少处理一次事件,这样可以保证整个系统的一致性。

Lagom的TopicProducer Helper提供了两种用于发布持久性实体的事件流的方法,用于非分片式读取事件流的singleStreamWithOffset以及与分片式读取事件流一起使用的taggedStreamWithOffset。这两种方法都采取回调,该回调采用主题制作者发布的最后一个偏移量,并允许通过PersistentEntityRegistry.eventStream方法从该偏移量恢复事件流,以获取读取流。

以下是发布单个不分片事件流的示例

要订阅一个主题,服务只需要调用Topic.subscribe()订阅所关心的话题。例如,如果服务想要收集早期HelloService发布的所有问候消息,您应该做的是@Inject HelloService并订阅问候语主题。

当调用Topic.subscribe()时,您将返回一个Subscriber实例。在上面的代码片段中,我们使用至少一次传递语义订阅了问候语主题。这意味着发送到问候语主题的每个消息至少收到一次。订阅者还提供了一个atMostOnceSource,它为您提供最多一次的传递语义。如果有疑问,默认使用至少一次交付语义。

最后,订阅者通过Subscriber.withGroupId分组在一起。订阅者组允许集群中的许多节点消费消息流,同时确保每个消息只能由集群中的每个节点处理一次。没有用户组,您所有的服务节点将获得流中的每个消息,导致其处理被重复。默认情况下,Lagom将使用与使用主题的服务名称相同的组ID。

服务内部通信

单个服务(统称为集群)的节点需要较少的去耦合。因此,服务内通信可以利用具有较少开销和更好性能的机制。

Akka遥控

分布式发布 - 订阅

事件流

下图阐述了分布在三个服务器上的Lagom系统服务内和服务间通信的每一种类型。在此示例中,订单服务发布到一个或多个Kafka主题,而用户服务订阅消费信息。用户服务使用Akka remoting与其他用户服务实例(集群成员)进行通信。送货服务和用户服务通过在服务电话中流式传输信息进行交换。

持续性,CQRS和事件溯源

每个微服务器应该拥有其数据。不必在不同服务之间共享数据库,因为这将导致服务之间的紧密耦合,最终使数据库成为应用程序的瓶颈和耦合点。以这种方式,每个微服务器都在清晰的边界内运行。为了在Lagom中实现这一点,持久性模块促进了使用事件源(ES)和命令查询责任分隔(CQRS)。事件溯源是将所有更改作为域事件捕获的做法,这是事件发生的不可变事实。事件采集用于聚合根,例如具有给定客户标识符的客户。 Lagom引入了PersistentEntity作为API与ES进行交互。持久实体也是事务边界。不变量可以保持在一个实体内,但不能跨越多个实体。 Lagom将事件流保留在数据库中。事件流处理器,其他服务或客户端读取并可选地对存储的事件进行操作。 Lagom支持持久性的阅读侧处理器和消息代理主题订阅者。要在实体启动时重新创建当前状态,将重放事件。

如果你熟悉JPA,值得注意的是,PersistentEntity可以像JPA @Entity一样用于类似的东西,但是有几个方面是不同的。例如,从需要的地方从数据库加载JPA @Entity,即可能有许多具有相同实体标识符的Java对象实例。相比之下,只有一个具有给定标识符的PersistentEntity实例。使用JPA,您通常只存储当前状态,并且未捕获状态达到的历史记录。您通过向其发送命令消息与PersistentEntity进行交互。实体将自动分布在服务集群中的节点之间。每个实体只在一个地方运行,并且消息可以被发送到实体,而不要求发送者知道实体的位置。一个实体保持活着,只要它被使用就将其当前的状态保存在内存中。当一段时间没有使用时,它将自动被钝化以释放资源。当实体启动时,它会重放存储的事件以恢复当前状态。这可以是完整的更改历史记录或从快照启动,这将减少恢复时间。

Lagom支持以下数据库:

Cassandra

PostgreSQL

MySQL

Oracle

H2

Cassandra完全支持并集成到开发环境中,无需安装,管理或配置它。有关配置项目以使用Cassandra的说明,请参阅为持久实体使用Cassandra。如果要使用上面列出的关系数据库之一,请参阅为持久性实体使用关系数据库,了解如何配置项目。 PersistentEntity的一个简单的存根看起来像:

使用BehaviorBuilder的setCommandHandler在“Behavior”中注册处理传入命令的功能。您应该为实体可以接收的每个命令类定义一个命令处理程序。

命令处理程序返回一个Persist指令,它定义什么事件或事件(如果有的话)持续存在。每个命令必须通过实现PersistentEntity.ReplyType接口来定义要用作命令的消息类型。

当一个事件成功保存时,通过将事件应用到当前状态来更新当前状态。用于更新状态的功能使用BehaviorBuilder的setEventHandler方法进行注册。您应该为实体可以持续的每个事件类定义一个事件处理程序。在持续新事件和重播事件时都使用事件处理程序。

事件处理程序通常只是更新状态,但它们也可以改变实体的行为,因为可以定义用于处理命令和事件的新功能。快照有助于减少在启动PersitentEntity时重新创建PersitentEntity所需的时间。

创建您的第一个Lagom应用程序

您需要开始的一切都是JDK(Java Development Kit)8和Maven(3.3或更高版本)。 Maven下载依赖项并为您创建项目结构。可能需要几秒钟到几分钟完成。确认先决条件后,打开控制台或命令窗口,并按照下列步骤操作:

  1. 为您的项目创建一个新的目录。 切换到新目录并输入以下内容(全部在一行):

mvn archetype:generate -DarchetypeGroupId=com.lightbend.lagom -DarchetypeArtifactId=maven-archetype-lagom-java -DarchetypeVersion=1.3.5

3.Maven提示您:

groupId - 通常是像com.example这样的东西。

artifactId - 成为顶级文件夹名称,例如my-first-project。

version - 您的项目的版本,按Enter接受默认值。

package - 默认为与groupId相同的值

4.输入Y接受值。 Maven创建项目。

5.更改为顶级项目文件夹并运行它:

mvn lagom:runAll

runAll命令需要一点时间。它启动了Hello World微服务器并将其注册到服务目录中。它还启动了一个Cassandra服务器和一个Web服务器。

6.当您看到消息“服务启动...”时,通过从任何HTTP客户端(例如浏览器)调用hello服务端点来验证服务是否正在运行:http:// localhost:9000 / api /Hello/World,他的请求返回消息Hello,World!

生产中的Lagom

Lagom没有规定任何特定的生产环境,但是Lightbend Enterprise Suite提供了开箱即用的支持。 Lagom sbt支持利用sbt本机打包器产生各种档案。默认情况下,可以生成zip存档,但也可以生成tar.gz,MSI,Debian,RPM,Docker等。如果使用Maven,Maven有许多插件可以为各种平台生成artifacts。 运行包需要提供服务定位器实现,即提供您的服务能够在运行时动态查找另一个位置的功能。在技术层面上,您提供了一个ServiceLocator的实现。请到Lagom官方文档中了解更多的信息。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT技术精选文摘 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档