幼儿饰品瑜伽美体用品微软
投稿投诉
微软创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

高并发没锁可不行,三种分布式锁详解

  Java中的锁主要包括synchronized锁和JUC包中的锁,这些锁都是针对单个JVM实例上的锁,对于分布式环境如果我们需要加锁就显得无能为力。在单个JVM实例上,锁的竞争者通常是一些不同的线程,而在分布式环境中,锁的竞争者通常是一些不同的线程或者进程。如何实现在分布式环境中对一个对象进行加锁呢?答案就是分布式锁。分布式锁实现方案
  目前分布式锁的实现方案主要包括三种:基于数据库(唯一索引)基于缓存(Redis,memcached,tair)基于Zookeeper
  基于数据库实现分布式锁主要是利用数据库的唯一索引来实现,唯一索引天然具有排他性,这刚好符合我们对锁的要求:同一时刻只能允许一个竞争者获取锁。加锁时我们在数据库中插入一条锁记录,利用业务id进行防重。当第一个竞争者加锁成功后,第二个竞争者再来加锁就会抛出唯一索引冲突,如果抛出这个异常,我们就判定当前竞争者加锁失败。防重业务id需要我们自己来定义,例如我们的锁对象是一个方法,则我们的业务防重id就是这个方法的名字,如果锁定的对象是一个类,则业务防重id就是这个类名。
  基于缓存实现分布式锁:理论上来说使用缓存来实现分布式锁的效率最高,加锁速度最快,因为Redis几乎都是纯内存操作,而基于数据库的方案和基于Zookeeper的方案都会涉及到磁盘文件IO,效率相对低下。一般使用Redis来实现分布式锁都是利用Redis的SETNXkeyvalue这个命令,只有当key不存在时才会执行成功,如果key已经存在则命令执行失败。
  基于Zookeeper:Zookeeper一般用作配置中心,其实现分布式锁的原理和Redis类似,我们在Zookeeper中创建瞬时节点,利用节点不能重复创建的特性来保证排他性。
  在实现分布式锁的时候我们需要考虑一些问题,例如:分布式锁是否可重入,分布式锁的释放时机,分布式锁服务端是否有单点问题等。基于数据库实现分布式锁
  上面已经分析了基于数据库实现分布式锁的基本原理:通过唯一索引保持排他性,加锁时插入一条记录,解锁是删除这条记录。下面我们就简要实现一下基于数据库的分布式锁。表设计CREATETABLEdistributedlock(idbigint(20)NOTNULLAUTOINCREMENT,uniquemutexvarchar(255)NOTNULLCOMMENT业务防重id,holderidvarchar(255)NOTNULLCOMMENT锁持有者id,createtimedatetimeDEFAULTNULLONUPDATECURRENTTIMESTAMP,PRIMARYKEY(id),UNIQUEKEYmutexindex(uniquemutex))ENGINEInnoDBDEFAULTCHARSETutf8;
  id字段是数据库的自增id,uniquemutex字段就是我们的防重id,也就是加锁的对象,此对象唯一。在这张表上我们加了一个唯一索引,保证uniquemutex唯一性。holderid代表竞争到锁的持有者id。加锁insertintodistributedlock(uniquemutex,holderid)values(uniquemutex,holderid);
  如果当前sql执行成功代表加锁成功,如果抛出唯一索引异常(DuplicatedKeyException)则代表加锁失败,当前锁已经被其他竞争者获取。解锁deletefrommethodLockwhereuniquemutexuniquemutexandholderidholderid;
  解锁很简单,直接删除此条记录即可。分析
  是否可重入:就以上的方案来说,我们实现的分布式锁是不可重入的,即是是同一个竞争者,在获取锁后未释放锁之前再来加锁,一样会加锁失败,因此是不可重入的。解决不可重入问题也很简单:加锁时判断记录中是否存在uniquemutex的记录,如果存在且holderid和当前竞争者id相同,则加锁成功。这样就可以解决不可重入问题。
  锁释放时机:设想如果一个竞争者获取锁时候,进程挂了,此时distributedlock表中的这条记录就会一直存在,其他竞争者无法加锁。为了解决这个问题,每次加锁之前我们先判断已经存在的记录的创建时间和当前系统时间之间的差是否已经超过超时时间,如果已经超过则先删除这条记录,再插入新的记录。另外在解锁时,必须是锁的持有者来解锁,其他竞争者无法解锁。这点可以通过holderid字段来判定。
  数据库单点问题:单个数据库容易产生单点问题:如果数据库挂了,我们的锁服务就挂了。对于这个问题,可以考虑实现数据库的高可用方案,例如MySQL的MHA高可用解决方案。基于缓存实现分布式锁,以Redis为例
  使用Jedis来和Redis通信。加锁publicclassRedisTool{privatestaticfinalStringLOCKSUCCESSOK;privatestaticfinalStringSETIFNOTEXISTNX;privatestaticfinalStringSETWITHEXPIRETIMEPX;加锁paramjedisRedis客户端paramlockKey锁的keyparamrequestId竞争者idparamexpireTime锁超时时间,超时之后锁自动释放returnpublicstaticbooleangetDistributedLock(Jedisjedis,StringlockKey,StringrequestId,intexpireTime){Stringresultjedis。set(lockKey,requestId,SETIFNOTEXIST,SETWITHEXPIRETIME,expireTime);returnOK。equals(result);}}
  可以看到,我们加锁就一行代码:
  jedis。set(Stringkey,Stringvalue,Stringnxxx,Stringexpx,inttime);
  这个set()方法一共五个形参:
  第一个为key,我们使用key来当锁,因为key是唯一的。
  第二个为value,这里写的是锁竞争者的id,在解锁时,我们需要判断当前解锁的竞争者id是否为锁持有者。
  第三个为nxxx,这个参数我们填的是NX,意思是SETIFNOTEXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作。
  第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期时间的设置,具体时间由第五个参数决定;
  第五个参数为time,与第四个参数相呼应,代表key的过期时间。
  总的来说,执行上面的set()方法就只会导致两种结果:1。当前没有锁(key不存在),那么久进行加锁操作,并对锁设置一个有效期,同时value表示加锁的客户端。2。已经有锁存在,不做任何操作。
  上述解锁请求中,SETIFNOTEXIST(不存在则执行)保证了加锁请求的排他性,缓存超时机制保证了即使一个竞争者加锁之后挂了,也不会产生死锁问题:超时之后其他竞争者依然可以获取锁。通过设置value为竞争者的id,保证了只有锁的持有者才能来解锁,否则任何竞争者都能解锁,那岂不是乱套了。解锁publicclassRedisTool{privatestaticfinalLongRELEASESUCCESS1L;释放分布式锁paramjedisRedis客户端paramlockKey锁paramrequestId锁持有者idreturn是否释放成功publicstaticbooleanreleaseDistributedLock(Jedisjedis,StringlockKey,StringrequestId){Stringscriptifredis。call(get,KEYS〔1〕)ARGV〔1〕thenreturnredis。call(del,KEYS〔1〕)elsereturn0end;Objectresultjedis。eval(script,Collections。singletonList(lockKey),Collections。singletonList(requestId));returnRELEASESUCCESS。equals(result);}}
  解锁的步骤:判断当前解锁的竞争者id是否为锁的持有者,如果不是直接返回失败,如果是则进入第2步。删除key,如果删除成功,返回解锁成功,否则解锁失败。
  注意到这里解锁其实是分为2个步骤,涉及到解锁操作的一个原子性操作问题。这也是为什么我们解锁的时候用Lua脚本来实现,因为Lua脚本可以保证操作的原子性。那么这里为什么需要保证这两个步骤的操作是原子操作呢?
  设想:假设当前锁的持有者是竞争者1,竞争者1来解锁,成功执行第1步,判断自己就是锁持有者,这是还未执行第2步。这是锁过期了,然后竞争者2对这个key进行了加锁。加锁完成后,竞争者1又来执行第2步,此时错误产生了:竞争者1解锁了不属于自己持有的锁。可能会有人问为什么竞争者1执行完第1步之后突然停止了呢?这个问题其实很好回答,例如竞争者1所在的JVM发生了GC停顿,导致竞争者1的线程停顿。这样的情况发生的概率很低,但是请记住即使只有万分之一的概率,在线上环境中完全可能发生。因此必须保证这两个步骤的操作是原子操作。分析
  是否可重入:以上实现的锁是不可重入的,如果需要实现可重入,在SETIFNOTEXIST之后,再判断key对应的value是否为当前竞争者id,如果是返回加锁成功,否则失败。
  锁释放时机:加锁时我们设置了key的超时,当超时后,如果还未解锁,则自动删除key达到解锁的目的。如果一个竞争者获取锁之后挂了,我们的锁服务最多也就在超时时间的这段时间之内不可用。
  Redis单点问题:如果需要保证锁服务的高可用,可以对Redis做高可用方案:Redis集群主从切换。目前都有比较成熟的解决方案。基于Zookeeper实现分布式锁加锁和解锁流程
  利用Zookeeper创建临时有序节点来实现分布式锁:当一个客户端来请求时,在锁的空间下面创建一个临时有序节点。如果当前节点的序列是这个空间下面最小的,则代表加锁成功,否则加锁失败,加锁失败后设置Watcher,等待前面节点的通知。当前节点监听其前面一个节点,如果前面一个节点删除了就通知当前节点。当解锁时当前节点通知其后继节点,并删除当前节点。
  其基本思想类似于AQS中的等待队列,将请求排队处理。其流程图如下:
  分析
  解决不可重入:客户端加锁时将主机和线程信息写入锁中,下一次再来加锁时直接和序列最小的节点对比,如果相同,则加锁成功,锁重入。
  锁释放时机:由于我们创建的节点是顺序临时节点,当客户端获取锁成功之后突然session会话断开,ZK会自动删除这个临时节点。
  单点问题:ZK是集群部署的,主要一半以上的机器存活,就可以保证服务可用性。利用curator实现
  Zookeeper第三方客户端curator中已经实现了基于Zookeeper的分布式锁。利用curator加锁和解锁的代码如下:加锁,支持超时,可重入publicbooleantryLock(longtimeout,TimeUnitunit)throwsInterruptedException{try{returninterProcessMutex。acquire(timeout,unit);}catch(Exceptione){e。printStackTrace();}returntrue;}解锁publicbooleanunlock(){try{interProcessMutex。release();}catch(Throwablee){log。error(e。getMessage(),e);}finally{executorService。schedule(newCleaner(client,path),delayTimeForClean,TimeUnit。MILLISECONDS);}returntrue;}三种方案比较

