幂等是浅谈幂等分布式系统中保证数据一致性和安全性的重要保障之一,尤其是大家都在金融、支付领域,明白其作为资损防控的浅谈幂等硬性指标体现在系统架构设计中。今天我们就来浅谈一下幂等相关的大家都设计。
幂等( idempotent、idempotence )的概念来源于数学,并被广泛应用于计算机科学。在数学中,其语意是 f ( x ) = f ( f ( x )),比如求取绝对值,abs ( x ) = abs ( abs ( x )),就是幂等的。
在计算机科学中,幂等即相同的请求调用一次和调用多次,服务端处理的的结果相同,并且最多受理一次。
我们就拿支付公司的资金调拨举个例子。一般的,第三方支付公司需要借助清算公司(如网联)提供的支付通道进行备付金账户资金调拨,以保证资金池充足可用。当第三方支付公司发起资金调拨请求时,如果清算公司的返回结果丢失,这时,支付公司是否可以重试?如果重试,是否会发生资金的重复调拨?
互联网公司的应用间存在物理边界,请求和响应信息会通过网络进行传递。我们说远程调用的结果会有三个状态:成功,失败,未知。前两者都是明确的状态,而未知具有不确定性,一般都是由网络超时、丢包引起的。如上例中,如果出现了超时,其实有两种方案,我们可以建立查询补偿机制,来研判是否要重新发起资金调拨。或者,清算公司做好幂等控制,支付公司可以无脑重试,既可以保证资金调拨业务的正常,又能保证不会发生多次调拨。
在架构设计中,幂等的应用面非常广泛,比如 MQ 规避重复消费、表单规避重复提交等。
幂等包含两大要素,幂等标记和关键请求参数。
幂等号:它对应服务端的唯一约束,在设计上,它一般由上游的幂等单号和来源组成。服务端的接口文档中,需要明确指出幂等号的信息组成,它的作用是对请求信息进行身份标识,相同幂等号的请求将被服务端识别为同一请求。
关键请求信息:接收的核心业务信息,常见的如收款账户、打款账户,打款金额、币种、商品数量等等。相同的请求中,调用方需要保证关键请求信息不变,一旦信息发生变动,则需要替换幂等号。
调用方需要保证幂等号不重复,且对同一业务单据的同一次操作,无论请求多少次,都要保证幂等号不变。
幂等号重复,原因基本如下
幂等号变化,原因基本如下
当服务端没有返回结果时,调用方关键业务请求参数不允许变更。
初次请求,由于网络异常导致 timeout 调用方没有拿到结果,而服务端受理成功。客户端修改单据金额,请求信息发生变化,调用方与服务端处理出错。
img
幂等号不持久化,对于异步回执处理,上下游数据稽核带来困难,所以幂等号持久化是一个基本要求。
RPC 调用,调用方的幂等号,是内存中根据业务映射拼接得来,不做持久化。
//内存中拼接幂等号request.setRequestId(BizTypeEnum.getPrefix(×xxDO.getBizType()) + xxxDO.getId()):
transactionTemplate.execute (status -> //生成流水号 xxx SerialDO serialDO = buildSerialDO(); //播入 aaa 表 serialDAO.insert(serialDO); someDAO.update (someDO) ; // dubbo 调用 rpc,流水号 xxxId 作为幂等号 invokeRpc(request); return true,));
transactionTemplate.execute (status -> //生成流水号 xxx SerialDO serialDO = buildSerialDO(); //播入 aaa 表 serialDAO.insert(serialDO); someDAO.update (someDO) ; return true;));// dubbo 调用 rpc,流水号 xxxId 作为幂等号invokeRpc(request);
/*** 外层已开启事务*/public static void execute (){ //更新单据状态 Runnable runnable = () -> { response = dubboService.call(request); }; register(runnable);} public static void register (Runnable runnable) { if (TransactionSynchronizationManager.isActualTrangactionActive()) { TransactionSynchronizationManager.registersynchronization( new TransactionSynchronizationAdapter() { @Override public void afterCommit () { runnable.run(); } } ); } else { LOGGER.debug( "No active transaction."); runnable.run(); }}
分布式下并发场景,并不能单纯的依赖查询做到插入 幂等。常见唯一性保障方式:
RPC 调用超时,本地事务回滚。下次重试,会生成新的幂等号,导致资损。
针对相同请求,不论调用方请求多少次,服务端仅受理一次,且受理结果相同。
售中退款的场景中,第一次服务端正常受理调用方请求,但调用方因为超时丢弃响应;当第二次调用方重试,服务端发现退款金额不足,返回受理失败,导致故障。
//1、基本校验//2、悲观锁内,可退款金额判断;Assert.isTrue(refundable(xxx), "cannot refund");//3、逻辑处理try { process(xxx);} catch (Exception e) { //幂等判断处理}
客户端收到服务端结果后,本着不信任的原则,针对关键业务请求参数如账户、 金额同服务端受理内容对比。
服务端做幂等判断时,只看幂等号,虽然第二次请求幂等号不变,但是金额又可能被篡改,如果服务端直接返回成功,将导致资金损失。
以上规则是借鉴历史项目和互联网经验总结而成,主要侧重于幂等设计的原则,幂等的落地方案有很多,比如幂等表、乐观锁、悲观锁等,这里就不赘述。
责任编辑:武晓燕 来源: 政采云技术 幂等计算机系统(责任编辑:焦点)
荣盛发展大股东质押公司7599万股股份 占公司总股本比例的1.75%