Redis实现定长队列
工作经常会碰到类似只保留最新的多少条的问题。直接删除此缓存、或者任由缓存里的数据增加,只取XX条的解决方案都过于粗糙。抽象出此问题,也就是如何维持一个固定大小的缓存。
解决方案1.0
每次添加新元素后,都会判断此缓存中的元素个数,如果大于XX则删除多余元素
$this->redis->lPush($key, $data); $count = $this->redis->lLen($key); $limit = 200; if($count > $limit) { $this->redis->rPop($key); }
解决方案2.0
上述方案,需要与redis通讯至少2次,至多3次,当然可以用事务把前两个redis操作合成一次通讯,但那也至多会有2次,能不能都是一次通讯呢?
我们努力的方向就是如何把元素个数判断给去掉,于是我们可以这么使用redis截取命令LTRIM与 ZREMRANGEBYRANK
/** * list添加元素维持固定长度,左侧入栈,右侧出栈 * @param string $key * @param string $data 添加的元素 * @param int $length 固定长度 * @return bool/array */ public function lPushLimit($key, $data, $length) { if(!$this->redis || empty($data) || $length <= 0){ return false; } return $this->redis->multi() ->lPush($key, $data) ->lTrim($key, 0, $length-1) ->exec(); } /** * list添加元素维持固定长度,右侧入栈,左侧出栈 * @param string $key * @param string $data 添加的元素 * @param int $length 固定长度 * @return bool/array */ public function rPushLimit($key, $data, $length) { if(!$this->redis || empty($data) || $length <= 0){ return false; } return $this->redis->multi() ->rPush($key, $data) ->lTrim($key, -$length, -1) ->exec(); } /** * zset添加元素时维持固定长度 * @param string $key * @param array $data 添加的元素 [6, 'sixth']/[6, 'sixth', 7, 'seventh'] * @param int $length 固定长度 * @param bool $pop_min 出栈元素是否为最小score值 * @return bool/array */ public function zAddLimit($key, $data, $length, $pop_min = true) { if(!$this->redis || empty($data) || $length <= 0){ return false; } if ($pop_min) { $start = 0; $stop = -$length-1; } else { $start = $length; $stop = PHP_INT_MAX; } return $this->redis->multi() ->zAdd($key, ...$data) ->zRemRangeByRank($key, $start, $stop) ->exec(); }