支付宝转账的分布式死锁问题

死锁

死锁的规范定义:集合中的每一个进程都在等待只能由本集合中的其他进程才能引发的事件,那么该组进程是死锁的。从广义上讲,这里的进程指的是一个执行单元。

问题描述

假设【账户A】给 【账户B】转账 500 元,在程序中的转账逻辑如下:

  1. 开启事务
  2. 【账户A】的余额减去 500 元
  3. 【账户B】的余额增加 500 元
  4. 提交事务

在集群环境下,在 server1、server2 服务上都部署了支付模块,在该环境下可能会出现如下的场景:

在 server1 上执行【账户A】给【账户B】转账 500 元;
在 server2 上执行【账户B】给【账户A】转账 500 元;
以上两个转账行为同时执行,那么在执行到转账逻辑的第三步的时候,server1 会请求对【账户B】进行加锁,server2 会请求对【账户A】进行加锁,由于此时的【账户A】已由 server1进行锁定,【账户B】已由 server2进行锁定,此时就会产生死锁问题。

解决方案

在并发编程中,我们经常遇到三个问题原子性问题、可见性问题、有序性问题。
通过上面的问题描述我们可以发现,在一个转账的过程中【账户A】、【账户B】的执行是有序的,但是在多个转账过程中【账户A】、【账户B】的执行是无序的。该问题类似并发编程的有序性问题,我们可以通过如下方式解决改问题:

在系统中对所有的账户进行排序:
【账户A】、【账户B】、【账户C】、【账户D】、【账户E】、【账户F】

在 server1 上执行【账户A】给【账户B】转账 500 元的逻辑:

  1. 开启事务
  2. 【账户A】的余额减去 500 元
  3. 【账户B】的余额增加 500 元
  4. 提交事务

在 server2 上执行【账户B】给【账户A】转账 500 元的逻辑:

  1. 开启事务
  2. 【账户A】的余额增加 500 元
  3. 【账户B】的余额减去 500 元
  4. 提交事务

将账户进行排序,保证转账过程中【账户A】始终先于【账户B】,这样就可以避免产生死锁问题。

解决方案有好多中,这里只提出我认为相对简单的一种方案,而且也是也在一线互联网公司广泛使用的一种方案。

死锁的预防方案

1.死锁预防 使引起死锁的必要条件不成立
– 资源排序,按资源序列申请
– 将所有并发事务排序,按标识符或者开始时间
– 有死锁危险的时候,事务退出已经占有的资源, 有两种方法:
等待-死亡: 重启较为年轻的事务, 较为年老的事务等待已经持有资源但是较为年轻的事务
受伤-等待: 年轻的等待年老的, 较年轻的重启,而重启事务并不一定是目前正在申请的事务

2.死锁检测
–检测死锁时循环等待的圈

以上为个人总结,如有不正之处,欢迎批评指正。

发布了54 篇原创文章 · 获赞 28 · 访问量 4220

猜你喜欢

转载自blog.csdn.net/qq_37174887/article/details/102936616