关于后端接口(幂等性?防并发?)的问题

2019-10-28 14:51:59 +08:00
 HonoSV

菜鸟最近遇到一种场景,有点想不明白如何处理:

设计一个接口从账户 A 转账到账户 B,一次只能有一笔没走完的流水(中间流程很长)。

如何防止同一个账户( A )在同一时间重复提交多笔流水呢?

目前我能想到的解决方法就是加锁,但是效率低下。

求问一下 V 站大佬,这种场景一般如何解决呢?

2908 次点击
所在节点    程序员
13 条回复
lihongjie0209
2019-10-28 14:56:24 +08:00
需求就是一个账户只能有一笔流水, 为什么会效率低呢? 你难道用的是全局锁?
HonoSV
2019-10-28 14:59:51 +08:00
@lihongjie0209 哈哈,是全局锁
opengps
2019-10-28 14:59:54 +08:00
冒充一下大牛回答下:提交方做提交标识,后端用标识做幂等性校验。( https://www.opengps.cn/Blog/View.aspx?id=426 ,欢迎点评 )
要求标识需要:
前端处理到位:一个页面,不返回成功怎么提交都是同一个标识。处理成功则刷新标识
后端处理到位:对处理的标识,加锁防止并发争用,同一个标识只执行一次,多次提交返回相同结果
evoluc
2019-10-28 15:05:54 +08:00
这个用个乐观锁?
baiyi
2019-10-28 15:10:48 +08:00
转账这个操作在接口设计上肯定不是幂等的,可以用 3 楼说的,client_token 做校验
wangyzj
2019-10-28 15:11:11 +08:00
tcc
lihongjie0209
2019-10-28 15:18:21 +08:00
@HonoSV #2 那你把锁缩小到账户就好了, 每个账户持有一把锁
luozic
2019-10-28 15:23:29 +08:00
这个你可以看系统线程调度同步的那个思想,信号量和互斥锁,至于这个具体实现可以前后端也可以纯后端。
polythene
2019-10-28 15:27:18 +08:00
幂等的最简单的一个方法就是为每个请求 /交易创建一个 ID,在真正执行前检查一下
laminux29
2019-10-28 16:05:29 +08:00
你的这个需求,可以通过分发唯一 Tick ( ID,或 uint64 )来解决,也就是每一笔账单、每一个处理环节,都会有一个唯一的 Tick,这样账单与处理就不会出错了。

接着,性能压力,也转移到 Tick 组件。

最后,Tick 组件这一块又有非常成熟的方法来处理性能问题。比如提前生成、批量分发等等。
crclz
2019-10-28 22:08:37 +08:00
这跟幂等没啥关系。
加应用锁(有业务意义的锁),具体实现可以是分布式锁,用来锁住某个人的某个业务。例如 key="user:66 category=transfer-money"。也可以是对关系型数据库里面的某条记录加 X 锁(独占锁),例如新建一个专门加锁的表。

如果这个转账是多阶段的、多个事务的,那么就应该将数据库里面某个字段作为标志位,在第一个事务里面将标志位设为 1,在最后一个事务结束后设置为 0。其他笔转账想要开启第一个事务的话,首先检测标志位是否为 0,如果不为 0,则表明有一笔处理中的转账。
加锁效率不低。因为没有锁住热点数据,没有争用。
OldCarMan
2019-10-29 02:43:58 +08:00
11 楼正解。
dany813
2019-10-29 11:02:03 +08:00
每个请求带个 request_id ?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/613668

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX