1.Lagom概念介绍
lagom框架包含一系列的可以支持我们从开发到部署的库以及开发环境:
>在开发阶段,可以通过一个简单的命令构建我们的项目,启动所有你的服务,并且可以支持所有的lagom基础设置层。当你修改了代码,logom是有热加载的。开发环境可以让你在几分钟内添加进一个新的服务或者加入一个现有的lagom开发团队
>你可以使用java或者scala创建微服务。Lagom为服务通信提供了一个特别的的无缝体验。服务定位,通信协议以及其他的问题都被Lagom处理掉了,提供了方便和效率。同时,Lagom对于持久化是支持ES(事件源)和CQRS(命令查询职责分离)的。
>在任意你选择的平台上部署。为了简化部署,Lagom有很多可以开箱机用的产品组件,比如Application Monitoring(监控的)。这些产品组件提供了一种在容器环境中的简单的方式来部署,测量,监控和管理Logam服务
设计一个达到高伸缩和面对意想不到的失败具有弹性微服务系统是机器苦难的,如果没有Lagom这样的框架,你需要去处理在高度的分布式系统中所有复杂的线程和并发的问题,你是可以避免这些缺陷,同时提高工作效率的。Logam允许你在现有的约束下采用响应式架构。例如你可以想下面这样创建微服务:
>与遗留系统/或者替换程序的整体功能
>使用Cassandra或者你自己选择的数据库和/或与其他数据存储集成
2.Lagom设计理念
考虑由Jonas Bonér提出的响应式微服务的一些基础的需求:
>隔离是弹性和灵活力的先决条件并且服务边界之间的消息通讯是异步
>自主服务通过发布它的协议/API只能保证自己的行为。服务需要可被寻址的,它应该是位置透明的
>现在需要的是,每一个微服务都为自己的状态和持久化负责
如下的这些特性,促进这些最佳实践:
>lagom默认是异步的---他的API让服务间通信通过一流的流的概念。所有的Lagom API为了异步的流而使用AKKA Stream的异步的IO能力;java API使用jdk1.8的CompletionStage来处理异步计算;scala使用Future
>与传统的中央管理的数据库对比,Lagom倾向分布式的持久化模式。我们鼓励--但不是必须--事件源的架构来持久化。Lagom的默认的持久化实体的模式是采用ES(事件源)与CQRE结合的方式。为什么事件源那么重要呢,下面单独解释下:
ES管理数据持久化:
当我们设计微服务时候,需要记住每一个微服务都应该有自己的数据和直连的数据库,其他的服务使用服务API于数据进行交互。但是这里不能在不同的服务间共享数据库,因为这会导致服务
之间的紧耦合。
在这种情况下,每一个微服务定义一个限界上下文,类似于DDD领域驱动的限界上下文。
为了实现解耦的架构,Lagom的持久化促进了ES和CQRS的使用。事件源是捕获所有的改变当做领域事件的实践,即已经发生的不可改变的事实。举例,在一个使用ES的系统中,当Mike从他的银
行账户中取出钱,那个事件就可以被简单存储为“¥100.00 取款”,而不是在CRUD程序中的复杂的相互作用。如果使用CRUD,那么在包装的事务务提交之前,可能会发生各种各样的查询和修改
操作事件源ES被用于聚合根,就像是携带有用户标识的用户-Mike一样。写的一端完全的约束在聚合中。这就使得很容易去思考维持不变性和验证传入的命令。但是有一点不同需要注意,当聚
合可以回复通过特定的标识符查询时候时候可以采用这个模型,但是它不能用于服务跨多个聚合的查询。因此,你需要根据查询服务提定制化的数据视图。
lagom持久化事件流进入数据库中,事件流处理器,其他服务或者客户端,读或者可选择的,执行,存储时间。lagom支持persistent read-side processors(读端持久化处理器)和
message broker topic subscribers(消息代理主题订阅者),你当然可以通过raw stream of events(原生事件流)创建你自己的事件流处理器。
如果你不想使用事件源ES和CQRS,那么你也可以使用其他的在Lagom中的持久化模块。如果您选择不使用Lagom持久模块,Lagom的持久化模块CassandraSession提供了一个异步的API去存储
数据进Cassandra.但是你您可以实现您的Lagom服务与任何数据存储解决方案
你应该选择使用其他比Lagom持久化模块,记得使用异步api来实现最好的可伸缩性。如果您正在使用阻塞api,这样JDBC、JPA,你应该仔细管理阻塞用专用的线程池的固定/有限大小的组件调用
这些阻塞api。不要通过几个异步的调用来串联阻塞,例如服务API调用。
>Lagom为管理客户端和服务端发现,提供了一个执行服务注册和服务网关用于的内部设施的实现。可以查看5.4 Registering and discovering services,有详细介绍
3.在多语言系统中的Logam
Lagom并不期待你的系统中的每个服务都是Lagon服务,毕竟,使用微服务的最大的优势,就是首先为每个微服务可以选择最适合的语言或者技术。Lagom的标准通信协议习惯用法的和通用兼容设计驱
动的API让它可以在一个多种语言的系统工作的很好。
Lagom服务调用映将同步通信射到标准HTTP,将流或者异步的消息映射到WebSockets。任何语言的框架支持这些协议的话,都是可以很简单的消费Logam服务,相反,Lagom服务可以很容易跟任何暴露
REST API的服务交互。
一个Loagom服务的API指定了服务如何使用HTTP。REST服务调用被HTTP的URL和METHOD标识,而请求而和相应的头部信息则是可以自定义的。Lagom的信息是被序列化了的,默认下是用Json,使用
惯用的的一些映射库来简单的让Json在线表现出来
4.开发环境概述
通过maven或者sbt可以很快的开发出Lagom项目。
5.Lagom构建基本思想
如果做得好,采用活性microservice架构可以大大提高开发组织的效率和速度。Lagom 提供灵活构建方法,支持个人及团队的发展,并且可以随着时间的推移而发展。你可以把你所有的微服务放在
当个maven项目中,每一个服务都可以被分开构建,或者构建多个服务构成的一个组。
下面是我们需要开率的一些利弊:
>单独构建多服务:(单一版本)
>开发新功能往往需要同时处理多个服务.让那些服务在相同的构建中无冲突的开发体验。
>然而,随着开发人员构建的数量增加,彼此之间会减缓开发效率
>多次构建,对于每个服务管着一组小的服务(维护多个版本)
>每个微服务都可以独立的改变并且被隔离开来开发的也会更快。在realise的时候,依赖的服务就可以更新以使用更新后的新的服务
>然而,多个版本增加了复杂度,您需要发布服务让他们对其他服务是可用的。实现还需要导入在某版本下的特别的依赖。 Splitting a system into multiple builds讲了如何
解决这种麻烦
在开始的时候,他通常在同一个构建中保持所有的服务是有意义的。
比如当一个系统整处于功能开发阶段,你可以将服务拆分,分别构建。同样的原则也适用于团队工作。重要的是需求与构建要同步。
6.组件技术
作为一个完整的微服务平台,Lagom聚集了技术的集合并在他们之上添加价值,一些库文件,工具,以及lagom使用和支持的服务器等都在Lightbend中很成熟了。其他的第三方资源,当您在lagom框
架下开发,您还可以利用这些技术:
>AKKA----Lagom的持久化,发布订阅和节点都是在AKKA基础上实现的。Lightbend具有即时构建,分布式和弹性的消息驱动程序的工具集
>跨多个服务器扩展微服务,Lagom提供的AKKA Cluster可以提供聚集
>在实现服务描述,Lagom服务可以很‘简小’或者‘流式’,建立在AKKA strams之上Lagomm服务
>Cassandra 默认的持久化
>Guice 类似于playkuangjia,Lagom使用它完成依赖的注入
>play框架
>slf4j logback日志
>Typesafe Config Library:Lagom和它的许多组件技术是使用类型安全配置库配置
>序列化 jackson
7.API概述
Lagom提供了java和scala的API。java版本的API是假定你已经熟悉了新特定,例如lambda和默认方法,和Optional接口等java1.8的知识。Lagom的绝大多数是用scala实现的,但是这些实现的
细节不是你应该关系你的,你应该知识专注于java的API开发。
Lagom提供的服务接口文档让开发者可以快速的定义接口并立即实现他们。
你使用的那些重要的API包括:
>"服务API":提供了一种方法来声明和实现服务接口以供应客户端使用。位置透明性,客户发现服务通过服务定位器.服务API支持异步流媒体服务之间除了同步请求-响应调用
>消息代理API:提供了可以通过主题进行发现数据的分布式的发布订阅模型。一个话题就是一个允许服务去push或者push数据的通道。
>持久化:为存储数据的服务提供了事件源持久化实体。Lagom管理持久化实体的分布在集群节点,使得我们可以切分和水平扩展。lagom管理持久化实体的分布在集群节点,使得我们可以
切分和水平扩展。Cassandra是作为一个数据库提供开箱即用的,但其他数据库也是支持的。
8.设计你的微服务系统
Bonér的响应式微服务架构这本书对于微服务系统架构很有帮助。要想有处理复杂的领域的能力,是需要时间和经验的。Lagom提供的API可以为你提供实用的指导。
我们建议先从小开始,首先,确定一个可以消费异步消息的简单的微服务需求,它不需要很复杂甚至提供了大量的属性值。部署简单可以降低了风险,可以快速的成功。然后,在架构层面,
拿出一个可以划分的核心服务,并把它划分进微服务系统中,当你们一次一次的碰到问题处理问题,那么你和你的团队的开发效率会越来越高效。使用想DDD这样的思想可以帮助你可以你的团队
处理企业系统固有的复杂性
替换掉大块系统
当设计一款微服务系统来替换掉一个大的系统时候,依赖于需求额和已存在的架构,你的方案可能各不相同。例如,如果它是很好很合理设计的,你首先可能不会与遗留组件进行连接,并在当前专注
于迁移功能。如果合理的停机时间是不被接受的,你需要仔细计划,从旧系统中选择可用的老的功能以用于新的服务中。
比如,设想一个为多个部门处理核心业务功能的企业整体应用。他也许有被会计,打折,销售和运营锁使用的库存功能----每个模块以不同的方式使用着它。DDD鼓励这样一个庞大而笨拙的模型分解
成有限的上下文。Each Bounded Context defines a boundary that applies to a particular team, addresses specific usage, and includes the data schema and physical
elements necessary to materialize the system for that context.(实在不知道咋翻译了)。限界上下文可以让一个小的团队专注于在同一时间,并行的工作在一个上文中。
在第一个实现阶段,你可能会修改从发布会计部门感兴趣的一个特定用例的库存事件来开始修改这个庞然大物的老旧工程系统。下面的图阐释了我们的系统发布事件到Kafka中,kafka是一个指定
订阅/发布模式的流式平台。并且kafka可以作为一个集群运行,那样可以提供更好的性能和可靠性。
![图片描述][1]
接下来,就想下面的这个图片展示的,你可能创建一个微服务,订阅这个主题,拉取处理kafka的数据。一个微服务的多个实例可以提供高伸缩性和容错性。遗留功能就扔可以在你测试或者微调的
微服务中保存下来。
![图片描述][2]
然后,想接下来的这个图片展示的,你可能会修改这个庞然大物般的系统,让其调用HTTTP与新的微服务交互,来代替全部的业务逻辑都走自身体统
![图片描述][3]
这个内部的业务逻辑从本来的庞大的系统,迁移到了新的微服务或者一组微服务中。而这也只是将功能点前移除庞大系统的一种高层次的方式
9.制定特别的微服务
无论你是从一个乱写的,或者分解一个庞然大物般的大系统进微服务,下面的这些问答可以帮助你:
问:一个服务职能做一件事吗?
答:是的。如果你不能使用一个短句就能完整的表示一个为服务于的完整目的,那么你的服务可能会庞大,例如:
>一个适当大小的服务:“这个服务在用户之间管理者友好的关系”
>服务执行多种功能,应该被分解掉:“这个服务管理着用户的朋友关系,聚合所有的用户的朋友的活动,所以它可以被消费掉”
问:服务应该是自治的吗?
答:一个服务应该为自己的行为负责。不应该依赖于其他的服务来处理它的事情。
例如,考虑一个订单服务,服务的协议允许你创建一笔订单,添加订单的各种分类。添加支付的详情,确认订单的支付。然而,有一个其他的系统处理这支付,如果这堵的服务没有运行会
怎么样呢??这种依赖性意味着订单服务不是自治,它依赖了支付这个领域
一个自治服务会接受确认请求无论支付服务的状态。
一个自治的服务应该接收确认请求,无论付款服务的状态是什么。他还有可能是异步的方式,确保付款最终被处理完成。
问:这项服务拥有其自己的数据吗?
答:一个服务,如果他是唯一的从数据库中写和读的服务,那么它就可以拥有自己的数据。
如果你发现你设计的多个服务从同一个数据库拿取数据,那么就该考虑下设计了。选择一个服务作为所有者,需要其他服务使用该服务的协议取读取
10.内部和外部的交互
如前面在第二小节讨论的,服务应该被隔离并且是自治的。这样的服务通过网络发送消息的形式,与其他的服务进行交互。为了实现服务的实现性能和韧性,你应该经常通常是在在不同的节点
运行行多个相同的服务实例,内部的交互也是在网络上。此外,第三方和/或遗留系统也可能为microservice系统消耗或提供信息。
下列主题更详细地讨论这些通信路径:
①在微服务内部交互
在原则上相似,但是网络上的交互和内部的交互有着不同的需要,Lagom提供了多种实现选项。服务间通信必须使用松耦合的协议和保持隔离和自治的消息格式。协调不同服务之间的变更可能会很困难,而且成本高昂。您可以利用以下的优势在您的系统中实现这一点:
>Service calls,要不同步,要么异步,允许服务去与其他的服务使用发布的API和标准的协议(例如HTTP协议或者说是WenSocket)进行交互。
>发布消息到代理,例如像时候Apache的kafka,将进一步实现解耦。Lagom的Message Broker API(消息代理代理API)提供了至少一次的语义。如果一个新实例开始发布信息,它的消息被添加到先前发出的事件中。如果一个新实例订阅一个主题,它们将接收所有事件、过去、当前和未来(只要它们已订阅)。
单个服务的节点(统称为一个集群)需要更小的耦合。他们共享相同的代码,并由一个团队或个人共同管理。由于这个原因,服务间通信可以可以利用具有较少开销和更好性能的机制。例如:
>很多lagom的组件内部使用AKKA remoting。你可以直接在你的服务中使用它
>分布式的发布-订阅可以被用用于低延迟,节点之间至多一次消息。限制包括:
1.网络中断会导致消息丢失。
2.当一个新实例启动时,加入集群,并订阅,它将不会收到在订阅之前发送的消息。
>数据库和其他持久性存储可以看作是服务通信的节点的另一种方式.对于使用持久实体的微服务,lagom鼓励使用事件流,而且它还可以运用异步的交互,并可以通过事件日志提供保证。
这张图展示了在三个服务器上分布的lagom系统中各类型的服务间和服务内通信。在示例中,Order服务发布到一个或多个Kafka主题,而用户服务订阅该信息。用户服务使用Akka remoting与其他用户服务实例(集群成员)进行通信。通过在服务调用中流传输服务和用户服务交换信息
![图片描述][4]
在微服务系统之外与各方进行沟通
Lagom促进了异步通信的使用,在必要时不阻止同步通信的使用。第三方可以从发布到代理API的Lagom服务异步获取数据,并享受至少一次的保证。Lagom服务还公开了第三方以同步交换数据的API。这通常映射到HTTP。Lagom服务api也通过websocket支持将数据流到外部客户端。有关更多信息,请参见服务描述符。
与外部世界的交互可能意味着使用互联网服务的客户,如浏览器、移动应用程序或物联网设备。在使用标准HTTP或WebSockets时,典型的客户机不直接与单个服务通信。通常,网络边界作为一个边界,一个受控制的通信点充当外部世界与内部世界之间的中介。在Lagom,这个通信点是一个服务网关。设想你的微服务系统是一个中世纪的城市,周围有一堵墙,只有一扇门提供进出的唯一通道。墙壁内的交流是免费和直接的,但是来自外部世界的通信必须通过服务网关,如下图所示:
![图片描述][5]
11.注册和发现服务
为了具有弹性和可扩展性,系统必须支持位置透明性。这就可以允许你在不同的主机上运行相同的微服务实例,当出现问题的时候可以让一个实例从一个主机到另外的地方,增加主机的数量以实现负载变化。在这样的反应系统中,微服务实例一直在移动,客户端和其他微服务都需要一种方法来定位可用的服务实例
在开发期间,Lagom为您的微服务系统提供以下功能:
1.服务注册
2.客户端服务发现
3.服务端服务发现
服务注册:
服务注册表与微服务实例进行协作,以维护最新的查找表。注册表包括每个可用的微服务实例的主机和端口。当负载变化时,系统可以在任何位置生成或销毁实例,同时继续满足请求。您可以设计一个系统,使微服务能够自动注册,或者您可以使用第三方注册服务
当启动一个Lagom microservice实例时,注册者将注册微服务的名称,服务注册表上的本地服务描述符的URL和名称,这样他们就可以被定位了。在为服务提供一个实例时,注册员也必须更新服务注册表。Lagom的开发环境提供了一个服务注册中心和注册中心的实现,这样您就可以在本地运行您的微服务。
许多可用的技术提供服务注册中心功能,您需要选择和/或为您的服务开发一个服务定位器,以便在您的部署环境中运行(例如,Lagom ZooKeeper服务定位器)。你可能需要找到一种方法来将你的Lagom服务与注册商连接起来。Lagom的ConductR(这个东西我会在快速开始的那个里面讲)方式的集成使得这两个步骤无缝衔接。
客户端一端的服务发现
引自Bonér’s 的Reactive Microservices Architecture: Design Principles for Distributed Systems书:
一旦存储了每个服务的信息,就可以通过服务注册中心提供服务,服务注册中心可以使用一个名为客户端服务发现的模式来查找信息
Lagom为每个服务描述符创建服务客户机,以便应用程序可以与Lagom服务进行交互。假设一个非lagom应用程序想要使用hello服务,它可以使用welcome service客户端并简单地调用hello方法。welcome service的客户端想要使用服务注册表,找到一个有效的 URL,在那个地址下welcome服务是可用和完成请求。这种方法需要使用Lagom提供的代码。在生产中,插入服务的服务定位器将是参与此客户端发现的一个元素。在后续的快速开始哪里的Integrating with non-Lagom services这一节,你可以看到更多使用情况.
服务端发现:
引自Bonér’s 的Reactive Microservices Architecture: Design Principles for Distributed Systems书:
另一个策略是信息存储和维护在一个负载均衡器[…]使用一种称为服务器端服务发现的模式。
如果不能在每个客户机上嵌入服务定位器,则可以使用服务器端服务发现。此模式使用服务网关允许客户端使用服务描述符注册提供的端点。在这个模型中,浏览器只需要知道服务网关在哪里。当使用服务器端发现时,只有在调用被添加到ACL时才能到达服务描述符的调用。
例如,浏览器可以通过请求服务网关中的/ hello / steve路径向用户显示hello消息。这时服务网关将会知道哪一个服务提供这个端点,而且会向服务注册中心请求该服务的一个实例。服务注册中心将可以响应请求的实例的主机和端口返回。最后,服务网关将执行请求并将结果返回给浏览器。
为了简化服务器端服务发现的测试,Lagom开发环境下会启动所有服务以及服务注册中心和服务网关。
12.使用不可变的对象 (immutable objects)
一个从被创建了之后就不可以被修改的不可变对象有如下的优点:
>基于不可变对象的代码更清晰,更有可能是正确的。涉及意外变化的错误根本无法发生。
>多个线程可以同时安全地访问不可变的对象。
在Lagom中,不可变对象在如下的几个地方是必须的,例如:
>服务请求和响应类型
>持久的实体命令、事件和状态
>发布和订阅邮件
Lagom并不关心如何定义不可变对象。您可以手工编写构造函数和getter,但是我们建议使用第三方工具来生成它们。使用第三方工具,如Immutables工具或Lombok,比手工编写更容易,也更不易出错,而且生成的代码更短,更容易阅读。
以下各节将提供关于immutables的更多信息:
>Mutable and immutable examples(可变和不可变的例子)
>Lombok的例子
>Immutables tool example(Immutables 工具的例子)
Mutable and immutable examples(可变和不可变的例子):
在一个可变对象的下面例子中,setter方法可以用于在构建后修改对象:
![图片描述][6]
简单的不变性
Lombok example
下面的示例展示了使用Lombok实现的用户的定义。Lombok为您处理以下细节
>将属性变为privte和final
>为每一个属性创建getter方法
>重写equals和hashcode方法和更加友好的toString
>创建一个满属性的构造器
下面是样例,使用的是注解方式
![图片描述][7]
上图中的实例并没有展示出Lombok的一些其他非常有用的注解,例如@Builder或者@Wither,它们可以帮助你创建生成器和复制方法。请注意,Lombok不是一个不可更改的库,而是一个代码生成库,这意味着一些设置可能不会创建不可变的对象。例如:Lombok的@Data是等价于@Lombok的@Value。但是还会合成可变方法。当创建不可变类不要使用Lombok的@Data
那么如何使用Lombok呢??
step1.加入maven
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
</dependency>
step2.与IDE集成
与IntelliJ IDEA 集成,你需要一个Lombok Plugin for IntelliJ IDEA插件,并开启注解驱动。 (Settings / Build,Execution,Deployment / Compiler / Annotation Processors and tick Enable annotation processing)
与eclipse集成:run运行 java -jar lombok.jar,这里有小视频:https://projectlombok.org/
Immutables tool example(Immutables工具样例)
下面是使用Immutables的用户(如上面的ImmutableUser)的相应定义:
![图片描述][8]
mmutables generates for you:
>构建器(在类有很多字段时非常方便)
>正确的实现,hashCode,toString,equals
>来基于旧的实例来复制方法来创建新实例,例如 withEmail
使用方法step1.
<dependency>
<groupId>com.lightbend.lagom</groupId>
<artifactId>lagom-javadsl-immutables_2.11</artifactId>
<version>${lagom.version}</version>
</dependency>
step2.与IDE集成
eclipse:https://www.lagomframework.com/documentation/1.3.x/java/ImmutablesInIDEs.html#Eclipse
IDEA:https://www.lagomframework.com/documentation/1.3.x/java/ImmutablesInIDEs.html#IntelliJ-IDEA
Collections:
如果一个不可变对象包含一个集合,那么集合也必须是不可变的。
下面是一个具有可变集合的对象的例子:
![图片描述][9]
上述的例子,只有final的private属性,方法不提供属性的set方法,只提供getter方法。但是,列表对象是可以产生原处修改的,比如我们调用getter()方法获取到集合,但是我们就可以调用集合的add方法。
一个可能的修复将使列表防御在构造函数复制和使用 Collections.unmodifiableList 在 getter,像这样︰
![图片描述][10]
但这种方式,进行编码时,它是容易犯错误,我们再次建议想下面这样让不可变的处理:
下面的这是ImmutableUser2的定义:
![图片描述][11]
getPhoneNumbers方法将返回一个实例com.google.common.collect.ImmutableList
guava和PCollections
如上面所示,不可变对象默认使用Guava immutable collections
Guava collections要比简单的java.util.collections要好。但是Guava在某些操作的时候是稍显笨重的(例如:对于当前存在的collection做一个稍微修改的拷贝)
因此,我们推荐pcollection,它是一个集合库,它是为不可变性和效率而设计的。
上面的示例看起来像使用一个PCollection:
![图片描述][12]
这是如何定义由空集合初始化的可选集合
![图片描述][13]
持久化‘collections’
有两种不同的,有可能混淆的用法的关于数据的“持久化”一次。、
您将在pcollection文档和其他地方看到“持久”数据结构的引用。“”持久化“”这个单词的意思意味着即使您构建了一个已修改的集合副本的最初的‘persists’.在本文档的其余部分中,“持久化”指的是持久存储,如持久化实体和下面的示例。
进一步的阅读:
Immutables文档在这里有更多关于不可变集合的详细信息。https://immutables.github.io/immutable.html#array-collection-and-map-attributes
13.管理数据持久性
在设计微服务时,请记住每个服务都应该拥有它的数据并直接访问数据库。其他服务应该使用服务API来与数据交互。必须在不同的服务之间不共享数据库,因为这会导致服务之间过于紧密的耦合。这样,每个微服务都在一个清晰的边界内运行,类似于域驱动设计中的有限上下文策略模式。
为了实现这种分离的体系结构,Lagom的持久性模块促进了事件源和CQRS的使用。事件源是将所有变更捕获为域事件的实践,这是已经发生的事情的不可变事实。例如:在一个使用ES的系统中,当迈克把钱从他的银行账户里拿出来的时候,这一事件可以简单的存储为"取出100.00 美元"。而不是像在CRUD应用程序中进行的复杂交互,在包装事务提交之前,需要进行各种读取和更新操作。
事件源被用于聚合根,像在以前的样例中(聚合根的信息,可以去看我的关于聚合根的博文)的带有唯一标识ID的客户Mike,,write-side在聚合中保持一致。这样就可以很容易地解释一些事情,比如维护不变量和验证传入命令。当你采用这个模型的时候的一个显著的不同点,您需要注意的是,聚合可以回答特定标识符的查询,但不能用于服务跨多个聚合的查询。因此,您需要创建针对服务提供的查询定制的数据的另一个视图。
Lagom将事件流持久化到数据库中。事件流处理器、其他服务或客户机、读取和选择、操作、存储事件。Lagom提供persistent read-side processors和 message broker topic subscribers。当然,你也可以使用raw stream of event创建自己的时间流.
如果您不想使用事件源和CQRS,您可能应该使用其他东西,而不是在Lagom中的持久性模块(不过,我们建议您先阅读事件采购的优势。)如果你选择不使用Lagom的持久性模块,在Lagom持久性模块中,CassandraSession提供了用于存储Cassandra数据的异步API。但是,您可以使用任何数据存储解决方案来实现您的Lagom服务。
如果您选择使用其他东西,而不是Lagom的持久性模块,记住要使用异步api以获得最佳的可伸缩性.如果你使用阻塞的APIs,例如JDBC或者JPA,您应该通过使用固定/有限大小的专用线程池来仔细管理阻塞api的组件。不要通过几个异步调用(例如服务API调用)来串联阻塞。
14.事件源ES的优势
多年来,开发人员实现持久性使用传统的创建、读取、更新、删除(CRUD)模式。正如前面介绍的,如果采购模型实现持久性存储状态更改为历史事件捕获业务活动发生之前写的数据存储。这将事件存储机制,允许他们被聚合,或者放在一个组与逻辑边界。事件采购的模式之一,使并发、分布式系统实现高性能、可伸缩性和弹性。
在一个分布式体系结构中,事件采购提供了以下优点
>在传统的CRUD模型中,实体实例通常会表示为一个可变对象在内存和一个可变行关系数据库表中。这导致了臭名昭著的对象关系阻抗失配。对象关系映射器是用来填补这一鸿沟,但带来新的复杂性。
事件源ES模型对待数据库就像对待一个序列化时间的append-only log一样。它并不试图对每个实体的状态或直接在数据库模式之间的关系进行建模。这大大简化了代码从数据库中写入和读取
>一个实体如何达到其当前状态的历史仍在存储事件。事务型数据和查账式数据之间的一致性是有保证的,因为这些是相同的数据
>你现在有能力分析事件流和重要的业务信息来自它——也许甚至都不考虑当时的事件设计。你可以在我们的系统活动中添加新的视图而不会使写入方面更加复杂
>由于所有类型的事件都都只需添加到数据存储区,所以它可以提高写入性能。这里没有更新和删除
>事件源系统很容易测试和调试。命令和事件可以模拟用于测试目的。事件日志提供了一个良好的记录进行调试。如果在生产中检测到一个问题,你可以回放事件日志在受控环境中了解一个实体进入不好
的状态。
15.读写分离
编写或保存数据的功能与读取或查询数据的功能完全不同。实现读写分离,能够独立地提供最好的经验,试图将读和写的操作封装一起的模型很少有好的表现。
在CQRS模式下,写的一端的实体集中于更新命令,并且您可以对不同类型的查询和报告作业进行优化。这种分离实现更好的可伸缩性,因为read-side可以独立地扩展到多个节点上,并且它通常位于需要大量可伸缩性的read-side上。
例如:在竞价系统中,“take the write”是非常重要的,答复投标人我们已尽快接受了投标,这意味着写吞吐量是最重要的。同样的应用程序可能会有一些复杂的统计视图,或者分析师可能会使用这些数据来找出最佳的竞标策略和趋势,这些read-side用例通常需要某种表达性查询功能和不同的数据模型,而不是写端。将读取端与写端分离的结果是最终的一致性,对写端的更新可能无法立即在readside中可见。
17.部署可伸缩的弹性系统
实现真正的响应式系统:
>将您的微服务部署到集群中,这样它们就可以按要求按要求伸缩,并且在面对网络瓶颈或故障时保持弹性,以及硬件或软件错误
>确保系统所依赖的组件(例如服务网关和message broker)不暴露单点故障。
>使用数据存储的功能来提供冗余或复制
您可以在您的选择的适当技术上部署,Lagom支持产品套件开箱即用。Lightbend产品套件是为Llagom的一个完美的匹配。它提供;了如下的特性:
>一种与打包工件分开管理配置的方法
>跨多个节点的整合日志。
>自动重新启动意外终止服务的监控系统。
>能够轻松快速地伸缩自如。
>处理网络故障,特别是那些可能导致大脑分裂的问题。
>自动种子节点发现,确保服务的新实例与已经运行的服务联接相同的集群。
>他能够对你的服务进行滚动更新。
>支持跨集群的监视服务。
>在生产前在本地测试服务的能力。
好的,下面请参考另外的文档Lagom reference guide(Lagom参考指南)