08-分布式

1、分布式中 接口的幂等性的设计

在高并发场景的架构里,幂等性是必须得保证的。比如说提交作业。

查询和删除不在 幂等讨论范围。

1、建唯一索引id

每次操作,都根据操作和内容生成唯一的id,在执行之前先判断id是否存在,如果不存在,则

执行后续操作,并且保存到数据库或者redis等。

2、token机制

由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交。前端在数据提交

前要向后端服务申请token,token放到 Redis 或 JVM 内存。

如果在token有效时间内,提交后台校验token,同时删除token,生成新的token返回。

判断token是否存在redis中,存在表示第一次请求,可以继续执行业务,执行业务完成后,最

后需要把redis中的token删除。

3、建去重表

将业务中有唯一标识的字段保存到去重表,如果表中存在,则表示已经处理过了。

4、版本控制

增加版本号,当版本号符合时,才能更新数据

5、状态控制

例如订单有状态已支付 未支付 支付中 支付失败,当处于未支付的时候才允许修改为支付中

2、说说你对分布式事务的理解?

可以从 场景、理论、解决方案三个角度来说。

2.1、场景

多个服务或者多个库,要保持在一个事务中。

我们执行一次任务,可能要操作多个服务或者多个库。

2.2、理论ACID、CAP、BASE。

ACID 指数据库事务正确执行的四个基本要素:

  1. 原子性(Atomicity)
  2. 一致性(Consistency)
  3. 隔离性(Isolation)
  4. 持久性(Durability)

CAP

一致性(Consistency)、

可用性(Availability)、

分区容忍性(Partition tolerance)。

BASE理论

Basically Available(基本可用)

Soft state(软状态)

Eventually consistent(最终一致性)

2.3、解决方案

seata,消息队列+本地事件表,事务消息,最大努力通知方案,tcc

3、什么是两阶段提交(2PC)?

两阶段提交2PC 是分布式事务中最强大的事务类型之一。

3.1、 两个阶段提交流程:

第一阶段 事务协调者询问各个 事务数据源(资源管理器) 是否准备好,投票阶段。

第二阶段 事务协调者根据资源管理器反馈的情况执行commit 或者 fallback操作。

处理流程如下:

阶段一

a) 协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待答复。

b) 各参与者执行事务操作,将 undo 和 redo 信息记入事务日志中**(但不提交事务)**。

c) 如参与者执行成功,给协调者反馈 yes,否则反馈 no。

阶段二

如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(rollback)消息;

否则,发送提交(commit)消息。两种情况处理如下:

情况1:当所有参与者均反馈 yes,提交事务

a) 协调者向所有参与者发出正式提交事务的请求(即 commit 请求)。

b) 参与者执行 commit 请求,并释放整个事务期间占用的资源。

c) 各参与者向协调者反馈 ack(应答)完成的消息。

d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务提交。

情况2:当有一个参与者反馈 no,回滚事务

a) 协调者向所有参与者发出回滚请求(即 rollback 请求)。

b) 参与者使用阶段 1 中的 undo 信息执行回滚操作,并释放整个事务期间占用的资源。

c) 各参与者向协调者反馈 ack 完成的消息。

d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务。

3.2、 两阶段提交(2PC)问题

1、性能问题(阻塞问题):所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,比如数

据库的连接一直占用着,容易导致性能瓶颈。

优化: 资源管理器执行完之后,将数据库的连接断开,并记录到日志中。

2、可靠性问题:如果协调者 存在单点故障问题 ,资源管理器将一直处于锁定状态。

优化:我们可以通过集群 的方式 提高 协调者的高可用。

3、数据一致性问题:在阶段 二 中,如果出现资源管理器在执行commit之前 挂了的情况,有可能

导致数据不一致。

优化:通过脚本对数据进行监控

**优点:尽量保证了数据的强一致,**适合对数据强一致要求很高的关键领域。(其实也不能100%保

证强一致)。

**缺点:实现复杂,牺牲了可用性,对性能影响较大,**不适合高并发高性能场景。

3.3、两阶段提交(2PC)的应用

seata,lcn,tcc。

4、什么是补偿性事务(TCC)?

TCCTry Confifirm Cancel)采用的补偿机制。

TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和

补偿(撤销)操作。

它分为三个步骤:

1。Try 阶段主要是 对业务系统做检测及资源预留。

2。Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默

认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。

3。Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

4.1、使用场景

业务场景:比如转账

技术场景:比如保证MySQL和Redis的数据一致性。

