目录
问题:setnx刚好获取到锁,业务逻辑出现异常,导致锁无法释放
分布式环境下,怎么保证线程安全 – 一中晴哥威武 – 博客园
分布式集群中的线程安全问题
相比于单一部署的服务器来说,分布式架构同一个模块的系统部署了多台;对于单一服务来说,只要保证一台机器上的对于共享资源的访问是同步进行的就能保证线程安全了;
但是对于分布式系统而已,保证一台服务器的同步,并不能保证访问共享资源是同步的;
比如机器A里面采用了锁的方式进行数据的读写,机器B也是,但是它们锁住的对象不相同,导致线程不安全。
所以可以考虑使用分布式锁的方式来保证分布式中的线程的安全线,这样不同的服务不同的线程通过竞争分布式锁来获取共享资源的操作权限;
例如redis的分布式锁、zookeeper锁,都可以作为分布式线程安全的手段。
解决方法
串行化
有的时候可以通过串行化可能产生并发问题操作,牺牲性能和扩展性,来满足对数据一致性的要求。比如分布式消息系统就没法保证消息的有序性,但可以通过变分布式消息系统为单一系统就可以保证消息的有序性了。另外,当接收方没法处理调用有序性,可以通过一个队列先把调用信息缓存起来,然后再串行地处理这些调用。
分布式锁
为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
– 互斥性。在任意时刻,只有一个客户端能持有锁。
– 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
– 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
– 加锁和解锁必须具有原子性。
Redis如何实现呢?
相当于把Redis当做一个锁的中心,所有的服务器如果有加锁的需求,都需要通过这个“中心”实现。
set lock uuid nx ex 12
设置lock 的值为uuid
nx 表示为不允许再设置
ex 表示过期时间 12s
比如在一台机子上 运行时 一个线程 在Redis中设置了 lock
其他机子如果想要执行程序 但是无法拿到这个锁
set 成功就会返回1 不成功就会返回0
问题:setnx刚好获取到锁,业务逻辑出现异常,导致锁无法释放
解决:设置过期时间,自动释放锁。
所以必须设置过期时间 否则别的线程无法拿到锁了
问题:可能会释放其他服务器的锁。
一台服务器做完需要同步的操作后就可以 del 锁了 让别的服务器去用
所须在删除锁之前先进行判断 看是不是自己的锁,通过 uuid进行锁的标识
如果是自己的锁 那么删除 别人在set lock 为自己的uuid,如果不是自己的说明 已经过了过期时间 则自动释放。
问题:删除操作缺乏原子性。
在判断是自己的uuid 后准备删除 这时候正好过期,被另一个线程拿到了这把锁。
也会误删 所以需要使得判断和删除时原子性的,可以使用Lua脚本实现判断和删除操作的原子性。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92822.html