Skip to content

面渣逆袭-分布式

About 3367 wordsAbout 11 min

2025-08-07

分布式理论

1、说说cap原则

指在一个分布式系统中,consistency一致性、availability可用性、partition tolerance分区容错性这三个基本需求,最多只能同时满足其中2个。

一致性:指数据在多个副本之间能够保持一致的特性

可用性:指系统提供的服务必须一直处于可用状态,每次请求都能够得到不错的响应

分区容错性:分布式系统遇到网络故障时,任然能够对外提供满足一致性和可用性的服务。

4、BASE理论了解吗?

base理论时基于cap理论演化而来的,核心思想即便不能达到强一致性,也可以根据应用特点采用适当的方式来达到最终一致性的效果。

  • ba 基本可用

basically available,什么是基本可用,假设系统出现了不可预知的故障,但还是能用,只是相对于正常的系统而言,可能响应时间上损失,或者功能降级。

  • s 软状态

soft state, 什么是硬状态?要求多个节点的数据副本都是一致的,这是一种硬状态。

软状态也称为弱状态,相比硬状态,系统允许存在中间状态,并认为这种状态不影响系统可用性。

  • e 最终一致性

eventually consistent,在一定时间后,达到最终状态,保证所有的副本数据一致性,从而达到数据的最终一致性。

分布式锁

单体时代,可用直接用本地锁来实现资源的竞争,分布式系统需要用到分布式锁。

5、有哪些分布式锁的实现方案?

常见的方案有三种:mysql分布式锁、zookepper分布式锁、redis分布式锁。

  • mysql分布式锁实现

用数据库实现分布式锁比较简单,创建一张表,数据库对字段唯一性约束。加锁的时候,在锁表中增加一条记录即可,释放锁的时候删除记录。

这种属于数据库io操作,效率不高,而且频繁操作会增大数据库的开销,高并发场景中使用不多

  • zookepper实现分布式锁

lock节点,在此节点下创建自节点可以保证顺序。zookepper比较重,zk实现分布式锁,用的也比较少

  • redis实现分布式锁。

redis实现分布式锁是最广泛的方式。

redis执行命令是单线程的,利用这个特性,实现分布式锁最简单的一个命令:

setNx(set if not exist) // 如果不存在则更新
setNx resourceName value

加锁之后如果机器宕机,就会出新无法解锁的情况,所以需要加入超时时间。

set resourceName value ex 5 nx

Redission客户端,良好的封装了分布式锁的api,支持redlock。

分布式事务

6、什么是分布式事务?

在分布式环境下,会涉及到多个数据,比如说支付库、商品哭、订单库。因此要保证跨服务的食物一执行就变的非常复杂。

分布式食物其实就是将单一库的事务扩大到多库,目的就是为了保证跨服务的数据一致性。

7、分布式事务有哪些常见的实现方案?

  • 二阶段提交 2pc:通过准备和提交阶段保证一致性,但性能较差。
  • 三阶段提交 3pc:在2pc的基础上增加了一个超时机制,降低了阻塞,但仍然存在数据不一致的风险。
  • tcc:根据业务逻辑拆分try、commit、cancel三个阶段,适合锁定资源的业务场景
  • 本地消息表:在数据库中存储事务事件,通过定时任务处理消息。
  • 基于mq的分布式事务:通过消息队列来实现异步确保,利用重试机制保障最终一致性,适用于对实时性要求不高的场景。

说说2pc两阶段提交?

XA协议

在协议里,有三个角色

ap application 应用系统,tm transaction manager 事务管理器,rm resource manager 资源管理器

准备阶段:事务管理器tm 要求每个涉及到事务的数据库预提交次操作,并反映是否可以提交。

提交阶段:事务协调器 要求每个数据提交数据,或者回滚数据。

优点,尽量保证了数据的强一致性,实现成本低,在各大主流数据库都有自己的实现,mysql从5.5开始支持

缺点,1 单点问题,事务管理器重要,如果在准备阶段宕机,rm资源管理器会一直阻塞。2 同步阻塞,在准备就绪之后,rm中的资源就会一直处于阻塞,直到提交完成,才会释放资源。3 数据不一致,第二阶段提交,如果部分任务收到commit操作,一部分因为网络没有收到commit操作。

3pc了解吗?

三个阶段 cancommit, precommit, docommit

cancommit:准备阶段,协调者向参与者发送commit请求,参与者如果可以提交就返回yes,否则返回no

precommit:预提交阶段,协调者根据参与者的返回判断是执行还是中断,参与者执行完操作之后返回ack响应,同时开始等待最终的指令。

docommit:提交阶段,协调者根据参与者在准备阶段的响应判断是执行事务,如果参与者都返回正确的ack响应,则提交事务,如果参与者一个或者多个收到错误的ack或者超时,中断事务;如果参与者无法及时收到协调者的提交,在等待超时之后,会继续进行事务提交。

无论是2pc还是3pc都不能保证分布式系统中的数据100%一致。

tcc了解吗?

tcc是在两阶段的一个变种,针对每个操作,都需要有一个其对应的确认和取消操作,当操作成功调用确认操作,操作失败调用取消

try:尝试待执行业务。

confirm:确认执行业务,如果try阶段执行成功,接着执行confirm阶段。

cancel:取消待这习惯呢业务,如果try阶段执行失败,执行cancel阶段。