4.2、补偿性事务(TCC)的优缺点

优点:

性能提升:资源管理器 实现控制资源锁 的粒度变小,不会锁定整个资源。

数据最终一致性:基于 Confirm 和 Cancel 的幂等性,保证事务最终完成确认或者取消,保证数据

的一致性。

可靠性解决了 XA 协议的协调者单点故障问题,由主业务方 发起并控制整个业务活动,业务活

动管理器也变成多点,引入集群

缺点:

TCC 的 Try、Confirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开发成本。

5、消息队列和事件表是如何实现分布式事务的

6、 分布式ID生成有几种方案?

6.1、分布式ID的特性

唯一性:确保生成的ID是全网唯一的。

有序递增性:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的。

高可用性:确保任何时候都能正确的生成ID。

带时间:ID里面包含时间,不容易重复。

6.2、UUID

算法的核心思想是 结合机器的网卡、当地时间、一个随机数 来生成UUID

优点:本地生成,**生成简单,性能好,**没有高可用风险

缺点:长度过长 ,存储冗余,且无序不可读,查询效率低

6.3、数据库自增ID

使用数据库的id自增策略,如 MySQL 的 auto_increment。并且可以使用两台数据库分别设置不同步长,生成不重复ID的策略 来实现高可用。

优点:数据库生成的ID绝对有序,高可用实现方式简单

缺点:需要独立部署数据库实例,成本高,有性能瓶颈

6.4、批量生成ID

一次按需批量生成多个ID,每次生成都需要访问数据库,将数据库修改为最大的ID值,并在

内存中记录当前值及最大值

优点:避免了每次生成ID都要访问数据库并带来压力,提高性能

缺点:属于本地生成策略,存在 单点故障,服务重启(内存中记录的最大值丢失)造成ID不连续

6.5、Redis生成ID

Redis的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所

以能保证生成的 ID 肯定是唯一有序的。

优点:不依赖于数据库,灵活方便,且性能优于数据库;数字ID天然排序。

缺点:如果系统中没有Redis,还需要引入新的组件,增加系统复杂度;

6.6、Twitter的snowflflake算法(重点)

优点:高性能,低延迟,按时间有序,一般不会造成ID碰撞

缺点:需要独立的开发和部署,依赖于机器的时钟

1位符号位

正数为 0,负数为 1,且实际系统中所使用的ID一般都是正数,所以最高位为 0。

41位时间戳(毫秒级)

存储时间戳的差值(当前时间戳 - 起始时间戳),这里的起始时间戳一般是ID生成器开始使用

的时间戳。

10位数据机器位

这10位决定了分布式系统中最多可以部署 1 << 10 = 1024个节点。超过这个数量,生成的ID

就有可能会冲突。

12位毫秒内的序列

6.7、百度UidGenerator

UidGenerator是百度开源的分布式ID生成器,基于于snowflflake算法的实现。

6.8、美团Leaf

Leaf 是美团开源的分布式ID生成器,能保证全局唯一性、趋势递增、单调递增、信息安全,

但也需要依赖关系数据库、Zookeeper等中间件。

7、常见的负载均衡算法有哪些?

轮询负载均衡算法

挨个发,适合于所有服务器硬件都相同的场景。

代码实现:用i 保存服务器的编号。第一次来 取0,第二次来 取1 ,第三次来 取 0。

加权轮询算法

按照权重不同来分发,基本上是基于配置。

代码实现:

比如:两个服务权重分别是6和4,我们的方法,在1-10之间取 随机数,比如取到 1-6,就走6的权重,取到7-10,就走4权重的服务。

随机轮询算法

代码实现:这个就随意了。

最少链接

记录每个服务器正在处理的 连接数 (请求数),将新的请求 分发到最少连接的服务器上,这

是最符合负载均衡的算法。

代码实现:放到redis里,每次调用一次,服务次数+1。

原地址散列

**根据请求来源的ip地址 进行hash计算,**只要原地址不变,每次请求映射来的后面提供服务的

节点也不变。这有利于进行session信息的维护。

8、数据库如何处理大数据量

对数据库进行:分区、分库分表,主从架构(读写分离)

分区:

原来的一个数据库在磁盘是一个文件,把这个文件分成4个文件,放到不同的位置实现隔离

数据访问。

分库分表:

水平分库/表,各个库和表的结构一模一样,数据量不一样。

垂直分库/表,各个库和表的结构不一样,数据量一样。

主从架构(读写分离):

读写分离:主机负责写,从机负责读。

