vlambda博客
学习文章列表

Java进阶:分布式理论、架构设计(自定义RPC)笔记

分布式系统:是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。

集群:多个人在一起做同样的事。
分布式:多个人在一起做不同的事。


====================================


CAP定理:
一个分布式系统不可能同时满足一致性(C:Consistency),可用性(A:Availability)和分区容错性(P:Partition tolerance)这三个基本需求,最多只能同时满足其中的2个。
C 一致性:分布式系统当中的一致性指的是所有节点的数据一致,或者说是所有副本的数据一致。
A 可用性:Reads and writers always succeed。也就是说系统一直可用,而且服务一直保持正常
P 分区容错性:系统在遇到一些节点或者网络分区故障的时候,仍然能够提供满足一致性和可用性的服务

CAP只能3选2
P相当于分布式,一般不会舍弃;
根据情况舍弃A或C

BASE理论:
让C与A协调,都达到目标效果。
BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。

Basically Available(基本可用):允许损失部分可用性。
Soft state(软状态):允许系统数据存在中间状态。(及同步中)
Eventually consistent(最终一致性):不需要实时保证系统数据的强一致性,只保证最终一致性。


====================================


分布式理论:一致性协议2PC
2PC:Two-Phase Commit缩写。即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase)。
2PC用来解决分布式事务问题,事务管理器会先询问一个事务中的每个节点,是否可以commit;如果都可以,则通知每个节点进行commit操作;只要有节点不可以,那就通知每个节点执行回滚操作。
2PC协议优点:原理简单,实现方便。
2PC协议缺点:同步阻塞,只要有节点没有准备好commit,其它节点就需要等待。
单点问题:如果事务管理器宕机,每个事务节点都会处于锁定状态,不可用。
数据不一致问题:如果有节点已进行commit操作,其它节点没有进行commit操作,此时事务管理器宕机,会造成数据不一致。
过于保守:一旦有一个节点出现问题,那么事务管理器只能等待它超时,然后才能认为它有问题,进行回滚操作。


----------------------------------


分布式理论:一致性协议3PC
3PC,three phase commit,是2PC的改进版,将2PC的"提交事务请求"过程一分为二,共形成了由CanCommit、PreCommit、doCommit三个阶段组成的事务处理协议。

3PC与2PC的比较:
协调者:事务管理器。
参与者:事务节点(具体执行回滚或提交的每个节点)。
2PC中,只有协调者有超时机制,即在一定时间内没有收到参与者的消息则默认失败。
3PC中,对于协调者与参与者都设置了超时机制,如果参与者在preCommit步骤收到yes命令,而在doCommit步骤没有收到命令,也会自动进行本地commit,从而释放资源。(2PC中资源会被锁定,同步阻塞)
同时,这样也会有问题,并没有完全解决事务一致性的问题。

3PC中,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。


====================================


一致性算法:Paxos
Paxos算法是Lamport提出的一种基于消息传递的分布式一致性算法。

Google的很多大型分布式系统都采用了Paxos算法来解决分布式一致性问题。
ZooKeeper、以及MySQL5.7推出的用来取代传统的主从复制的MySQL Group Replication等也采用了Paxos算法解决分布式一致性问题。

Paxos算法简要理解:
在分布式系统中,每个节点都有可能故障,每个节点之间的通信链路也可能故障;
保持分布式系统数据一致性时,我们希望每个节点按顺序执行一系列同样的数据更新操作,如[op1,op2,op3...],这样就保证了数据一致性。
Paxos算法需要解决的问题就是,在上述分布式系统中,快速且正确地在集群内部对某个数据的值达成一致。

例如,当有多个参与者、一个协调者时;有多个参与者想修改数据,协调者可以采用"谁先到听谁的"的方式。
但是当协调者宕机,就会有问题。
所以实际场景中,有多个参与者,多个协调者,这时有多个参与者想修改数据,会比较混乱。
Paxos算法就是为了解决这个问题而生的。


*感觉这个对Paxos协议的作用说的清楚点,关于如何保证对外服务读写一致性。
https://www.zhihu.com/question/65387136/answer/230842819


----------------------------------


Paxos相关概念:
提案(Proposal):不同节点发送的消息。
Client客户端:客户端向分布式系统发起请求,并等待响应。
Proposer提案发起者:分布式系统某个节点收到客户端的请求,发起提案。
Acceptor决策者:可以接受(accept)提案。如果某个提案被选定(chosen),那么该提案里的value就被选定了。
Learners:最终决策的学习者。

问题描述:
假如有一组可以提出提案的进程集合,那么对于一个一致性算法需要保证以下几点:
●在这些被提出的提案中,只有一个被选定
●如果没有提案被选出,就不应该有被选定的提案。
●当一个提案被选定后,那么所有进程都应该能学习(learn)到这个被选定的value。


----------------------------------


P1:一个Acceptor必须接受它收到的第一个提案
规定:一个提案被选定需要半数以上的Acceptor接受
P2:如果某个value为v的提案被选定了,那么每个编号更高的被选定提案的value必须也是v。
P2a:如果某个value为v的提案被选定了,那么每个编号更高的被Acceptor接受的提案的value必须也是v。
P2b:如果某个value为v的提案被选定了,那么之后任何Proposer提出的编号更高的提案的value必须也是v。
P2c:对于任意的Mn和Vn,如果提案[Mn,Vn]被提出,那么肯定存在一个由半数以上的Acceptor组成的集合S,满足以下两个条件中的任意一个:
要么S中每个Acceptor都没有接受过编号小于Mn的提案。
要么S中所有Acceptor批准的所有编号小于Mn的提案中,编号最大的那个提案的value值为Vn


