记一次工作中遇到的类并发的问题

时间:2021-07-25 04:12:33

前言

  首先说一下业务场景:我们系统中的视频全部存储在第三方的云平台上,我们需要调用其接口来对视频进行操作。由于第三方平台的原因,这个操作可能存在0-30秒的延迟,在这期间如果有其他请求对这个视频进行操作就会出现并发问题(一个视频只允许操作一次)。

  其实这个问题算不上真正的并发问题,不过其类似于并发,所以我把它叫做类并发问题。

解决方案

    系统是一个分布式系统,所以传统的使用同步队列等同步操作无法使用,所以采用分布式锁解决该问题。分布式锁的实现方式一般有三种:1. 基于数据库的锁;2. 基于Redis的锁;3. 基于ZK的锁。

  关于分布式锁的介绍后续我会写一篇博文,这里由于业务逻辑不需要非常高的可靠性,因为其本身并发量并不高,所以采用最简单的基于数据库的锁。

  数据库锁是利用了数据库的唯一索引,当收到请求时,会把往数据库插入一条数据,如果插入成功则表示获取锁成功,否则失败。流程图如下:

记一次工作中遇到的类并发的问题

  核心加锁步骤如下:

     1. 首先收到用户请求之后会用向数据库insert一条数据,来获取锁,如果获取成功则表示该视频是第一次操作,开始操作。

    2. 如果获取锁失败则判断操作是否超时,如果超时则会重新对该视频进行一次操作,未超时则不作任何处理。

  PS:这里引入超时的原因是因为如果视频正在被操作,这时候服务器崩了,这样当用户第二次请求操作这个视频时可以重启操作。

  上面两个判断其实使用一条SQL即可完成:

INSERT INTO lock_table(video_id, STATUS, overtime)
VALUES
    (#{videoId},#{status},#{overtime})
WHERE
    NOT EXISTS (
        SELECT
            1
        FROM
            lock_table
        WHERE
            video_id = #{videoId}
        AND CURRENT_TIMESTAMP () < overtime
    )

  当第一次操作该视频时where条件返回true可以正常获取锁,当第二次操作该视频且操作未超时,则where条件返回false,当第二次操作该视频且操作超时,where条件返回true但是SQL会报错,以此来表示操作超时。