9、什么是可靠消息最终一致性方案?

它是保证事务最终一致性的一种方案,允许数据在业务中出现短暂的不一致状态。

可靠消息 最终一致性方案是指:消息发送者 执行完本地事务后,同时发出一条消息,消息的消费

者 一定能够接收消息 并可以成功处理自己的事务。

这里面强调两点:

可靠消息:消息发送者 一定得把消息传递到 消费者。

最终一致性:最终消息发送者 的业务处理 和 消息的消费者 的业务处理得完成,达成最终一致。

9.1、可靠消息最终一致性 问题分析

事务发起方和消息中间件之间,事务消费方和消息中间件之间,都有网络通信,由于网络通

信的不确定性,这块会导致数据的问题。下面针对导致的问题来分别进行解决。

(1) 事务发起方 本地事务 和 消息发送之间的原子性问题。

即本地事务 执行成功和消息的发送成功,要么都成功,要么都失败。

java 复制代码
begin transaction;

操作数据库;

发送消息;

commit transaction;

如果操作数据库出错,回滚,不影响数据;如果发送消息出错,也回滚,不影响数据。

这么一看似乎可以保证原子性,但是会有一种情况,发送消息响应超时,导致数据库回滚,

但是消息已经发送成功了。这时原子性还是无法保证的,这个时候就需要人工补偿了。

(2) 事务消费方 本地事务 和 消息消费 的原子性问题。

如果由于程序故障,导致事务消费方 重启,那么需要消息中间件要有消息重发机制;

由于网络延时的存在,当事务消费方消费消息成功,没有向消息中间件响应时,而消息中间

件由于重发机制,会再次投递消息,就导致了消息重复消费的问题。此时在消费方要有幂等性解决

方案。

10、RocketMQ在分布式事务中如何应用的?

它在4.3之后的版本支持了事务消息,为解决分布式事务提供了便利 。

RocketMQ的事务消息,主要为了解决 事务生产方 执行业务 和 消息发送的原子性问题。

具体流程如下:

(1)发送half message。在执行本地业务之前,先向消息队列发送一条事务消息,此时叫做half

message, 此时消息被标记为(Prepared预备状态),此时的消息是无法被消费者消费的,需要

生产者对消息进行二次确认后,消费者才能去消费它。

(2)消息队列回应half message发送成功。

(3)当事务发起方收到消息队列的成功响应之后,开始执行本地业务。

(4)如果本地事务执行成功,则向消息队列发送half message的确认,这样事务消费方就可以消

费消息了。

(5)**如果本地事务执行失败,则向消息队列发送half message的回滚,删除half message。**事

务消费方就无法消费消息。

(6)回查机制。由于网络闪断,生产者应用重启等原因,导致生产者无法对消息队列中的half

message进行二次确认时,消息队列中的half message就不知道应该怎么办了。此时消息队列会定

时扫描长期处于half message的消息,并发起一个回查机制,来确认此时的half message应该是

**提****交还是回滚。**此时,消息队列主动询问生产者该消息的最终状态(提交还是回滚),即为消息的

回查机制。

11、请说说微服务注册中心的存储结构

11.1、为什么需要注册中心?

服务太多,使用注册中心方便管理。注册中心相当于通讯录、花名册。

11.2、注册中心的存储结构

注册中心示例:

打开Eureka的源码,它的存储结构是用的ConcurrentHashMap,它的key是服务名,值是个Map。值的Map中键是服务实例ID,值是租约(租约里面包括服务信息)

key: value

<服务名:<服务实例1:ip+port,服务配置等等>,<服务实例1:ip+port,服务配置等等>>

12、设计一个注册中心需要写哪些接口?

注册中心需要提供一个接口,让服务调用它来进行服务的登记注册,这就是注册中心的第一

个功能, 接受服务注册

服务注册完成后,注册中心得知道这个服务是否还是有效服务?所以需要服务定期地告诉注

册中心,自己的工作状态(是否可用)。此时需要注册中心提供第二个功能, 接受服务心跳

当服务下线时,要通知注册中心自己要下线,注册中心需要提供对应的接口,来让服务调

用。此时需要注册中心的第三个功能, 接受服务下线

如果服务挂了,没有及时通知注册中心,此时注册中心也发现服务最近没有发送心跳。注册

中心要主动剔除挂了的服务。此时需要注册中心第四个功能, 服务剔除

注册表中存储的信息,是要供其他服务查询的,就像通讯录一样,是要供主人查阅的,所以

