1 非公平锁
如上实现方式在并发问题比较严重的情况下,性能会下降的比较厉害,主要原因是,所有的连接都在对同一个节点进行监听,当服务器检测到删除事件时,要通知所有的连接,所有的连接同时收到事件,再次并发竞争,这就是羊群效应
。
这种加锁方式是非公平锁的具体实现:如何避免呢,我们看下面这种方式。
2 公平锁
InterProcessMutex就是公平锁的实现。
参见Apache curator5.0原理分析 《分布式锁InterProcessMutex使用及原理分析》
如上借助于临时顺序节点,可以避免同时多个节点的并发竞争锁,缓解了服务端压力。这种实现方式所有加锁请求都进行排队加锁,是公平锁的具体实现。
2.1 共享锁
如果单纯的采用InterProcessMutex,存在性能问题。
共享锁详情参见Apache curator API 《共享的可重入读写锁InterProcessReadWriteLock》
前面这种加锁方式有一个共同的特质,就是都是互斥锁,同一时间只能有一个请求占用,如果是大量的并发上来,性能是会急剧下降的,所有的请求都得加锁,那是不是真的所有的请求都需要加锁呢?
答案是否定的,比如如果数据没有进行任何修改的话,是不需要加锁的,但是如果读数据的请求还没读完,这个时候来了一个写请求,怎么办呢?有人已经在读数据了,这个时候是不能写数据的,不然数据就不正确了。直到前面读锁全部释放掉以后,写请求才能执行,所以需要给这个读请求加一个标识(读锁),让写请求知道,这个时候是不能修改数据的。不然数据就不一致了。如果已经有人在写数据了,再来一个请求写数据,也是不允许的,这样也会导致数据的不一致,所以所有的写请求,都需要加一个写锁,是为了避免同时对共享数据进行写操作。
举个例子
1、读写并发不一致
2、双写不一致情况
从上面两幅图,能看到当读读操作,直接可以不影响,如果是写操作和读操作或者写写,之间都会涉及不一致情况。
Zookeeper 共享锁实现原理: