背景:
在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等。大部分是解决方案基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。
项目实践
任务队列用到分布式锁的情况比较多,在将业务逻辑中可以异步处理的操作放入队列,在其他线程中处理后出队,此时队列中使用了分布式锁,保证入队和出队的一致性。关于redis队列这块的逻辑分析,我将在下一次对其进行总结,此处先略过。
接下来对redis实现的分布式锁的逻辑代码进行详细的分析和理解:
1、为避免特殊原因导致锁无法释放, 在加锁成功后, 锁会被赋予一个生存时间(通过 lock 方法的参数设置或者使用默认值), 超出生存时间锁将被自动释放.
2、锁的生存时间默认比较短(秒级, 具体见 lock 方法), 因此若需要长时间加锁, 可以通过 expire 方法延长锁的生存时间为适当的时间. 比如在循环内调用 expire
3、系统级的锁当进程无论因为任何原因出现crash,操作系统会自己回收锁,所以不会出现资源丢失。
4、但分布式锁不同。若一次性设置很长的时间,一旦由于各种原因进程 crash 或其他异常导致 unlock 未被调用,则该锁在剩下的时间就变成了垃圾锁,导致其他进程或进程重启后无法进入加锁区域。
<"Lock:$name"; while(true) { $result = $this->redis->setnx($redisKey, (string)$expireAt); if($result !== false) { //对$redisKey设置生存时间 $this->redis->expire($redisKey, $expire); //将最大生存时刻记录在一个数组里面 $this->lockedNames[$name] = $expireAt; return true; } //以秒为单位,返回$redisKey 的剩余生存时间 $ttl = $this->redis->ttl($redisKey); // TTL 小于 0 表示 key 上没有设置生存时间(key 不会不存在, 因为前面 setnx 会自动创建) // 如果出现这种情况, 那就是进程在某个实例 setnx 成功后 crash 导致紧跟着的 expire 没有被调用. 这时可以直接设置 expire 并把锁纳为己用 if($ttl < 0) { $this->redis->set($redisKey, (string)$expireAt, $expire); $this->lockedNames[$name] = $expireAt; return true; } // 设置了不等待或者已超时 if($timeout <= 0 || microtime(true) > $timeoutAt) break; // 挂起一段时间再试 usleep($waitIntervalUs); } return false; } /** * 给当前锁增加指定的生存时间(秒), 必须大于 0 * * @param string 锁的标识名 * @param int 生存时间(秒), 必须大于 0 */ public function expire($name, $expire) { if($this->isLocking($name)) { if($this->redis->expire("Lock:$name", max($expire, 1))) { return true; } } return false; } /** * 判断当前是否拥有指定名称的锁 * * @param mixed $name */ public function isLocking($name) { if(isset($this->lockedNames[$name])) { return (string)$this->lockedNames[$name] == (string)$this->redis->get("Lock:$name"); } return false; } /** * 释放锁 * * @param string 锁的标识名 */ public function unlock($name) { if($this->isLocking($name)) { if($this->redis->deleteKey("Lock:$name")) { unset($this->lockedNames[$name]); return true; } } return false; } /** 释放当前已经获取到的所有锁 */ public function unlockAll() { $allSuccess = true; foreach($this->lockedNames as $name => $item) { if(false === $this->unlock($name)) { $allSuccess = false; } } return $allSuccess; } }
此类很多代码都写上了注释,只要认真理解下,就很容易懂得如何在redis实现分布式锁了。
Redis,分布式锁
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新动态
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]