分布式概念
- 一、分布式介绍
- 1.1 分布式计算
- 1.1.1 分布式计算的方法
- 1.1.1 分布式计算与互联网的普及
- 1.1.2 分布式计算项目
- 1.1.3 参与计算
- 1.2 分布式存储系统
- 1.2.1 P2P 数据存储系统
- 1.2.2 云存储系统
- 1.3 应用
- 二、分布式基础概念
- 2.1 微服务
- 2.2 集群
- 2.3 分布式
- 2.4 节点
- 2.5 远程调用
- 2.6 负载均衡
- 2.6.1 负载均衡算法:
- 2.7 服务注册、服务发现、注册中心
- 2.8 配置中心
- 2.9 服务熔断、服务降级
- 2.9.1 雪崩场景:
- 2.9.2 服务熔断:
- 2.9.3 服务降级:
- 2.10 API 网关
- 三、分布式理论
- 3.1 分布式系统概念和存在的问题
- 3.2 分布式系统存在的问题
- 3.3 分布式理论:一致性
- 3.4 一致性分类
- 3.5 分布式理论:CAP定理
- 3.6 一致性
- 3.7 可用性
- 3.8 分区容错性
- 3.9 分布式理论:BASE理论
- 3.0 分布式理论:一致性协议2PC
- 3.11 分布式理论:一致性协议3PC
- 3.12 分布式理论:一致性算法Paxos
- 3.13 分布式理论:一致性算法Raft
- 3.14 领导人Leader选举
- 3.15 日志复制(保证数据一致性)
- 四、分布式系统设计策略
- 4.1 心跳检测机制
- 4.2 高可用设计
- 4.2.1 主备模式
- 4.2.2 互备模式
- 4.2.3 集群模式
- 4.3 容错性设计
- 4.4 负载均衡策略
- 五、分布式架构网络通信
- 5.1 基本原理
- 5.2 RPC基本概念
- 5.3 RMI远程方法调用
- 5.4 同步、异步、阻塞、非阻塞
- 5.5 BIO
- 5.6 NIO
- 5.7 AIO
- 5.8 Netty
- 5.9 基于Netty自定义RPC
一、分布式介绍
分布式计算是计算机科学中一个研究方向,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给多个计算机进行处理,最后把这些计算结果综合起来得到最终的结果。分布式网络存储技术是将数据分散地存储于多台独立的机器设备上。分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,不但解决了传统集中式存储系统中单存储服务器的瓶颈问题,还提高了系统的可靠性、可用性和扩展性。
当计算机的程序和数据通过网络分布在多于一个的计算机上时,计算就成为“分布式的”。以前的计算通常是由计算中心完成的。尽管仍存在这样的计算中心,大小企业却逐渐将应用程序移至(分布到)企业中能最有效地完成计算的地点进行,通常是桌面工作站、局域网服务器、部门服务器、Web服务器和其他服务器的混合。比较流行的是客户/服务器模式,客户机只具有一定的功能,其他的功能需要从提供服务的服务器那里获得。HTTP协议就是一个例子。在分布式计算环境中,数据的存储和处理可在本地工作站上进行。
1.1 分布式计算
分布式计算是近年提出的一种新的计算方式。所谓分布式计算就是在两个或多个软件互相共享信息,这些软件既可以在同一台计算机上运行,也可以在通过网络连接起来的多台计算机上运行。分布式计算是一种计算方法,和集中式计算是相对的。随着计算技术的发展,有些应用需要非常巨大的计算能力才能完成,如采用集中式计算,需要耗费相当长的时间来完成。分布式计算将该应用分解成许多小的部分,分配给多台计算机进行处理。这样可以节约整体计算时间,大大提高计算效率。
分布式计算比起其它算法具有以下几个优点:
1、稀有资源可以共享;
2、通过分布式计算可以在多台计算机上平衡计算负载;
3、可以把程序放在最适合运行它的计算机上;
其中,共享稀有资源和平衡负载是计算机分布式计算的核心思想之一。
实际上,网格计算就是分布式计算的一种。如果我们说某项工作是分布式的,那么,参与这项工作的一定不只是一台计算机,而是一个计算机网络,显然这种“蚂蚁搬山”的方式将具有很强的数据处理能力。网格计算的实质就是组合与共享资源并确保系统安全。
1.1.1 分布式计算的方法
分布式计算是利用互联网上的计算机的 CPU 的闲置处理能力来解决大型计算问题的一种计算科学。下面,我们看看它是怎么工作的:
首先,要发现一个需要非常巨大的计算能力才能解决的问题。这类问题一般是跨学科的、极富挑战性的、人类急待解决的科研课题。其中较为著名的是:
1.解决较为复杂的数学问题,例如:GIMPS(寻找最大的梅森素数)。
2.研究寻找最为安全的密码系统,例如:RC-72(密码破解)。
3.生物病理研究,例如:Folding@home(研究蛋白质折叠,误解,聚合及由此引起的相关疾病)。
4.各种各样疾病的药物研究,例如:United Devices(寻找对抗癌症的有效的药物)。
5.信号处理,例如:SETI@Home(在家寻找地外文明)。
从这些实际的例子可以看出,这些项目都很庞大,需要惊人的计算量,仅仅由单个的电脑或是个人在一个能让人接受的时间内计算完成是绝不可能的。在以前,这些问题都应该由超级计算机来解决。但是, 超级计算机的造价和维护非常的昂贵,这不是一个普通的科研组织所能承受的。随着科学的发展,一种廉价的、高效的、维护方便的计算方法应运而生——分布式计算!
1.1.1 分布式计算与互联网的普及
随着计算机的普及,个人电脑开始进入千家万户。与之伴随产生的是电脑的利用问题。越来越多的电脑处于闲置状态,即使在开机状态下CPU的潜力也远远不能被完全利用。我们可以想象,一台家用的计算机将大多数的时间花费在“等待”上面。即便是使用者实际使用他们的计算机时,处理器依然是寂静的消费,依然是不计其数的等待(等待输入,但实际上并没有做什么)。互联网的出现, 使得连接调用所有这些拥有闲置计算资源的计算机系统成为了现实。
1.1.2 分布式计算项目
那么,一些本身非常复杂的但是却很适合于划分为大量的更小的计算片断的问题被提出来,然后由某个研究机构通过大量艰辛的工作开发出计算用服务端和客户端。服务端负责将计算问题分成许多小的计算部分,然后把这些部分分配给许多联网参与计算的计算机进行并行处理,最后将这些计算结果综合起来得到最终的结果。
当然,这看起来也似乎很原始、很困难,但是随着参与者和参与计算的计算机的数量的不断增加, 计算计划变得非常迅速,而且被实践证明是的确可行的。一些较大的分布式计算项目的处理能力已经可以达到甚至超过世界上速度最快的巨型计算机。
您也可以选择参加某些项目以捐赠的 CPU内核处理时间,您将发现您所提供的 CPU 内核处理时间将出现在项目的贡献统计中。您可以和其他的参与者竞争贡献时间的排名,您也可以加入一个已经存在的计算团体或者自己组建一个计算小组。这种方法很利于调动参与者的热情。
1.1.3 参与计算
随着民间的组队逐渐增多, 许多大型组织(例如公司、学校和各种各样的网站)也开始了组建自己的战队。同时,也形成了大量的以分布式计算技术和项目讨论为主题的社区,这些社区多数是翻译制作分布式计算项目的使用教程及发布相关技术性文章,并提供必要的技术支持。
那么谁可能加入到这些项目中来呢? 当然是任何人都可以! 如果您已经加入了某个项目,而且曾经考虑加入计算小组, 您将在中国分布式计算总站及论坛里找到您的家。任何人都能加入任何由我站组建的分布式计算小组。希望您在中国分布式总站及论坛里发现乐趣。
参与分布式计算——一种能充分发挥您的个人电脑的利用价值的最有意义的选择——只需要下载有关程序,然后这个程序会以最低的优先度在计算机上运行,这对平时正常使用计算机几乎没有影响。如果你想利用计算机的空余时间做点有益的事情,还犹豫什么?马上行动起来吧,你的微不足道的付出或许就能使你在人类科学的发展史上留下不小的一笔呢。
1.2 分布式存储系统
分布式存储系统,是将数据分散存储在多台独立的设备上。传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。大数据时代的来临使得对分布式存储系统的研究具有重要的意义:
针对海量数据存储,分布式数据存储以其良好的可扩展性。健壮性和高效性超越了传统的集中式存储技术,但针对其本身的许多性能指标比如数据冗余度、数据存取速度、带宽占用率、存储花费和可靠性等使得不同的系统和不同的个人、企业对存储要求的侧重点不同。数据存储多考虑存取效率、存储花费,对数据抗毁性研究甚少。
针对海量数据的管理和维护,维护数据一致性是分布式存储系统维护数据的一个重点方向,由于互联网环境千变万化,数据更新速度和转换频率不断加快,使得数据一致性维护面临诸多问题,如可靠性问题、数据冗余问题、网络动荡问题和恶意攻击等问题严重影响了一致性维护策略的制定和发展。
1.2.1 P2P 数据存储系统
P2P数据存储系统采用 P2P 网络的特点,即每个用户都是数据的获取者和提供者,没有中心节点,所以每个用户都是对等存在的。利用这种特点建立而成的P2P 数据存储系统可以将数据存放于多个对等节点上,当需要数据时,可以利用固定的资源搜索算法寻找数据资源,从而获取想要的数据。
P2P 数据存储系统的这种特点使得它非常适合存储大量数据。首先,由于没有中心服务器的存在,数据被分散存储与各个对等节点上,这样就不会出现某个节点负载过重的问题,可扩展性好;其次,对于网络攻击的抗打击能力强,当存在网络攻击时,受打击的节点损失的数据仅仅是整个数据存储系统的一小部分,大部分资源仍然处于安全状态;最后,得益于P2P网络优良的可扩展性和易维护性,P2P 数据存储系统也有着这些优点。
1.2.2 云存储系统
云存储系统是一种网络存储系统,通过将大量的数据存储服务器集合起来,在内部表现为多个存储服务器协同工作,共同承担数据存储的任务,将数据存储任务划分为多个子任务并行存储,从而减小了数据存储的时间,并增加数据安全性。简单来说,云存储就是将数据或者文件存放到云端,数据使用者可以在任意地方通过互联网非常方便的存取数据,并且数据存储在云端有着高安全性、低花费等优点。
1.3 应用
所谓分布式就是指数据和程序可以不位于一个服务器上,而是分散到多个服务器,以网络上分散分布的地理信息数据及受其影响的数据库操作为研究对象的一种理论计算模型。分布式有利于任务在整个计算机系统上进行分配与优化,克服了传统集中式系统会导致中心主机资源紧张与响应瓶颈的缺陷,解决了网络GIS 中存在的数据异构、数据共享、运算复杂等问题,是地理信息系统技术的一大进步。
传统的集中式GIS 起码对两大类地理信息系统难以适用,需用分布式计算模型。第一类是大范围的专业地理信息系统、专题地理信息系统或区域地理信息系统。这些信息系统的时空数据来源、类型、结构多种多样,只有靠分布式才能实现数据资源共享和数据处理的分工合作。比如综合市政地下管网系统,自来水、燃气、污水的数据都分布在各自的管理机构,要对这些数据进行采集、编辑、入库、提取、分析等计算处理就必须采用分布式,让这些工作都在各自机构中进行,并建立各自的管理系统作为综合系统的子系统去完成管理工作。而传统的集中式提供不了这种工作上的必要性的分工。第二类是在一个范围内的综合信息管理系统。城市地理信息系统就是这种系统中一个很有代表性的例子。世界各国管理工作城市市政管理占很大比例,城市信息的分布特性及城市信息管理部门在地域上的分散性决定了多层次、多成份、多内容的城市信息必须采用分布式的处理模式。
很明显,传统的集中式地理信息系统不能满足分工明确的现代社会的需求,分布式地理信息系统的进一步发展具有不可阻挡的势头。而且,分布式GIS 与网络GIS 、客户/服务器GIS计算模型、WWW计算模型的关系都很密切。分布式GIS 是实现网络GIS 的途径,是实现NGIS的一种重要计算模型;CIS模型实际上是分布式GIS 可供采用的一种具体化计算模型;WWW模型实际上也是分布式GIS模型可采用的一种具体化模型,而且也是具有相当发展前途的分布式GIS模型。分布式GIS 与当今主导地理信息系统发展方向的技术的紧密联系使分布式GIS相应地成为地理信息系统的主要发展趋势。
二、分布式基础概念
2.1 微服务
拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行
2.2 集群
是一种物理形态
将几台服务器集中在一起,实现同一业务
2.3 分布式
是一种工作方式
若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统
将不同的业务分布在不同的地方
2.4 节点
集群中的一个服务器
2.5 远程调用
分布式系统中,各个服务可能处于不同主机,但是服务之间不可避免的需要互相调用,我们称为远程调用。
SpringCloud 中使用 HTTP+JSON 的方式完成远程调用。
2.6 负载均衡
A 服务调用 B 服务,B 服务部署在多台机器,A 发送请求到任意一个服务器均可完成调用。
为了使每台服务器不至于忙于处理请求,可以将请求均衡到每一个服务器,提升网站的可用性。
2.6.1 负载均衡算法:
轮询:请求依次按顺序分发到不同的可用服务器执行,循环分发请求。
最小连接:分发请求到连接数最少的服务器。场景:处理请求用时较长的场景。
散列:根据用户请求的 IP 地址的散列(hash)来选择要转发的服务器。场景:需要处理状态而要求用户能连接到相同服务器。
2.7 服务注册、服务发现、注册中心
A 服务调用 B 服务、C 服务,但是 A 服务不知道 B、C 服务所在的服务器是正常还是下线,注册中心可以帮助解决。
注册中心实时知道哪些服务正常,哪些服务下线,也能记录新增的正常服务。服务之间调用不需要去判断哪些服务正常,注册中心会告诉服务有效的调用地址。
**服务注册:**服务将自己的 IP 和端口报告给注册中心的过程。
**服务发现:**查询可用微服务列表及其网络地址的机制。
**注册中心:**集中记录每个服务的地址,注册和注销服务。
**服务检查:**检查已注册的服务,如发现某服务长时间无法访问,则会从注册中心移除该服务。
2.8 配置中心
每个服务都有大量配置,更新一个配置,需要同步到每个服务,如何修改每个服务的配置呢?
每个服务从配置中心获取配置,自动更新自己的配置。
2.9 服务熔断、服务降级
下单场景:用户下单了一个商品,客户端调用订单服务来生成预付款订单,订单服务调用商品服务查看下单的哪款商品,商品服务调用库存服务判断这款商品是否有库存,如有库存,则可以生成预付款订单。
2.9.1 雪崩场景:
第一次滚雪球:库存服务不可用(如响应超时等),库存服务收到的很多请求都未处理完,库存服务将无法处理更多请求。
第二次滚雪球:因商品服务的请求都在等库存服务返回结果,导致商品服务调用库存服务的很多请求未处理完,商品服务将无法处理其他请求,导致商品服务不可用
第三次滚雪球:因商品服务不可用,订单服务调用商品服务的的其他请求无法处理,导致订单服务不可用。
第四次滚雪球:因订单服务不可用,客户端将不能下单,更多客户将重试下单,将导致更多下单请求不可用。
2.9.2 服务熔断:
设置服务的超时,当被调用的服务某段时间内失败率达到某个阈值,则对该服务开启短路保护,后来的请求不调用这个服务,直接返回默认的数据。
2.9.3 服务降级:
对非核心业务降级运行:某些服务不处理,或者简单处理(抛异常、返回 Null、返回 Mock 数据)
2.10 API 网关
抽象了微服务中都需要的公共功能
提供了负载均衡、自动熔断、灰度发布、统一认证、限流、日志统计功能
三、分布式理论
3.1 分布式系统概念和存在的问题
分布式系统,就是一个业务拆分成多个子业务,分布在不同的服务器节点,共同构成的系统称为分布式系统。
集群:多个人在一起作同样的事。
分布式:多个人在一起作不同的事。
特点:分布性、对等性、并发性、缺乏全局时钟、故障总数会发生
3.2 分布式系统存在的问题
通信异常:网络不确定性导致分布式系统无法顺利进行一次网络通信
网络分区:整个系统网络被切分,导致分布式系统出现局部小集群,小集群要完成整个分布式系统的功能。
节点故障:组成分布式系统的某个服务器出现宕机
三态:每次请求都存在的三种状态,失败、成功、超时。超时通常是发送过程中丢失或者响应过程中丢失。
3.3 分布式理论:一致性
数据在多份副本中存储时,各副本中的数据是一致的。
数据的ACID四原则:原子性、一致性、隔离性、持续性。
3.4 一致性分类
强一致性:要求系统写入什么,读出来的也会是什么,对系统性能影响最大,难实现。
弱一致性:约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致, 但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。
弱一致性之读写一致性:用户读取自己写入结果的一致性,保证用户永远能够第一时间看到自己更新的内容,也就是写到了主库,但是读却走了从库,导致读写可能不一致,通过设定时间戳,让更新后一段时间都从主库读来实现。
弱一致性之单调读一致性:本次读到的数据不能比上次读到的旧,也就是第一次读主库最新值,第二次读从库还是旧值,通过根据用户ID计算一个hash值,再通过hash值映射到机器,让用户每次都访问一台机子来实现。
弱一致性之因果一致性:节点 A 在更新完某个数据后通知了节点 B,那么节点 B 之后对该数据的访问和修改都是基于 A 更新后的值。
弱一致性之最终一致性:最弱一致性模型,不考虑所有的中间状态的影响,只保证当没有新的更新之后,经过一段时间之后,最终系统内所有副本的数据是正确的。它最大程度上保证了系统的并发能力,在高并发的场景下,它也是使用最广的一致性模型。
3.5 分布式理论:CAP定理
一个分布式系统不可能同时满足一致性(C:Consistency),可用性(A: Availability)和分区容错性(P:Partition tolerance)这三个基本需求,最多只能同时满足其中的2个。
3.6 一致性
目标:
1.商品服务写入主数据库成功, 则想从数据库查询数据也成功
2.商品服务写入主数据库失败,则向从数据库查询也失败
实现:
1.写入主数据库后要数据同步到从数据库,同步有一定延迟。
2.写入主数据库后,在向从数据库同步期间要将从数据库锁定, 等待同步完成后在释放锁,以免在写新数据后,向从数据库查询到旧的数据。
3.7 可用性
目标:
1.从数据库接收到数据库查询的请求则立即能够响应数据查询结果
2.从数据库不允许出现响应超时或错误
实现:
1.写入主数据库后要将数据同步到从数据
2.由于要保证数据库的可用性,不可以将数据库中资源锁定
3.即使数据还没有同步过来,从数据库也要返回查询数据, 哪怕是旧数据,但不能返回错误和超时.
3.8 分区容错性
目标:
1.主数据库想从数据库同步数据失败不影响写操作
2.其中一个节点挂掉不会影响另一个节点对外提供服务
实现:
1.尽量使用异步取代同步操作,如使用异步方式将数据从主数据库同步到从数据库, 这样节点之间能有效的实现松 耦合;
2.添加数据库节点,其中一个从节点挂掉,由其他从节点提供服务。
3.9 分布式理论:BASE理论
BASE:全称:Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)
对CAP中一致性和可用性权衡的结果,即无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
Basically Available(基本可用):
分布式系统在出现不可预知故障的时候,允许损失部分可用性,比如12306抢票,他给你延时查询,响应非常久,又比如双十一抢购,订单付款时内部出现某种错误,网页这边提示你数据加载失败,让你重试,即不失败也不成果,进入降级处理。
Soft state(软状态):允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本之间进行数据同步的过程中存在延迟。
Eventually consistent(最终一致性):最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
3.0 分布式理论:一致性协议2PC
两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Preparephase)、提交阶段(commit phase),2是指两个阶段,P是指准备阶段,C是指提交阶段。
准备阶段(Prepare phase):
事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。(Undo日志是记录修改前的数据,用于数据库回滚, Redo日志是记录修改后的数据,用于提交事务后写入数据文件)
提交阶段(commit phase):
如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。
缺点
同步阻塞:他需要等第一阶段所有节点全部完成之后才能执行第二阶段。
单点问题:严重依赖于事务管理协调者,一旦协调者出现问题导致整个流程无法完成。
数据不一致:第二阶段事务管理器逐个向资源节点发生提交请求,当发送到一半,事务管理器宕机了,前面的资源节点会提交,后面的回滚,导致数据不一致。而且当资源节点出现问题无法向协调者发送响应信息,事务管理者只能依赖超时机制进行事务中断。
3.11 分布式理论:一致性协议3PC
将 2PC 的提交阶段过程一分为三,形成了由 CanCommit、PreCommit和doCommit三个阶段组成的事务处理协议。
CanCommit:协调者给参与者发送事务响应等待全部回应。
PreCommit:协调者收到全部参与者响应,yes发送执行事务预提交,并反馈ACK,如果有一个参与者未反馈或者反馈no,中断事务。
doCommit:协调者收到所有参数值ACK反馈,向所有参与者发送提交指令,参与者完成之后向协调者发送ACK响应,但是有一个问题,也就是进入第三阶段,如果协调者因宕机等原因没有向参与者发送提交doCommit请求或回滚abort请求,参与者到达超时时间自动提交,也就是如果是要准备回滚的话,就出现了问题。
2PC对比3PC
1) 协调者和参与者都设置了超时机制,降低了整个事务的阻塞时间和范围,解决了之前的同步阻塞。
2) 通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较 于2PC而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。
3) 3PC协议并没有完全解决数据不一致问题。
3.12 分布式理论:一致性算法Paxos
此算法用于解决分布式系统一致性问题。
当出现多个参与者,要保证数据事务一致性,就引入了3PC进行协调,协调者也可能宕机,所以协调者也做了集群,当每个参与者发送了不同的指令给协调者,协调者就必须有一个真正的决策者来保证数据的一致性。
提案(Proposal)
提案 (Proposal):Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value),最终要达成一致的value就在提案里。
Paxos算法的角色
Client:客户端向分布式系统发出请求 ,并等待响应。
Proposer:提案发起者提倡客户请求,试图说服Acceptor对此达成一致,并在发生冲突时充当协调者以推动协议向前发展。
Acceptor:决策者可以接受(accept)提案;如果某个提案被选定(chosen),那么该提案里的value就被选定了。
Learners:最终决策学习者充当该协议的复制因素。
一致性算法的保证
1)在这些被提出的提案中,只有一个会被选定 。
2)如果没有提案被提出,就不应该有被选定的提案。
3)当一个提案被选定后,那么所有进程都应该能学习(learn)到这个被选定的value。
Paxos算法提案规则
总结:提案规则P2c =>P2b=>P2a=>P2,通过P2和P1来保证一致性,概括就是决策者必须接受收到的第一个提案,当只有一个决策者,那么第一个提案就是最终提案,当多个决策者,以半数以上决策者接收的提案为最终提案,当决策者选定了一个提案,后续提案只能增长序列编号,不能更改提案的值。
Proposer生成提案规则->Acceptor接受提案规则
Proposer生成提案之前,应该先去『学习』已经被选定或者可能被选定的value,然后以 该value作为自己提出的提案的value。如果没有value被选定,Proposer才可以自己决定value的值。
理解:提案者1先发送一个prepare给决策者,并携带一个map,这个map只有key,编号n,value是null,当决策者接受了这个提案,就把当做了最终提案保存了下来,并返回了一个空value回来,这里有一个规则,如果决策者是多个,需要超过半数返回才行,如果没有超过半数,重新提交prepare给决策者,接着提案者1再往map里面放入值,提交给决策者,决策者就把这个map替换了之前的空null的map,并返回ack,如果超过半数返回了ack,此value就被确定,否则重新提交prepare给决策者,当完成后如果又有另一个提案者2提交了提案,他的编号是n+1,决策者接收了,但是决策者已经有最终提案了,这时候他会把value返回给提案者2,让提案者2学习,把自己map集合的value值替换成决策者返回的值,提案者学习完毕,再次提交,这时候决策者就接受了提案者2的提案,把之前的提案进行了替换,而且编号低于n+1的提案会被决策者直接拒绝,这样值没变,保证了数据的一致性,还可以通过编号实现对不符合规则的提案过滤。
Learner学习被选定的value
当决策者接受了一个提案,就会把这个提案发给所有学习者,来保证数据一致性。
保证Paxos算法的活性
两个Proposer依次提出了一系列编号递增的提案,但是每次根据响应塞值提交又因为编号不一致,被另一个提案者编号给递增,导致又恢复到最开始提交prepare,最终陷入死循环,没有value被选定。
解决:通过选取主Proposer,并规定只有主Proposer才能提出议案。这样一来只要主Proposer和过半的Acceptor能够正常进行网络通信,那么只能是主Proposer提出一个编号更高的提案,该提案终将会被批准,这样通过选择一个主 Proposer,整套Paxos算法就能够保持活性。
3.13 分布式理论:一致性算法Raft
Raft算法分为两个阶段,首先是选举过程,然后在选举出来的领导人带领进行正常操作,主要用于管理复制日志的一致性算法。
Raft算法三模块:领导人选举、日志复制、安全性。
3.14 领导人Leader选举
Raft通过选举一个领导人,然后给予他全部的管理复制日志的责任来实现一致性。
三个角色(任何服务器都可以当三个角色之一):
领导者(leader):处理客户端交互,日志复制等动作,一般一次只有一个领导者
候选者(candidate):候选者就是在选举过程中提名自己的实体,一旦选举成功,则成为领导者
跟随者(follower):类似选民,完全被动的角色,这样的服务器等待被通知投票
理解:当服务启动的时候,所有服务器follower都是初始状态,每个服务器都有一个定时器,超时时间为election timeout(一般为150-300ms),当某个服务器达到超时时间,他就成为了候选者,先给自己投上一票,然后发送消息给其他服务器,当其他服务器超过半数收到了他的消息,相当于获取到了选票,他就成了领导者,而其他服务器全部成了跟随者,这时候领导者就开始根据间隔时间向跟随者发送心跳检测包,证明我还活在,也就是心跳机制,而跟随者每次接受到消息,就初始化自己内部的定时器,当某个服务器定时器达到超时时间,没有收到领导者的消息,那么跟随者会觉得领导者挂了,他就摇身一变称为候选者,开始篡位,重复之前的过程,成为领导者,当他成为领导者之后,当前任领导者就算回来了,也只能变成跟随者。
特殊情况:四个服务器,当其中两个服务器同时达到超时成为候选者,并且每个服务器拿到自己一票,另外一个服务器一票,这时候的机制就是这两个服务器重新定时,先达到超时的服务器成为候选者,并发送通知进一步成为选举者。
3.15 日志复制(保证数据一致性)
Leader选出后,就开始接收客户端的请求。Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他服务器发起 AppendEntries RPC复制日志条目。当这条日志被复制到大多数服务器上,Leader将这条 日志应用到它的状态机并向客户端返回执行结果。
1)客户端的每一个请求都包含被复制状态机执行的指令。
2)leader把这个指令作为一条新的日志条目添加到日志中,然后并行发起 RPC 给其他的服务器,让他们复制这条 信息。
3)跟随者响应ACK,如果 follower 宕机或者运行缓慢或者丢包,leader会不断的重试,直到所有的 follower 最终都 复制了所有的日志条目。
4)通知所有的Follower提交日志,同时领导人提交这条日志到自己的状态机中,并返回给客户端。
四、分布式系统设计策略
分布式常用设计策略:如何检测当前节点还活着? 如何保障高可用? 容错处理? 负载均衡?
4.1 心跳检测机制
心跳顾名思义,就是以固定的频率向其他节点汇报当前节点状态的方式。收到心跳,一般可以认为一个节点和现在的网络拓扑是良好的。心跳汇报时,一般也会携带一些附加的状态、元数据信息,以便管理。
理解:Client请求Server,Server转发请求到具体的Node获取请求结果。Server需要与三个Node节点保持心跳连接,确保Node可以正常工作,若Server没有收到Node3的心跳时,Server认为Node3失联,当Node3不一定是宕机了,可能是网络中断、任务繁忙导致检测超时等等,通过周期检测心跳机制、累计失效检测机制来判断节点是否挂掉,如果真正挂掉,从集群中移除,等恢复后再加进来。
4.2 高可用设计
系统架构设计中必须考虑的因素之一,通常是指经过设计来减少系统不能提供服务的时间。
系统高可用性的常用设计模式包括三种:主备(Master-SLave)、互备(Active-Active)和集群(Cluster)模式。
4.2.1 主备模式
最常用的模式,当主机宕机时,备机接管主机的一切工作,待主机恢复正常后,按使用者的设定以自动(热备)或手动(冷备)方式将服务切换到主机上运行,数据库称为MS模式,MySQL、Redis就采用MS模式实现主从复制,保证高可用。
master中所有操作都会以“事件”的方式记录在二进制日志中,也就是bin-log,其他数据库作为slave通过一个I/O线程与主服务器保持通信,并监控master的二进制日志文件的变化,如果发现master二进制日志文件发生变化,则会把变化复制到自己的relay-log日志中,然后slave的一个SQL线程会把相关的“事件”执行到自己的数据库中,以此实现从数据库和主数据库的一致性,也就实现了主从复制。
4.2.2 互备模式
两台主机同时运行各自的服务工作且相互监测情况,开启互相备份同步,只有对写要求较高,需要多台数据库服务器存储写入数据,比如微博之类的网站。
4.2.3 集群模式
集群模式是指有多个节点在运行,同时可以通过主控节点分担服务请求。如Zookeeper。集群模式需要解决主控节 点本身的高可用问题,一般采用主备模式来把某个节点当做master。
4.3 容错性设计
提高系统对于错误包容的能力,保障分布式环境下相应系统的高可用或者健壮性,也提升了系统的安全性。
比如Redis的缓存穿透。
当一个请求进来时,从缓存中查询不到,这时候就会进去数据库查,如果是一个恶意的请求,比如id为-1,这个值根本不存在,制造大量请求进行攻击,越过缓存,数据库服务器可能就会承受不住压力而宕机,这时候就需要一个容错性设计来保证数据库的安全,可以通过布隆过滤器或者在第一次请求,为null时仍然返回一个值存储缓存,并设置一定的过期时间,再次请求就会直接经过缓存返回,来保证系统的高可用。
4.4 负载均衡策略
使用多台集群服务器共同分担计算任务,把网络请求及计算分配到集群可用的不同服务器节 点上,从而达到高可用性及较好的用户操作体验。
负载均衡器有硬件解决方案F5,也有软件解决方案Nginx、LVS等等。
负载均衡策略:
1) 轮询:默认就是轮询,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器。
2) 最少连接:当前谁连接最少,分发给谁。
3) IP地址哈希:确定相同IP请求可以转发给同一个后端节点处理,以方便session保持。
4) 基于权重的负载均衡:配置Nginx把请求更多地分发到高配置的后端服务器上,把相对较少的请求分发到低配服务器。
五、分布式架构网络通信
5.1 基本原理
网络通信就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络IO来实现,其中传输协议比较出名的有tcp、udp等等,tcp、udp都是在基于Socket概念上为某类应用场景而扩展出的传输协议,网络IO,主要有bio、nio、aio三种方式。其实就是使用不同的传输协议和IO技术实现服务器之间的远程方法调用。
TCP:面向连接的协议,速度不快,安全,因为他要经过三次握手,安全性要求更高四次握手。
UDP:广播协议,面向无连接,速度快,不安全,就是相当于广播一样只管发出去就完事了。
BIO:阻塞IO NIO:非阻塞IO AIO:非阻塞IO
5.2 RPC基本概念
RPC远程过程调用,核心模块就是通讯和序列化,他不是具体的技术,而是指整个网络远程调用过程,常用RPC实现框架Dubbo、Hessian、HSF等等。
RPC四个核心的组件,分别是Client,Client Stub,Server以及Server Stub,即客户端、客户端存根、服务端、服务端存根。
1) 客户端以接口方式调用客户端存根。
2) 客户端存根收到调用后,把方法、参数等封装成消息体进行序列化成二进制文件,从而在网络中传输。
3) 客户端存根将请求发送给服务器存根。
4) 服务器存根收到消息后对消息体进行反向序列化。
5) 服务端存根根据解码结果调用本地服务端。
6) 服务端进行服务处理,即执行方法并返回结果。
7) 服务端存根收到结果,将结果封装成消息体,并进行序列化成二进制文件。
8) 服务端存根返回消息给客户端存根。
9) 客户端存根收到消息后对消息体进行反序列化解码。
10)客户端存根返回解码结果,客户端得到最终结果。
RPC的目标是要把2、3、4、7、8、9这些步骤都封装起来。
5.3 RMI远程方法调用
远程方法调用 (Remote Method Invocation),是java原生支持的远程调用 ,采用JRMP(Java Remote Messageing protocol)作为通信协议,纯java版本的分布式远程调用解决方案。
客户端
1)存根/桩(Stub):远程对象在客户端上的代理。
2)远程引用层(Remote Reference Layer):解析并执行远程引用协议。
3)传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。
服务端
1) 骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法,并接收方法执行后的返回值。
2) 远程引用层(Remote Reference Layer):处理远程引用后向骨架发送远程方法调用。
3) 传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。
注册表
URL形式注册远程对象,并向客户端回复对远程对象的引用。
运行过程:首先启动server服务端,向注册表发布对象,再启动客户端,客户端就从注册表获取远程对象引用,接着客户端生成对应的代理对象,也就是Stub桩对象,他和远程对象具有相同的接口和方法列表,接着通过远程引用层Remote Reference Layer进行转化成远程引用对象,传递给传输层Transport,由传输层发送TCP协议到服务端的传输层Transport,接着服务端的传输层调用远程引用层Remote Reference Layer,把远程引用对象转化成服务端本地对象,然后传递给骨架Skeleton,骨架根据请求去调用服务端进行对应方法执行,并获取返回结果,接着骨架Skeleton又一层一层往回返,最终客户端获取结果。
5.4 同步、异步、阻塞、非阻塞
同步:用户进程触发IO操作等待或者轮训的方式查看IO操作是否就绪。
异步:当一个异步进程调用发出之后,调用者不会立刻得到结果。而是在调用发出之后,被调用者通过状态、通知来通知调用者,或者通过回调函数来处理这个调用。
阻塞:当一个线程需要获取一把锁,一直等待这个锁释放。
非阻塞:当一个线程需要获取一把锁,并不会一直等待,他跑去做其他事,等通知者告知他锁被释放,他在回来获取锁接着干事。
5.5 BIO
同步阻塞IO,B代表blocking,jdk1.4之前唯一IO模型。
一个连接一个线程,即客户端有连接请求时服务器端就启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池改善,但是同样的无法避免大量线程的创建,并发请求效率低。
5.6 NIO
同步非阻塞IO,JDK 1.4 及以上版本。
一个请求一个通道,即客户端发送的连接请求都会注册到多路复用器上,多路复用器(也称为选择器)轮询到连接有IO请求时才启动一个线程进行处理。
通道(Channels)
NIO 新引入的最重要的抽象是通道的概念。Channel数据连接的通道。 数据可以从Channel读到Buffer,也可以从buffer写到Channel中。
缓冲区(Buffer)
就是存数据的地方,通过缓冲区提高读写效率,通道channel可以向缓冲区Buffer中写数据,也可以向buffer中存数据。
选择器(Selector)
使用选择器,借助单一线程,就可对数量庞大的活动 I/O 通道实时监控和维护。
BIO模型中,一个连接来了,会创建一个线程,对应一个while死循环,死循环的目的就是不断监测这条连接上是否有数据可以读,而NIO他创建了一个多路复用器selector,连接来了之后现进多路复用器,通过检查这个selector,不需要再批量死循环,就可以批量监测出有数据可读的连接,进而读取数据。
5.7 AIO
异步非阻塞IO,JDK7开始支持。
当有流可以读时,操作系统会将可以读的流传入read方法的缓冲区,并通知应用程序,对于写操作,OS将write方法的流写入完毕,操作系统会主动通知应用程序。因此read和write都是异步的,完成后调用回调函数通知。
5.8 Netty
Netty 是由 JBOSS 提供一个异步的、 基于事件驱动的网络编程框架。
NIO缺点
1)NIO 的类库和 API 繁杂,使用麻烦。
2)可靠性不强,开发工作量和难度都非常大。
3)NIO 的 Bug。例如 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100%。
Netty优点
1)对各种传输协议提供统一的API 。
2)高度可定制的线程模型——单线程模型、一个或多个线程池模型。
3)更好的吞吐量,更低的等待延迟 。
4)更少的资源消耗 。
5)最小化不必要的内存拷贝。
netty模型
Netty 抽象出两组线程池, BossGroup 专门负责接收客 户端连接, WorkerGroup 专门负责网络读写操作。 NioEventLoop 表示一个不断循环执行处理 任务的线程, 每个 NioEventLoop 都有一个 selector, 用于监听绑定在其 上的 socket 网络通道。 NioEventLoop 内部采用串行化设计, 从消息的读取->解码->处理->编码->发送, 始终由 IO 线 程 NioEventLoop 负责。
Netty核心组件
ChannelHandler 接口及其实现类,相当于之前NIO里面的accept、read、write方法。
ChannelPipeline 是一个Handler的集合,它负责处理和拦截 inbound 或者 outbound 的事件和操作,相当于一个 贯穿 Netty 的链。
ChannelHandlerContext这是事件处理器上下文对象,Pipeline链中的实际处理节点。每个处理节点ChannelHandlerContext中包含一个 具 体 的 事 件 处 理 器 ChannelHandler , 同 时 ChannelHandlerContext 中也绑定了对应的 pipeline 和 Channel 的信息,方便对 ChannelHandler 进行调用。
ChannelFuture 核心,表示Channel 中异步 I/O 操作的结果,在 Netty 中所有的 I/O 操作都是异步的, I/O 的调用会直接返回,调用者并不能立刻获得结果,但是可以通过 ChannelFuture 来获取 I/O 操作的处理状态,结果要等执行完毕后获取。
EventLoopGroup 和其实现类 NioEventLoopGroup,EventLoopGroup(最上面模型中的Boss Group) 是一组 EventLoop(可以理解成一个线程,最上面模型中的NIOEventLoop) 的抽象, Netty 为了更好的利用多核 CPU 资源, 一般会有多个 EventLoop 同时工作,每个EventLoop 维护着一个Selector实例,线程池一般是两个,一次处理连接,一次进行操作。
ServerBootstrap 和 Bootstrap ServerBootstrap 是 Netty 中的服务器端启动助手,通过它可以完成服务器端的各种配置;Bootstrap是Netty 中的客户端启动助手,通过它可以完成客户端的各种配置。
5.9 基于Netty自定义RPC
两种常用远程调用
1)是基于HTTP的restful形式的广义远程调用,以spring could的feign和restTemplate为代表,采用的协议是HTTP的7层 调用协议,并且协议的参数和响应序列化基本以JSON格式和XML格式为主。
2)是基于TCP的狭义的RPC远程调用,以阿里的Dubbo为代表,主要通过netty来实现4层网络协议,NIO来异步传输, 序列化也可以是JSON或者hessian2以及java自带的序列化等,可以配置。
运转实现图
服务端
1) 通过main方法启动服务器,设定ip和端口,调用实现类的startServer方法。
2) 在startServer方法创建启动引导类并监听要做的事,通过自定义UserServiceHandler来实现自定义逻辑的监听来并加到启动引导类的通道中。
3) 当有读操作出现,就会进入自定义处理器,执行相应逻辑并返回结果,最后把结果写回客户端。
客户端
1) 通过main方法启动服务器,首先调用createProxy,传递接口类和参数,进行代理对象的构造。
2) 当代理对象创建之后,调用代理对象对应的方法时,就会进去JDK动态代理的invoke拦截方法内部进行客户端初始化。
3) 初始完毕之后,开始设置参数,即最开始定义参数拼接方法传递参数
4) 当参数也设置完毕之后就可以通过线程池对call方法进行调度,进行写操作,写完阻塞,等待服务器返回数据之后唤醒继续写,这是通过互斥锁来实现读写交替。
5) 最后返回结果给客户端。