目录
3.1、当W是2、R是2的时候,W+R>N,这种情况对于客户端就是强一致性的
一、分布式架构介绍
1、什么是分布式系统
分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。通俗的理解,所谓分布式系统,就是一个业务拆分成多个子业务,分布在不同的服务器节点,共同构成的系统称为分布式系统,同一个分布式系统中的服务器节点在空间部署上是可以随意分布的,这些服务器可能放在不同的机柜中,也可能在不同的机房中,甚至分布在不同的城市。
2、分布式与集群的区别
集群: 多个服务器做同一个事情。
分布式: 多个服务器做不同的事情。
3、分布式系统特性
- 分布性:空间中随机分布。这些计算机可以分布在不同的机房,不同的城市,甚至不同的国家。
- 对等性:分布式系统中的计算机没有主/从之分,组成分布式系统的所有节点都是对等的。
- 并发性:同一个分布式系统的多个节点,可能会并发地操作一些共享的资源,诸如数据库或分布式存储。
- 缺乏全局时钟:既然各个计算机之间是依赖于交换信息来进行相互通信,很难定义两件事件的先后顺序,缺乏全局时钟控制序列。
- 故障总会发生:组成分布式的计算机,都有可能在某一时刻突然间崩掉。分的计算机越多,可能崩掉一个的几率就越大。如果再考虑到设计程序时的异常故障,也会加大故障的概率。
- 处理单点故障:单点SPoF(Single Point of Failure),某个角色或者功能只有某一台计算机在支撑,在这台计算机上出现的故障是单点故障。
4、分布式系统面临的问题
4.1、通信异常
网络本身的不可靠性,因此每次网络通信都会伴随着网络不可用的风险(光纤、路由、DNS等硬件设备或系统的不可用),都会导致最终分布式系统无法顺利进行一次网络通信,另外,即使分布式系统各节点之间的网络通信能够正常执行,其延时也会大于单机操作,存在巨大的延时差别,也会影响消息的收发过程,因此消息丢失和消息延迟变的非常普遍。
4.2、网络分区
网络之间出现了网络不连通,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成了若干个孤立的区域,分布式系统就会出现局部小集群,在极端情况下,这些小集群会独立完成原本需要整个分布式系统才能完成的功能,包括数据的事务处理,这就对分布式一致性提出非常大的挑战。
4.3、节点故障
节点故障是分布式系统下另一个比较常见的问题,指的是组成分布式系统的服务器节点出现的宕机或"僵死"现象,根据经验来说,每个节点都有可能出现故障,并且经常发生。
4.4、三态
分布式系统每一次请求与响应存在特有的“三态”概念,即成功、失败和超时。
4.5、重发
分布式系统在发生调用的时候可能会出现失败、超时的情况,这个时候需要重新发起调用。
4.6、幂等
(1)场景一
(2)场景二
(3)场景三
二、分布式理论
1、数据一致性
1.1、什么是分布式数据一致性
分布式数据一致性,指的是数据在多份副本中存储时,各副本中的数据是一致的。
1.2、副本一致性
分布式系统当中,数据往往会有多个副本。多个副本就需要保证数据的一致性。这就带来了同步的问题,因为网络延迟等因素,我们几乎没有办法保证可以同时更新所有机器当中的包括备份所有数据。就会有数据不一致的情况。
总得来说,我们无法找到一种能够完全满足分布式系统中数据一致性解决方案。因此,如何既保证数据的一致性,同时又不影响系统运行的性能,是每一个分布式系统都需要重点考虑和权衡的。于是,一致性级别由此诞生。
2、一致性分类
2.1、强一致性
这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大。但是强一致性很难实现。
2.2、弱一致性
这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。
2.3、最终一致性
最终一致性也是弱一致性的一种,它无法保证数据更新后,所有后续的访问都能看到最新数值,而是需要一个时间,在这个时间之后可以保证这一点(就是在一段时间后,节点间的数据会最终达到一致状态),而在这个时间内,数据也许是不一致的,这个系统无法保证强一致性的时间片段被称为「不一致窗口」。不一致窗口的时间长短取决于很多因素,比如备份数据的个数、网络传输延迟速度、系统负载等。
3、CAP定理
CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
一致性 | 所有节点访问时都是同一份最新的数据副本 |
可用性 | 每次请求都能获取到非错的响应,但是不保证获取的数据为最新数据 |
分区容错性 | 分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障 |
3.1、一致性
这里指的是强一致性。在写操作完成后开始的任何读操作都必须返回该值,或者后续写操作的结果。也就是说,在一致性系统中,一旦客户端将值写入任何一台服务器并获得响应,那么之后client从其他任何服务器读取的都是刚写入的数据。
- 客户端向G1写入数据v1,并等待响应
- 此时,G1服务器的数据为v1,而G2服务器的数据为v0,两者不一致
- 接着,在返回响应给客户端之前,G2服务器会自动同步G1服务器的数据,使得G2服务器的数据也是v1
- 一致性保证了不管向哪台服务器(比如这边向G1)写入数据,其他的服务器(G2)能实时同步数据
- G2已经同步了G1的数据,会告诉G1,我已经同步了
- G1接收了所有同步服务器的已同步的报告,才将“写入成功”信息响应给client
- client再发起请求,读取G2的数据
- 此时得到的响应是v1,即使client读取数据到G2
3.2、可用性
系统中非故障节点收到的每个请求都必须有响应。在可用系统中,如果我们的客户端向服务器发送请求,并且服务器未崩溃,则服务器必须最终响应客户端,不允许服务器忽略客户的请求。
3.3、分区容错性
允许网络丢失从一个节点发送到另一个节点的任意多条消息,即不同步。也就是说,G1和G2发送给对方的任何消息都是可以放弃的,也就是说G1和G2可能因为各种意外情况,导致无法成功进行同步,分布式系统要能容忍这种情况。
3.4、CAP三者不能同时满足论
(1)CA(一致性和可用性)
关注一致性和可用性。它需要非常严格的全体一致的协议。CA系统不能容忍网络错误或节点错误,一旦出现这样的问题,整个系统就会拒绝写请求,因为它并不知道对面的那个结点是否挂掉了,还是只是网络问题。唯一安全的做法就是把自己变成只读的。
(2)CP(一致性和分区容错性)
关注一致性和分区容忍性。它关注的是系统里大多数人的一致性协议。这样的系统只需要保证大多数结点数据一致,而少数的结点会在没有同步到最新版本的数据时变成不可用的状态。这样能够提供一部分的可用性。
(3)AP(可用性和分区容错性)
这样的系统关心可用性和分区容忍性。因此,这样的系统不能达成一致性,需要给出数据冲突,给出数据冲突就需要维护数据版本。
3.5、如何进行三选二
放弃了一致性,满足分区容错,那么节点之间就有可能失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会容易导致全局数据不一致性。对于互联网应用来说,机器数量庞大,节点分散,网络故障再正常不过了,那么此时就是保障AP,放弃C的场景,而从实际中理解,像网站这种偶尔没有一致性是能接受的,但不能访问问题就非常大了。
对于银行来说,就是必须保证强一致性,也就是说C必须存在,那么就只用CA和CP两种情况,当保障强一致性和可用性(CA),那么一旦出现通信故障,系统将完全不可用。另一方面,如果保障了强一致性和分区容错(CP),那么就具备了部分可用性。实际究竟应该选择什么,是需要通过业务场景进行权衡的(并不是所有情况都是CP好于CA,只能查看信息但不能更新信息有时候还不如直接拒绝服务)。
4、BASE理论
上面我们讲到CAP不可能同时满足,而分区容错性是对于分布式系统而言,是必须的。最后,我们说,如果系统能够同时实现CAP是再好不过的了,所以出现了BASE理论,BASE:全称:Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)三个短语的缩写,Base理论是对CAP中一致性和可用性权衡的结果,其来源于对大型互联网分布式实践的总结,是基于CAP定理逐步演化而来的。其核心思想是:既是无法做到强一致性,但是每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
4.1、基本可用
什么是基本可用呢?假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
- 响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在1秒返回结果;
- 功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单,但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面;
4.2、软状态
什么是软状态呢?相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种 “硬状态”。软状态指的是:允许系统中的数据存在中间状态,并认为该状态不会影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
4.3、最终一致性
上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性。从而达到数据的最终一致性。这个时间期限取决于网络延时,系统负载,数据复制方案设计等等因素。
三、分布式一致性协议
1、两阶段提交协议(2PC)
两阶段提交协议,简称2PC(2 Prepare Commit),是比较常用的解决分布式事务问题的方式,要么所有参与进程都提交事务,要么都取消事务,即实现ACID中的原子性(A)的常用手段。
分布式事务:事务提供一种操作本地数据库的不可分割的一系列操作“要么什么都不做,要么做全套(All or Nothing)”的机制,而分布式事务就是为了操作不同数据库的不可分割的一系列操作“要么什么都不做,要么做全套(All or Nothing)”的机制。
- 优点:原理简单
- 缺点:
- 同步阻塞:所有参与者的事务操作逻辑都处于阻塞状态,当参与者占有公共资源时,其它节点访问公共资源会处于阻塞状态;
- 单点问题:如果协调器出现问题,那么二阶段提交就无法正常运转,参与者会一直处于事务锁定状态,无法继续完成操作;
- 数据不一致:当执行事务提交的时候,协调者向所有参与者发送commit之后,发生了局部网络异常或者协调者没能发送完commit命令,会导致只有部分参与者收到了命令并提交了事务,导致数据不一致;
- 太过保守:在进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应信息的话,此时协调者只能依靠自身的超时机制来判断是否需要中断事务,这样的策略过于保守,即没有完善的容错机制,任意一个结点的失败都会导致整个事务的失败。
2、三阶段提交协议(3PC)
三阶段提交协议出现背景:一致性协议中设计出了二阶段提交协议(2PC),但是2PC设计中还存在缺陷,于是就有了三阶段提交协议,这便是3PC的诞生背景。
三阶段提交升级点(基于二阶段):
- 三阶段提交协议引入了超时机制。
- 在第一阶段和第二阶段中,引入了一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
简单讲:就是除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
3、NWR协议
NWR是一种在分布式存储系统中用于控制一致性级别的一种策略。在亚马逊的云存储系统中,就应用NWR来控制一致性。
- N:在分布式存储系统中,有多少份备份数据
- W:代表一次成功的更新操作要求至少有w份数据写入成功
- R:代表一次成功的读数据操作要求至少有R份数据成功读取
NWR值的不同组合会产生不同的一致性效果,当W+R>N的时候,整个系统对于客户端来讲能保证强一致性。
以常见的N=3、W=2、R=2为例:
- N=3,表示任何一个对象都必须有三个副本
- W=2表示,对数据的修改操作只需要在3个副本中的2个上面完成就返回
- R=2表示,从三个对象中要读取到2个数据对象,才能返回
3.1、当W是2、R是2的时候,W+R>N,这种情况对于客户端就是强一致性的
在上图中,如果R+W>N,则读取操作和写入操作成功的数据一定会有交集(如图中的 Node2),这样就可以保证一定能够读取到最新版本的更新数据,数据的强一致性得到了保证。在满足数据一致性协议的前提下,R或者W设置的越大,则系统延迟越大,因为这取决于最慢的那份备份数据的响应时间。
3.2、当R+W<=N,无法保证数据的强一致性
因为成功写和成功读集合可能不存在交集,这样读操作无法读取到最新的更新数值,也就无法保证数据的强一致性。
4、Paxos协议
Paxos协议其实说的就是Paxos算法,Paxos算法是基于消息传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。
自Paxos问世以来就持续垄断了分布式一致性算法,Paxos这个名词几乎等同于分布式一致性。 Google的很多大型分布式系统都采用了Paxos算法来解决分布式一致性问题,如Chubby、Megastore 以及Spanne等。开源的ZooKeeper,以及MySQL 5.7推出的用来取代传统的主从复制的MySQL Group Replication等纷纷采用Paxos算法解决分布式一致性问题。然而,Paxos的最大特点就是难,不仅难以理解,更难以实现。
在常见的分布式系统中,总会发生诸如机器宕机或网络异常(包括消息的延迟、丢失、重复、乱序,还有网络分区)等情况。Paxos算法需要解决的问题就是如何在一个可能发生上述异常的分布式系统中,快速且正确地在集群内部对某个数据的值达成一致,并且保证不论发生以上任何异常,都不会破坏整个系统的一致性。
Paxos的版本有:Basic Paxos , Multi Paxos, Fast-Paxos, 具体落地有Raft 和zk的ZAB协议。
4.1、Raft
Paxos是论证了一致性协议的可行性,但是论证的过程据说晦涩难懂,缺少必要的实现细节,而且工程实现难度比较高, 广为人知实现只有zk的实现zab协议。Paxos协议的出现为分布式强一致性提供了很好的理论基础,但是Paxos协议理解起来较为困难,实现比较复杂。然后斯坦福大学RamCloud项目中提出了易实现,易理解的分布式一致性复制协议Raft。Java, C++,Go 等都有其对应的实现之后出现的Raft相对要简洁很多。引入主节点,通过竞选确定主节点。节点类型:Follower、Candidate 和 Leader。
Leader会周期性的发送心跳包给Follower,每个Follower都设置了一个随机的竞选超时时间,一般为150ms~300ms,如果在这个时间内没有收到Leader的心跳包,就会变成Candidate,进入竞选阶段,通过竞选阶段的投票多的人成为Leader。
(1)相关概念
- 节点状态
- Leader(主节点):接受client更新请求,写入本地后,然后同步到其他副本中
- Follower(从节点):从Leader中接受更新请求,然后写入本地日志文件。对客户端提供读请求
- Candidate(候选节点):如果Follower在一段时间内未收到Leader心跳。则判断Leader可能故障,发起选主提议。节点状态从 Follower 变为 Candidate 状态,直到选主结束。
- termId:任期号,时间被划分成一个个任期,每次选举后都会产生一个新的termId,一个任期内只有一个Leader。
- RequestVote:请求投票,candidate 在选举过程中发起,收到多数派响应后,成为Leader。
4.2、ZAB
5、Lease机制
Lease机制,翻译过来即是租约机制,是一种在分布式系统常用的协议,是维护分布式系统数据一致性的一种常用工具。
Lease机制有以下几个特点:
- Lease是颁发者对一段时间内数据一致性的承诺;
- 颁发者发出Lease后,不管是否被接收,只要Lease不过期,颁发者都会按照协议遵守承诺;
- Lease的持有者只能在Lease的有效期内使用承诺,一旦Lease超时,持有者需要放弃执行,重新申请Lease。
5.1、解决了什么问题?
分布式系统中,如何确认一个节点是否工作正常?如果有5副本1-5。其中1号为主副本。
在分布式中最直观的处理方法是在每个副本与主副本维护一个心跳,期望通过心跳是否存在而判断对方是否依旧存活。心跳方法其实根本无法解决分布式下节点是否正常的这个的这个问题。考虑如下场景:在某个时刻Node1主节点突然出现网络抖动或者网络中断情况(注意:不是宕机),导致从节点无法接受到心跳。
会在剩下的副节点中选取一当主节点。
Lease的原理:
1、引入中心节点负责下发Lease
2、出现网络问题
在01:05期间如果出现网络抖动导致其他节点申请Lease会申请失败, 因为中心节点在01:10之前都会承认有主节点,不允许其他节点在申请Lease。
3、如果网络恢复
4、如果到01:10时间,主节点会进行续约操作,然后在下发新的Lease
- 主节点宕机:lease机制天生即可容忍网络、lease接收方的出错,时间即Lease剩余过期时长
- 中心节点异常:颁发者宕机可能使得全部节点没有lease,系统处于不可用状态,解决的方法就是使用一个小集群而不是单一节点作为颁发者。
- 时差问题:中心节点与主节点之间的时钟可能也存在误差,只需要中心节点考虑时钟误差即可。
lease时间长短一般取经验值1-10秒即可。太短网络压力大,太长则收回承诺时间过长影响可用性。
5.2、应用
- GFS(Google 文件系统)中,Master通过lease机制决定哪个是主副本,lease在给各节点的心跳响应消息中携带。收不到心跳时,则等待lease过期,再颁发给其他节点。
- chubby中,paxos选主后,从节点会给主颁发lease,在期限内不选其他节点为主。另一方面,主节点给每个client节点发送lease,用于判断client死活。
四、分布式系统设计策略
在分布式环境下,有几个问题是普遍关心的:
- 如何检测当前节点还活着?
- 如何保障高可用?
- 容错处理
- 负载均衡
1、心跳检测
在分布式环境中,我们提及过存在非常多的节点(Node)。那么就有一个非常重要的问题,如何检测一个节点出现了故障乃至无法工作了?通常解决这一问题是采用心跳检测的手段,如同通过仪器对病人进行一些检测诊断一样。
心跳顾名思义,就是以固定的频率向其他节点汇报当前节点状态的方式。收到心跳,一般可以认为一个节点和现在的网络是良好的。当然,心跳汇报时,一般也会携带一些附加的状态、元数据信息,以便管理。
若Server没有收到Node3的心跳时,Server认为Node3失联。但是失联是失去联系,并不确定是否是Node3故障,有可能是Node3处于繁忙状态,导致调用检测超时;也有可能是Server与Node3之间链路出现故障或闪断。所以心跳不是万能的,收到心跳可以确认节点正常,但是收不到心跳也不能认为该节点就已经宣告“死亡”。此时,可以通过一些方法帮助Server做决定:周期检测心跳机制、累计失效检测机制。
2、高可用
高可用(High Availability)是系统架构设计中必须考虑的因素之一,通常是指:经过设计来减少系统不能提供服务的时间。
系统高可用性的常用设计模式包括三种:主备(Master-SLave)、互备(Active-Active)和集群(Cluster)模式。
2.1、主备模式
主备模式就是Active-Standby模式,当主机宕机时,备机接管主机的一切工作,待主机恢复正常后,按使用者的设定以自动(热备)或手动(冷备)方式将服务切换到主机上运行。在数据库部分,习惯称之为MS模式。MS模式即Master/Slave模式,这在数据库高可用性方案中比较常用,如MySQL、Redis等就采用MS模式实现主从复制,保证高可用,如图所示。
2.2、互备模式
互备模式指两台主机同时运行各自的服务工作且相互监测情况。在数据库高可用部分,常见的互备是MM模式。MM模式即Multi-Master模式,指一个系统存在多个master,每个master都具有 read-write 能力,会根据时间戳或业务逻辑合并版本。
2.3、集群模式
集群模式是指有多个节点在运行,同时可以通过主控节点分担服务请求。集群模式需要解决主控节点本身的高可用问题,一般采用主备模式。
2.4、高可用下的“脑裂问题”
(1)什么是脑裂
在高可用(HA)系统中,当联系两个节点的"心跳线"断开时(即两个节点断开联系时),本来为一个整体、动作协调的HA系统,就分裂成为两个独立的节点(即两个独立的个体)。由于相互失去了联系,都以为是对方出了故障,两个节点上的HA软件像"裂脑人"一样,"本能"地争抢"共享资源"、争起"应用服务"。就会发生严重后果:
- 共享资源被瓜分、两边"服务"都起不来了;
- 两边"服务"都起来了,但同时读写"共享存储",导致数据损坏(常见如数据库轮询着的联机日志出错)。
(2)出现的原因
一般来说,裂脑的发生,有以下几种原因:
- 高可用服务器各节点之间心跳线链路发生故障,导致无法正常通信。
- 因网卡及相关驱动坏了,ip配置及冲突问题(网卡直连)。
- 因心跳线间连接的设备故障(网卡及交换机)。
- 因仲裁的机器出问题(采用仲裁的方案)。
- 高可用服务器上开启了iptables防火墙阻挡了心跳消息传输。
- 高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败。
- 其他服务配置不当等原因,如心跳方式不同,心跳广插冲突、软件Bug等。
(3)脑裂预防方案
- 添加冗余的心跳线 [即冗余通信的方法]:同时用两条心跳线路 (即心跳线也HA),这样一条线路坏了,另一个还是好的,依然能传送心 跳消息,尽量减少"脑裂"现象的发生几率;
- 仲裁机制:当两个节点出现分歧时,由第3方的仲裁者决定听谁的。这个仲裁者,可能是一个锁服务,一 个共享盘或者其它什么东西;
- Lease机制
- 隔离(Fencing)机制:
- 共享存储fencing:确保只有一个Master往共享存储中写数据。
- 客户端fencing:确保只有一个Master可以响应客户端的请求。
- Slave fencing:确保只有一个Master可以向Slave下发命令。
3、容错性
容错顾名思义就是IT系统对于错误包容的能力。容错的处理是保障分布式环境下相应系统的高可用或者健壮性,一个典型的案例就是对于缓存穿透问题的解决方案。
我们来具体看一下这个例子,问题描述:
我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回。这个时候如果我们查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了意义,在流量大时,或者有人恶意攻击,如频繁发起为id为“-1”的条件进行查询,可能DB就挂掉了。
那这种问题有什么好办法解决呢?
- 临时存放null值
- 使用布隆过滤器
布隆过滤器
布隆过滤器的巨大用处就是,能够迅速判断一个元素是否在一个集合中。因此他有如下三个使用场景:
- 网页爬虫对URL的去重,避免爬取相同的URL地址
- 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱(同理,垃圾短信)
- 缓存穿透,将所有可能存在的数据缓存放到布隆过滤器中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。
接下来我们来谈谈布隆过滤器的原理:其内部维护一个全为0的bit数组,需要说明的是,布隆过滤器有一个误判率的概念,误判率越低,则数组越长,所占空间越大。误判率越高则数组越小,所占的空间越小。
布隆过滤器其中重要的实现就是位图的实现,也就是位数组,并且在这个数组中每一个位置只有0和1两种状态,每个位置只占用1个字节,其中0表示没有元素存在,1表示有元素存在。如下图所示就是一个简单的布隆过滤器示例(一个key值经过哈希运算和位运算就可以得出应该落在哪个位置):
哈希碰撞:
上面我们发现,lonely和wolf落在了同一个位置,这种不同的key值经过哈希运算后得到相同值的现象就称之为哈希碰撞。发生哈希碰撞之后再经过位运算,那么最后肯定会落在同一个位置。
如果发生过多的哈希碰撞,就会影响到判断的准确性,所以为了减少哈希碰撞,我们一般会综合考虑以下2个因素:
- 1、增大位图数组的大小(位图数组越大,占用的内存越大)。
- 2、增加哈希函数的次数(同一个key值经过1个函数相等了,那么经过2个或者更多个哈希函数的计算,都得到相等结果的概率就自然会降低了)。
布谷鸟过滤器
Java的使用:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>22.0</version>
</dependency>
</dependencies>
public class Test {
private static int size = 1000000;
private static BloomFilter<Integer> bloomFilter =BloomFilter.create(Funnels.integerFunnel(), size);
public static void main(String[] args) {
for (int i = 0; i < size; i++) {
bloomFilter.put(i);
}
List<Integer> list = new ArrayList<Integer>(1000);
// 故意取10000个不在过滤器里的值,看看有多少个会被认为在过滤器里
for (int i = size + 10000; i < size + 20000; i++) {
if (bloomFilter.mightContain(i)) {
list.add(i);
}
}
System.out.println("误判的数量:" + list.size());
}
}
使用布隆过滤器解决redis缓存穿透(伪代码):
String get(String key) {
String value = redis.get(key);
if (value == null) {
if(!bloomfilter.mightContain(key)){
return null;
}else{
value = db.get(key);
if(value == null){
bloomfilter.put(key);
}else{
redis.set(key, value);
}
}
}
return value;
}
4、负载均衡
负载均衡:其关键在于使用多台集群服务器共同分担计算任务,把网络请求及计算分配到集群可用的不同服务器节点上,从而达到高可用性及较好的用户操作体验。 如图,不同的用户client1、client2、client3访问应用,通过负载均衡器分配到不同的节点。
负载均衡器有硬件解决方案,也有软件解决方案。硬件解决方案有著名的F5,软件有LVS、HAProxy、Nginx等。 以Nginx为例,负载均衡有以下6种策略:
五、分布式架构服务调用
1、服务调用
和传统的单体架构相比,分布式多了一个远程服务之间的通信,不管是SOA还是微服务,他们本质上都是对于业务服务的提炼和复用。那么远程服务之间的调用才是实现分布式的关键因素。
2、实现方式
2.1、HTTP协议通信框架
(1)HttpURLConnection
java原生HttpURLConnection是基于http协议的,支持get,post,put,delete等各种请求方式,最常用的就是get和post。
(2)Apache Common HttpClient
HttpClient 是Apache Common下的子项目,可以用来提供高效的、最新的、功能丰富的支持。HTTP 协议的客户端编程工具包,并且它支持 HTTP协议最新的版本。
- 实现了所有 HTTP 的方法(GET,POST,PUT,HEAD等)
- 支持 HTTPS 协议
- 支持代理服务器等
(3)OKhttp3
OKHttp是一个当前主流的网络请求的开源框架, 用于替代HttpUrlConnection和Apache HttpClient:
- 支持http2.0,对一台机器的请求共享一个socket。
- 采用连接池技术,可以有效的减少Http连接数量。
- 无缝集成GZIP压缩技术。
- 支持Response Cache,避免重复请求域名多IP支持。
(4)RestTemplate
Spring RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率,所以很多客户端比如Android或者第三方服务商都是使用RestTemplate请求restful服务。
- 面向 URL 组件,必须依赖于主机 + 端口 + URI
- RestTemplate 不依赖于服务接口,仅关注 REST
- 相应内容 Spring Cloud Feign
2.2、RPC框架
RPC全称为remote procedure call,即远程过程调用。借助RPC可以做到像本地调用一样调用远程服务,是一种进程间的通信方式。常见的RPC框架有一下几种:
(1)Java RMI
Java RMI(Romote Method Invocation)是一种基于Java的远程方法调用技术,是Java特有的一种RPC实现。
(2)Hessian
Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。
(3)Dubbo
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成。Dubbo是一款高性能、轻量级的开源Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
(4)gRCP
gRPC是由Google公司开源的一款高性能的远程过程调用(RPC)框架,可以在任何环境下运行。该框架提供了负载均衡,跟踪,智能监控,身份验证等功能,可以实现系统间的高效连接。
3、跨域调用
3.1、什么是跨域
在分布式系统中,会有调用其他业务系统,导致出现跨域问题,跨域实质上是浏览器的一种保护处理。如果产生了跨域,服务器在返回结果时就会被浏览器拦截(注意:此时请求是可以正常发起的,只是浏览器对其进行了拦截),导致响应的内容不可用,产生跨域的几种情况有一下:
3.2、解决方案
(1)jsonp
缺点:不支持post,而且代码编写复杂。
(2)httpClient
使用httpClient内部转发
(3)设置响应头允许跨域
response.setHeader(“Access-Control-Allow-Origin”, “*”); 设置响应头允许跨域。
(4)网关
- 基于Nginx搭建企业级API网关接口
- 基于zuul搭建企业级API网关接口。 Zuul是spring cloud中的微服务网关。
- 网关:是一个网络整体系统中的前置门户入口。请求首先通过网关,进行路径的路由,定位到具体的服务节点上。可以使用zuul的过滤器的请求转发去解决跨域问题。
- 基于Gateway搭建API网关接口。
六、分布式服务治理
1、服务协调
分布式协调技术主要用来解决分布式环境当中多个进程之间的同步控制,让他们有序的去访问某种临界资源,防止造成"脏数据"的后果。
分布式锁也就是我们分布式协调技术实现的核心内容
分布式锁的实现方式:
- 基于缓存(redis等)实现锁:
- 获取锁的时候使用setnx加锁,并使用expire命令为锁添加一个失效时间,超过该时间自动释放锁,锁的value是一个随机值,释放锁的时候进行判断(防止锁被其它线程释放);
- 获取锁的时候,还需要设置一个获取的超时时间,超过则放弃获取锁;
- zookeeper它内部是一个分层的文件系统目录树结构,规定同一个目录下面只能有一个唯一文件名,基于zk实现分布式锁的步骤:
- 创建一个目录mylock
- 线程a想要获取锁,就在该目录下创建临时顺序节点
- 获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁
- 线程b获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点
- 线程a处理完,删除自己的节点,线程b监听到变更事件,判断自己是不是最小节点,如果是则获得锁。
2、服务削峰
2.1、为什么要削峰?
主要是还是来自于互联网的业务场景,例如,春节火车票抢购,大量的用户需要同一时间去抢购;以及大家熟知的阿里双11秒杀, 短时间上亿的用户涌入,瞬间流量巨大(高并发)。
2.2、削峰方案
削峰从本质上来说就是更多地延缓用户请求,以及层层过滤用户的访问需求,遵从“最后落地到数据库的请求数要尽量少”的原则。
(1)消息队列削峰
要对流量进行削峰,最容易想到的解决方案就是用消息队列来缓冲瞬时流量,把同步的直接调用转换成异步的间接推送,中间通过一个队列在一端承接瞬时的流量洪峰,在另一端平滑地将消息推送出去。
消息队列中间件主要解决应用耦合,异步消息,流量削锋等问题。常用消息队列系统:目前在生产环境,使用较多的消息队列有ActiveMQ、RabbitMQ、 ZeroMQ、Kafka、RocketMQ 等。在这里,消息队列就像“水库”一样,拦截上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。
(2)流量削峰漏斗(层层削峰)
分层过滤其实就是采用“漏斗”式设计来处理请求的,这样就像漏斗一样,尽量把数据量和请求量一层一层地过滤和减少了。如下图所示:
- 分层过滤的核心思想:
- 通过在不同层次尽可能的过滤掉无效请求;
- 通过CDN过滤掉大量的图片,静态资源的请求;
- 再通过类似redis这样的分布式缓存过滤请求。
- 分层过滤的基本原则:
- 对写数据进行基于时间的合理分片,过滤掉过期的失效时间;
- 对写请求做限流保护,将超出系统承载能力的请求过滤掉;
- 涉及到的读数据不做强一致性校验,减少因为一致性校验产生的瓶颈问题;
- 对写数据进行一致性校验,只保留最后有效的数据。
3、服务降级
3.1、什么是服务降级
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心服务正常运作或高效运作。
整个架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,我们可以将一些不重要或不紧急的服务或任务进行服务的延迟使用或暂停使用。
3.2、降级策略
当触发服务降级后,新的交易再次到达时,我们该如何来处理这些请求呢?从分布式,微服务架构全局的视角来看,降级处理方案:
- 页面降级 —— 可视化界面禁用点击按钮、调整静态页面
- 延迟服务 —— 如定时任务延迟处理、消息入MQ后延迟处理
- 写降级 —— 直接禁止相关写操作的服务请求
- 读降级 —— 直接禁止相关读的服务请求
- 缓存降级 —— 使用缓存方式来降级部分读频繁的服务接口
针对后端代码层面的降级处理策略,则我们通常使用以下几种处理措施进行降级处理:
- 抛异常
- 返回NULL
- 调用Mock数据
- 调用Fallback处理逻辑
3.3、分级降级
结合服务能否降级的优先原则,并根据台风预警(都属于风暴预警)的等级进行参考设计,可将分布式服务架构的所有服务进行故障风暴等级划分为以下四种:
4、服务限流
4.1、什么是限流?
限流并非新鲜事,在生活中亦无处不在,下面例举一二:
- 博物馆:限制每天参观总人数以保护文物
- 地铁安检:有若干安检口,乘客依次排队,工作人员根据安检快慢决定是否放人进去。遇到节假日,可以增加安检口来提高处理能力,同时增加排队等待区长度。
- 水坝泄洪:水坝可以通过闸门控制泄洪速度。
以上"限流"例子,可以让服务提供者稳定的服务客户。限流的目的是通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待。
4.2、多维度限流
在请求到达目标服务接口的时候, 可以使用多维度的限流策略,这样就可以让系统平稳度过瞬间来临的并发。
4.3、限流算法
(1)计数器(固定窗口)
计数器限制每一分钟或者每一秒钟内请求不能超过一定的次数,在下一秒钟计数器清零重新计算。
存在问题:
客户端在第一分钟的59秒请求100次,在第二分钟的第1秒又请求了100次, 2秒内后端会受到200次请求的压力,形成了流量突刺。
(2)计数器(滑动窗口)
滑动窗口其实是细分后的计数器,它将每个时间窗口又细分成若干个时间片段,每过一个时间片段,整个时间窗口就会往右移动一格。
时间窗口向右滑动一格,这时这个时间窗口其实已经打满了100次,客户端将被拒绝访问,时间窗口划分的越细,滑动窗口的滚动就越平滑,限流的效果就会越精确。
(3)漏桶
漏桶算法类似一个限制出水速度的水桶,通过一个固定大小FIFO队列+定时取队列元素的方式实现,请求进入队列后会被匀速的取出处理(桶底部开口匀速出水),当队列被占满后后来的请求会直接拒绝(水倒的太快从桶中溢出来) 。
优点:是可以削峰填谷,不论请求多大多快,都只会匀速发给后端,不会出现突刺现象,保证下游服务正常运行。
缺点:就是在桶队列中的请求会排队,响应时间拉长。
(4)令牌桶
令牌桶算法是以一个恒定的速度往桶里放置令牌(如果桶里的令牌满了就废弃),每进来一个请求去桶里找令牌,有的话就拿走令牌继续处理,没有就拒绝请求。
令牌桶的优点是可以应对突发流量,当桶里有令牌时请求可以快速的响应,也不会产生漏桶队列中的等待时间,缺点就是相对漏桶一定程度上减小了对下游服务的保护。
5、服务熔断
5.1、什么是熔断?
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
5.2、熔断机制
- 开启熔断:
- 在固定事件窗口内,接口调用超时比例达到一定阈值,会开启熔断。
- 进入熔断后,后续对该服务的调用不再经过网络,而是直接执行本地的默认方法,达到服务降级的效果。
- 熔断恢复:熔断不可能是永久的,当经过了规定时间后,服务将从熔断状态恢复过来,再次接受调用方的远程调用。
5.3、熔断机制的实现
(1)SpringCloud Hystrix
Spring Cloud Hystrix是基于Netflix的开源框架Hystrix实现,该框架实现了服务熔断、线程隔离等一系列服务保护功能。对于熔断机制的实现,Hystrix设计了三种状态:
- 熔断关闭状态(Closed):服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
- 熔断开启状态(Open):在固定时间内(Hystrix默认是10秒),接口调用出错比率达到一个阈值(Hystrix默认为 50%),会进入熔断开启状态。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。
- 半熔断状态(Half-Open):在进入熔断开启状态一段时间之后(Hystrix默认是5秒),熔断器会进入半熔断状态。所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态,如果成功率仍旧很低,则重新进入熔断开启状态。
(2)Sentinel
Sentinel和Hystrix的原则是一致的:当调用链路中某个资源出现不稳定,例如:表现为timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,防止避免影响到其它的资源,最终产生雪崩的效果。
Sentinel 熔断手段:
- 通过并发线程数进行限制
- 通过响应时间对资源进行降级
- 系统负载保护
6、服务链路追踪
6.1、什么是链路追踪
分布式微服务架构上通过业务来划分服务的,通过REST调用对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用会越来越复杂。
分布式链路追踪(Distributed Tracing),也叫分布式链路跟踪,分布式跟踪,分布式追踪等等。其实就是将一次分布式请求还原成调用链路。显示的在后端查看一次分布式请求的调用情况,比如各个节点上的耗时、请求具体打到了哪台机器上、每个服务节点的请求状态等等。
6.2、链路跟踪具备的功能
(1)故障快速定位
通过调用链跟踪,一次请求的逻辑轨迹可以用完整清晰的展示出来。开发中可以在业务日志中添加调用链ID,可以通过调用链结合业务日志快速定位错误信息。
(2)各个调用环节的性能分析
(3)数据分析
调用链绑定业务后查看具体每条业务数据对应的链路问题,可以得到用户的行为路径,经过了哪些服务器上的哪个服务,汇总分析应用在很多业务场景。
(4)生成服务调用拓扑图
通过可视化分布式系统的模块和他们之间的相互联系来理解系统拓扑。点击某个节点会展示这个模块的详情,比如它当前的状态和请求数量。
6.3、链路跟踪设计原则
- 设计目标
- 低侵入性,应用透明
- 低损耗
- 大范围部署,扩展性
- 埋点和生成日志
- 埋点即系统在当前节点的上下文信息,可以分为客户端埋点、服务端埋点,以及客户端和服务端双向型埋点。埋点日志通常要包含以下内容:TraceId、RPCId、调用的开始时间,调用类型,协议类型,调用方ip和端口,请求的服务名等信息
- 调用耗时,调用结果,异常信息,消息报文等
- 抓取和存储日志
- 日志的采集和存储有许多开源的工具可以选择,一般来说,会使用离线+实时的方式去存储日志,主要是分布式日志采集的方式。典型的解决方案如Flume结合Kafka。
- 分析和统计调用链数据
- 一条调用链的日志散落在调用经过的各个服务器上,首先需要按TraceId汇总日志,然后按照RpcId 对调用链进行顺序整理。调用链数据不要求百分之百准确,可以允许中间的部分日志丢失。
- 计算和展示
- 汇总得到各个应用节点的调用链日志后,可以针对性的对各个业务线进行分析。需要对具体日志进行整理,进一步储存在HBase或者关系型数据库中,可以进行可视化的查询。
6.4、链路跟踪trace模型
tarce模型,主要有以下概念:
Client && Server:对于跨服务的一次调用,请求发起方为client,服务提供方为Server各术语在一次分布式调用中,关系如下图所示:
链路跟踪系统实现:大的互联网公司都有自己的分布式跟踪系统,比如Google的Dapper,Twitter的zipkin,淘宝的鹰眼,新浪的Watchman,京东的Hydra等等。
七、架构设计的基本原则
1、开闭原则
1.1、定义
开闭原则:软件实体应当对扩展开放,对修改关闭,这就是开闭原则的经典定义。 这里的软件实体包括以下几个部分:
- 项目中划分出的模块
- 类与接口
- 方法
开闭原则的含义是:当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。
1.2、作用
开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。具体来说,其作用如下。
- 对软件测试的影响
- 可以提高代码的可复用性
- 可以提高软件的可维护性
1.3、实现方式
可以通过“抽象约束、封装变化”来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。
举例:
1、学校有许多的课程,其中有一门课程为java课程,我们需要打印出该课程的id、名称以及售价,为此新建一个接口类ICourse和实现类JavaCourse,JavaCourse实现接口ICours:
2、此时,正好赶上节日,我们有一个促销活动,JAVA课程我们打六折
- 第一种:在ICours新增打折方法getDiscountPrice,这种会将所有实现ICours接口的实现类都得做改变;
- 第二种:每次打折我们都修改JavaCourse类,这种代码显然是不合理的,这样破坏了原本稳定的代码;
- 第三种:新建一个JavaDiscountCourse类继承JavaCourse,并在JavaDiscountCourse新增加一个打折 即可。
2、单一职责原则
2.1、定义
单一职责原则又称单一功能原则,这里的职责是指类变化的原因,单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。该原则提出对象不应该承担太多职责,如果一个对象承担了太多的职责,至少存在以下两个缺点:
- 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;
- 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代
码或代码的浪费。
2.2、优点
单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点:
- 降低类的复杂度
- 提高类的可读性
- 提高系统的可维护性
- 变更引起的风险降低
2.3、实现方式
单一职责原则是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,再封装到不同的类或模块中。而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验。
下面以大学学生工作管理程序为例介绍单一职责原则的应用。
3、接口隔离原则
3.1、定义
接口隔离原则要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两
者是不同的:
- 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离;
- 单一职责原则主要是约束类,它针对的是程序中的实现和细节;
- 接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。
3.2、优点
接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下 5 个优点:
- 提高系统的灵活性和可维护性
- 降低系统的耦合性
- 保证系统的稳定性
- 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义
- 能减少项目工程中的代码冗余
3.3、实现方式
在具体应用接口隔离原则时,应该根据以下几个规则来衡量:
- 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
- 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
- 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同深入了解业务逻辑。
- 提高内聚,减少对外交互。
- 使接口用最少的方法去完成最多的事情。
4、里氏替换原则
4.1、定义
里氏替换原则主要阐述了有关继承的一些原则。里氏替换原则是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。总结:子类可以扩展父类的功能,但不能改变父类原有的功能。
4.2、作用
里氏替换原则的主要作用如下:
- 里氏替换原则是实现开闭原则的重要方式之一。
- 它克服了继承中重写父类造成的可复用性变差的缺点。
- 它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
- 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需
求变更时引入的风险。
5、依赖倒置原则
5.1、定义
依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依
赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。
5.2、作用
依赖倒置原则的主要作用如下。
- 可以降低类间的耦合性。
- 可以提高系统的稳定性。
- 可以减少并行开发引起的风险。
- 可以提高代码的可读性和可维护性。
6、迪米法特原则
6.1、定义
迪米特法则又叫作最少知识原则,迪米特法则的定义是:只与你的直接朋友交谈,不跟“陌生人”说话。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
6.2、作用
迪米特法则要求限制软件实体之间通信的宽度和深度,正确使用迪米特法则将有以下两个优点。
- 降低了类之间的耦合度,提高了模块的相对独立性。
- 由于亲合度降低,从而提高了类的可复用性和系统的扩展性。
6.3、实现方式
从迪米特法则的定义和特点可知,它强调以下两点:
- 从依赖者的角度来说,只依赖应该依赖的对象。
- 从被依赖者的角度说,只暴露应该暴露的方法。
7、合成复用原则
7.1、定义
合成复用原则(Composite Reuse Principle,CRP)又叫组合/聚合复用原则 (Composition/Aggregate Reuse Principle,CARP)。它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的, 两者都是开闭原则的具体实现规范。
7.2、重要性
通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
- 继承复用破坏了类的封装性
- 子类与父类的耦合度高
- 它限制了复用的灵活性
采用合成复用原则时,他可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
- 它维持了类的封装性
- 新旧类之间的耦合度低
- 复用的灵活性高
八、分布式与微服务
1、介绍
分布式系统是指一组网络中的计算机通过消息传递协作共同完成任务,这类系统的特点是扩展性强、可靠性高、物理上分散但逻辑上协同。微服务是分布式服务架构的一种良好实现。
分布式服务与微服务对比:
- 区别
- 架构设计
- 分布式服务:通常指将一个大型服务分解为多个服务,部署在不同的服务器上,通过远程调用通信。特点是资源共享、负载均衡和高可用性
- 微服务:一种分布式实现方案,将应用程序分解为一组小型、松耦合的服务,每个服务都围绕特定的业务功能构建,并且可以独立部署和扩展
- 服务粒度
- 分布式服务:服务的粒度相对较大,一个服务包含多个功能模块
- 微服务:服务的粒度更小,每个服务都是围绕单一职责原则构建的,通常只负责一项具体的业务
- 耦合性
- 分布式服务:服务之间的耦合性较高,它们可能需要共享数据和状态
- 微服务:服务之间的耦合性低,每个服务都是自包含的,拥有自己的数据存储和业务逻辑
- 架构设计
- 联系:微服务可以被视为是分布式服务架构的一种实现方式,每个微服务都是一个分布式的服务节点,它们共同组成一个分布式系统。
微服务常见架构:
2、SpringCloud
SpringCloud是一系列框架的有序集合,它利用SpringBoot的开发便利性简化了分布式系统基础设施的开发,如:服务的注册与发现、配置中心、消息总线、断路器、数据监控等,都可以用SpringBoot等风格做到了一键启动和部署。SpringBoot并没有重复造轮子,它只是将目前各家公司开发的比较成熟、经得起考验的服务框架组合起来,最终给开发者留出一套简单易懂、易部署和易维护的分布式系统开发包。
目前分布式微服务的核心组件对比:
Dubbo | SpringCloud | SpringCloudAlibaba |
Zookeeper / Redis | Eureka / Consul | Eureka / Nacos |
Dubbo | Feign | Dubbo / Feign |
无 | SpringCloudConfig | SpringCloudConfig / Nacos |
无 | SpringCloudGateway / Zuul | SpringCloudGateway / Zuul |
dubbo-admin(功能弱) | Hystrix | Sentinel |