1、RocketMQ的事务消息是如何实现的?
1、消息生产者发送事务消息,属于半消息,这里的半消息指的不是半消息,而是消费者不可见的消息。(同步发送的)
2、消息中间件收到生产者的信息后,会回调生产者,使生产者调用本地的事务方法。
3、本地事务需要返回执行结果给消息中间件。
4、消息中间件接收到本地事务的执行结果后,再决定如何处理半消息。如果收到的是commit,就把半消息转换为完整消息,然后对消费者可见,如果收到的是rollback,就把半消息删除掉。
5、消息中间件对于长时间未处理的半消息进行回查本地事务的执行结果进行下一步的处理。
2、支付过程中如何保证支付参数不被篡改?
下面以支付宝支付为例
使用可逆的非对称算法RSA,具体过程如下:
1、把支付过程中的参数转为JSON字符串,使用应用的私钥对JSON字符串进行加密,得到密文(签名),随着请求一并传递。
2、支付宝会获取到所有的参数,将密文使用应用的公钥进行解密,得到明文,和传递过来的参数进行对比。
3、支付宝会回调接口,使用支付宝的私钥对参数进行加密,需要在应用程序中配置支付宝的公钥,对密文进行解密操作。
4、如果这几个对的过程,返回的都是true,那么参数就没有被篡改,如果返回false,就说明参数被篡改了。
3、项目中的幂等性是怎么做的?
1、使用状态机。就是在数据库语句后面添加一个状态条件,当我们想要去修改数据的时候就必须去判断是否在当前状态中,如果状态被修改过了,其他线程再进来想修改状态,就修改不了了。(注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助 )
2、使用流水表。把操作过的数据存入一张流水表中,利用数据表的id唯一特性,只能修改,不能插入相同id的内容,从而解决幂等性操作。
3、token机制,防止页面重复提交。
业务要求:
页面的数据只能被点击提交一次
发生原因: 由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交
解决办法: 集群环境:采用token加redis(redis单线程的,处理需要排队) 单JVM环境:采用token加redis或token加jvm内存
处理流程:
数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间
提交后后台校验token,同时删除token,生成新的token返回
token特点: 要申请,一次有效性,可以限流
注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用
4、支付过程付款了,但是订单状态没有发生改变,该如何解决?
1、我们在项目中是没有出现过这个问题的,因为支付宝有回调,在25个小时内会回调8次。
2、回调逻辑有问题的话,我们可以使用人工手段,通过调用交易查询接口,客服确认交易状态,会进行人工的补单。
5、简述分布式事务出现的场景,如何解决分布式事务?
一、场景:
1.不同服务器上的服务访问同一数据库或不同服务器的服务访问不同的数据库--->涉及跨JVM进程产生分布式事务
2.单体系统访问多个数据库-->跨数据库实例产生分布式事务
二、解决办法
1.使用2PC。2pc指的是两阶段提交协议,将整个事务流程分为两个阶段:p-->准备阶段,c-->提交阶段,具体的落地方案使用XA方案:执行流程如下:
1.应用程序(AP)持有用户库和积分库两个数据源
2.AP通过TM(事务管理器)通知用户库RM新增用户,同时通知积分库RM为该用户新增积分,RM此时并未提交事务,此时用户和积分资源锁定
3.TM收到执行回复,只要有一方失败则分别向其他RM发起回滚事务,回滚完毕,资源锁释放
4.TM收到执行回复,全部成功,此时向所有RM发起提交事务,提交完毕,资源锁释放优点:提高了数据一致性的概率,实现成本较低
缺点:单点问题:事务协调者宕机
同步阻塞:延迟了提交时间,加长了资源阻塞时间
数据不一致:提交第二阶段,依然存在commit结果未知的情况,有可能导致数据不一致
2、使用可靠消息机制(常用)。是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致
3、使用TCC(代码侵入非常强,不建议使用)。
TCC是Try,Confirm,Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try,确认Confirm,撤销Cancel.Try操作做业务检查及资源预留,Confirm做业务确认操作,Cancel实现一个与Try相反的操作即回滚操作.
TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作,
若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel操作若执行失败,TM将会重试(节选分布式事务及各场景解决方案_DZT_BOSS的博客-CSDN博客_需要分布式事务的场景)
4、使用seata-AT模式
Seata-AT模式的执行流程如下:
A服务的TM向TC申请开启一个全局事务,TC就会创建一个全局事务并返回一个唯一的XID
A服务的RM向TC注册分支事务,并及其纳入XID对应全局事务的管辖
A服务执行分支事务,向数据库做操作4. A服务开始远程调用B服务,此时XID会在微服务的调用链上传播
B服务的RM向TC注册分支事务,并将其纳入XID对应的全局事务的管辖
B服务执行分支事务,向数据库做操作
全局事务调用链处理完毕,TM根据有无异常向TC发起全局事务的提交或者回滚
TC协调其管辖之下的所有分支事务, 决定是否回滚
Seata-AT模式实现2PC与传统2PC的差别:
架构层次方面,传统2PC方案的 RM 实际上是在数据库层,RM本质上就是数据库自身,通过XA协议实现,而 Seata的RM是以jar包的形式作为中间件层部署在应用程序这一侧的。
两阶段提交方面,传统2PC无论第二阶段的决议是commit还是rollback,事务性资源的锁都要保持到Phase2完成才释放。而Seata的做法是在Phase1 就将本地事务提交,这样就可以省去Phase2持锁的时间,整体提高效率。
AT模式代码实现:
1.分布式事务发起方只需要贴
@GlobalTransactional
注解即可2.分支分布式事务贴上
@Transactional
即可