你的场景真的适合使用分布式锁吗?

最近面试很多候选人的时候,在以往的工作中都使用过分布式锁,问他使用场景,都是认为并发了,要使用分布式锁控制;接着问:为什么要选用分布式锁呢?很多候选人就不知道该从何说起,这也表明了对技术的前期选型并没有思考,盲目的使用技术;

关于分布式锁的文章我也写了很多篇了,都是自己工作中遇到的或者是和公司大佬讨论的结晶(当然,如果有错误的地方欢迎大佬评论纠正):
1. redis实现分布式锁踩坑记录
2. Redisson分布式锁——踩坑记录
3. Redis分布式锁与Zk分布式锁的详解与选型
4. zookeeper使用过程中需要注意的坑

1. 分布式锁是为分布式而准备的

很多候选人对自己系统部署情况不太了解,也不知道自己的项目到底是集群部署还是单机。相信有些程序员面临的还是有单机部署的情况;

首先排除一个问题就是:单机没有必要使用分布式锁,单机使用JDK提供的Lock或者synchronized完全可以解决并发问题;

有些候选人认为分布式系统/集群部署,使用分布式锁是正确的选择;这句话,对,也不对;

2. 分布式系统并发非分布式锁不可吗?

先来举个例子:
需求:比如你正确做一个库存管理,库存表t_stock有个字段:num 保存库存数量;
部署:集群部署;
如果此需求交到你手里,你该怎么去实现?

程序员tom 实现思路:
在这里插入图片描述

程序员jack 实现思路:
在这里插入图片描述

是不是有小伙伴认为jack的实现方案在分布式系统中会存在问题;

解释一下为什么jack的方案无论是集群还是分布式系统都不会存在扣减错误问题呢?
其实这种实现方式是将并发控制交给了数据库事务去处理,比如:线程A在更新库存时id=1的库存记录会加记录锁,线程B再想更新时,需要阻塞等待线程A提交/回滚后才能继续;

合适场景:

  1. 数据库访问压力不大;(因为是将锁的控制交给了数据库去控制,如果量大会造成数据库性能问题)
  2. 扣减库存逻辑简单,没有复杂的计算;
  3. 未分库/分表,如果有分库分表,更新的逻辑只对单行进行更新也没有问题;

把这些搞明白了,以后再选型是否要用分布式锁就明了了;

3. 项目中的分布式锁被我删掉了

3.1 现流程

在我的项目中有一种场景,扣减库存的,现有逻辑如下:
在这里插入图片描述

这里说明一下扣减库存和生成出入库流水记录的逻辑:

  1. 查询现有库存情况;
    result: select num,occupancy from t_stock where id = 1; – num库存量,occupancy库存占用量,先占用,处理完后再减占用;

  2. 更新库存;
    result.setNum(result.num+1);
    result.setOccupancy(result.occupancy+1);

    update t_stock set num = result.num,occupancy=result.occupancy where id = 1;

  3. 生成出入库明细
    insert into t_inoutstock values(x,x,x,result.num,result.occupancy);

存在的问题:
因为更新库存并非原子操作,需要先查询,基于查询的值再更新,然后再生成出入库明细;
那问题出在哪呢?
线程A:更新调拨出库库存(库存id=1)之后,锁释放,开始执行调拨入库单的时候,此时线程B更新库存id=1的记录时,可以获取锁,因为线程A已经把更新库存id=1的锁释放,但由于线程A事务未提交,造成事务B查询的库存值为旧值,那么更新下去值也成为了旧值;

3.2 新流程

在这里插入图片描述

更新之后的扣减库存流程:

  1. 更新库存;
    update t_stock set num = num -1,occupancy=occupancy+1 where id = 1;
  2. 查询库存;
    result: select num,occupancy from t_stock where id = 1;
  3. 生成出入库明细
    insert into t_inoutstock values(x,x,x,result.num,result.occupancy);

为什么把分布式的控制给删除掉了?

  1. 并发量不是特别大,数据库能够承受;
  2. 因为更新库存进来之后,是先更新库存,再查询,这样可以保证后面的查询一定是准确的;

有的同学就想说了,那万一线程A更新后查询时,线程B更新了同一条库存了呢?这个可以放心因为此时线程A的事务并未提交,线程B更新库存时,一定会阻塞;

所以,大家在选择技术的时候,不要觉得非得使用上一些非常高大尚的技术才会显得很厉害,真正能把业务控制住才算真正的成功;

4. 补充

  • 2021-01-08 补充

在项目中之前使用的分布式锁封装了一些SDK供其他item使用时,反馈的一些不同场景下的问题,我在第3节中讲到的这些,有一种场景不太适合:
在这里插入图片描述
在这种场景下,stocklocation+stockNo虽然标识唯一性,但是由于加了删除标识,就没有办法在创建唯一索引,此时,此场景用第3节中的去除分布式锁就不太合适;这里提示一下,以免误人子弟;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值