目录
一、分布式ID的生成方案?
1.分布式ID需要满足 的条件?
全局唯一:必须保证ID是全局性唯一的,基本要求
高性能:高可用低延时,ID生成响应要块,否则反倒会成为业务瓶颈
高可用:100%的可用性是骗人的,但是也要无限接近于100%的可用性
好接入:要秉着拿来即用的设计原则,在系统设计和实现上要尽可能的简单
趋势递增:最好趋势递增,这个要求就得看具体业务场景了,一般不严格要求
方案 | 描述 | 优点 | 缺点 |
---|---|---|---|
UUID | UUID是通用唯一标识码的缩写,其目的是让分布式系统中所有元素都有唯一的辨识标志,无需中央控制器进行指定 | 生成方便,不需要借助第三方插件 | ①UUID占用16个比特,占用空间大; ②UUID不是递增有序的数据,数据写入IO随机性大,索引效率下降。 |
数据库自增主键 | Mysql数据库设置主键且自增 | ①数字型,占用空间小,易排序; ②数据库自动编码,速度快,增量增长,按顺序存放,对于检索非常有利; | ①由于MySQL数据存储在磁盘中,导致其并发性能不高; ②设置分布式ID要考虑数据库的分库分表,改造复杂; ③由于主键是自增的,数据容易泄露 |
Redis自增 | Redis计数器,incr命令实现原子性自增 | Redis使用内存,并发性能好 | ①由于是内存存储,数据易丢失; ②自增,数据容易泄露 ③Redis单点故障,影响序列服务的可用性。 |
雪花算法 | 分布式ID经典解决方案 | ①高性能高可用:生成时不依赖于数据库,完全在内存中生成; ②容量大:每秒能生成数百万的自增ID; ③ID自增:存入数据库中,索引效率高 | 时钟回拨,有非常小的概率ID会重复 |
雪花算法: 共占用64位bit,其主要有以下四个部分组成
位 | 作用 |
符号位 | 占用1bit,固定为0; 因为二进制里第一个bit如果是1,那么都是负数,但是我们生成的id都是正数,所以第一个bit同一都是0. |
时间戳 | 占用41bit,可以支持69年的跨度 |
机器ID | 占用10bit,记录工作及其id,代表的是这个服务最多可以部署在2^10台机器上,也就是1024台机器 |
序列号 | 占用12bit,用来记录同一个毫秒内产生的不用id(每好眠能够删除4095个ID,不算全0) |
2. 是否可以做订单号?
UUID组成:时间序列、全局唯一的机器识别号、时间戳。
UUID:如果不考虑时钟回拨问题的基础上,可以做订单号,但是不能使用java.utild 的基于伪随机数的方法。而是采用基于时间的。任何基于随机数的方法都不能确保重复问题。
为什么不建议UUID做订单号? (1)很难区分先后时间,必须去看创建时间;(2)UUID一般生成以后都是一个36长度的字符串组成,必须用varchar类型存储,非常占空间;(3)对于B+Tree插入效率更低,因为mysql数据库都有事务性的要求,存储引擎多少InnoDB,存储数据使用的是B+Tree,B+Tree数据区是天然有序的,UUID不可控。
二、分布式锁
1.分布式锁应用场景?
场景 |
(1)系统是一个分布式系统/集群模式,仅靠Java的锁是锁不住的; |
(2)多个微服务共同操作一个共享资源,比如数据库中的唯一用户数据; |
(3)同步访问,即多个进程共同操作共享资源; |
(4)用分布式锁进行限流; |
2.实现分布式锁的方式?
方式 | 原理 | 优点 | 缺点 |
redis | (1)【lua】脚本(SETNX命令+expire键过期)+watch Dog机制+LUA(删除时判断锁是不是自己要删的那把) ①SETXN命令:全程【SET key value if Not exists】,当且仅当key不存在时,才会设置并返回true;如果设置不超过则返回false,然后进入循环请求状态,直到获取到锁(是否自旋可以自定义);【根据是否设置key成功判断是否获取锁成功】 ②expire键过期:SETNX必须设置国球时间,原因是为了防止redis在SET成功后,突然宕机了如果不设置键过去时间,那么这个key永远都存在,其它微服务永远获取不到分布式锁; ③watch Dog机制:保证成功获取到锁的微服务在没有执行结束前,一直保持持有分布式锁的状态;一旦expire达到过期时机,此时若系统还在执行,那么watch Dog就会帮助系统续上锁的过期时间; ④删除时判断锁:目的是确保删除的是自己持有的锁,防止误删了其它微服务的锁; (2)Redisson框架:提供了lock、unloc命令、分布式信号量等机制 | ①redis分布式锁完全基于内存,并发性能好,速度快; ②redis单线程IO多路复用,减少了多个线程在创建时的开销,避免不必要的上下文切换以及资源竞争导致的锁开销; ③redis提供了丰富的数据结构,全程hash操作,加锁释放锁速度快; ④redis基于LUA脚本等,确保加锁与释放锁的原子性。 | ①redis只保证最终一致性,集群模式(主写从读)下主从同步会有延迟,分布式锁有丢失的可能性,故强一致性的业务不推荐使用redis分布式锁,而是Zookeeper分布式锁。 |
Zookeeper | 前提:临时顺序节点: 1-顺序(规定这么获得锁):当多个客户端进行竞争分布式锁,每个客户端都会在某个和指定的唯一zk节点下创建一个临时顺序节点;这个节点是递增的,规定越早创建临时顺序节点的客户端能获取到锁(即节点序号最小的获得锁) 2-临时(规定怎么释放锁):当客户端与zookeeper集群断开连接时,临时顺序系欸但自动被删除(释放锁); 根据Zookeeper的临时顺序节点实现分布式锁 ① 客户端A连接到ZK,在指定的唯一节点下调用creat()方法创建名为"/业务ID/lock-"的临时顺序节点; ② 客户端A调用getChildren(“业务ID”)方法获取全部创建的临时顺序节点; ③ 客户端A获取到全部的临时顺序节点后,判断是否拿到了分布式锁: | ① Zookeeper集群是基于CP模式的,它基于Zookeeper原子播送歇息,支持自动恢复与原子播送,能够实现强一致性 ; | ① Zookeeper由于网络波动等,不能保证每次服务的可用性; ② 由于Zookeeper每次进行锁操作前都要创建若干节点,完成后还要删除节点,会浪费很多时间;在并发性能上不如redis,因为redis只是简单的数据内存存储删除操作; |
Mysql | 根据Mysql的主键id唯一性实现分布式锁 ①抢锁时,携带主键/唯一索引向表中插入数据; ②抢锁成功:若数据库中,待插入的主键id不存在,则插入成功; ③抢锁失败:若插入的数据所在主键id已经存在,那么插入失败; ④释放锁:即删除插入的那个主键id所在行的数据。 | 分布式锁实现简单,锁的获取与释放完全是MySQL在控制; | ① 若加上分布式锁后,事务执行过程中宕机,有死锁的风险; ② 没有锁过期时间,还是容易死锁; ③ 数据库若是单点操作,那么数据库一旦挂掉,整个业务系统都不可用; |
三、限流策略
方式 | 原理 | 缺点 |
计数器 | 在指定的时间周期内设定访问量阈值,比如一分钟,直到流量超过100次访问,那么就触发限流算法;待到下一个周期进行访问时,访问次数清零; | 不能处理短期内的大并发请求 |
滑窗 | 滑窗是计数器限流算法的升级版;计数器限流算法比如在周期的最后几秒和下一个周期的前几秒突然出现大规模访问,计数器算法是处理不了的;因此引入了滑窗限流法,时间周期不再固定,而是将原本的周期切分程多个小的时间窗口,分别维护每个小的时间窗口 | 计数器的进阶 |
漏桶 | 漏桶容量(访问阈值)=漏桶的流出速度(处理速度)✖可接受的等待时长 ①当请求速度小于漏桶的流出速度时,在漏桶容量范围内,可以按照漏桶的流出速度排队进行正常处理; ②当请求速度大于漏桶流出速度时,则触发限流策略; | 不能处理短期内的大并发请求 |
令牌桶 | 准备一个初始已经存放了一定数量令牌的容器,同时系统以恒定的速率向令牌桶中持续放入令牌; 客户端发送请求,要先取得令牌,拿到令牌才有资格访问系统;当令牌桶满的时候,新生成的令牌会被抛弃,不放入桶中; 由于令牌桶初始已经有了很多令牌,因此能够处理短时间内的大量请求 | 漏桶进阶 |
四、你设计微服务时遵循什么原则?
原则 | 描述 |
单一职责原则 | 每个微服务能独立、有界限的工作,只关注主键的业务,做到高内聚 |
服务自治原则 | 每个服务要独立开发,独立测试、独立构建、独立部署、独立运行,与其它微服务解耦 |
轻量级通信原则 | 每个微服务之间的调用是轻量级的,并且能够跨平台、跨语言;采用dubbo和restful风格,消息队列等进行通信 |
粒度进化原则 | 注意微服务粒度把控 |
五、分布式事务
1. 分布式理论
(1)CAP理论
CAP理论指的是:分区容错性(p)必须保证的前提下,一致性(C)和可用性(A)只能保证一个
A和C只能保证其一的原因:
如果保证了一致性(C),那么我们就要保证客户端在任意时刻,在任意一个节点读到的值都是一致的;而可用性(A)是允许部分节点故障时,集群还能继续响应,那么就无法保证故障节点非故障节点之间的一致性了;反过来也是一样的道理,因此A和P无法共存。
CAP原理 | 描述 |
一致性 (Consistency) | 在分布式系统中所有服务器节点中,在同一时刻都是同样的值; |
可用性 (Availability) | 在服务器集群中一部分节点故障后,集群整体还能继续响应客户端的读写请求; |
分区容错性 (Partition tolerance) | 在分布式系统中遇到任何网络分区故障,系统依然能对外提供服务; |
(2)BASE理论
BASE理论是CAP理论的延申,思想是:既然无法做到强一致性(CAP),那么就保证弱一致性,即最终一致性;
Base理论在秒杀系统中,可以结合消息队列使用;
BASE理论 | 描述 |
基本可用 (Basically Available) | 基本可用指的是分布式系统在出现故障时,允许损失部分可用性(例如响应时间、功能上的可用性) eg:秒杀系统中,当流量高峰时,为了保护系统的整体可用性,将部分消费者引导到一个降级页面; |
软状态 (Soft State) | 软状态是指的允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据会有多个副本,允许不同副本同步的延时就是软装他的体现 eg:用户支付后,第三方支付系统返回给订单系统的这段时间,给用户显示“支付中”; |
最终一致性 (Eventual Consistency) | 最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。 eg:用户取消订单后,发送MQ消息,经过一段时间后,库存回滚; |
(3)一致性理论
从客户端角度,多进程并发访问时,更新过的数据在不同进程如何获取的不同策略,决定了不同的一致性。
理论 | 描述 |
---|---|
强一致性 | 读写操作后,能立刻看到更新过的数据 |
弱一致性 | 能容忍部分或者全部数据看不到 |
最终一致性 | 经过一段时间后,能够看到更新后的数据 |
2.分布式事务解决方案
模式 | 特点 | 描述 |
---|---|---|
刚性事务 | 满足CP理论: 一致性与分区容错性 | ① XA协议 (2pc、JTA、JTS、3pc):由于同步阻塞,处理效率低,不适合大型网站分布式场景 |
柔性事务 | 满足AP(BASE)理论 :基本可用,最终一致 | ① TCC/FMT、Saga (状态机模式、Aop模式)、本地事务消息、消息事务 (半消息):结合业务改造,最终一致性,实现补偿接口,实现资源锁定接口,高并发,更适合长事务 |
3.刚性事务:XA协议
(1)XA规范
在XA规范中有三个角色:应用程序、事务管理器、资源管理器
角色 | 作用 |
---|---|
应用程序 | 业务层,定义哪些操作属于一个事务 |
事务管理器 | 接收【应用程序】的事务请求,对全局事务进行管理,管理事务分支状态,协调【资源管理器】处理,通知资源管理器哪些操作属于全局事务以及事务分支等 |
资源管理器 | 一般是数据库DB,也可以是消息队列MQ、文件系统等 |
<1>XA规范主要定义了全局的事务管理器和局部的资源管理器之间的接口。XA接口是双向的系统接口,在事务管理器以及一个或多个资源管理器之间形成通信桥梁。
<2>XA规范使用两阶段提交 (2pc) 协议来保证所有资源同时提交或回滚任何特定的事务;
<3>XA是数据库的分布式事务,保证强一致性(CP);在整个过程中,从prepare → commit → rollback的整个过程中,事务管理器一直把持着数据库的锁,如果有其他人要修改数据库的该条数据,就必须等待锁的释放,存在长事务风险;
(2)两阶段提交(2pc)
协调者: 全局事务管理器
参与者: 局部资源管理器
阶段 | 描述 |
阶段一:准备阶段 (投票阶段) | 1)事务询问: 协调者 (事务管理器) 向所有参与者发送事务内容,询问是否可以执行提交操作,并开始等待各参与者 (资源管理器) 进行响应; 2)执行事务: 各参与者节点,执行事务操作,并将信息写入undo log日志与redo log日志 (注意:若成功这里其实每个参与者都已经执行了事务操作); 3)各参与者向协调者反馈事务问询的响应: 成功执行返回Yes,否则返回No; |
阶段二:提交阶段 (执行阶段) | 1)提交事务:若所有参与者 (资源管理器) 均回复yes,那么执行事务提交操作; ① 发送请求: 协调者向所有的参与者发送Commit请求; ② 事务提交: 参与者收到Commit请求后,会正式的执行事务提交操作,并在完成提交操作之后,释放在整个事务执行期间占用的资源; ③ 反馈结果: 参与者在完成事务提交后,向协调者回复ACK消息; ④ 完成事务: 协调者收到全部参与者的提交ACK后,完成提交事务; 2)中断事务:若存在某一参与者向协调者发送No响应,或者等待超时;那么协调者就会中断事务; ① 发送回滚请求: 协调者向所有参与者发送rollback请求; ② 回滚: 参与者收到请求后,利用本地的undolog日志,执行rollback操作。并在回滚结束后释放该事务所占用的系统资源; ③ 反馈回滚结果: 参与者在完成回滚操作后,向协调者回复回滚ACK消息; ④ 中断事务: 协调者收到全部参与者的回滚ACK消息后,完成中断事务; |
2pc的缺点
缺点 |
① 同步阻塞导致并发性能不高: 本地事务 (参与者) 在全局事务 (事务管理器) 没 commit 或 callback前都是阻塞等待的,全局事务等待回复的时间由事务时间最长的那个本地事务决定; |
② 单点故障导致高可用问题: 由于协调者 (事务管理器) 是单点,一旦出现故障,每个参与者都无法释放事务资源,也无法完成事务提交; |
③ 丢失消息导致的数据不一致问题: 在2pc的第二阶段,协调者给所有参与者发送完Commit请求或者回滚请求后,出现网络崩溃,导致只有部分节点收到请求,并执行;此时整个分布式系统就会出现数据不一致现象; |
④ 过于保守: 2pc协议没有设计较为完善的容错机制,任意一个节点的失败都会导致整个事务的失败。 |
(3)三阶段提交(3pc)
3pc解决的问题
3pc解决的问题 | 不能解决的问题 |
---|---|
① 解决了协调者的单点故障,无法释放资源的问题: 针对2pc的同步阻塞与单点故障问题,3pc对于协调者与参与者都设置了超时时间,而2pc只有协调者才拥有超时机制;当进入第三阶段时,由于网络超时/网络分区等原因,如果第二阶段没有中断事务,虽然参与者没有收到commit或者abort响应,但是由于第二阶段的预提交所有参与者都回复了yes,他有理由相信:成功提交的几率很大; ② 由于解决了单点故障问题,从侧面上也降低了整个事务的组设时间与范围 | ① 3pc依然无法解决数据不一致问题: 最后一个阶段,由于网络问题等,部分参与者收到了协调者发送的doCommit请求或者rollback请求,有一部分没有收到,就会导致数据不一致现象; |
对协调者设置超时时间,避免了由于协调者单点故障情况下,导致无法释放资源的问题;由于3pc的CanCommit、PreCommit、DoCommit三个阶段的设计,相较于2PC而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。参与者自身的超时机制会在超时后,自动进行本地commit,从而释放资源;这种机制也侧面降低了整个事务的阻塞时间和范围;
-
但是
3pc依然无法解决数据不一致的问题;
阶段 | 描述 |
---|---|
阶段一 询问阶段 (CanCommit) | 1)事务询问: 协调者 (事务管理器) 向所有参与者发送包含事务内容的canCommit的请求,询问是否可以执行事务提交,并等待应答; 2)各参与者反馈事务询问: 正常情况下,如果参与者认为可以顺利执行事务,则返回Yes,否则返回No; 3)各参与者向协调者反馈事务问询的响应: 成功执行返回Yes,否则返回No; |
阶段二 PreCommit阶段 (执行阶段) | 1)执行事务预提交:若所有参与者 (资源管理器) 均回复yes,那么执行事务提交操作; ① 发送预提交请求: 协调者向所有节点发出PreCommit请求,并进入prepared阶段; ② 事务预提交: 参与者收到PreCommit请求后,会开始事务操作,并将Undo和Redo日志写入本机事务日志; ③ 反馈结果: 各参与者成功执行事务操作,同时将反馈以ACK响应形式发送给协调者,同时等待最终的Commit或Abort指令; 2)中断事务:若存在某一参与者向协调者发送No响应,或者等待超时;那么协调者就会中断事务; ① 发送中断请求: 协调者向所有参与者发送Abort请求; ② 中断事务: 无论是参与者收到协调者的Abort请求,还是参与者等待协调者请求过程中出现超时,参与者都会中断事务; |
阶段三 doCommit阶段 (最终提交/回滚阶段) | 1)执行事务提交:协调者在上一阶段收到全部参与者回复的ACK消息; ① 发送提交请求: 若协调者收到了全部参与者的ACK响应,那么就从预提交状态转换为提交状态,并向全部的参与者发送doCommit请求; ② 事务提交: 参与者收到doCommit请求后,会正式执行事务提交操作,并在完成提交操作后释放占用资源; ③ 反馈结果: 参与者将在完成事务提交后,向协调者发送ACK消息; ④ 完成事务: 协调者接收到所有参与者的Ack消息后,完成事务。 2)回滚事务:协调者接收到任一个参与者发送的No响应,或在超时时间内,仍旧没收到反馈消息,就会回滚事务: ① 发送中断请求: 协调者向所有的参与者发送rollback请求; ② 事务回滚: 参与者收到rollback请求后,会利用阶段二中的Undo消息执行事务回滚,并在完成回滚后释放占用资源; ③ 反馈结果: 参与者在完成回滚后向协调者发送Ack消息; ④ 完成事务: 协调者接收到所有参与者反馈的Ack消息后,完成事务回滚。 |
4.柔性事务:补偿型+通知型
柔性事务有两个特性:基本可用和柔性状态
①基本可用:是指分布式系统出现故障的时候允许损失一部分的可用性。
②柔性状态:是指允许系统存在中间状态,这个中间状态不会影响系统整体的可用性,比如数据库读写分离的主从同步延迟等。柔性事务的一致性指的是最终一致性。
类型 | 描述 |
补偿型(同步) | TCC(Try Confirm Commit) |
通知型(异步) | MQ事务消息、最大努力通知型 |
(1)通知型事务
通知类型 | 描述 | 实现 |
概念 | 通知型事务的主流实现是通过MQ(消息队列)来通知其它事务参与者自己事务的执行状态,引入MQ组件,有效的将事务参与者进行解耦,各参与者都可以异步执行,所以通知型事务又被称为异步事务; | MQ消息队列 |
使用场景 | 通知型事务主要适用于那么需要异步更新数据,并且对数据的实时性要求较低的场景 | ①异步确保型事务:主要适用于内部系统的数据最终一致性保障,因为内部相对比较可控,如订单和购物车、收获与清算、支付与结算等场景; ②最大努力通知:主要用于外部系统,因为外部的网络环节更加复杂和不可信,所以只能尽最大努力去通知实现数据最终一致性,比如充值平台和运营平台、支付 对接等等跨网络系统级别对接; |
①异步确保型事务(MQ)
指将一系列同步的事务操作修改为基于消息队列异步执行的操作,来避免分布式事务中同步阻塞带来的数据操作性能下降。
MQ事务消息方案
基于MQ的事务消息方案主要依靠MQ的版消息机制来实现投递消息和参与者自身本地事务的一致性保障。半消息机制实现原理其实是借鉴2pc的思路,是二阶段提交的广义拓展。
半消息:在原队列执行后的逻辑,如果后面的本地逻辑出错,则不发送消息,如果通过则MQ发送;
MQ实现通知型事务的流程
步骤 | 描述 |
---|---|
1. 生产者→MQ | 生产端首先发送半消息到MQ,MQ收到半消息后进行反馈,然后生产端开始执行本地事务; 定时回查事务状态: 如果在这个过程中生产端宕机或者超时,那么MQ服务器会循环的进行定时回查事务状态,确保MQ对这个半消息是需要提交给消费端还是直接丢弃; |
2. MQ→消费者 | 生产者根据本地事务的执行结果,向MQ发送commit或者是rollback消息 ① 如果消息是rollback,那么MQ就丢弃消息不进行投递; ② 如果是commit,那么MQ就会将消息发送给消费者; |
3. 消费者执行本地事务 | 消费者收到MQ的消息,执行本地事务; 消息确保消费机制: 消息消费成功与否主要是用MQ确保的 (比如消息确认机制、消息重试机制等) |
①最大努力通知
最大努力通知方案的目标,就是发起通知方通过一定的机制,最大努力将业务处理结果通知到接收方;
最大努力通知型的最终一致性:本质是通过引入定期检验机制实现最终一致性,对业务的侵入性较低,适合于最终一致性敏感度比较低、业务链路较短的场景。
MQ的ACK机制实现最大努力通知
最大努力通知事务的特性 |
① 消息重复通知机制: 消息发送方按照一定时间间隔的重复发送消息,直到接收消息的一方回复ACK; |
② 消息校对机制: 消息发送方要提供幂等性服务接口,提供给消息接收方进行查询,防止消息重复消费; |
(2)补偿型事务
TCC分布式事务
模块 | 描述 |
---|---|
Try 阶段 | 调用 Try 接口(自定义的prepare逻辑),尝试执行任务,完成所有业务检查,并锁定业务资源; 此阶段可以通过两个CC阶段来提交或回滚; |
Confirm阶段 | 对业务系统做确认提交,调用Confirm接口(自定义的commit逻辑),确认执行业务操作,不做业务检查,只使用Try阶段锁定的业务资源; TCC中添加了事务日志,如果此阶段操作失败,那么会根据事务日志进行重试,因此CC阶段需要 支持幂等性;如果重试失败,则需要人工介入进行恢复与处理; |
Cancel阶段 | 当业务执行错误,调用Cancel接口(自定义的rollback逻辑),需要回滚已执行的业务取消,释放锁定资源; 操作失败同样根据TCC事务日志进行重试处理; |
TCC方案的异常问题解决方案:
问题 | 描述 | 解决方案 |
---|---|---|
TCC空回滚问题 | TCC阶段异常没有执行成功,但是Cancel阶段的回滚操作却执行了 (对数据进行了修改),违反了一致性 | 解决问题的关键: ① 全局事务贯穿整个分布式事务调用链,额外增加一张分支事务记录表,其中记录着全局事务ID与分支事务ID; ② 在第一阶段的Try阶段若正常执行,则分支事务表进行记录;当Cancel阶段执行时,首先查询是否存在该全局事务ID对应的Try记录 (为了防止查询的时候没有Try记录,返回查询结果的时候又有Try记录了,此时可以用分布式锁),若有则正常回滚;否则不回滚; |
TCC幂等问题 | 如果Confirm阶段或者Concel阶段返回执行失败结果(其实已经执行成功,但是响应回去的是失败),此时会根据是否日志进行重试,为了防止多次Confirm或者Concel,因此CC阶段必须支持幂等性; | 具体解决方法: 全局事务日志 + 分支事务日志 在分支事务日志中添加一个Confirm与Concel执行状态的字段,重试执行Confirm或者Concel时,先查一下是否执行过;没执行过了就执行,执行过了就不再执行;(依然存在分布式问题,查询字段的时候没有执行,返回查询结果的时候有执行记录了,同样用分布式锁解决) |
TCC悬挂问题 | 分支事务Try阶段,由于网络发生拥堵,造成超时;此时达到超时时间后,分支事务执行Confirm或Concel,待到执行结束后,此时Try的网络阻塞解除,Try开始执行,那么此时预留资源就会卡住,无法进一步的再进行处理; | 具体解决方法: 全局事务日志 + 分支事务日志 在执行第一阶段Try时,首先查询分支事务日志是否有第二段记录,若有则不执行Try; |
六、幂等性的解决方案(token机制)
查询操作与删除操作本身就具备幂等性,无需处理
token机制 | |
对外提供的API如何保证幂等性 |
接口层面,保持接口访问的隐蔽性和有效性,保证接口只有可信任的来源才可以访问。 访问接口时,携带来源source标识与来源方seq序列号,这 两个字段在提供API访问接口的服务本地做联合索引;当第三方调用时,先在本系统中查询一下是否处理过;如果已处理,则返回响应的处理结果;如果没有处理过,则进行相应处理后再返回结果; |
用户层面如何保证幂等性 | $user_token = md5('用户的uid' + 'Unix时间戳' + '证书私钥') ① 数据提交前要向服务申请token,生成的token放到redis中,token设置有效时间; |
其它处理幂等性问题的方法:
方案 |
token机制 |
数据库唯一索引 |
分布式锁 |
乐观锁或悲观锁 |