前言
首先说一下业务场景:我们系统中的视频全部存储在第三方的云平台上,我们需要调用其接口来对视频进行操作。由于第三方平台的原因,这个操作可能存在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会报错,以此来表示操作超时。