标签:状态 AC zed 子节点 redis 主键 自己的 bsp 进入
Java提供了两种内置的锁的实现,一种是由JVM实现的synchronized和JDK提供的Lock,当你的应用是单机或者说单进程应用时,可以使用synchronized或Lock来实现锁。
synchronized与RetreenLock区别处:Synchronized是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成,ReentrantLock类提供了一些高级功能,主要有:
Java中锁的种类有:
从宏观上分为如下两种:
但是,当你的应用涉及到多机、多进程共同完成时,例如现在的互联网架构,一般都是分布式的RPC框架来支撑,那么这样你的Server有多个,由于负载均衡的路由规则随机,相同的请求可能会打到不同的Server上进行处理,那么这时候就需要一个全局锁来实现多个线程(不同的进程)之间的同步。
实现全局的锁需要依赖一个第三方系统,此系统需要满足高可用、一致性比较强同时能应付高并发的请求。
常见的处理办法有三种:数据库、缓存(redis,memcached,tair)、分布式协调系统(Zookeeper)。数据库和缓存是比较常用的,但是分布式协调系统是不常用的。
分布式锁的设计应该是:
------------------------------------------------------------------------
数据库实现:
利用主键唯一规则(或者利用Mysql行锁的特性)
首先我们利用主键唯一规则,在争抢锁的时候向DB中写一条记录,这条记录主要包含锁的id、当前占用锁的线程名、重入的次数和创建时间等,如果插入成功表示当前线程获取到了锁,如果插入失败那么证明锁被其他人占用,等待一会儿继续争抢,直到争抢到或者超时为止。
重入主要实现思路是,在每次获取锁之前去取当前锁的信息,如果锁的线程是当前线程,那么更新锁的count+1,并且执行锁之后的逻辑。如果不是当前锁,那么进行重试。释放的时候也要进行count-1,最后减到0时,删除锁标识释放锁。
优点:实现简单
缺点:没有超时保护机制,mysql存在单点,并发量大的时候请求量太大、没有线程唤醒机制,用异常去控制逻辑多少优点恶心。
-------------------------------------------------------------------------
缓存分布式锁:
缓存实现分布式锁还是比较常见的,因为缓存比较轻量,并且缓存的响应快、吞吐高。最重要的是还有自动失效的机制来保证锁一定能释放。
缓存的分布式锁主要通过Redis实现,setNX是Redis提供的一个原子操作,如果指定key存在,那么setNX失败,如果不存在会进行Set操作并返回成功。我们可以利用这个来实现一个分布式的锁,主要思路就是,set成功表示获取锁,set失败表示获取失败,失败后需要重试。
优点:实现简单,吞吐量十分客观,对于高并发情况应付自如,自带超时保护,对于网络抖动的情况也可以利用超时删除策略保证不会阻塞所有流程。
缺点:单点问题、没有线程唤醒机制、网络抖动可能会引起锁删除失败。
---------------------------------------------------------------------------
基于zookeeper:
zookeeper是一个分布式一致性协调框架,主要可以实现选主、配置管理和分布式锁等常用功能,因为Zookeeper的写入都是顺序的,在一个节点创建之后,其他请求再次创建便会失败,同时可以对这个节点进行Watch,如果节点删除会通知其他节点抢占锁。步骤:
Curator是Netflix开源的一套ZooKeeper客户端框架,curator-recipes库里面集成了很多zookeeper的应用场景,因此,需要使用zookeeper的分布式锁功能,可以使用curator-recipes库。
优点:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。
缺点:因为需要频繁的创建和删除节点,性能上不如Redis方式。
参考:
https://juejin.im/post/5a0be84e6fb9a0450b65ec97
https://www.jianshu.com/p/c2b4aa7a12f1
标签:状态 AC zed 子节点 redis 主键 自己的 bsp 进入
原文地址:https://www.cnblogs.com/zhang-qc/p/8877730.html