一、分布式锁作用及其原理
1.为什么要有分布式锁
答:分布式服务中,如果各个服务节点需要去竞争资源,没办法使用单机多线程中JDK自带的锁,故此时需要分布式锁来协调。
2.企业中有哪些常见的手段来实现分布式锁
zookeeper、redis、memcache
3.分布式锁的原理
zookeeper:去创建相应的节点,创建成功,则表示获取到相应的锁,创建失败,则表示获取锁失败
redis、memcache:对应的去设置一个值做为锁的一标志,每次获取锁的时候,判断对应的值是否存在,存在则无法获取,不存在,则设置相应的值,表示获取到锁。(redis 使用setnx,memcache使用add)
二、基于zookeeper实现分布式锁的多种方式
注意事项: 创建节点的时候,一定要创建临时节点(session断开后会自动删除临时节点),避免应用获取到锁后,宕机,导致锁一致被持有
第一种:基于单一节点实现分布式锁,既程序连接上zk之后,就尝试去创建指定节点,如果创建成功,则表示成功获取锁,如节点已经存在,代表获取锁失败,程序进入短暂的休眠期,之后再次重试,直到成功为止。获取的锁使用完后,释放锁时,删除改指定的节点即可。(存在问题,如果节点存在,系统就会抛出异常,就会休眠重试,再次创建,这样不断的轮训会非常消耗资源)
第二种:使用ZK的watche机制。在第一种的基础上,为了避免这样的不断重试产生报错和浪费资源,可以使用ZK的watche机制,在创建节点时,添加一个watched。当我删除节点后,就用watched去通知外面在等待的其他程序,但是这样同样存在问题,就是如果我外面等待着一堆的程序,我这watched这个无脑通知,就会同时唤醒一堆的休眠中的程序来争取这次创建节点的机会(羊群效应)
第三种:创建有序节点。就是在第二种方式的基础上,我规定每次创建的节点的都是有序,同时我在删除了我自己创建的节点后,我使用watched机制通知要创建下一个顺序节点的程序来接手我用完的锁,然后新的成绩创建自己顺序的节点名既可以,以此类推既可以解决问题