今年暑假买游戏笔记本,从入门到旗舰价位,联想拯救者还够打吗?当下正值暑期放假,估计会有不少小伙伴都想趁着空余时间好好的研究一番游戏本选择,看看在不少商家都放出活动的情况下都有哪些真香选择。对于潜在消费者来说,联想拯救者系列应该是一个绕不……入伏后,爱喝酒的请注意牢记3不喝,身体不受罪,轻松过夏三伏天,是一年当中最热的时候,今年的三伏天,已然来到,相信不少朋友都感受到了它的热情!老祖宗们按照天干地支的计算方法,根据气候、物候、时令的变化,发现出其中的规律,并总结……华为nova10Pro上手星环设计再创新,营造和谐对称感华为nova系列标志性的设计风格带来引领业界的美学潮流,至今全球已有超过2亿的nova星人。这次全新升级的nova10系列不仅延续了上一代nova9系列极具辨识度的星环设计,还……中国股市车联网概念股强势来袭,这5家建议收藏(名单)车联网通俗地说,就是把汽车连接到开放的网络上,然后解决驾驶过程中的各种痛点。这里应该注意的是,当前的车载系统只是车辆网络的几个分支。比如苹果的Carplay、腾讯的WeD……老戏骨钱洁剧中给赵丽颖当妈,戏外结婚生子也是好妈妈万众期待的《幸福到万家》近日开播,收获不少好评。这部剧是由当红女星赵丽颖主演的,并且导演是拍过《甄嬛传》的郑晓龙。从阵容上就可以看出这部剧不一般,该剧选择了农村题材,女性……足不出户体验乡村旅游!全篇干货!详解国内外创意农业发展路径艺术行动一直是国内外政府非常重视的部分。乡村本身体现了自然悠闲的生活方式,人们抛离大都市的焦虑和浮躁,进入心静和沉淀的状态,享受慢节奏、静生活的慵懒、安逸和优雅的氛围,而艺术本……夏季要忌茶?建议大家,无论喝什么茶,这2种茶尽量少喝为好夏天大家都喜欢喝茶,这个季节喝茶还是要注意一下禁忌的。无论喝什么茶,下面这2种尽量少喝为好!快看看你有没有踩过雷吧。第一种,功能茶茶文化在中国是一种特殊的文化,很多……iQOO10Pro曝光200W快充1TB存储,又是堆料狂魔要说到国产手机品牌,大家第一时间想到的会是华为、小米、OPPO以及vivo四大品牌,为了提升在国内市场的份额,这四大品牌也繁衍出了很多子品牌,其中发展最快的还是vivo旗下的i……首冠出炉!马来西亚31印度,李宗伟接班人21爆冷前世界第1北京时间8月3日,英联邦运动会羽毛球比赛正在进行。本届英联邦运动会,羽毛球一共有6个比赛项目,率先开始的是混合团体比赛。半决赛中,马来西亚3:0零封东道主英格兰队,成功晋级决赛……NASA太阳动力学观测站捕捉到太阳爆发的中度耀斑美国东部时间4月20日,太阳爆发了一场中等强度的耀斑,其在当天晚上9:59达到顶峰。NASA的太阳动力学观测站(SDO)一直在观测太阳并捕捉到了这一事件的图像。实际上,SDO还……适合糖尿病患者食用的家常菜大白菜对糖尿病人的好处大白菜含有丰富膳食纤维和营养素大白菜降糖金牌营养素之膳食纤维能量:17千卡100g白菜含有丰富膳食纤维,可抑制机体对碳水化合物的吸收,缓解餐后血糖上升的速度。因此,……三维光场非线性调控理论研究取得进展近期,中国科学院西安光学精密机械研究所瞬态光学与光子技术国家重点实验室副研究员曾健华团队及其合作者在三维光场的非线性调控前沿理论方面取得两项研究进展,分别以Matterwave……
老家这种土灶台还有人用吗?炒出来的菜香味太上头了近几天,天气晴好,随家人一道去拜访乡下一位亲戚,看到了久违的土灶台和木制的老碗柜,是那么的熟悉而又亲切,时间仿佛让我回到四十年前,重温儿时那段难忘而又温暖的记忆。时光匆匆……罗马诺德佩的未来是开放的,他有可能在一月份离开直播吧11月10日讯在自己的Caughtoffside专栏节目中,转会专家罗马诺分析了巴萨前锋德佩的情况,他表示,这名球员可能在一月份离队。罗马诺这样写道:孟菲斯德佩的未……不用吃药,用三个法宝就可以把我们的身体养好现在我们生活在物质资源极其丰富的年代,既然不讲究数量,我们就要在质量上下功夫。所以我们所有的人都要明白一个道理:现在我们餐桌上的食物不是用来饱肚子的,而是用来养命的。第一……画家崔晓晓去西藏会上瘾编者按:从藏北的广漠草原,到有着西藏小江南美誉的林芝从2012年开始的7年时间里,画家崔晓晓先后8次前往西藏采风,足迹遍布西藏。《吉祥西藏》组画已成为他重要的代表作之一。为何多……(国际)澳大利亚悉尼蓝花楹盛开每年的春夏之交,澳大利亚悉尼的蓝花楹盛开。这是11月8日在澳大利亚悉尼大学拍摄的盛开的蓝花楹。新华社发(胡泾辰摄)11月7日,在澳大利亚悉尼,人们从蓝花楹树下走过。……向芮乃伟致敬崔精超越芮乃伟的神迹了吗?现在说还为时过早韩国女子国手崔精在半决赛中战胜了韩国排名第二的卞相壹杀进了第27届三星杯的决赛。有棋友在为崔精叫好的同时,认为崔精已经超越芮乃伟成为世界围棋史上场绝对实力最强的女子棋手。……NT终于过了,大家帮我看看男宝宝还是女宝宝第一次做NT小家伙一整天都趴着,不肯转过来,不管怎么运动,吃甜的,吃辣的,喝冰奶茶都不配合,前后做了四五次都不配合,一直趴着,动一下肚子他就踢踢小脚丫就是不肯翻身,没办法医生让……26分6板35分3断!上海男篮两隐藏奇兵齐爆发,李春江没有看12192,上海男篮大胜广州男篮,避免遭遇连败。从比赛的过程来看,上海男篮打得极具统治力,全场压制对手的进攻,在布莱德索伤缺的情况下,大外援奥布莱恩特撑起球队的进攻,全场轰下3……YD亿等新能源锂电池获Nokia5710XpressAudi诺基亚推出的这台Nokia5710XpressAudio手机最大的亮点,在手机的背部内置了一个充电盒,里面放置着一对真无线耳机,平时隐藏于滑盖之下,需要时直接开盖即可取出使用。……康养视线从一老一小两类重点人群入手破解康养运营的难题国家卫健委强调关注生命早期1000天(这才是不要输在起跑线上)2016年,《世界卫生组织孕产妇和婴幼儿营养全面实施计划》提出:生命最初1000天,改变一生,改变未来……油耗进一步降低,搭载2。0T插混全景天窗,体验宝马5系PHE越来越高的油价,让不少消费者在买车的时候,都开始关注新能源车型。目前来看,除了比亚迪、本田、丰田等车型开始布局新能源市场,像BBA等豪华品牌也开始了新能源车型的研发,这其中就包……锂行业专题海外锂企业近况更新,供给的低预期正在显现(报告出品方作者:民生证券,邱祖学、张航)1海外锂矿2022Q3综述:产销大幅提升,新增产能顺利投放高锂精矿价格刺激,棕地矿山复产顺利,西澳锂矿2022Q3产销量大幅提升……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网