前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >可重入分析

可重入分析

作者头像
devi
发布2021-11-03 14:37:53
7310
发布2021-11-03 14:37:53
举报
文章被收录于专栏:搬砖记录搬砖记录

可重入分析

引言: 微服务中,网络调用随处可见,也带来了很多问题,对于底层搬砖程序员,最明显的影响就似乎分布式事务、网络波动异常等。接口可重入以及接口无状态往往是解决这些问题的关键。

1. 什么是“可重入”

一般情况下,可重入指的是接口(函数)可以重复调用且不发生异常。 个人认为,与幂等相比,可重入是一个业务概念。

幂等指的是相同输入必定有相同输出,而可重入不一定要保证每次都是相同输出,只要保证逻辑正确即可。

比如登录接口,第一次登录成功后进行重复登录,若返回“登录成功”此时是幂等的(也是可重入的),若返回“您已登录”此时是可重入的但非幂等。

个人觉得没必要纠结幂等与可重入的概念细节差异。

注:重入问题和不可重入问题和可重入问题,都是同一个问题,都是指:可能存在不可重入的情况,但是想要保证可重入。

2. 可能出现重入问题的接口

非幂等接口必定存在重入问题,但该粒度不是本文分析重点。

2.1 单个网络调用

单个网络调用也会发生不可重入问题,这是极其容易被忽视的情况。

举一个简单的例子,以mysql为例。

需求:给张三的余额增加10元,并记录流水。 分析:两条数据变动,需要使用事务,没有其他复杂逻辑。 SQL语句1:update t_account set balance=balance+10 where user_name='张三'; SQL语句2:insert into t_balance_detail values('张三', '+10');

问题:如果给mysql发送了udpate请求,但mysql长时间未返回,直到触发超时异常,这时候,无法确定这10元是否增加,且无法重入进行补偿。

解决:前端传入一个seq_id(其实就是订单号),专门用于解决重入问题。 假设seq_id=‘SEQ’: SQL语句1:select count(*) from t_account where seq_id='SEQ' 若结果不为零,说明已经执行过,直接返回成功。 SQL语句2:update t_account set balance=balance+10 where user_name='张三'; SQL语句3:insert into t_balance_detail values('张三', '+10', 'SEQ');

(SQL语句1也可以略去,改成有条件插入,若存在相同seq_id的,则取消本次事务)。

2.2 多段网络调用

假设需求依旧是“给张三的余额增加10元,并记录流水”,但是流水和余额不在同一个库里面,且无法使用分布式事务。 那么执行流程如下: 方式一: 1.给张三的余额增加10元 2.记录流水 方式二 1.记录流水 2.给张三的余额增加10元

对于方式一,显然,如果1成功但是2失败了,就陷入了数据不一致的困境。

但是,使用方式二,当1成功但是2失败了,这时候seq_id也没用了,我们发现seq_id存在,但是实际上余额并没有加上。

上述问题看似无解,且实际上,光靠该系统本身,确实是无解的,必须引入其他解决方案。

简单且常用的方案就是对账,定期检查流水与余额,若不一致,则告警人工接入(或者以流水为准触发自动充值)。 上述方案时延较长,对于充值这种实时业务不友好。

其次就是引入分布式事务(可参考网上方案)。

2.3 有状态接口

有状态接口可分为“内存有状态接口”和“持久化有状态接口”。 内存有状态接口指的是状态保存在内存中,比如类的静态属性。 持久化有状态接口指的是状态保存在外部存储中,比如mysql中存着订单付款状态。

异常示例: 接口状态流转为0->1->2->0,期望状态是调用完一次之后,状态回到0,但是如果执行到中间时发生异常,导致状态没有扭转,会影响后续调用。

假设1状态转为2状态时crush,重入时,会重新执行1->2的逻辑,这时候需要保证1->2之间的逻辑时可重入的。

3. 可重入保证的关键场景

1.发生异常后重试(链路未执行完毕) 2.正常情况下的重复调用(链路已执行完毕)

4. 可重入的判断依据

“可重入”的判断,难以覆盖全面且完全正确,因为有些“重入”是纯业务的概念,比如“给张三增加10元”,假如改成“记录一次点击事件”,那么无论mysql是否返回,其实不影响重入业务。

理论上,程序的任何一步都可能crush,因此,只要存在数据变更的接口,就可能存在重入问题

对于必定发生的情况,此处做了罗列。

必定可重入: 无数据变更(幂等接口)必定可重入

必定不可重入: 存在多段网络调用进行数据变更的接口,前段逻辑的返回值受数据变化影响,且该数据会被当前接口修改(重入时可能出现后段逻辑不可达的情况)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-11-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 可重入分析
  • 1. 什么是“可重入”
  • 2. 可能出现重入问题的接口
    • 2.1 单个网络调用
      • 2.2 多段网络调用
        • 2.3 有状态接口
        • 3. 可重入保证的关键场景
        • 4. 可重入的判断依据
        相关产品与服务
        云数据库 SQL Server
        腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档