分布式锁
分布式锁常规情况下都是使用redis来实现。很早以前,使用SETNX加过期命令进行设置,无法保证原子性。但随着时代的发展,redis已经支持一条指令(set指令)实现setnx加过期时间。
什么是线程不安全?
线程不安全指的是多个线程操作一个资源,期望值和获取到的数据不一致。
可能存在的问题
没有一种解决方案是银弹
- 在使用分布式锁的情况下,需要考虑如果一个线程获取到锁之后,如果业务处理产生了耗时操作,或者调用第三方接口超时,导致当前线程拿到的锁过期,这个时候,其他线程就会获取锁,然后进入业务处理方法,此时可能会出现线程不安全的情况。
- 解决方案:针对超时导致锁过期,其他线程进入的情况,可根据业务,设置一个合理的过期时间。或者自动续期。采用Redisson就可以实现自动续期
- 针对第一种情况,还存在如果第一个线程耗时,锁以及过期,线程2拿到了锁,但是这个时候,线程1执行完成了。这个时候,线程1就释放了线程2的锁
- 解决方案:给锁一个唯一标识,只有锁的唯一标识和当前线程设置的唯一标识对应上了才能删除。但是删除的时候需要先根据key获取到uuid。无法保证原子性。所以还得结合lua脚本保证原子性。
- 大量请求打击到redis服务上,导致redis服务崩溃。
- 解决方案:redis进行高可用配置,配置主从以及哨兵机制。但是这种解决方案也会存在锁失效的情况,就是如果主节点挂了,但是锁的状态还没同步到其他节点,就会出现其他线程可以获取锁的情况。redis的作者提示了redLock(红锁)但是这种解决方案似乎是存在问题,对于时钟问题比较敏感。如果要防止上面的问题,最终还是需要有一个兜底的方案,保证锁出问题的情况下,不会对数据的结果产生太大的问题。
谨记:一个分布式锁,在极端情况下,不一定是安全的。如果对数据很敏感,一定要有兜底的策略。当然,现在似乎人肉解决数据不一致的情况是比较常见的。
Redis常用操作类库Redisson
如果非必须,建议使用Redisson进行开发,多人开发的肯定比自己造轮子的强
但是也要理解原理