就是最近做开机视频,最近出现的一个问题就是因为视频转码是调别的部门的转码接口,我们部门把我们机器上的视频推过去之后,等视频部门转码之后会回调我们的接口,把转码后的视频地址
推送给我们,推送我们的时候,我们就把视频下载到自己的cdn服务器上,然后更新表数据,最近在监控视频转码接口的log日志会发现如果转码很快的话会在同一秒回调我们两次接口,因为视频转码那边
是第一次发的是低频,第二次发的是高频,而且建议我们这边使用第二次推送的链接,所以如果我们这边推送的视频多的话会导致我们这边一直在更新数据库,因此也可能发生并发的情况,之前出现过一次
这种情况,在代码逻辑没问题的情况下,我们这边查看了binlog日志,查找为什么已经更新过的字段又在第二次被更新了回去,后来会发现回调我们接口的时候是同一秒,因为读取和保存状态这两个操作不是原子的(所谓院子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何context switch线程切换)因此,我们这边的除了加报警日志外,在修改表的那段代码中也加了redis的分布式锁
针对redis的分布式锁,很多地方都会用分布式锁来限制程序的并发执行,分布式锁本质就是在redis里面占一个位置,当别的进程也来执行这段代码的时候,发现已经有人抢占了,只好放弃或者稍后再试
占坑一般使用setnx(set if not exists)指令,只允许一个客户端占用,先来先占,用完了再调用del指令释放,但是有个问题就是如果逻辑执行到中间出现异常,del指令没有调用就形成死锁,于是我们拿到锁之后加一个过期时间,比如5s,即使中间出现问题也会保证5s后自动释放,但是以上逻辑还是有问题,如果在setnx和expir之间服务器进程突然挂掉啦,也会形成死锁,其实这种问题的根源就在于setnx和expire是两条指令而不是原子指令,如果这两条指令可以一起执行就不会有问题,于是redis2.8版本作者加入啦set指令的扩展参数,使得setnx和expire指令可以一起执行,彻底解决了分布式锁的乱象
set key value true ex 5 nx
即set key value [EX seconds] [PX milliseconds] [NX|XX]
以上明亮就是setnx和expire组合在一起的原子指令。
以上这块技术就非常适应我这块业务需求,我也争取多学习,在业务需要的时候都用明白。