菜鸟最近遇到一种场景,有点想不明白如何处理:
设计一个接口从账户 A 转账到账户 B,一次只能有一笔没走完的流水(中间流程很长)。
如何防止同一个账户( A )在同一时间重复提交多笔流水呢?
目前我能想到的解决方法就是加锁,但是效率低下。
求问一下 V 站大佬,这种场景一般如何解决呢?
1
lihongjie0209 2019-10-28 14:56:24 +08:00
需求就是一个账户只能有一笔流水, 为什么会效率低呢? 你难道用的是全局锁?
|
2
HonoSV OP @lihongjie0209 哈哈,是全局锁
|
3
opengps 2019-10-28 14:59:54 +08:00
冒充一下大牛回答下:提交方做提交标识,后端用标识做幂等性校验。( https://www.opengps.cn/Blog/View.aspx?id=426 ,欢迎点评 )
要求标识需要: 前端处理到位:一个页面,不返回成功怎么提交都是同一个标识。处理成功则刷新标识 后端处理到位:对处理的标识,加锁防止并发争用,同一个标识只执行一次,多次提交返回相同结果 |
4
evoluc 2019-10-28 15:05:54 +08:00
这个用个乐观锁?
|
5
baiyi 2019-10-28 15:10:48 +08:00
转账这个操作在接口设计上肯定不是幂等的,可以用 3 楼说的,client_token 做校验
|
6
wangyzj 2019-10-28 15:11:11 +08:00
tcc
|
7
lihongjie0209 2019-10-28 15:18:21 +08:00
@HonoSV #2 那你把锁缩小到账户就好了, 每个账户持有一把锁
|
8
luozic 2019-10-28 15:23:29 +08:00
这个你可以看系统线程调度同步的那个思想,信号量和互斥锁,至于这个具体实现可以前后端也可以纯后端。
|
9
polythene 2019-10-28 15:27:18 +08:00
幂等的最简单的一个方法就是为每个请求 /交易创建一个 ID,在真正执行前检查一下
|
10
laminux29 2019-10-28 16:05:29 +08:00
你的这个需求,可以通过分发唯一 Tick ( ID,或 uint64 )来解决,也就是每一笔账单、每一个处理环节,都会有一个唯一的 Tick,这样账单与处理就不会出错了。
接着,性能压力,也转移到 Tick 组件。 最后,Tick 组件这一块又有非常成熟的方法来处理性能问题。比如提前生成、批量分发等等。 |
11
crclz 2019-10-28 22:08:37 +08:00
这跟幂等没啥关系。
加应用锁(有业务意义的锁),具体实现可以是分布式锁,用来锁住某个人的某个业务。例如 key="user:66 category=transfer-money"。也可以是对关系型数据库里面的某条记录加 X 锁(独占锁),例如新建一个专门加锁的表。 如果这个转账是多阶段的、多个事务的,那么就应该将数据库里面某个字段作为标志位,在第一个事务里面将标志位设为 1,在最后一个事务结束后设置为 0。其他笔转账想要开启第一个事务的话,首先检测标志位是否为 0,如果不为 0,则表明有一笔处理中的转账。 加锁效率不低。因为没有锁住热点数据,没有争用。 |
12
OldCarMan 2019-10-29 02:43:58 +08:00
11 楼正解。
|
13
dany813 2019-10-29 11:02:03 +08:00
每个请求带个 request_id ?
|