一 分布式微服务的区别
1. 最大的区别是微服务是个组件化的,有自己独立的资源,可以独立运行,可插拔。
2. 合理资源分配
比如订单系统压力大了我们可以单独给订单系统加机器,而分布式需要挪动很多逻辑
3. 人尽其才
因为服务拆分粒度细,可以使用各种语言开发服务,而分布式就不能这样完美
4. 加快部署
挂了之后可以尽快启动一个docker镜像
一:CAP定理和Base理论
(1)CAP定理
C:一致性,同一数据的多个副本是否实时相同。
A:可用性,在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请
求(对数据更新具备高可用性)。
P:分区容忍性,分区容错性约束了一个分布式系统具有如下特性:分布式系统在遇
到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的
服务,除非是整个网络环境都发生了故障。
定理:任何分布式系统只可同时满足二点,没法三者兼顾。
忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进
行取舍。
实际选择:对于一个分布式系统,我们始终要假设网络是不可靠的,所以分区容错性
是对一个分布式系统最基本的要求,所以我们更多的是尝试在可用性和一
致性之间寻找一个平衡点。让分布式集群始终对外提供可用的一致性服
务。例如数据库分库就是采用的最终一致性。
一致性和可用性的说明:
对于一致性和可用性的完整解释请参考文章:
http://blog.csdn.net/jewes/article/details/43495639
假设我们用一台服务器A对外提供存储服务,为了避免这台服务器宕机导致服务
不可用,我们又在另外一台服务器B上运行了同样的存储服务。每次用户在往服务器
A写入数据的时候,A都往服务器B上写一份,然后再返回客户端。一切都运行得很
好,用户的每份数据都存了两份,分别在A和B上,用户访问任意一台机器都能读取
到最新的数据。这时不幸的事情发生,A和B之间的网络断了导致A和B无法通信,也
就是说网络出现了分区,那么用户在往服务器A写入数据的时候,服务器A无法将该
数据写入到服务器B。这时,服务器A就必须要做出一个艰难的选择:
(a)选择一致性而牺牲可用性:为了保证服务器A和B上的数据是一致的,服务器A决
定暂停对外提供数据写入服务,从而保证了服务器A和B上的数据是一致,但是牺
牲了可用性。
注意:这里的可用性不是我们通常所说的高可用性(比如,服务器宕机导致服务不
可用),而是指服务器虽然活着,但是却不能对外提供写入服务。
(b)选择可用性而牺牲一致性:为了保证服务不中断,服务器A先把数据写入到了本
地,然后返回客户端,从而让客户端感觉数据已经写入了。这导致了服务器A和
B上的数据就不一致了。
分区容错性的说明:
一个分布式系统里面,节点组成的网络本来应该是连通的。然而可能因为一些故
障,使得有些节点之间不连通了,整个网络就分成了几块区域。数据就散布在了这些
不连通的区域中。这就叫分区。
当一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分
就访问不到这个数据了。这时分区就是无法容忍的。提高分区容忍性的办法就是一个
数据项复制到多个节点上,那么出现分区之后,这一数据项就可能分布到各个区里。
容忍性就提高了。然而,要把数据复制到多个节点,就会带来一致性的问题,就是多
个节点上面的数据可能是不一致的。要保证一致,每次写操作就都要等待全部节点写
成功,而这等待又会带来可用性的问题。总的来说就是,数据存在的节点越多,分区
容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更
新所有节点数据所需要的时间就越长,可用性就会降低。
(2)BASE理论:
全称:Basically Available(基本可用),Soft state(软状态),和
Eventually consistent(最终一致性)三个短语的缩写。
Base 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大型互联网分布式
实践的总结,是基于 CAP 定理逐步演化而来的。其核心思想是:满足 CAP 理论,
通过 牺牲强一致性来保证系统可用性。由于牺牲了强一致性,系统在处理请求的过
程中,数据可以存在短时的不一致。
(a)Basically Available(基本可用):假设系统,出现了不可预知的故障,但还是能
用,相比较正常的系统而言:
Ⅰ:响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基
本可用的搜索引擎可以在 1 秒作用返回结果。
Ⅱ:功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一
笔订单,但是到了大促期间,为了保护购物系统的稳定性,部分消费者可
能会被引导到一个降级页面。
(b)Soft state(软状态)
要求多个节点的数据副本都是一致的,这是一种 “硬状态”。
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的
整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
(c)Eventually consistent(最终一致性)
最终数据是一致的就可以了,而不是时时保持强一致。
例如一个电商系统,当用户下单并支付后,系统需要修改订单的状态并且
增加用户积分。支付成功,订单也成功,但增加积分失败,此时,不应回滚支
付和订单,而应通过一些补偿方法来让积分得以正确地增加。
二:两阶段提交协议和三阶段提交协议
1.两阶段提交协议
(1)两阶段提交协议介绍
(a)请求阶段(commit-request phase,或称表决阶段,voting phase)
事务协调者通知每个参与者准备提交或取消事务,然后进入表决过程,参与者
要么在本地执行事务,写本地的redo和undo日志,但不提交,到达一种"万事俱
备,只欠东风"的状态。请求阶段,参与者将告知协调者自己的决策: 同意(事务
参与者本地作业执行成功)或取消(本地作业执行故障)。
(b)提交阶段(commit phase)
在该阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消。当且
仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协
调者将通知所有的参与者取消事务。参与者在接收到协调者发来的消息后将执
行响应的操作。
(2)两阶段提交协议的缺点
(a)同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有
公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
(b)单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下
去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务
资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选
举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问
题)
(c)数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之
后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这
回导致只有一部分参与者接受到了commit请求。
2.三阶段提交协议
(1)三阶段提交协议简介
三阶段提交(Three-phase commit),也叫三阶段提交协议(Three-phase
commit protocol),是二阶段提交(2PC)的改进版本。
与两阶段提交不同的是,三阶段提交有两个改动点:
(a)引入超时机制。同时在协调者和参与者中都引入超时机制。
(b)两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最
后真正提交。说白了这样减少了阻塞。
(2)三阶段提交协议详细介绍
(a)CanCommit阶段
3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送
commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
(i)事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事
务提交操作。然后开始等待参与者的响应。
(ii)响应反馈 参与者接到CanCommit请求之后,正常情况下,如果其自身
认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈
No。
(b)PreCommit阶段
协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。
根据响应情况,有以下两种可能。
假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事
务的预执行。
(i)发送预提交请求协调者向参与者发送PreCommit请求,并进入Prepared
阶段。
(ii)事务预提交参与者接收到PreCommit请求后,会执行事务操作,并将
undo和redo信息记录到事务日志中(未提交事务)。
(iii)响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时
开始等待最终指令。
假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协
调者都没有接到参与者的响应,那么就执行事务的中断:
(i)发送中断请求 协调者向所有参与者发送abort请求。
(ii)中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收
到协调者的请求),执行事务的中断。
(c)doCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况:
执行提交
(i)发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进
入到提交状态。并向所有参与者发送doCommit请求。
(ii)事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完
成事务提交之后释放所有事务资源。
(iii)响应反馈 事务提交完之后,向协调者发送Ack响应。
中断事务
协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,
也可能响应超时),那么就会执行中断事务。
(i)发送中断请求 协调者向所有参与者发送abort请求
(ii)事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来
执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
(iii)反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息
(iv)中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。
(v)完成事务 协调者接收到所有参与者的ack响应之后,完成事务。
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者
rebort请求时,会在等待超时之后,会继续进行事务的提交。(其实这个应该是
基于概率来决定的,当进入第三阶段时,说明参与者在第二阶段已经收到了
PreCommit请求,那么协调者产生PreCommit请求的前提条件是他在第二阶段开
始之前,收到所有参与者的CanCommit响应都是Yes。(一旦参与者收到了
PreCommit,意味他知道大家其实都同意修改了)所以,一句话概括就是,当进
入第三阶段时,由于网络超时等原因,虽然参与者没有收到commit或者abort响
应,但是他有理由相信:成功提交的几率很大。 )
(3)三阶段提交协议和两阶段提交协议的区别
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及
时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源
并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,
协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行
了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一
致的情况。
三:如何保证微服务架构的数据一致性?
现在有三种方案:可靠消息最终一致性、TCC补偿性事务解决方案、最大努力通知。
1.可靠消息最终一致性
基于MQ的解决方案,需要业务系统结合MQ消息中间件实现,在实现过程中需要保证
消息的成功发送及成功消费。即需要通过业务系统控制MQ的消息状态。
此方案涉及3个模块:
(1)上游应用:执行业务并发送 MQ 消息。
(2) 可靠消息服务和MQ消息组件:协调上下游消息的传递,并确保上下游数据
的一致性。
(3)下游应用:监听 MQ 的消息并执行自身业务。
分两个阶段:
第一阶段:上游应用执行业务并发送 MQ 消息。
上游应用将本地业务执行和消息发送绑定在同一个本地事务中,保证要
么本地操作成功并发送MQ消息,要么两步操作都失败并回滚。
上游应用和可靠消息之间的业务交互图如下:
(1)上游应用发送待确认消息到可靠消息系统。
(2)可靠消息系统保存待确认消息并返回。
(3)上游应用执行本地业务。
(4)上游应用通知可靠消息系统确认业务已执行并发送消息。
(5)可靠消息系统修改消息状态为发送状态并将消息投递到 MQ 中间
件。
假设第(4)、(5)步因为网络不好没发出去,或者网络不好没接收
到等情况,会出现业务执行成功,但消息依然未确认的情况。这个时
候我们通过“可靠性消息服务”来解决该问题。
第二阶段:下游应用监听 MQ 消息并执行业务(第二阶段)
下游应用监听 MQ 消息并执行业务,并且将消息的消费结果通知可靠
消息服务。可靠消息的状态需要和下游应用的业务执行保持一致,可
靠消息状态不是已完成时,确保下游应用未执行,可靠消息状态是已
完成时,确保下游应用已执行。
下游应用和可靠消息服务之间的交互图如下:
(1)下游应用监听 MQ 消息组件并获取消息。
(2)下游应用根据 MQ 消息体信息处理本地业务。
(3)下游应用向 MQ 组件自动发送 ACK 确认消息被消费。
(4)下游应用通知可靠消息系统消息被成功消费,可靠消息将该消息
状态更改为已完成。
假设第(4)步因为网络不好,可靠消息没有接到消费成功的消息,导致
消息消费成功但是可靠消息系统的状态为“未消费”或是干脆就是MQ把消
息丢了,我们同样可以通过消息重发解决。
通过分析以上两个阶段可能失败的情况,为了确保上下游数据的最终一致性,在可
靠消息系统中,需要开发“消息状态确认”和“消息重发”两个功能以实现BASE理论的
Eventually Consistent(最终一致性)特性。
(1)消息状态确认
可靠消息服务定时监听消息的状态,如果存在状态为待确认并且超时的消息,
则表示上游应用和可靠消息交互中的步骤(4)或者 (5) 出现异常。可靠消
息则携带消息体内的信息向上游应用发起请求查询该业务是否已执行。上游应
用提供一个可查询接口供可靠消息追溯业务执行状态,如果业务执行成功则更
改消息状态为已发送,否则删除此消息确保数据一致。
(2)消息重发
可靠消息服务发现可靠消息服务中存在消息状态为已发送并且超时的消息,则
表示可靠消息服务和下游应用中存在异常的步骤,无论哪个步骤出现异常,可
靠消息服务都将此消息重新投递到 MQ 组件中供下游应用监听。下 游应用监
听到此消息后,在保证幂等性的情况下重新执行业务并通知可靠消息服务此消
息已经成功消费,最终确保上游应用、下游应用的数据最终 一致性。
当然在实际接入过程中,需要引入 人工干预 功能。比如引入重发次数限
制,超过重发次数限制的将消息修改为死亡消息,等待人工干预。
2.TCC(Try-Confirm-Cancel)
TCC 方案是二阶段提交的另一种实现方式,它涉及3个模块,主业务、从业务和
活动管理器(协作者)。
下面这张图是互联网上关于 TCC 比较经典的图示:
第一阶段:主业务服务分别调用所有从业务服务的try操作,并在活动管理器中记录所
有从业务服务。当所有从业务服务try成功或者某个从业务服务try失败时,
入第二阶段。
第二阶段:活动管理器根据第一阶段从业务服务的try结果来执行confirm或cancel操
作。如果第一阶段所有从业务服务都try成功,则协作者调用所有从业务
服务的confirm操作,否则,调用所有从业务服务的cancel操作。
在第二阶段中,confirm 和 cancel 同样存在失败情况,所以需要对这两种情况做异
常处理 以保证数据一致性。
Confirm 失败:则回滚所有 confirm 操作并执行 cancel 操作。
Cancel 失败:从业务服务需要提供自动 cancel 机制,以保证 cancel 成功。
目前有很多基于 RPC 的 TCC 框架,但是不适用于微服务架构下基于 HTTP 协议的
交互模式。我们这次只讨论基于 HTTP 协议的 TCC 实现。具体的实现流程如下:
(1)主业务服务调用从业务服务的try操作,并获取 confirm/cancel接口和超时时
间。
(2)如果从业务都try成功,主业务服务执行本地业务,并将获取的confirm/cancel
接口发送给活动管理器,活动管理器会顺序调用从业务1和从业务2的confirm
接口并记录请求状态,如果请求成功,则通知主业务服务提交本地事务。如果
confirm部分失败,则活动管理器会顺序调用从业务1和从业务2的cancel接口
来取消try的操作。
(3)如果从业务部分或全部try失败,则主业务直接回滚并结束,而try成功的从业
务服务则通过定时任务来处理处于try完成但超时的数据,将这些数据做回滚
处理保证主业务服务和从业务服务的数据一致。
代入开篇提到的案例,通过 TCC 方案,订单服务在订单状态修改之前执行预增
积分操作(try),并从积分服务获取confirm/cancel预增积分的请求地址。如果预增
积分 (try)成功,则订单服务更改订单状态并通知活动管理器,活动管理器请求积
分模块的 confirm 接口来增加积分。如果预增积分(try)失败,则订单服务业务回
滚。积分服务通过定时任务删除预增积分(try)超时的数据。另外如果活动管理器
调用积分服务的confirm接口失败,则活动管理器调用积分服务cancel接口来取消预
增积分,从而,保证订单和积分数据的最终一致性。
通过上面的对可靠消息服务和TCC方案的描述,我们 解决了技术栈一致和不一
致的两种情况下的数据一致性问题。但是,通常在这些核心业务上有 很多附加业务,
比如当用户支付完成后,需要通过短信通知用户支付成功。这一类业务的成功或者失
败不会影响核心业务,甚至很多大型互联网平台在并高并发的情况下会主动关闭这一
类业务以保证核心业务的顺利执行。那么怎么处理这类情况呢,我们来看看最大努力
通知方案。
3.最大努力通知
最大努力通知方案涉及三个模块
(1)上游应用,发消息到MQ队列。
(2)下游应用(例如短信服务、邮件服务),接受请求,并返回通知结果。
(3)最大努力通知服务,监听消息队列,将消息存储到数据库中,并按照通知规则
调用下游应用的发送通知接口。
具体流程如下:
(1)上游应用发送MQ消息到MQ组件内,消息内包含通知规则和通知地址。
(2)最大努力通知服务监听到MQ内的消息,解析通知规则并放入延时队列等待触
发通知。
(3)最大努力通知服务调用下游的通知地址,如果调用成功,则该消息标记为通知
成功,如果失败则在满足通知规则(例如5分钟发一次,共发送10次)的情况下
重新放入延时队列等待下次触发。
最大努力通知服务表示在不影响主业务的情况下,尽可能地确保数据的一致性。
它需要开发人员根据业务来指定通知规则,在满足通知规则的前提下,尽可能的确保
数据的一致,以尽到最大努力的目的。
根据不同的业务可以定制不同的通知规则,比如通知支付结果等相对严谨的业务,
可以将通知频率设置高一些,通知时间长一些,比如隔5分钟通知一次,持续时间1小时。
如果不重要的业务,比如通知用户积分增加,则可以将通知频率设置低一些,时间短一
些,比如10分钟通知一次,持续 30 分钟。
代入上面提到的支付成功短信通知用户的案例,通过最大努力通知方案,当支付成
功后,将消息发送到MQ中间件,在消息中,定义发送规则为5分钟一次,最大发送数为
10次。最大努力通知服务监听MQ消息并根据规则调用消息通知服务(短信服务)的消
息发送接口,并记录每次调用的日志信息。在通知成功或者已通知10次时,停止通知。
4.总结
四.分布式锁
1.Zookeeper实现分布式锁
(1)原理:使用zookeeper中的临时有序节点,详细见本篇“五 Zookeeper”。
2.Redis实现分布式锁
set的多参数命令,指定NX操作和过期时间(高版本);低版本的redis不支持set的多
参数命令。
五.Zookeeper
学习zookeeper推荐阅读的一篇博客
https://www.cnblogs.com/crazylqy/p/7132133.html
1.Zookeeper介绍
Zookeeper是Hadoop下的一个子项目,它是一个针对大型分布式系统的可靠的协调系
统,提供的功能包括配置维护、名字服务、分布式同步、组服务等。Zookeeper是可以
集群复制的。集群间通过Zab协议来保持数据的一致性。该协议包括两个阶段:leader
election阶段和Atomic broadcas阶段。leader election阶段,集群中将选举一个出一个
leader,其它机器称为follower,所有写操作都被传送给leader,并通过broadcas将所
有更新告诉follower,当leader崩溃或是leader失去大多数follower时,需要重新选取一
个新的leader,让所有服务器都恢复到一个正确的状态。当leader被选举出来且大多数
服务器完成了和leader的状态同步(状态同步是指数据同步)后,leader election的过
程就结束了,将进入Atomic broadcas的过程。
有空看看不同的介绍,有的地方叫两种服务:
https://www.jianshu.com/p/5dce97c9ba85
2.Zookeeper节点类型
持久节点、持久有序、临时节点、临时有序节点(重点,Zookeeper的分布式锁使用的
该节点类型)
持久和临时的概念一目了然,就不介绍了。
有序节点:假如当前有一个父节点为/lock,我们可以在这个父节点下面创建子节点;
zookeeper提供了一个可选的有序特性,例如我们可以创建子节点
“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前的子
节点数量自动添加整数序号,也就是说如果是第一个创建的子节点,那么生
成的子节点为/lock/node-0000000000,下一个节点则为
/lock/node-0000000001,依次类推。
临时节点:客户端可以建立一个临时节点,在会话结束或者会话超时后,zookeeper会
自动删除该节点。
3.Zookeeper的事件通知机制
在读取数据时,我们可以同时对节点设置事件监听(也叫订阅),当节点数据或结构变
化时,zookeeper会通知订阅它的客户端。当前zookeeper有如下四种事件:
* 节点创建;
* 节点删除;
* 节点数据修改;
* 子节点变更。
4.Zookeeper实现分布式锁
简单的说是(心跳+通知)
(1)公平方式
下面描述使用zookeeper实现分布式锁的算法流程,假设锁空间的根节点为/lock:
(a)客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对
应的子节点为/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。
(b)客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中
序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得
子节点变更通知后重复此步骤直至获得锁。
(c)执行业务代码;
(d)完成业务流程后,删除对应的子节点释放锁
(2)非公平方式
每个进程p尝试创建临时节点znode,名为/lock。如果进程p成功创建了znode,就表示它
获得了锁并可以继续执行其临界区域的代码。其他进程因znode存在而创建/lock失败。因
此,进程监听/lock的变化,并在检测到/lock删除时再次尝试创建节点来获得锁。当收到
/lock删除的通知时,如果进程p还需要继续获取锁,它就继续尝试创建/lock的步骤,如果
其他进程已经创建了,就继续监听节点。
问题:为什么要使用临时节点而不是持久节点
步骤1中创建的临时节点能够保证在故障的情况下锁也能被释放,考虑这么个场
景:假如客户端a当前创建的子节点为序号最小的节点,获得锁之后客户端所在
机器宕机了,客户端没有主动删除子节点;如果创建的是永久的节点,那么这个
锁永远不会释放,导致死锁;由于创建的是临时节点,客户端宕机后,过了一定
时间zookeeper没有收到客户端的心跳包判断会话失效,将临时节点删除从而释
放锁;
问题:关于 API中设置监听器的操作与读操作是原子性。
考虑这么个场景:客户端a对应子节点为/lock/lock-0000000000,客户端b对应子
节点为/lock/lock-0000000001,客户端b获取子节点列表时发现自己不是序号最
小的,但是在设置监听器前客户端a完成业务流程删除了子节点
/lock/lock-0000000000,客户端b设置的监听器岂不是丢失了这个事件从而导致
永远等待了?这个问题不存在的。因为zookeeper提供的API中设置监听器的操
作与读操作是原子执行的,也就是说在读子节点列表时同时设置监听器,保证不
会丢失事件。
5. Zookeeper是如何实现数据一致性的?
原文:https://blog.csdn.net/qqqq0199181/article/details/80865828
答:是通过ZAB协议
ZAB协议介绍:
(1)学习协议前需要了解的几个概念
-- 事务
zookeeper作为一个分布式协调服务,需要leader节点去接受外部请求,转化为内部操作(比如创
建,修改,删除节点),需要原子性执行的几个操作就组成了事务,这里用T代表。zookeeper要
求有序的处理事务,因此给每个事务一个编号,每进来一个事务编号加1,假设leader节点中进来
n个事务,可以表示为T1,T2,T3…Tn。为了防止单点问题导致事务数据丢失,leader节点会把事务
数据同步到follower节点中。
-- 事务队列
leader和follower都会保存一个事务队列,用L表示,L=T1,T2,T3…Tn,leader的事务队列是接受
请求保存下来的,follower的事务队列是leader同步过来的,因此leader的事务队列是最新,最全
的。
-- 任期
在zookeeper的工作过程中,leader节点奔溃,重新选举出新的leader是很正常的事情,所以
zookeeper的运行历史中会产生多个leader,就好比一个国家的历史中会相继出现多为领导人。为
了区分各个leader,ZAB协议用一个整数来表示任期,我们假设用E表示任务。zookeeper刚运行时
选举出的第一个leader的任期为E=1;第一个leader奔溃后,下面选举出来的leader,任期会加1,
E=2;一次类推。加入任期概念的事务应该表示为T(E,n)
(2)协议过程:
(a)选举leader
-- 每个follower广播自己事务队列中最大事务编号maxId
-- 获取集群中其他follower发出来的maxId,选取出最大的maxId所属的follower,
投票给改follower,选它为leader。
-- 统计所有投票,获取投票数超过一半的follower被推选为leader
(b)同步数据
-- 各个follower向leader发送自己保存的任期E
-- leader,比较所有的任期,选取最大的E,加1后作为当前的任期E=E+1
-- 将任期E广播给所有follower
-- follower将任期改为leader发过来的值,并且返回给leader事务队列L
-- leader从队列集合中选取任期最大的队列,如果有多个队列任期都是最大,则选
取事务编号n最大的队列Lmax。将Lmax最为leader队列,并且广播给各个
follower。
-- follower接收队列替换自己的事务队列,并且执行提交队列中的事务。
至此各个节点的数据达成一致,zookeeper恢复正常服务。
(c)广播
-- leader节点接收到请求,将事务加入事务队列,并且将事务广播给各个follower。
-- follower接收事务并加入都事务队列,然后给leader发送准备提交请求。
-- leader 接收到半数以上的准备提交请求后,提交事务同时向follower 发送提交事
务请求follower提交事务。
(2)这里有一个我不了解的知识:Zookeeper中的角色
zookeeper 存在leader,follower,observer三种角色,这三种角色在实际服务集群中都是
服务节点。
leader:处理所有请求,为客户的提供读和写服务
follower:只提供读服务,有机会通过选举成为leader
observer:只提供读服务
由以上三种角色的介绍可知,zookeeper中所有请求都是交给leader处理的,因此,
如果leader挂了,zookeeper就无法再提供服务,这就是单点问题。所幸在leader挂了
之后,follower能够通过选举成为新的leader。
5.Zookeeper作为dubbo注册中心的原理
简单的说是(心跳+临时节点+通知)
在zookeeper中,进行服务注册,实际上就是在zookeeper中创建了一个
znode节点,该节点存储了该服务的IP、端口、调用方式(协议、序列化方式)
等。该节点承担着最重要的职责,它由服务提供者(发布服务时)创建,以供服
务消费者获取节点中的信息,从而定位到服务提供者真正网络拓扑位置以及
得知如何调用。RPC服务注册、发现过程简述
如下:
* 服务提供者启动时,会将其服务名称,ip地址注册到配置中心。
* 服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地
址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去
请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者
的服务器调用服务。
注意:这里的客户端缓存根据Zookeeper的节点的更新而自动更新是
应该是dubbo实现的。
* 当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列
表中移除。同时,注册中心会将新的服务IP地址列表发送给服务消费者机
器,缓存在消费者本机。
* 当某个服务的所有服务器都下线了,那么这个服务也就下线了。同样,当
服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送
给服务消费者机器,缓存在消费者本机。
* 服务提供方可以根据服务消费者的数量来作为服务下线的依据感知服务的
下线&上线
zookeeper提供了“心跳检测”功能,它会定时向各个服务提供者发送
一个请求(实际上建立的是一个 socket 长连接),如果长期没有响应,服
务中心就认为该服务提供者已经“挂了”,并将其剔除,比如100.19.20.02这
台机器如果宕机了,那么zookeeper上的路径就会只剩
/HelloWorldService/1.0.0/100.19.20.01:16888。服务消费者会去监听相应
路径(/HelloWorldService/1.0.0),一旦路径上的数据有任何变化(增加
或减少),zookeeper都会通知服务消费方服务提供者地址列表已经发生改
变,从而进行更新。更为重要的是zookeeper 与生俱来的容错容灾能力(比
如leader选举),可以确保服务注册表的高可用性。使用 zookeeper 作为注
册中心时,客户端订阅服务时会向 zookeeper 注册
自身;主要是方便对调用方进行统计、管理。但订阅时是否注册 client 不是
必要行为,和不同的注册中心实现有关,例如使用 consul 时便没有注册。
6.Zookeeper和Eureka比较
(1)Zookeeper实现的是CP,Eureka实现的是AP
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分
钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服
务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,
当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行
leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间
整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署
的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,
虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不
能容忍的;由于它不能很好的处理网络分区的问题,所以会导致一些客户
端状态会丢失(如果在同一个网络分区(partition)的节点数(nodes)
数达不到ZooKeeper选取Leader节点的“法定人数”时,它们就会从
ZooKeeper中断开,当然同时也就不能提供Service发现服务了,导致连
接到这些节点的客户端状态丢失)。
Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka
各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节
点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注
册或如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还
在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最
新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果
在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户
端与注册中心出现了网络故障,此时会出现以下几种情况:
* Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
* Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它
节点上(即保证当前节点依然可用)
* 当网络稳定时,当前实例新的注册信息会被同步到其它节点中
扩展1:Zookeeper做服务发现就是个错误
* 因为相对于CP,更能接受的是AP
* ZooKeeper本身并没有正确的处理网络分割的问题
在ZooKeeper中,如果在同一个网络分区(partition)的节点数
(nodes)数达不到ZooKeeper选取Leader节点的“法定人数”时,
它们就会从ZooKeeper中断开,当然同时也就不能提供Service
发现服务了,导致连接到这些节点的客户端状态丢失。Pinterest
与Airbnb公司通过增加客户端缓存的方案来解决该问题,但是这
种方式只是从表面上解决这个问题,因为当部分或者所有
节点跟ZooKeeper断开的情况下,每个节点还可以从本地缓存中
获取到数据并不一定是所有的服务注册信息,所引这导致我们并
不能得到一个CP的系统也不能得到一个AP的系统。
扩展2:Zookeeper为什么实现CP
ZooKeeper是Hadoop的一个子项目,旨在解决大规模分布式应用
场景下,服务协调同步(Coordinate Service)的问题。ZooKeeper
是分布式协调服务,它的职责是保证数据(注:配置数据,状态数
据)在其管辖下的所有服务之间保持同步、一致,所以就不难理解
为什么ZooKeeper被设计成CP而不是AP特性的了,如果是AP的,
那么将会带来恐怖的后果。
https://my.oschina.net/thinwonton/blog/1622905
zookeeper使用场景:https://blog.csdn.net/he90227/article/details/70157046
(2)Zookeeper是服务端的负载均衡而Eureka是服务端的负载均衡
客户端模式:
调用端调用微服务时,首先到服务注册中心获取服务列表,然后在根据调用
端本地的负载均衡策略进行服务调用。(服务列表保存在客户端)
服务端模式:
调用端直接像服务注册中心发起请求,服务注册中心在通过自身负载均衡策
略,对微服务进行调用。调用端不需要维护服务的发现逻辑。(服务列表保存
在服务端)
7.ACL
Zkeeper本身提供了ACL机制,表示为scheme:id:permissions,第一个字段表示采用哪
一种身份认证机制,第二个id表示用户,permissions表示相关权限(如只读,读写,
管理等)。
scheme有如下几种:
world:默认方式,相当于全世界都能访问。
auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上
下文中的授权用户)。
digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。
ip:使用Ip地址认证
permissions:
代表ZK中的操作权限,有5种:
CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、改、查、管理权限,
这5种权限简写为crwda(即:每个单词的首字符缩写)
注:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作
权限。
设置访问控制:
方式一:(推荐)
* 增加一个认证用户
addauth digest 用户名:密码明文
eg. addauth digest user1:password1
* 设置权限
setAcl /path auth:用户名:密码明文:权限
eg. setAcl /test auth:user1:password1:cdrwa
* 查看Acl设置
getAcl /path
方式二:
* setAcl /path digest:用户名:密码密文:权限
注:这里的加密规则是SHA1加密,然后base64编码。
五.dubbo(相关文档已上传到博客的附件中)
1.Zookeeper
2.Rpc
下面我只记录了一些重要内容,关于Rpc比较详细的内容在:
https://blog.csdn.net/mindfloating/article/details/39474123/
https://blog.csdn.net/kingcat666/article/details/78577079
用着的时候在看吧。
(1)概念
远程过程调用协议,通过网络从远程计算机上请求调用某种服务。RPC 的主要功
能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损
失本地调用的语义简洁性。
Rpc和Rmi的区别
* 语言范围不同
Rpc不区分语言和操作系统而Rmi(全称是Java Rmi)只属于Java的。
* 方法调用方式不同(略,闲的蛋疼在看)
RMI中是通过在客户端的Stub对象作为远程接口进行远程方法的调用。每个远程
方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被
添加到这个远程接口(stub)上,那么这个新方法就不能被RMI客户方所调用。
RPC中是通过网络服务协议向远程主机发送请求,请求包含了一个参数集和一个
文本值,通常形成“classname.methodname(参数集)”的形式。RPC远程主机就去
搜索与之相匹配的类和方法,找到后就执行方法并把结果编码,通过网络协议发
回。
* 调用结果的返回形式不同(略,闲的蛋疼在看)
Java是面向对象的,所以RMI的调用结果可以是对象类型或者基本数据类型;
RMI的结果统一由外部数据表示 (External Data Representation, XDR) 语言表
示,这种语言抽象了字节序类和数据类型结构之间的差异。
Rpc和Http
* RPC主要是基于TCP/IP协议的,而HTTP服务主要是基于HTTP协议的,我们都
知道HTTP协议是在传输层协议TCP之上的,所以效率来看的话,RPC要好一些。
* RPC服务主要是针对大型企业的,而HTTP服务主要是针对小企业的,因为
RPC效率更高,而HTTP服务开发迭代会更快。
* 其实在很久以前,我对于企业开发的模式一直定性为HTTP接口开发,也就是我
们常说的RESTful风格的服务接口。的确,对于在接口不多、系统与系统交互较
少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、
开发方便。利用现成的http协议进行传输。我们记得之前本科实习在公司做后台
开发的时候,主要就是进行接口的开发,还要写一大份接口文档,严格地标明输
入输出是什么?说清楚每一个接口的请求方法,以及请求参数需要注意的事项等。
比如下面这个例子:
POST http://www.httpexample.com/restful/buyer/info/share
接口可能返回一个JSON字符串或者是XML文档。然后客户端再去处理这个返回
的信息,从而可以比较快速地进行开发。但是对于大型企业来说,内部子系统较
多、接口非常多的情况下,RPC框架的好处就显示出来了,首先就是长链接,不
必每次通信都要像http一样去3次握手什么的,减少了网络开销;其次就是RPC框
架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调
用方来说是无感知、统一化的操作。
(2)Rpc介绍
一个完整的RPC架构里面包含了四个核心的组件,分别是Client、Server、
Client Stub以及Server Stub。
客户端(Client):服务的调用方。
服务端(Server):真正的服务提供者。
客户端存根(Client Stub):存放服务端的地址消息,再将客户端的请求参数打包
成网络消息,然后通过网络远程发送给服务方。
服务端存根(Server Stub):接收客户端发送过来的消息,将消息解包,并调用
本地的方法。
一次Rpc调用大约分10次
* 服务消费方(client)调用以本地调用方式调用服务;
* client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
* client stub找到服务地址,并将消息发送到服务端;
* server stub收到消息后进行解码;
* server stub根据解码结果调用本地的服务;
* 本地服务执行并将结果返回给server stub;
* server stub将返回结果打包成消息并发送至消费方;
* client stub接收到消息,并进行解码;
* 服务消费方得到最终结果。
扩展知识
Rmi调用过程(平时不用看,用得着时候或是闲的蛋疼在看)
* 客户调用客户端辅助对象stub上的方法
* 客户端辅助对象stub打包调用信息(变量,方法名),通过网络发送给服务端辅
助对象skeleton
* 服务端辅助对象skeleton将客户端辅助对象发送来的信息解包,找出真正被调用
的方法以及该方法所在对象
* 调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象skeleton
* 服务端辅助对象将结果打包,发送给客户端辅助对象stub
* 客户端辅助对象将返回值解包,返回给调用者
* 客户获得返回值
3.socket
注册中心与生产者、消费者之间的心跳检测是基于socket长连接的,所以有必要了
解socket。了解socket查看文章:有空在把这的知识补全
https://www.cnblogs.com/embedded-linux/p/6261894.html
http://m.elecfans.com/article/630956.html
Socket的特点:
Socket 传输方式适合于对传输速度,安全性,实时交互,费用等要求高的应用中,
如网络游戏,手机应用,银行内部交互等。
基于http协议传输的特点:基于http协议传输方式适合于对传输速度,安全性要求
不是很高,且需要快速开发的应用。如公司OA系统,互联网服务等。
创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协
议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连
接。
Socket 传输的特点:
优点
1) 传输数据为字节级,传输数据可自定义,数据量小(对于手机应用讲:费用低)
2) 传输数据时间短,性能高
3) 适合于客户端和服务器端之间信息实时交互
4) 可以加密,数据安全性强
缺点:
1) 需对传输的数据进行解析,转化成应用级的数据
2) 对开发人员的开发水平要求高
3) 相对于Http协议传输,增加了开发量
基于Http协议传输的定义和其特点
目前基于http协议传输的主要有http协议 和基于http协议的Soap协议(web service),
常见的方式是 http 的post 和get 请求,web 服务。
优点:
1) 基于应用级的接口使用方便
2) 程序员开发水平要求不高,容错性强
缺点:
1) 传输速度慢,数据包大(Http协议中包含辅助应用信息)
2) 如实时交互,服务器性能压力大。
3) 数据传输安全性差
建立socket连接:
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,
另一个运行于服务器端,称为ServerSocket 。 套接字之间的连接过程分为三个步
骤:服务器监听,客户端请求,连接确认。
服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的
状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。
为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指
出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连
接请求。
连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就
响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描
述发给客户 端,一旦客户端确认了此描述,双方就正式建立连接。而服
务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请
求。
4. dubbo图
4.dubbo原理
(1)注册中心(本节介绍了分布式系统中的注册中心是个什么鬼,但是放在后面了)
注册中心和每个Server/Client之间会作一个实时的心跳检测(因为它们都是建立
的Socket长连接,该功能由Zookeeper实现),比如几秒钟检测一次。收集每个
Server提供的服务的信息,每个Client的信息,整理出一个服务列表,如:
serviceName | serverAddressList | clientAddressList |
UserService | 192.168.0.1,192.168.0.2,192.168.0.3,192.168.0.4 | 172.16.0.1,172.16.0.2 |
ProductService | 192.168.0.3,192.168.0.4,192.168.0.5,192.168.0.6 | 172.16.0.2,172.16.0.3 |
OrderService | 192.168.0.10,192.168.0.12,192.168.0.5,192.168.0.6 | 172.16.0.3,172.16.0.4 |
当某个Server不可用,那么就更新受影响的服务对应的serverAddressList,即把这
个Server从serverAddressList中剔除出去(从地址列表中删除),同时将推送
serverAddressList给这些受影响的服务的clientAddressList里面的所有Client。如:
192.168.0.3挂了,那么UserService和ProductService的serverAddressList都要把
192.168.0.3删除掉,同时把新的列表告诉对应的Client 172.16.0.1,172.16.0.2,
172.16.0.3;当某个Client挂了,那么更新受影响的服务对应的clientAddressList
ConfigServer根据服务列表,就能提供一个web管理界面,来查看管理服务的提供
者和使用者。新加一个Server时,由于它会主动与ConfigServer取得联系,而
ConfigServer又会将这个信息主动发送给Client,所以新加一个Server时,只需要
启动Server,然后几秒钟内,Client就会使用上它提供的服务。
dubbo与zookeeper的交互过程:https://blog.csdn.net/qq_27529917/article/details/80632078
(2)client
调用服务的机器,每个Client启动时,主动与ConfigServer建立Socket长连接,并
将自己的IP等相应信息发送给ConfigServer。Client在使用服务的时候根据服务名称
去ConfigServer中获取服务提供者信息(这样ConfigServer就知道某个服务是当前哪
几个Client在使用),Client拿到这些服务提供者信息后,与它们都建立连接,后面
就可以直接调用服务了,当有多个服务提供者的时候,Client根据一定的规则来进行
负载均衡,如轮询,随机,按权重等。一旦Client使用的服务它对应的服务提供者有
变化(服务提供者有新增,删除的情况),ConfigServer就会把最新的服务提供者列
表推送给Client,Client就会依据最新的服务提供者列表重新建立连接,新增的提供者
建立连接,删除的提供者丢弃连接。
(3)Server
真正提供服务的机器,每个Server启动时,主动与ConfigServer建立Scoket长连接,
并将自己的IP,提供的服务名称,端口等信息直接发送给ConfigServer,
ConfigServer就会收集到每个Server提供的服务的信息。
(4)这样做的好处
(i)只要在Client和Server启动的时候,ConfigServer是好的,服务就可调用了,如果后
面ConfigServer挂了,那只影响ConfigServer挂了以后服务提供者有变化,而Client
还无法感知这一变化。
(ii)Client每次调用服务是不经过ConfigServer的,Client只是与它建立联系,从它那里
获取提供服务者列表而已。
(iii)调用服务-负载均衡:Client调用服务时,可以根据规则在多个服务提供者之间轮流
调用服务。
(iv)服务提供者-容灾:某一个Server挂了,Client依然是可以正确的调用服务的,当前
提是这个服务有至少2个服务提供者,Client能很快的感知到服务提供者的变化,
并作出相应反应。
(v)服务提供者-扩展:添加一个服务提供者很容易,而且Client会很快的感知到它的存
在并使用它。
(5)现在开始介绍一下分布式系统的注册中心
这里我摘录了一些
(1)为什么要使用服务的注册中心
分布式服务框架部署在多台不同的机器上,例如服务提供者在集群A,服务调用者
在集群B,那么B在调用A的服务的过程中,集群A的机器需要和集群B的机器进行
通信。那么会出现如下问题:
(i)集群A的服务调用者如何发现集群B的服务提供者
(ii)集群A的服务调用者如何选择集群B中的某一台服务提供者机器发起调用
(iii)集群B的服务提供者机器上/下线之后,集群A中调用者如何感知到这台
机器的上/下线,不在对已下线的机器发起调用。
(iv)集群B提供的某个服务如何获知集群A中那些机器正在消费该服务。
以上问题将通过服务注册中心来解决,采用服务注册中心来实时存储更新服务提供
者信息及该服务的实时调用者信息。
其工作过程如下:
(i)在服务启动的时候,将服务提供者信息主动上报到服务注册中心进行服务注册
(ii)服务调用者启动的时候,将服务提供者信息从注册中心下拉到服务调用者机器
本地缓存,服务调用者从本地缓存的服务提供者列表中,基于某种负载均衡策
略选择一台服务提供者发起远程调用。
(iii)服务注册中心能够感知服务提供者集群中某一台机器下线,将该机器服务提供
者信息从注册中心删除,并且通知服务调用者集群中的每一台机器,是的服务
调用者不在调用该机器。
服务注册中心有下面几个优点:
(i)软负载及透明化路由:服务提供者和服务调用者之间相互解耦,服务调用者不
需要硬编码服务提供者地址。
(ii)服务动态发现及可伸缩能力:服务提供者机器增减能被服务调用者通过注册中
心动态感知,而且通过增减机器可以实现服务的
弹性伸缩
(iii)通过注册中心可以动态的监控服务运行质量及服务依赖,为服务提供服务治理
能力。
注册中心其实充当是服务的协调者,一般包含如下几个功能:
(i)服务发现:
服务注册/反注册:保存服务提供者和服务调用者的信息
服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功
能
服务路由(可选):具有筛选整合服务提供者的能力。
(ii)服务配置(不包括其它无关配置):
配置订阅:服务提供者和服务调用者订阅微服务相关的配置
配置下发(可选):主动将配置推送给服务提供者和服务调用者
(iii)服务健康检测
检测服务提供者的健康情况
5.dubbo和webservice
(1)WebService
(a)效率不高基于soap协议,其主要的特点是跨语言、跨平台的。项目中不推荐使用,
可用于不同公司间接口的调用。
(b)若使用restful形式的服务:http+json。很多项目中应用。如果服务太多,服务之间
调用关系混乱,需要治疗服务。
(2)使用dubbo。使用rpc协议进行远程调用,直接使用socket通信。传输效率高,并且可以
统计出系统之间的调用关系、调用次数。使用Java语言开发,只能用于Java语言开发的
项目间的通信,不具备跨语言,跨平台的特点。
(3)WebService是什么鬼
https://blog.csdn.net/u013168253/article/details/79695492
5.dubbo功能详细
(1)常规用法,Hello World例子
生产者
IDemoService.java
package com.baizhi.service; public interface IDemoService { /** * 求和 * @param x * @param y * @return */ public int sum(Integer x ,Integer y); /** * 计算连个数的乘积 * @param x * @param y * @return */ public int multi(Integer x ,Integer y); }
DemoService_v1.java