日常开发中,秒杀下单、抢红包等等业务场景,都需要用到分布式锁。而Redis非常适合作为分布式锁使用。
分布式锁是”线程同步”的延续
最近首度应用”分布式锁”,现在想想,分布式锁不是孤立的技能点,这其实就是跨主机的线程同步。
单机 服务器 可以通过共享某堆内存来标记上锁/解锁,线程同步说到底是建立在单机操作系统的用户态/内核态对共享内存的访问控制。
而分布式服务器不是在同一台机器上:跨主机,因此需要将锁标记存储在所有机器进程都能看到的地方。
在开发很多业务场景会使用到锁,例如库存控制,抽奖等。
例如库存只剩1个商品,有三个用户同时打算购买,谁先购买库存立即清零,不能让其他二人也购买成功。
我们常说的线程安全、线程同步方案,包括此次的分布式锁都是基于
“多线程/多进程对特定资源同时有更新操作”。
Redis SET resource-name anystring NX EX max-lock-time
是一种最简单的分布式锁实现方案。
SET 命令支持多个参数:
因为SET命令参数可以替代SETNX,SETEX,GETSET,这些命令在未来可能被废弃。
上面的命令返回OK(或经过重试),客户端就获取到这个锁;
使用DEL命令解锁;到达超时时间会自动释放锁。
在解锁时,增加一些设计,让系统更加健壮:
3.不要使用固定的String值作为锁标记值,而是使用一个不易被猜中的随机值, 业内称为token
4.不使用DEL命令释放锁,而是发送script去移除key
第3、4点是为了解决 :“锁提前过期,客户端A还没有执行完,然后客户端B获取了锁,这时客户端A执行完了,会不会在删锁的时候把B的锁给删掉” — 4是3技术上的推荐实现。
脚本如下:
redis.call(,KEYS1]==ARGV[1])redis.call(,KEYS[1])0end
下面使用StackExchange.Redis 写了基于以上考量的代码示例:
//////Acquiresthelock./////////随机值//////非阻塞锁staticboolLock(stringkey,stringtoken,intexpireSecond=10,doublewaitLockSeconds=0){varwaitIntervalMs=50;boolisLock;DateTimebegin=DateTime.Now;{isLock=Connection.GetDatabase().StringSet(key,token,TimeSpan.FromSeconds(expireSecond),When.NotExists);(isLock);//不等待锁则返回(waitLockSeconds==0);//超过等待时间,则不再等待((DateTime.Now-begin).TotalSeconds>=waitLockSeconds);Thread.Sleep(waitIntervalMs);}(!isLock);;}//////Releasesthelock.//////,lockwasreleased,otherwise.///Key.///valuestaticboolUnLock(stringkey,stringvalue){stringlua_script=@;try{varres=Connection.GetDatabase().ScriptEvaluate(lua_script,newRedisKey[]{key},newRedisValue[]{value});(bool)res;}catch(Exceptionex){Console.WriteLine($);;}}privatestaticLazylazyConnection=newLazy(()=>{ConfigurationOptionsconfiguration=newConfigurationOptions{AbortOnConnectFail=,ConnectTimeout=5000,};configuration.EndPoints.Add(,6379);ConnectionMultiplEXEr.Connect(configuration.ToString());});publicstaticConnectionMultiplexerConnection=>lazyConnection.Value;
以上代码新增了第五点考量:
\5. 为避免无限制抢锁,增加了非阻塞锁:轮询_s等待锁,未等到则不再抢锁
下面并行开启三个任务,同时减少库存:
staticvoidMain(string[]args){//尝试并行执行3个任务Parallel.For(0,3,x=>{stringtoken=$;boolisLocked=Lock(,token,5,10);(isLocked){Console.WriteLine($);Thread.Sleep(1000);Console.WriteLine($loki);}{Console.WriteLine($);}});}
可以看到三个并行任务依次获取/释放锁

本文从基础的线程安全、线程同步,认识到分布式锁是跨主机的资源线程/进程同步方案, 以步步为营的风格 演示了RedisSET命令做分布式锁的设计考量,好记性不如烂笔头。
伤仲永 然 一词多义辨析
重点词语:利:认为…有利可图奇:对…感到惊奇宾客:以宾客之礼相待的意思通假字:通“攀”牵,引◆学习重点: 1.最后一段的议论讲了什么道理? 答:说明了人的天资与后天学习的关系,强调后天学习对成才的重要性. 2.方仲永由天资过人变得泯然众人,原因是什么? 答:从方仲永个人情况来看,原因是父利其然也,日扳仲永环谒于邑人,贪图小利,目光短浅,而不使学.从道理上来说,原因是作者在后面的议论中所认为的那样.方仲永卒之为众人,是因为其受于人者不至,既没有受到后天正常的教育. 3.你对题目是怎样理解的? 答:伤是哀伤感伤之意.仲永,即方仲永,本文的一个神童.文章以伤仲永为题,写的是可伤之事,说的是可伤之道理.字里行间流露出作者对一个神童最终泯然众人的惋惜之情.本文借事说理,以方仲永为实例,说明一个人有天分不足诗,唯有后天的教育与学习,才能让人精益求精,更上一层楼,才能够真正成才. 4.你怎样理解文中的泯然众人矣? 答:泯然众人矣一句点明结局,痛惜之意溢于言表,发人深省.再过七年以后,是方仲永的第三个阶段,才能衰竭,成为了普通人. 5.作者主要表达的意思是什么? 答:本文通过叙述方仲永因为父亲不使学,而从神童到成为普通人的变化过程,说明天资固然重要,但没有好的后天的教育,再好的天赋也不可能得以发挥.告诉我们学习和教育对于人才的培养十分重要!
《极灵混沌决》的内容大致讲的是什么?
机灵混沌决等级划分是武徒、武者、武师、大武师、武灵、武王、武宗、武皇、武尊、武圣、武帝,武圣与武帝之间有个半帝之境称之为圣帝。 1. 机灵混沌决是一本修真小说,讲述了自幼痛失右臂,丹田破碎,万念俱灰的少年破碎极武,铸就巅峰武神路。 2. 斗破苍穹、混沌天体、修罗武神、星武神诀等都属于废柴流的小说。
已知a>0,a不等于1,解关于x的不等式:1+log2(a^x-1)≤log4(4-a^x)
1+log2(a^x-1)≤log4(4-a^x) =log2 2(a^x-1)≤log2 √(4-a^x) 2(a^x-1)≤√(4-a^x) 4(a^2x-2a^x+1)≤4-a^x 4a^2x-7a^x≤0 a^x(4a^x-7)≤0 0≤a^x≤7/4 由定义域知,a^x-1>0,1 1时,0
发表评论