HTML5技术

用Redis实现分布式锁 与 实现任务队列 - __kelly_(6)

字号+ 作者:H5之家 来源:博客园 2015-11-23 08:33 我要评论( )

到此,这两大块功能基本讲解完毕,对于任务队列,你可以写一个shell脚本,让服务器定时运行某些程序,实现入队出队等操作,这里我就不在将其与实际应用结合起来去实现了,大家理解好这两大功能的实现思路即可,由于

  到此,这两大块功能基本讲解完毕,对于任务队列,你可以写一个shell脚本,让服务器定时运行某些程序,实现入队出队等操作,这里我就不在将其与实际应用结合起来去实现了,大家理解好这两大功能的实现思路即可,由于代码用的是PHP语言来写的,如果你理解了实现思路,你完全可以使用java或者是.net等等其他语言去实现这两个功能。这两大功能的应用场景十分多,特别是秒杀,另一个就是春运抢火车票,这两个是最鲜明的例子了。当然还有很多地方用到,这里我不再一一列举。

 

  好了,本次总结和分享到此完毕。最后我附上 分布式锁和任务队列这两个类:

1 /** 2 *在redis上实现分布式锁 RedisLock { ; = []; __construct($param = NULL) { 9 $this->redisString = RedisFactory::get($param)->string; 10 } * 13 * 加锁 14 * @param [type] $name 锁的标识名 15 * @param integer $timeout 循环获取锁的等待超时时间,在此时间内会一直尝试获取锁直到超时,为0表示失败后直接返回不等待 16 * @param integer $expire 当前锁的最大生存时间(秒),必须大于0,如果超过生存时间锁仍未被释放,则系统会自动强制释放 17 * @param integer $waitIntervalUs 获取锁失败后挂起再试的时间间隔(微秒) 18 * @return [type] [description] lock($name, $timeout = 0, $expire = 15, $waitIntervalUs = 100000) { ; = time(); = $now + $timeout; = $now + $expire; = "Lock:{$name}"; 31 while (true) { = $this->redisString->setnx($redisKey, $expireAt); ($result != false) { ->redisString->expire($redisKey, $expireAt); ->lockedNames[$name] = $expireAt; ; 41 } = $this->redisString->ttl($redisKey); ttl小于0 表示key上没有设置生存时间(key是不会不存在的,因为前面setnx会自动创建) 47 //如果出现这种状况,那就是进程的某个实例setnx成功后 crash 导致紧跟着的expire没有被调用 ($ttl < 0) { 50 $this->redisString->set($redisKey, $expireAt); 51 $this->lockedNames[$name] = $expireAt; ; 53 } ($timeout <= 0 || $timeoutAt < microtime(true)) break; ($waitIntervalUs); 61 62 } ; 65 } * 68 * 解锁 69 * @param [type] $name [description] 70 * @return [type] [description] unlock($name) { ($this->isLocking($name)) { ($this->redisString->deleteKey("Lock:$name")) { ($this->lockedNames[$name]); ; 80 } 81 } ; 83 } * 86 * 释放当前所有获得的锁 87 * @return [type] [description] unlockAll() { = true; => $expireAt) { 93 if (false === $this->unlock($name)) { 94 $allSuccess = false; 95 } 96 } ; 98 } * 101 * 给当前所增加指定生存时间,必须大于0 102 * @param [type] $name [description] 103 * @return [type] [description] expire($name, $expire) { ($this->isLocking($name)) { = max($expire, 1); ($this->redisString->expire("Lock:$name", $expire)) { ; 113 } 114 } ; 116 } * 119 * 判断当前是否拥有指定名字的所 120 * @param [type] $name [description] 121 * @return boolean [description] isLocking($name) { (isset($this->lockedNames[$name])) { (string)$this->lockedNames[$name] = (string)$this->redisString->get("Lock:$name"); 128 } ; 131 } 132 133 } * 136 * 任务队列 RedisQueue { ; __construct($param = null) { 142 $this->_redis = RedisFactory::get($param); 143 } * 146 * 入队一个 Task 147 * @param [type] $name 队列名称 148 * @param [type] $id 任务id(或者其数组) 149 * @param integer $timeout 入队超时时间(秒) 150 * @param integer $afterInterval [description] 151 * @return [type] [description] enqueue($name, $id, $timeout = 10, $afterInterval = 0) { (empty($name) || empty($id) || $timeout <= 0) return false; (!$this->_redis->lock->lock("Queue:{$name}", $timeout)) { 159 Logger::get('queue')->error("enqueue faild becouse of lock failure: name = $name, id = $id"); ; 161 } = microtime(true) + $afterInterval; (() { (false === $this->_redis->zset->getScore("Queue:$name", $item)) { 169 $this->_redis->zset->add("Queue:$name", $score, $item); 170 } 171 } ->_redis->lock->unlock("Queue:$name"); ; 177 178 } * 181 * 出队一个Task,需要指定$id 和 $score 182 * 如果$score 与队列中的匹配则出队,否则认为该Task已被重新入队过,当前操作按失败处理 183 * 184 * @param [type] $name 队列名称 185 * @param [type] $id 任务标识 186 * @param [type] $score 任务对应score,从队列中获取任务时会返回一个score,只有$score和队列中的值匹配时Task才会被出队 187 * @param integer $timeout 超时时间(秒) 188 * @return [type] Task是否成功,返回false可能是redis操作失败,也有可能是$score与队列中的值不匹配(这表示该Task自从获取到本地之后被其他线程入队过) dequeue($name, $id, $score, $timeout = 10) { (empty($name) || empty($id) || empty($score)) return false; (!$this->_redis->lock->lock("Queue:$name", $timeout)) { 196 Logger:get('queue')->error("dequeue faild becouse of lock lailure:name=$name, id = $id"); ; 198 } 出队 = $this->_redis->zset->getScore("Queue:$name", $id); 203 $result = false; ($serverScore == $score) { = (float)$this->_redis->zset->delete("Queue:$name", $id); 208 if ($result == false) { 209 Logger::get('queue')->error("dequeue faild because of redis delete failure: name =$name, id = $id"); 210 } 211 } ->_redis->lock->unlock("Queue:$name"); ; 216 } * 219 * 获取队列顶部若干个Task 并将其出队 220 * @param [type] $name 队列名称 221 * @param integer $count 数量 222 * @param integer $timeout 超时时间 223 * @return [type] 返回数组[0=>['id'=> , 'score'=> ], 1=>['id'=> , 'score'=> ], 2=>['id'=> , 'score'=> ]] pop($name, $count = 1, $timeout = 10) { (empty($name) || $count <= 0) return []; (!$this->_redis->lock->lock("Queue:$name")) { 231 Logger::get('queue')->error("pop faild because of pop failure: name = $name, count = $count"); ; 233 } = []; 237 $array = $this->_redis->zset->getByScore("Queue:$name", false, microtime(true), true, false, [0, $count]); (=> $score) { 241 $result[] = ['id'=>$id, 'score'=>$score]; 242 $this->_redis->zset->delete("Queue:$name", $id); 243 } ->_redis->lock->unlock("Queue:$name"); == 1 ? (empty($result) ? false : $result[0]) : $result; 249 } * 252 * 获取队列顶部的若干个Task 253 * @param [type] $name 队列名称 254 * @param integer $count 数量 255 * @return [type] 返回数组[0=>['id'=> , 'score'=> ], 1=>['id'=> , 'score'=> ], 2=>['id'=> , 'score'=> ]] top($name, $count = 1) { (empty($name) || $count < 1) return []; = []; 263 $array = $this->_redis->zset->getByScore("Queue:$name", false, microtime(true), true, false, [0, $count]); (=> $score) { 267 $result[] = ['id'=>$id, 'score'=>$score]; 268 } == 1 ? (empty($result) ? false : $result[0]) : $result; 272 } 273 }

Redis分布式锁和任务队列代码

 

 

  如果此博文中有哪里讲得让人难以理解,欢迎留言交流,若有讲解错的地方欢迎指出。

 

  

  互相学习,共同进步!

 

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    2017-05-02 11:02

  • 调取百度地图接口,实现取自己的实时位置,然后可以在百度地图上添加信息标注 - QISHUANG

    调取百度地图接口,实现取自己的实时位置,然后可以在百度地图上添加

    2017-04-18 10:02

  • 计算机网络——DNS协议的学习与实现 - 学数学的程序猿

    计算机网络——DNS协议的学习与实现 - 学数学的程序猿

    2017-04-16 10:00

  • 前端实现搜索记录功能也就是天猫app历史记录存储方便浏览 - 今天的代码你撸了嘛

    前端实现搜索记录功能也就是天猫app历史记录存储方便浏览 - 今天的代

    2017-04-12 14:00

网友点评