----------------------------------


提案规则的生成及接收:
1.提案者发送提案给接受者,接受者接受提案。
2.提案者发送提案给接受者,接受者不接受提案,返回现在的value,让提案者学习。


----------------------------------


Acceptor算法优化:
优化前:消息复杂,多,耗费资源多。
优化后:如果Acceptor收到一个编号为N的Prepare请求,在此之前它已经响应过编号大于N的Prepare请求。根据Pla,该Acceptor不可能接收编号为N的提案。因此,该Acceptor可以忽略编号为N的Prepare请求。(不用返回拒绝信息,直接忽略)


----------------------------------


1.发送提案(Prepare)请求
2.有半数以上的提案被响应后,就可以发送accept请求,其中有提案编号和value。


----------------------------------


Paxos算法描述:


保证Paxos算法活性:防止提案编号循环增加,无法选出value。
选择一个主Proposer,只有它能发起提案。


====================================


Raft算法:
Raft是一种为了管理复制日志的一致性算法。
Raft提供了和Paxos算法相同的功能和性能,但是它的算法结构和Paxos不同。Raft算法更加容易理解并且更容易构建实际的系统。
Raft将一致性算法分解成了3个模块:
1.领导人选举
2.日志复制
3.安全性

目标:
1.选取Leader
2.日志复制

如果超过一半以上的节点挂掉,数据就不能保持一致。(如果发现当前节点数不是多数派,数据就不会进行同步)


=======================================


分布式系统设计策略:心跳检测机制:长时间收不到某个节点的心跳包,则认为该节点故障,需要修复。

分布式系统设计策略:高可用设计
常用的三种高可用设计模式:主备(Master-Slave)、互备(Active-Active)、集群(Cluster)

分布式系统设计策略:容错性设计:例如,如何防止缓存穿透。(查询id=-1等数据库不存在的字段)


====================================


分布式架构网络通信基本原理:
网络数据传输的要素:
协议:UDP、TCP
发送数据:Socket
IO:BIO(同步阻塞IO)、NIO(同步非阻塞IO)、AIO(异步非阻塞IO)
远程通讯技术:RMI、Hessian、SOAP、JMS


====================================


Stub会把java对象序列化与反序列化,然后传输。(因为网络传输是二进制的)

Java中RPC的框架比较多,常见的有Hessian、gRPC、Dubbo、HSF(High Speed Service Framework)等。


----------------------------------


Java RMI是远程方法调用,是java原生支持的远程调用,采用JRMP(java Remote Messageing protocol)作为通信协议,可以认为是纯Java版本的分布式远程调用解决方案。
1.客户端
(1)存根/桩(stub):远程对象在客户端上的代理。
(2)远程引用层(Remote Reference Layer):解析并执行远程引用协议
(3)传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。
2.服务端
(1)骨架(skeleton):读取客户端传递的方法参数,调用服务器的实际对象方法,并接收方法执行后返回的返回值
(2)远程引用层(Remote Reference Layer):处理远程引用后向骨架发送远程方法调用
(3)传输层(Transport):监听客户端的入栈链接,接收并转发调用到远程引用层。
3.注册表(Registry):以URL形式注册远程对象,并向客户端回复对远程对象的引用。


----------------------------------


RMI使用方法,java代码(省略,这个用的少)


====================================


BIO同步阻塞,Block-IO

NIO同步非阻塞,New IO或Non-Block IO

AIO异步非阻塞,Asynchronous I/O


----------------------------------


BIO:jdk1.4以前,只能使用BIO-同步阻塞。
ServerSocket serverSocket = new ServerSocket();
...
while(true){
Socket socket = serverSocket.accept();//这个方法就是同步阻塞状态
  new Thread(()->{...}).start();
}
//执行到这一步时,如果客户端没有发来请求,就会停在这里;如果客户端发来请求,才会执行下一步
如果有一个请求,服务器就会建立一个链接,使用一个线程进行处理。


----------------------------------


NIO:jdk1.4及以上版本。
客户端发送的链接请求都会注册到多路复用器上,多路复用器轮询到链接有IO请求时才启动一个线程处理。
避免了客户端在不进行IO操作时还与服务器建立链接的情况,节省了服务器链接资源。

NIO模型详细描述:使用selector注册器,当一条链接来了之后,先不创建一个while死循环去监听是否有数据可读了,而是直接把这条链接注册到selector上,然后,通过检查这个selector,就可以批量检测出有数据可读的链接,进而读取数据。


----------------------------------


AIO:从jdk7开始支持。
用于连接数目多且连接比较长(重操作)的架构,比如相册服务器。


====================================


Netty
是由JBOSS提供的一个异步的、基于事件驱动的网络编程框架。
Netty可以帮助我们快速、简单的开发出一个网络应用,相当于简化和流程化了NIO的开发过程。

知名的 Elasticsearch 、 Dubbo 框架内部都采用了 Netty。

----------------------------------


为什么要使用Netty

NIO缺点:
NIO的类库和API繁杂,使用麻烦;
可靠性不强,开发工作量和难度都非常大
NIO的Bug,例如Epoll Bug,会导致selector空轮询,最终导致CPU 100%。

Netty优点:
对各种传输协议提供了统一的API
高度可定制的线程模型——单线程、一个或多个线程池
更好的吞吐量,更低的等待延迟
更少的资源消耗
最小化不必要的内存拷贝


----------------------------------


基于Netty自定义RPC,Java代码(这个单独发一篇博客)