tcc是业务层面的分布式事务,保证了最终一致性,不会一直持有资源的锁。

优点,把数据库层的二阶段提交交给了应用层来实现,规避了数据库的2pc性能地下问题

缺点,tcc的try,confirm,cancel需要业务提供,开发成本高,tcc对业务的侵入较大和业务紧耦合,需要特定的场景和业务来设计响应的操作。

本地消息表了解吗?

本地消息表的核心思想是将分布式事务拆分成本地事务进行处理。

例如,可以在订单库新增一个消息表,将新增订单和新增消息放到一个事务里面完成,然后通过伦序的方式查询消息表,将消息推送到mq,库存服务去消费mq。

本地消息表这种方案实现了最终一致性,需要在业务系统里增加消息表,业务逻辑中多次插入db操作,所以性能会有损耗,而且最终一致性的间隔主要由定时任务的间隔时间决定。

mq消息事务了解吗?

基于mq的分布式事务是指将两个事务通过消息队列进行异步解藕,利用重试机制保障最终一致性,适用于对实时性要求不高的场景。

订单服务执行自己的本地事务,并发送消息到mq,库存服务接收到消息后,执行自己的本地事务,如果消费失败,可以利用重试机制确保最终一致性。

延迟队列在分布式事务中通常用于异步补偿、定时校验和故障重试等场景,确保数据最终一致性。

当主事务执行完成后,延迟队列会在一定时间后检查各个子事务的状态,如果有失败的子事务,可以出发补偿操作、重试和回滚。当分布式锁因为某些原因未被正常释放时,可以通过延迟队列在超时后

分布式设计

11、说说什么事幂等性?

是一个数学上的概念,用在接口上的话,可以理解为,同一个接口,多次发出同一个请求,请求的结果是一致的,简单来说,即时多次调用如一次。

在系统运行中可能出现的问题:

1 用户填写表单,保存按钮不小心快速点了2次,表中生成了两条数据,只有id不同。

2 开发人员为了解决接口超时,会引入重试机制,第一次消费者已经处理了,但是响应还没有到生产者哪里,于是会再次发起请求,这样也产生了重复的数据。

3 mq消费者在读取消息事,有时候会读取到重复数据,

在分布式系统中,只要下游服务有写保存更新操作,都有可能产生幂等性问题。

幂等性和防重有些不同,防重强调的事防止数据重复,幂等强调的事多次调用和一次,防重包含幂等。

怎么确保接口幂等性?

  • insert前先select

在保存数据insert之前,先根据requestId等字段先select一下,如果该数据已经存在,则直接返回,如果不存在,才执行insert

  • 加唯一索引

加唯一索引是一个非常简但是有效的办法,如果重复插入数据的话,就会抛出异常,为了保证幂等性的话,一般需要捕获这个异常

  • 加悲观锁

更新逻辑,比如更新用户账户余额,可以加悲观锁,把对应用户的那一行数据锁住,同一时刻只允许一个请求获得锁,其他请求则等待。

  • 加乐观锁

更新逻辑也可以加乐观锁,性能更好,可以在表中增加一个timestamp或者version字段,在更新前先查询一下数据,将version也作为更新条件,同时也更新version

  • 建防重表

有时候表中数据并非所有的场景都不允许产生重复数据,只有某些特定场景才不允许,这个时候,就可以使用防重表的方式。例入消息消费中,创建防重表,存储消息的唯一id

  • 状态机

有些业务是有状态的,比如订单表中,1下单2已支付,可以通过限制状态的流动来完成幂等。

  • 分布式锁

直接在数据库上加锁的做法性能不够友好,可以使用分布式锁的方式,目前最流行的就是redis实现分布式锁,具体实现就是使用redission框架。

  • token机制

请求接口之前,需要先获取一个唯一的token,在带着这个token去完成业务操作,服务端根据这个token是否存在,来判断是否重复的请求。

分布式限流

12、你了解哪些限流算法

  • 计数器

实现逻辑就是从第一个请求进来之后,在接下来的时间段,没进来一个请求,计数器就加一,直到超过最大请求数的请求会被拒绝,等到时间结束后计数器清零,重新开始计数。

最大的弊端就是,比如前面10ms通过了最大请求数,后面990ms的请求就只能拒绝,这个现象叫做“突刺现象”。

  • 漏桶算法

就是桶底出水的速度恒定,进水的速度可能快慢不一,但是当进水量大于出水量的时候,水会被装在桶里面,不会直接被丢弃,但是桶也是有容量限制的,当桶装满水后溢出的部分还是会被丢弃的。

算法实现:可以准备一个队列来保存展示处理不了的请求,然后通过一个线程池定时从队列中获取请求来执行。

  • 令牌桶算法

令牌桶就是生产访问令牌的地方,生产的速度恒定,用户访问的时候当桶中有令牌就可以访问,否则被触发限流。

算法实现:guava ratelimiter限流,是谷歌提供的限流,其基于令牌桶算法,比较适用于单实例的系统。

Changelog

8/20/25, 11:06 AM
View All Changelog
  • 4c155-Merge branch 'dev1'on

求求了,快滚去学习!!!

求求了求求了,快去学习吧!

【题单】贪心算法

不知道方向的时候,可以多看看书,书会给你指明下一步该干什么,加油!