面渣逆袭:分布式十二问,万字图文详解
大家好,我是老三,不管今年金三银四如何,面渣逆袭系列继续,这期我们来看看分布式。
分布式理论
1. 说说CAP原则?
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性)这3个基本需求,最多只能同时满足其中的2个。
选项 | 描述 |
---|---|
Consistency(一致性) | 指数据在多个副本之间能够保持一致的特性(严格的一致性) |
Availability(可用性) | 指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(不保证获取的数据为最新数据) |
Partition tolerance(分区容错性) | 分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障 |
2. 为什么CAP不可兼得呢?
首先对于分布式系统,分区是必然存在的,所谓分区指的是分布式系统可能出现的字区域网络不通,成为孤立区域的的情况。
那么分区容错性(P)就必须要满足,因为如果要牺牲分区容错性,就得把服务和资源放到一个机器,或者一个“同生共死”的集群,那就违背了分布式的初衷。
那么满足分区容错的基础上,能不能同时满足一致性
和可用性
?
假如现在有两个分区N1
和N2
,N1和N2分别有不同的分区存储D1和D2,以及不同的服务S1和S2。
- 在满足
一致性
的时候,N1和N2的数据要求值一样的,D1=D2。 - 在满足
可用性
的时候,无论访问N1还是N2,都能获取及时的响应。
假如现在有这样的场景:
- 用户访问了N1,修改了D1的数据。
- 用户再次访问,请求落在了N2。此时D1和D2的数据不一致。
接下来:
- 保证
一致性
:此时D1和D2数据不一致,要保证一致性就不能返回不一致的数据,可用性
无法保证。 - 保证
可用性
:立即响应,可用性得到了保证,但是此时响应的数据和D1不一致,一致性
无法保证。
所以,可以看出,分区容错的前提下,一致性
和可用性
是矛盾的。
3. CAP对应的模型和应用?
CA without P
理论上放弃P(分区容错性),则C(强一致性)和A(可用性)是可以保证的。实际上分区是不可避免的,严格上CA指的是允许分区后各子系统依然保持CA。
CA模型的常见应用:
- 集群数据库
- xFS文件系统
CP without A
放弃A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
CP模型的常见应用:
- 分布式数据库
- 分布式锁
AP wihtout C
要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。
AP模型常见应用:
- Web缓存
- DNS
举个大家更熟悉的例子,像我们熟悉的注册中心ZooKeeper
、Eureka
、Nacos
中:
- ZooKeeper 保证的是 CP
- Eureka 保证的则是 AP
- Nacos 不仅支持 CP 也支持 AP
4. BASE理论了解吗?
BASE(Basically Available、Soft state、Eventual consistency)是基于CAP理论逐步演化而来的,核心思想是即便不能达到强一致性(Strong consistency),也可以根据应用特点采用适当的方式来达到最终一致性(Eventual consistency)的效果。
BASE的主要含义:
- Basically Available(基本可用)
什么是基本可用呢?假设系统出现了不可预知的故障,但还是能用,只是相比较正常的系统而言,可能会有响应时间上的损失,或者功能上的降级。
- Soft State(软状态)
什么是硬状态呢?要求多个节点的数据副本都是一致的,这是一种“硬状态”。
软状态也称为弱状态,相比较硬状态而言,允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
- Eventually Consistent(最终一致性)
上面说了软状态,但是不应该一直都是软状态。在一定时间后,应该到达一个最终的状态,保证所有副本保持数据一致性,从而达到数据的最终一致性。这个时间取决于网络延时、系统负载、数据复制方案设计等等因素。
分布式锁
单体时代,可以直接用本地锁来实现对竞争资源的加锁,分布式环境下就要用到分布式锁了。
5. 有哪些分布式锁的实现方案呢?
常见的分布式锁实现方案有三种:MySQL分布式锁
、ZooKepper分布式锁
、Redis分布式锁
。
5.1 MySQL分布式锁如何实现呢?
用数据库实现分布式锁比较简单,就是创建一张锁表,数据库对字段作唯一性约束。
加锁的时候,在锁表中增加一条记录即可;释放锁的时候删除记录就行。
如果有并发请求同时提交到数据库,数据库会保证只有一个请求能够得到锁。
这种属于数据库 IO 操作,效率不高,而且频繁操作会增大数据库的开销,因此这种方式在高并发、高性能的场景中用的不多。
5.2 ZooKeeper如何实现分布式锁?
ZooKeeper也是常见分布式锁实现方法。
ZooKeeper的数据节点和文件目录类似,例如有一个lock节点,在此节点下建立子节点是可以保证先后顺序的,即便是两个进程同时申请新建节点,也会按照先后顺序建立两个节点。
所以我们可以用此特性实现分布式锁。以某个资源为目录,然后这个目录下面的节点就是我们需要获取锁的客户端,每个服务在目录下创建节点,如果它的节点,序号在目录下最小,那么就获取到锁,否则等待。释放锁,就是删除服务创建的节点。
ZK实际上是一个比较重的分布式组件,实际上应用没那么多了,所以用ZK实现分布式锁,其实相对也比较少。
5.3 Redis怎么实现分布式锁?
Redis实现分布式锁,是当前应用最广泛的分布式锁实现方式。
Redis执行命令是单线程的,Redis实现分布式锁就是利用这个特性。
实现分布式锁最简单的一个命令:setNx(set if not exist),如果不存在则更新:
setNx resourceName value
加锁了之后如果机器宕机,那我这个锁就无法释放,所以需要加入过期时间,而且过期时间需要和setNx同一个原子操作,在Redis2.8之前需要用lua脚本,但是redis2.8之后redis支持nx和ex操作是同一原子操作。
set resourceName value ex 5 nx
- Redission
当然,一般生产中都是使用Redission客户端,非常良好地封装了分布式锁的api,而且支持RedLock。
分布式事务
6.什么是分布式事务?
分布式事务是相对本地事务而言的,对于本地事务,利用数据库本身的事务机制,就可以保证事务的ACID特性。
而在分布式环境下,会涉及到多个数据库。
分布式事务其实就是将对同一库事务的概念扩大到了对多个库的事务。目的是为了保证分布式系统中的数据一致性。
分布式事务处理的关键是:
- 需要记录事务在任何节点所做的所有动作;
- 事务进行的所有操作要么全部提交,要么全部回滚。
7.分布式事务有哪些常见的实现方案?
分布式常见的实现方案有 2PC、3PC、TCC、本地消息表、MQ消息事务、最大努力通知、SAGA事务 等等。
7.1 说说2PC两阶段提交?
说到2PC,就不得先说分布式事务中的 XA 协议。
在这个协议里,有三个角色:
- AP(Application):应用系统(服务)
- TM(Transaction Manager):事务管理器(全局事务管理)
- RM(Resource Manager):资源管理器(数据库)
XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。
两阶段提交的思路可以概括为: 参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情况决定各参与者是否要提交操作还是回滚操作。
- 准备阶段:事务管理器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交
- 提交阶段:事务协调器要求每个数据库提交数据,或者回滚数据。
优点: 尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持。
缺点:
- 单点问题:事务管理器在整个流程中扮演的角色很关键,如果其宕机,比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
- 同步阻塞:在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
- 数据不一致:两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能,比如在第二阶段中,假设协调者发出了事务commit的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
7.2 3PC(三阶段提交)了解吗?
三阶段提交(3PC
)是二阶段提交(2PC
)的一种改进版本 ,为解决两阶段提交协议的单点故障和同步阻塞问题。
三阶段提交有这么三个阶段:CanCommit
,PreCommit
,DoCommit
三个阶段
- CanCommit:准备阶段。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
- PreCommit:预提交阶段。协调者根据参与者在准备阶段的响应判断是否执行事务还是中断事务,参与者执行完操作之后返回ACK响应,同时开始等待最终指令。
- DoCommit:提交阶段。协调者根据参与者在准备阶段的响应判断是否执行事务还是中断事务:
- 如果所有参与者都返回正确的
ACK
响应,则提交事务 - 如果参与者有一个或多个参与者收到错误的
ACK
响应或者超时,则中断事务 - 如果参与者无法及时接收到来自协调者的提交或者中断事务请求时,在等待超时之后,会继续进行事务提交
- 如果所有参与者都返回正确的
可以看出,三阶段提交解决的只是两阶段提交中单体故障和同步阻塞的问题,因为加入了超时机制,这里的超时的机制作用于 预提交阶段 和 提交阶段。如果等待 预提交请求 超时,参与者直接回到准备阶段之前。如果等到提交请求超时,那参与者就会提交事务了。
无论是2PC还是3PC都不能保证分布式系统中的数据100%一致。
7.3 TCC了解吗?
TCC(Try Confirm Cancel) ,是两阶段提交的一个变种,针对每个操作,都需要有一个其对应的确认和取消操作,当操作成功时调用确认操作,当操作失败时调用取消操作,类似于二阶段提交,只不过是这里的提交和回滚是针对业务上的,所以基于TCC实现的分布式事务也可以看做是对业务的一种补偿机制。
-
Try:尝试待执行的业务。订单系统将当前订单状态设置为支付中,库存系统校验当前剩余库存数量是否大于1,然后将可用库存数量设置为库存剩余数量-1,。
-
Confirm:确认执行业务,如果Try阶段执行成功,接着执行Confirm 阶段,将订单状态修改为支付成功,库存剩余数量修改为可用库存数量。
-
Cancel:取消待执行的业务,如果Try阶段执行失败,执行Cancel 阶段,将订单状态修改为支付失败,可用库存数量修改为库存剩余数量。
TCC 是业务层面的分布式事务,保证最终一致性,不会一直持有资源的锁。
- 优点: 把数据库层的二阶段提交交给应用层来实现,规避了数据库的 2PC 性能低下问题
- 缺点:TCC 的 Try、Confirm 和 Cancel 操作功能需业务提供,开发成本高。TCC 对业务的侵入较大和业务紧耦合,需要根据特定的场景和业务逻辑来设计相应的操作
7.4 本地消息表了解吗?
本地消息表的核心思想是将分布式事务拆分成本地事务进行处理。
例如,可以在订单库新增一个消息表,将新增订单和新增消息放到一个事务里完成,然后通过轮询的方式去查询消息表,将消息推送到MQ,库存服务去消费MQ。
执行流程:
- 订单服务,添加一条订单和一条消息,在一个事务里提交
- 订单服务,使用定时任务轮询查询状态为未同步的消息表,发送到MQ,如果发送失败,就重试发送
- 库存服务,接收MQ消息,修改库存表,需要保证幂等操作
- 如果修改成功,调用rpc接口修改订单系统消息表的状态为已完成或者直接删除这条消息
- 如果修改失败,可以不做处理,等待重试
订单服务中的消息有可能由于业务问题会一直重复发送,所以为了避免这种情况可以记录一下发送次数,当达到次数限制之后报警,人工接入处理;库存服务需要保证幂等,避免同一条消息被多次消费造成数据不一致。
本地消息表这种方案实现了最终一致性,需要在业务系统里增加消息表,业务逻辑中多一次插入的DB操作,所以性能会有损耗,而且最终一致性的间隔主要有定时任务的间隔时间决定
7.5 MQ消息事务了解吗?
消息事务的原理是将两个事务通过消息中间件进行异步解耦。
订单服务执行自己的本地事务,并发送MQ消息,库存服务接收消息,执行自己的本地事务,乍一看,好像跟本地消息表的实现方案类似,只是省去 了对本地消息表的操作和轮询发送MQ的操作,但实际上两种方案的实现是不一样的。
消息事务一定要保证业务操作与消息发送的一致性,如果业务操作成功,这条消息也一定投递成功。
执行流程:
- 发送prepare消息到消息中间件
- 发送成功后,执行本地事务
- 如果事务执行成功,则commit,消息中间件将消息下发至消费端
- 如果事务执行失败,则回滚,消息中间件将这条prepare消息删除
- 消费端接收到消息进行消费,如果消费失败,则不断重试
消息事务依赖于消息中间件的事务消息,例如我们熟悉的RocketMQ就支持事务消息(半消息),也就是只有收到发送方确定才会正常投递的消息。
这种方案也是实现了最终一致性,对比本地消息表实现方案,不需要再建消息表,对性能的损耗和业务的入侵更小。
7.6 最大努力通知了解吗?
最大努力通知相比实现会简单一些,适用于一些对最终一致性实时性要求没那么高的业务,比如支付通知,短信通知。
以支付通知为例,业务系统调用支付平台进行支付,支付平台进行支付,进行操作支付之后支付平台会去同步通知业务系统支付操作是否成功,如果不成功,会一直异步重试,但是会有一个最大通知次数,如果超过这个次数后还是通知失败,就不再通知,业务系统自行调用支付平台提供一个查询接口,供业务系统进行查询支付操作是否成功。
执行流程:
- 业务系统调用支付平台支付接口, 并在本地进行记录,支付状态为支付中
- 支付平台进行支付操作之后,无论成功还是失败,同步给业务系统一个结果通知
- 如果通知一直失败则根据重试规则异步进行重试,达到最大通知次数后,不再通知
- 支付平台提供查询订单支付操作结果接口
- 业务系统根据一定业务规则去支付平台查询支付结果
8.你们用什么?能说一下Seata吗?
我们用比较常用的是Seata——自己去实现分布式事务调度还是比较麻烦的。
Seata 的设计目标是对业务无侵入,因此它是从业务无侵入的两阶段提交(全局事务)着手,在传统的两阶段上进行改进,他把一个分布式事务理解成一个包含了若干分支事务的全局事务。而全局事务的职责是协调它管理的分支事务达成一致性,要么一起成功提交,要么一起失败回滚。也就是一荣俱荣一损俱损~
Seata 中存在这么几种重要角色:
- TC(Transaction Coordinator):事务协调者。管理全局的分支事务的状态,用于全局性事务的提交和回滚。
- TM(Transaction Manager):事务管理者。用于开启、提交或回滚事务。
- RM(Resource Manager):资源管理器。用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或者回滚分支事务。
S’eata整体执行流程:
- 服务A中的 TM 向 TC 申请开启一个全局事务,TC 就会创建一个全局事务并返回一个唯一的 XID
- 服务A中的 RM 向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
- 服务A开始执行分支事务
- 服务A开始远程调用B服务,此时 XID 会根据调用链传播
- 服务B中的 RM 也向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
- 服务B开始执行分支事务
- 全局事务调用处理结束后,TM 会根据有误异常情况,向 TC 发起全局事务的提交或回滚
- TC 协调其管辖之下的所有分支事务,决定是提交还是回滚
分布式一致性算法
9.分布式算法paxos了解么 ?
Paxos
有点类似前面说的 2PC
,3PC
,但比这两种算法更加完善。在很多多大厂都得到了工程实践,比如阿里的 OceanBase
的 分布式数据库, Google
的 chubby
分布式锁 。
Paxos算法是什么?
Paxos
算法是 基于消息传递 且具有 高效容错特性 的一致性算法,目前公认的解决 分布式一致性问题 最有效的算法之一。
Paxos算法的工作流程?
角色
在Paxos中有这么几个角色:
- Proposer(提议者) : 提议者提出提案,用于投票表决。
- Accecptor(接受者) : 对提案进行投票,并接受达成共识的提案。
- Learner(学习者) : 被告知投票的结果,接受达成共识的提案。
在实际中,一个节点可以同时充当不同角色。
提议者提出提案,提案=编号+value,可以表示为[M,V],每个提案都有唯一编号,而且编号的大小是趋势递增的。
算法流程
Paxos算法包含两个阶段,第一阶段Prepare(准备)、第二阶段Accept(接受)。
Prepare(准备)阶段
- 提议者提议一个新的提案 P[Mn,?],然后向接受者的某个超过半数的子集成员发送编号为Mn的准备请求
- 如果一个接受者收到一个编号为Mn的准备请求,并且编号Mn大于它已经响应的所有准备请求的编号,那么它就会将它已经批准过的最大编号的提案作为响应反馈给提议者,同时该接受者会承诺不会再批准任何编号小于Mn的提案。
总结一下,接受者在收到提案后,会给与提议者两个承诺与一个应答:
- 两个承诺:
- 承诺不会再接受提案号小于或等于 Mn 的 Prepare 请求
- 承诺不会再接受提案号小于Mn 的 Accept 请求
- 一个应答:
- 不违背以前作出的承诺的前提下,回复已经通过的提案中提案号最大的那个提案所设定的值和提案号Mmax,如果这个值从来没有被任何提案设定过,则返回空值。如果不满足已经做出的承诺,即收到的提案号并不是决策节点收到过的最大的,那允许直接对此 Prepare 请求不予理会。
Accept(接受)阶段
- 如果提议者收到来自半数以上的接受者对于它发出的编号为Mn的准备请求的响应,那么它就会发送一个针对[Mn,Vn]的接受请求给接受者,注意Vn的值就是收到的响应中编号最大的提案的值,如果响应中不包含任何提案,那么它可以随意选定一个值。
- 如果接受者收到这个针对[Mn,Vn]提案的接受请求,只要该接受者尚未对编号大于Mn的准备请求做出响应,它就可以通过这个提案。
当提议者收到了多数接受者的接受应答后,协商结束,共识决议形成,将形成的决议发送给所有学习节点进行学习。
所以Paxos算法的整体详细流程如下:
算法的流程模拟,可以查看参考[13]。
Paxos算法有什么缺点吗?怎么优化?
前面描述的可以称之为Basic Paxos 算法,在单提议者的前提下是没有问题的,但是假如有多个提议者互不相让,那么就可能导致整个提议的过程进入了死循环。
Lamport 提出了 Multi Paxos 的算法思想。
Multi Paxos算法思想,简单说就是在多个提议者的情况下,选出一个Leader(领导者),由领导者作为唯一的提议者,这样就可以解决提议者冲突的问题。
10.说说Raft算法?
Raft算法是什么?
Raft
也是一个 一致性算法,和 Paxos
目标相同。但它还有另一个名字 - 易于理解的一致性算法。Paxos
和 Raft
都是为了实现 一致性 产生的。这个过程如同选举一样,参选者 需要说服 大多数选民 (Server) 投票给他,一旦选定后就跟随其操作。Paxos
和 Raft
的区别在于选举的 具体过程 不同。
Raft算法的工作流程?
Raft算法的角色
Raft
协议将 Server
进程分为三种角色:
- Leader(领导者)
- Follower(跟随者)
- Candidate(候选人)
就像一个民主社会,领导者由跟随者投票选出。刚开始没有 领导者,所有集群中的 参与者 都是 跟随者。
那么首先开启一轮大选。在大选期间 所有跟随者 都能参与竞选,这时所有跟随者的角色就变成了 候选人,民主投票选出领袖后就开始了这届领袖的任期,然后选举结束,所有除 领导者 的 候选人 又变回 跟随者 服从领导者领导。
这里提到一个概念 「任期」,用术语 Term
表达。
三类角色的变迁图如下:
Leader选举过程
Raft 使用心跳(heartbeat)触发Leader选举。当Server启动时,初始化为Follower。Leader向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat,就会等待一段随机的时间后发起一次Leader选举。
Follower将其当前term加一然后转换为Candidate。它首先给自己投票并且给集群中的其他服务器发送 RequestVote RPC 。结果有以下三种情况:
- 赢得了多数(超过1/2)的选票,成功选举为Leader;
- 收到了Leader的消息,表示有其它服务器已经抢先当选了Leader;
- 没有Server赢得多数的选票,Leader选举失败,等待选举时间超时(
Election Timeout
)后发起下一次选举。
选出 Leader
后,Leader
通过 定期 向所有 Follower
发送 心跳信息 维持其统治。若 Follower
一段时间未收到 Leader
的 心跳,则认为 Leader
可能已经挂了,然后再次发起 选举 过程。
分布式设计
11.说说什么是幂等性?
什么是幂等性?
幂等性是一个数学概念,用在接口上:用在接口上就可以理解为:同一个接口,多次发出同一个请求,请求的结果是一致的。
简单说,就是多次调用如一次。
什么是幂等性问题?
在系统的运行中,可能会出现这样的问题:
- 用户在填写某些
form表单
时,保存按钮不小心快速点了两次,表中竟然产生了两条重复的数据,只是id不一样。 - 开发人员在项目中为了解决
接口超时
问题,通常会引入了重试机制
。第一次请求接口超时了,请求方没能及时获取返回结果(此时有可能已经成功了),于是会对该请求重试几次,这样也会产生重复的数据。 - mq消费者在读取消息时,有时候会读取到
重复消息
,也会产生重复的数据。
这些都是常见的幂等性问题。
在分布式系统里,只要下游服务有写(保存、更新)的操作,都有可能会产生幂等性问题。
PS:幂等和防重有些不同,防重强调的防止数据重复,幂等强调的是多次调用如一次,防重包含幂等。
怎么保证接口幂等性?
-
insert前先select
在保存数据的接口中,在
insert
前,先根据requestId
等字段先select
一下数据。如果该数据已存在,则直接返回,如果不存在,才执行insert
操作。 -
加唯一索引
加唯一索引是个非常简单但很有效的办法,如果重复插入数据的话,就会抛出异常,为了保证幂等性,一般需要捕获这个异常。
如果是
java
程序需要捕获:DuplicateKeyException
异常,如果使用了spring
框架还需要捕获:MySQLIntegrityConstraintViolationException
异常。 -
加悲观锁
更新逻辑,比如更新用户账户余额,可以加悲观锁,把对应用户的哪一行数据锁住。同一时刻只允许一个请求获得锁,其他请求则等待。
select * from user id=123 for update;
这种方式有一个缺点,获取不到锁的请求一般只能报失败,比较难保证接口返回相同值。
-
加乐观锁
更新逻辑,也可以用乐观锁,性能更好。可以在表中增加一个
timestamp
或者version
字段,例如version
:在更新前,先查询一下数据,将version也作为更新的条件,同时也更新version:
update user set amount=amount+100,version=version+1 where id=123 and version=1;
更新成功后,version增加,重复更新请求进来就无法更新了。
-
建防重表
有时候表中并非所有的场景都不允许产生重复的数据,只有某些特定场景才不允许。这时候,就可以使用防重表的方式。
例如消息消费中,创建防重表,存储消息的唯一ID,消费时先去查询是否已经消费,已经消费直接返回成功。
-
状态机
有些业务表是有状态的,比如订单表中有:1-下单、2-已支付、3-完成、4-撤销等状态,可以通过限制状态的流动来完成幂等。
-
分布式锁
直接在数据库上加锁的做法性能不够友好,可以使用分布式锁的方式,目前最流行的分布式锁实现是通过Redis,具体实现一般都是使用Redission框架。
-
token机制
请求接口之前,需要先获取一个唯一的token,再带着这个token去完成业务操作,服务端根据这个token是否存在,来判断是否是重复的请求。
分布式限流
12.你了解哪些限流算法?
- 计数器
计数器比较简单粗暴,比如我们要限制1s能够通过的请求数,实现的思路就是从第一个请求进来开始计时,在接下来的1s内,每个请求进来请求数就+1,超过最大请求数的请求会被拒绝,等到1s结束后计数清零,重新开始计数。
这种方式有个很大的弊端:比如前10ms已经通过了最大的请求数,那么后面的990ms的请求只能拒绝,这种现象叫做“突刺现象”。
- 漏桶算法
就是桶底出水的速度恒定,进水的速度可能快慢不一,但是当进水量大于出水量的时候,水会被装在桶里,不会直接被丢弃;但是桶也是有容量限制的,当桶装满水后溢出的部分还是会被丢弃的。
算法实现:可以准备一个队列来保存暂时处理不了的请求,然后通过一个线程池定期从队列中获取请求来执行。
- 令牌桶算法
令牌桶就是生产访问令牌的一个地方,生产的速度恒定,用户访问的时候当桶中有令牌时就可以访问,否则将触发限流。
实现方案:Guava RateLimiter限流
Guava RateLimiter是一个谷歌提供的限流,其基于令牌桶算法,比较适用于单实例的系统。
这一期的分布式面试题就整理到这里了,主要是偏理论的一些问题,分布式其实是个很大的类型,比如分布式调用、分布式治理……
所以,这篇文章只是个开始,后面还会有分布式调用(RPC)、微服务相关的主题文章,敬请期待。
参考:
[1] . 《从Paxos到Zookeeper 分布式一致性原理与实践》
[2]. 分布式理论(一) - CAP定理
[3]. 分布式理论(二) - BASE理论
[4]. 分布式理论(三) - 2PC协议
[5] . CAP和BASE理论了解么?可以结合实际案例说下不
[6] 从分布式事务解决到Seata使用,一梭子给你整明白了
[7]. 高并发下如何保证接口的幂等性?
[8]. 分布式理论(三) - 2PC协议
[9]. 再有人问你分布式锁,这篇文章扔给他
[10]. 分布式理论(五) - 一致性算法Paxos
[11]. 《分布式系统技术及其案例分析》
[12].不就是分布式事务,这下彻底清楚了😎
[13].诸葛亮 VS 庞统,拿下 Paxos 共识算法
[14].http://icyfenix.cn/distribution/consensus/paxos.html
**⭐️面渣逆袭系列:**
- 面渣逆袭:Java基础五十三问
- 面渣逆袭:Java集合连环三十问
- 面渣逆袭:JVM经典五十问,这下面试稳了!
- 面渣逆袭:Java并发六十问
- 面渣逆袭:Spring三十五问,四万字+五十图详解!
- 面渣逆袭:二十二图、八千字、二十问,彻底搞定MyBatis!
- 面渣逆袭:计算机网络六十二问,三万字图文详解!速收藏!
- 面试字节,被操作系统问挂了
- 面渣逆袭:RocketMQ二十三问
- 面渣逆袭:Redis连环五十二问!三万字+八十图详解!
- 面渣逆袭:MySQL六十六问,两万字+五十图详解!有点六!
相关文章:

面渣逆袭:分布式十二问,万字图文详解
大家好,我是老三,不管今年金三银四如何,面渣逆袭系列继续,这期我们来看看分布式。 分布式理论 1. 说说CAP原则? CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性…...

设计模式C++实现23:中介者模式(Mediator)
部分内容参考大话设计模式第25章;本实验通过C语言实现。 一 原理 意图:用一个中介对象来封装一系列对象的交互,中介者使得各个对象不需要显示地相互引用,从而使耦合松散,而且可以独立地改变它们之间的交互。 上下文…...

Java方法【未完待续】
目录 前言 一、什么是方法? 二、方法的定义和调用 方法的定义 方法的调用 三、方法的重载 重载规则 实现理论 总结 前言 随着对Java这一编程语言的深入学习,大家可能会遇到一个熟悉又陌生的词——方法,其实Java方法就是我们学习C/C时…...

(考研湖科大教书匠计算机网络)第六章应用层-第一、二节:应用层概述和C/S及P2P
获取pdf:密码7281专栏目录首页:【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一:应用层概述二:客户/服务器(C/S)和对等(P2P)方式(1)客户/服务器&…...

禅道bug提醒脚本部署
环境准备 nginxpython3 服务器目录 以下目录为自定义配置,需在 nginx 默认配置文件的http{}内添加 include /www/conf/*.conf; 才会生效 /www ├── conf "存放配置文件 │ └── lowCode.zyl.conf "低代码bug统计页配置 ├── wwwlogs "存…...

利用spring的retry重试编写Feign远程调用重试
自定义注解FeignRetry为了解决上面提到的问题,让Feign调用的每个接口单独配置不同的重试机制。我们使用了面向切面编程并编写了一个自定义注解:FeignRetry。此注释的工作方式类似于Retryable的包装器,并与其共享相同的规范以避免混淆。Target…...

Docker启动RabbitMQ,实现生产者与消费者
目录 一、Docker拉取镜像并启动RabbitMQ 二、Hello World (一)依赖导入 (二)消息生产者 (三)消息消费者 三、实现轮训分发消息 (一)抽取工具类 (二)启…...

【C语言】函数栈帧的创建与销毁
Yan-英杰的主页 悟已往之不谏 知来者之可追 目录 0.ebp和esp是如何来维护栈帧的呢? 1.为什么局部变量的值不初始化是随机的? 2.局部变量是怎么创建的? 3 .函数是如何传参的?传参的顺序是怎样的 4.函数是如何调用的 …...

【Git】使用Git上传项目到远程仓库Gitee码云步骤详解
电脑里存放了很多项目,有的备份,有的没备份,如果不仔细分类管理的话,时间一长,到时看到那就会觉得非常杂乱,很难整理,这里有一个叫源代码托管,用过它的都知道,方便管理和…...

Head First设计模式---3.装饰者模式
3.1装饰者模式 亦称: 装饰者模式、装饰器模式、Wrapper、Decorator 装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 举个例子:天气很冷,我们一件一件穿衣服,…...

Python 算法交易实验48 表字段设计
说明 虽然说的是表,实际上用的是Mongo集合 基于ADBS(APIFunc DataBase Service)可以构造一个供后续研究、生产长时间使用的数据基础,这个基础包括了: 1 队列服务。通过队列,数据可以通过API实现零担和批量两种模式的快速存储。2 …...

库存管理系统-课后程序(JAVA基础案例教程-黑马程序员编著-第六章-课后作业)
【案例6-1】 库存管理系统 【案例介绍】 1.任务描述 像商城和超市这样的地方,都需要有自己的库房,并且库房商品的库存变化有专人记录,这样才能保证商城和超市正常运转。 本例要求编写一个程序,模拟库存管理系统。该系统主要包…...

【极海APM32替代笔记】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题)
【极海APM32替代笔记】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题) 【STM32笔记】低功耗模式配置及避坑汇总 前文: blog.csdn.net/weixin_53403301/article/details/128216…...

Python类变量和实例变量(类属性和实例属性)
无论是类属性还是类方法,都无法像普通变量或者函数那样,在类的外部直接使用它们。我们可以将类看做一个独立的空间,则类属性其实就是在类体中定义的变量,类方法是在类体中定义的函数。 在类体中,根据变量定义的位置不…...

Glide加载图片
使用Glide加载图片,默认情况下在内存中缓存该图片。这样的情况下如果我们保存头像在某个路径,当再次更换头像时可能由于缓存问题,UI上更新的不及时。 默认加载图片方式: Glide.with(context).load(coverPath).error(R.drawable.a…...

有关时间复杂度和空间复杂度的练习
目录 一、消失的数字 二、轮转数组 三、 单选题 一、消失的数字 数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在 O(n) 时间内完成吗? 注意:本题相对书上原题稍作改动 示例 1: 输入…...

linux服务器nfs数据挂载
参考:https://blog.csdn.net/qq_43721935/article/details/119889841?from_wecom1 1、NFS 介绍 NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问…...

Python 自动化测试必会技能板块—unittest框架
说到 Python 的单元测试框架,想必接触过 Python 的朋友脑袋里第一个想到的就是 unittest。的确,作为 Python 的标准库,它很优秀,并被广泛应用于各个项目。但其实在 Python 众多项目中,主流的单元测试框架远不止这一个。…...

mysql存储引擎、事务、索引
目录MySQL进阶存储引擎什么是存储引擎常用存储引擎事务什么是事务怎么理解提交事务 和回滚事务事务特性事务的隔离级别索引什么是索引索引的实现原理什么条件下,我们会考虑给字段添加索引呢?什么条件下,索引会失效?索引分类MySQL进阶 存储引…...

毕业论文图片格式、分辨率选择及高质量Word转PDF方法
已知1:毕业论文盲评通常需要提交PDF文件。 已知2:PDF文件太大可能会导致翻页卡顿以及上传盲评网站失败。 已知3:Word转PDF方法不当可能会导致图像模糊。 已知4:打印机分辨率通常为300dpi。 问题1:论文插图分辨率设置…...

华为外包测试2年,不甘被替换,168天的学习转岗成正式员工
我25岁的时候,华为外包测试,薪资13.5k,人在深圳。 内卷什么的就不说了,而且人在外包那些高级精英年薪大几十的咱也接触不到,就说说外包吧。假设以我为界限,25岁一线城市13.5k,那22-24大部分情况…...

简单的C++:【运算符重载】新手易学
学过C语言的同志们应该都知道位运算符>> 和 << (右移左移),但是这两个运算符在C中还是我们的输入和输出流操作符,那么这是为什么呢?,了解完本篇文章之后,我们再来回答这个问题。 C为…...

NPE:记一次脑残NPE的排查过程
目录 碎碎念: 如下这行报NPE: 排查过程: 解解方案: 小结: 空指针出现的几种情况: 如何从根源避免空指针: 赋值时自动拆箱出现空指针: 1、变量赋值自动拆箱出现的空指针 2、…...

canvas样式与颜色,字体,图片,状态,形变
色彩 fillStyle color 设置图形的填充颜色。 strokeStyle color 设置图形轮廓的颜色。 备注: 一旦您设置了 strokeStyle 或者 fillStyle 的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置…...

重识html
html 重识html 万维网用url统一资源定位符标识分布因特网上的各种文档 各种概念 URL: 统一资源定位器 它是WWW的统一资源定位标志,就是指网络地址 在WWW上,每一信息资源都有统一的且在网上唯一的地址 网页: 由文字 图片 视频 音乐各种元素排列组…...

Redis:缓存一致性问题(缓存更新策略)
Redis缓存的一致性1. 缓存1.1 缓存的作用:1.2 缓存的成本:2. 缓存模型3. 缓存一致性问题3.1 引入3.2 解决(1) 先更新数据库,再手动删除缓存(2) 使用事务保证原子性(3) 以Redis中的TTL为兜底3.3 案例:商铺信息查询和更新(1) 查询商…...

spring之声明式事务开发
文章目录一、声明式事务之全注解式开发1、新建springConfig类2、测试程序3、测试结果二、声明式事务之XML实现方式1、配置步骤2、测试程序3、运行结果附一、声明式事务之全注解式开发 基于之前的银行转账系统,将spring.xml配置文件嘎掉,变成全注解式开发…...

2023美赛参赛经历分享
今天早上登录MCM: The Mathematical Contest in Modeling (comap.com)发现论文提交已经显示Received。虽然这几天连连有开学恶补的期末考试,但还是忙里偷闲趁着新鲜写一篇关于美赛的参赛个人感受。跟我一起打这次美赛的都是软件等专业的hxd,他们之前没有…...

Elasticsearch在Linux中的单节点部署和集群部署
目录一、Elasticsearch简介二、Linux单节点部署1、软件下载解压2、创建用户3、修改配置文件4、切换到刚刚创建的用户启动软件5、测试三、Linux集群配置1、拷贝文件2、修改配置文件3、分别修改文件所有者4、启动三个软件5、测试四、问题总结1、在elasticsearch启动时如果报错内存…...

Scala的变量声明
文章目录变量声明(一)简单说明(二)利用val声明变量1,声明方式2,案例演示(三)利用var声明变量1,声明方式2,案例演示(四)换行输入语句&a…...