注册中心还需要第五个功能, 查询注册表中的服务信息

一般微服务中,每个服务都要避免单点故障,注册中心也要做集群所以还要涉及到注册中

心间,注册信息的同步 。这就是注册中心的第六个功能, 注册中心集群间注册表的同步

其实本质就是一个web服务,提供上面分析的5个接口,供服务调用。这就是平时所说的 注册

中心服务端 。那对应的调用注册中心的服务(业务服务),一般称之为 注册中心客户端

13、谈谈你对RESTful规范的理解?

RESTful其实是一种风格并不是一种协议,其实他就是普通的http请求。其中REST表示Resource

Representational State Transfer,直接翻译即"资源表现层状态转移"。

Resource代表互联网资源。每种"资源"对应一个URI。

Representational是"表现层"意思。**"资源"是一种消息实体,它可以有多种外在的表现形式,**比如

map3、avi等。它的具体表现形式,应该由HTTP请求的头信息Accept和Content-Type字段指定,

这两个字段是对"表现层"的描述。

State Transfer是指"状态转移"。客户端想要操作服务端资源,通过使用HTTP协议中的常用的四

**个****动词,让服务器端资源发生"状态转移"。**它们分别是获取资源的GET、新建或更新资源POST、

更新资源的PUT和删除资源的DELETE。

RESTful接口URL命名原则

命名原则1:HTTP方法后跟的URL 必须是名词且 统一成名词复数形式。

命名原则2:URL中不采用大小写混合的驼峰命名,尽量采用全小写单词,如果需要连接多个单

词,则采用"-"连接。

14、分布式系统中为什么引入熔断?

大家看一下下面的服务调用场景。C服务和D服务调用B服务,B服务调用A服务。在下面情况1中,服务正常调用。服务在运行过程中,A服务发生故障(网络延时,服务异常,负载过大无法及时响应),系统变成了情况2。由于B服务调用A服务,A服务出故障,导致B服务调用A的代码处也出故障,此时B服务也出故障了,系统变成了情况3。**以此类推,系统最终发展成A、B、C、D所有的服务都出错了,整个系统崩塌了。这就是雪崩,**如图所示。

雪崩效应

微服务系统之间通过互相调用来实现业务功能,但每个系统都无法百分之百保证自身运行不

出问题。在服务调用中,很可能面临依赖服务失效的问题(网络延时,服务异常,负载过大无法及

时响应),导致服务雪崩,这对于一个系统来说是灾难性的。 因此需要一个组件,能提供强大的容

错能力,当服务发生异常时,能提供保护和控制,把影响控制在较小范围内,不要造成所有服务的

雪崩。

什么时候恢复系统?

熔断开关状态:开(走降级的方法),关闭(正常的调用),半开()

15、描述一下熔断和降级的区别?

(1) 相似性

目的一致:都是从可用性和可靠性着想,防止系统的整体响应缓慢甚至崩溃而采用的技术手段。

最终表现类似 :对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用。

粒度一致:都是服务级别的。

④自治性要求很高:熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段。

(2) 区别

触发原因不一样:服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负

荷考虑。

管理目标的层次不一样:熔断是一个框架级的处理,每个服务都需要,而降级一般有业务层级之

分,例如,降级一般在服务调用的上层处理。

16、如何提升系统的并发能力?

分流:自动扩缩容、负载均衡,消息队列,数据库拆分(主从架构、分库分表)

导流:分布式缓存,cdn

并行/发:异步线程

17、你是依据什么来进行服务划分的?

进行微服务设计时,服务的数量相对于单体应用来说,会比较多,上个公司项目分了10个服务。

考虑的重点就是如何准确识别 系统业务的边界。只有每个服务的边界确定了,才能在以后的开发

中做到更好的协作。

18、微服务设计一般都遵循了什么原则?

(1)单一职责原则。让每个服务能独立,有界限的工作,每个服务只关注自己的业务。做到高内

聚,服务和服务之间做到低耦合。

(2)服务自治原则。每个服务要能做到独立开发、独立测试、独立构建、独立部署,独立运行,

与其他服务进行解耦。

(3)轻量级通信原则。让每个服务之间的调用是轻量级,并且能够跨平台、跨语言。例如采用

RESTful风格,利用消息队列进行通信等。

(4)粒度进化原则。服务的粒度随着业务和用户的发展而发展。

软件是为业务服务的,好的系统不是设计出来的,而是进化出来的。

19、什么是最大努力通知方案?

