在高并发请求的系统中,我们知道要控制多个线程对资源的并发访问,大都会用synchronize或者lock锁来实现同步,但是在分布式应用系统中,要控制一个事务的并发执行,需要跨JVM控制并发,那就需要用到分布式锁。
分布式锁的实现有很多方法,通常情况下只要是各个分布式应用能共同访问的资源我们都可以用来作分布式锁,区别只是性能,安全性,可用性等的考虑了,比如数据库,缓存服务以及业内推崇的zookeeper等。
数据库实现分布式锁思路:利用数据库唯一索引,悲观锁等特性。
1,先select没有数据就插入数据,谁插入成功谁就获得锁,通过delete数据进行释放锁,对于请求量大情况下数据库性能是瓶颈。
2,锁等待,如果线程未获得锁,则一般需要进行重试或者等待锁释放。这种需求则需要推翻1这种释放锁的方式,通过for update加锁,commit释放锁可以解决此问题。但随之而而来的问题是独占锁持有时间长的话,占用数据库连接会造成连接池占满的问题。
通过缓存服务实现分布式锁:memcached的add方法,redis的setnx方法都是原子操作,memcached的问题是内存不够或者宕机会丢失数据。redis可以持久化以及故障恢复,需要注意设置失效时间
基于zookeeper瞬时有序节点实现的分布式锁,大致思想为:每个客户端对某个功能加锁时,在zookeeper上的与该功能对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。
锁安全性高,zk可持久化,且能实时监听获取锁的客户端状态。一旦客户端宕机,则瞬时节点随之消失,zk因而能第一时间释放锁。性能开销比较高。