如果接入过支付宝或者微信的支付接口,会遇到这样一种流程。例如,APP调用支付宝或微信的

SDK进行了支付,钱已经从用户的支付宝或微信账户,转到了公司的支付宝或微信账户上,但是支

付系统,并不知道钱是否已经支付成功,需要支付宝或者微信回调公司的支付系统,才能进行后续

的业务, 这其实就是一个最大努力通知的解决方案。在方案中主要保证两点:

(1)**有一定的消息重复通知机制。**因为接收通知方(图中的我方支付系统)可能没有接收到通

知,此时要有一定的机制对消息进行重复通知。

(2)**消息校对机制。**如果尽最大努力也没有通知到接收方,或者接收方消费消息后要再次消费,

此时可由接收方主动向通知方查询消息信息来满足需求。

落地:

**最大努力通知,**其实针对内部系统和外部系统,有不同的做法。

(1)公司内部系统。**针对公司内部系统来做的话,可以通过系统直接订阅消息队列来完成。**因为

都是自己的系统,直接订阅就可以。

(2)公司外部系统。针对公司外部系统来做的话,直接让消费方订阅消息队列就有点不合适了,毕竟不能让两家公司同时对一个消息队列进行操作,所以此时,**可以在内部写一个程序来订阅消息队列,通过RPC的方式,调用消费方,使其被动的的接受通知消息。**在接支付宝和微信时,一般都是采用这种方式。

20、spring cloud和Dubbo你是如何做选择的?

采用微服务会带来 更清晰的业务划分 和 更好的可扩展性,在很多企业中十分流行。支持微服务的技术栈也是多种多样。当前主流的是Spring Cloud 和 Dubbo。

Spring Cloud的功能比Dubbo更全面,更完善,它可以与Spring其他项目无缝结合,完美对

接,整个软件生态环境比较好。

Spring Cloud就像品牌机,整合在Spring的大家庭中,并做了大量的兼容性测试,保证了机器

各部件的稳定。

Dubbo就像组装机,每个组件的选择自由度很高,但是如果你不是高手,如果你选择的某个

组件出问题,就会导致整个机器的宕机,造成整体服务的可不用。

21、Ribbon的原理是什么?

重点答以下三点。

(1)通过拦截器 对 被注解@LoadBalanced 修饰的RestTemplate进行 拦截。

(2)将RestTemplate中调用的服务名解析成具体的IP地址,由于一个服务名会对应多个地址,

那么在选择具体服务地址的时候,需要做负载均衡。

(3)确定目标服务的 IP 和 port 后,通过Httpclient进行http的调用。

22、能说一下你对 认证 和 授权 的认识吗?

(1)Authentication(认证) 是验证您的身份的凭据(例如用户名/用户ID和密码/手机验证码),

通过这个凭据,系统得以知道你就是你,也就是说系统存在 你这个用户。所以,Authentication 被

称为身份/用户验证。

(2)Authorization**(授权) 发生在 Authentication(认证) 之后。授权,它主要掌管访问系统**

**的****权限。**例如有些特定资源,只能是具有特定权限的人才能访问例如admin,有些对系统资源操作

例如删除、添加、更新只能特定人才具有。

相关推荐
一條狗1 小时前
随笔20241126 Kafka 消费者的自动提交与手动提交偏移量详解
分布式·kafka
运维&陈同学1 小时前
【kafka01】消息队列与微服务之Kafka详解
运维·分布式·后端·微服务·云原生·容器·架构·kafka
楚疏笃1 小时前
鸿蒙学习自由流转与分布式运行环境-跨端迁移(2)
分布式·学习·harmonyos
哼了个哈3 小时前
daos源码编译
分布式
Lostgreen3 小时前
分布式查询处理优化之数据分片
大数据·笔记·分布式
孙克旭_5 小时前
第五章 RabbitMQ高级
分布式·rabbitmq
Mr.Demo.7 小时前
[RabbitMQ] 保证消息可靠性的三大机制------消息确认,持久化,发送方确认
分布式·rabbitmq
小扳7 小时前
微服务篇-深入了解使用 RestTemplate 远程调用、Nacos 注册中心基本原理与使用、OpenFeign 的基本使用
java·运维·分布式·后端·spring·微服务·架构
LightOfNight7 小时前
Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)
服务器·数据库·redis·分布式·后端·缓存·中间件
cnsxjean17 小时前
SpringBoot集成Minio实现上传凭证、分片上传、秒传和断点续传
java·前端·spring boot·分布式·后端·中间件·架构