自动化

Redis 必知必会

2019-03-14  本文已影响15人  51reboot

Redis 必知必会

一、redis 需要掌握的知识点

二、redis常见应用场景 && 一些注意的地方

排行榜,计数器,社交网络,消息队列等

场景1: 遍历一个set || zset || hash 匹配某个 pattern 的所有元素。

/**
 * 给用户发放奖励
 */
public function runSendReward()
{
    $it = null;
    $this->_redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY);
    while ($arr_keys = $this->_redis->getRealConnect()->hScan(self::KEY_INVITE_PUPIL_REWARD, $it)) {
        foreach ($arr_keys as $memberId => $time) {
            if ($this->_redis->hExists(self::KEY_INVITE_SEND_REWARD, $memberId)) {
                continue;
            }
            $validPupils = $this->getPupils($memberId);
            $reward = $this->getRewardsByRule($validPupils);
            $reward = $reward['reward'];
            $ret = $this->sendActReward($memberId, $validPupils, $reward);
            if (false == $ret) {
                echo "Faild : member_id : {$memberId} \r\n";
            }
        }
    }
}

增量式迭代命令:

SCAN, HSCAN, SSCAN, ZSCAN

优点:

从完整遍历开始直到完整遍历结束期间, 一直存在于数据集内的所有元素都会被完整遍历返回; 这意味着, 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。

缺点:

1、同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。

2、如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的(undefined)。

注意:
1、遍历的时候处理重复出现的元素。

场景2: 注意分片 && 加锁

public function withdraw($memberId, $amount = '')
{
    if (empty($amount)) {
        $this->_err = self::$ERR_WITHDRAW_ERROR;
        return false;
    }

    //商城限制最高提现额度
    $maxWithdrawOnce = self::MAX_WITHDRAW_ONCE;
    if ($amount > $maxWithdrawOnce) {
        $leftAmount = bcsub($amount, $maxWithdrawOnce);
    } else {
        $leftAmount = 0;
    }

    $oLock = new Lock($this->_redis); //注意一定要枷锁
    $keyLock = $this->_getKeyWithdrawLock($memberId);
    if (!$oLock->acquire($keyLock, 0, 10)) {
        $this->_err = self::$ERR_WITHDRAW_DIFF_TIME;
        return false;
    }
    $params = [];
    $result = Servbox()->Mall_Order()->addOrderScene($memberId, $params);
    if (!$result) {
        $err              = Servbox()->Mall_Order()->getErrMsg();
        $debug['err_msg'] = $err;
        RegBox()->Log()->info("[actMS3] withdraw error . data: " . json_encode($debug));
        $this->_err = $err;
        return false;
    }

    //保存提现记录,扣除余额
    $keyAmount = $this->_getKeyAmount($memberId);
    $this->_redis->hSet($keyAmount, $memberId, bcmul($leftAmount, Model\Balance::UNIT_SCALE));
    $this->_setKeyExpire($keyAmount);
    $oLock->release($keyLock);

    return true;
}

//用户余额key
private function _getKeyAmount($memberId)
{
    $mod = $memberId % self::SLICE_NUM; 
    return sprintf(self::$KEY_ACT_AMOUNT, $mod);
}

场景3: 排行榜 && 队列

/**
 * @desc 添加中奖信息到列表
 * @param int $memberId
 * @param int $coinRewardNum
 */
private function _addTopList($memberId, $coinRewardNum)
{
    $key = $this->_getTopListKey();
    $statExpireDay = (int)$this->_conf['stat_expire_day'];
    if ($this->_redis->exists($key)) {
        $this->_redis->zIncrBy($key, $coinRewardNum, $memberId);
    } else {
        $this->_redis->zAdd($key, $coinRewardNum, $memberId);
    }
    $this->_redis->expire($key, self::DAY_SECONDS * $statExpireDay);
}

/**
 *  获取排行榜
 * @return array
 */
public function getTopList($num = 10)
{
    $key = $this->_getTopListKey();
    $list = $this->_redis->zRevRangeByScore($key,
        '+inf',
        '-inf',
        ['limit' => [0, $num + 5], 'withscores' => true]);

    $data = [];
    if ($list) {
        foreach ($list as $key => $val) {
            $nickname = $this->_container->Member()->getMemberInfoByField($key, 'nickname');
            if (!$nickname) continue;
            if (count($data) == $num) break;
            $temp['member_id'] = 'A'.$this->_hideMemberId($key);
            $temp['coin'] = $val;
            $temp['nickname'] = $nickname;
            $data [] = $temp;
        }
    }
    return $data;
}

三、redis常见问题

1、先读缓存还是先写数据库
2、缓存更新策略(使用场景、一致性、维护成本)

3、缓存穿透解决

缓存空对象(场景:数据频繁变化实时性高; 缺点:更多的空间,短时间内有不一致的情况-可以利用消息系统主动清除) 布隆过滤器拦截(场景:数据相对固定实时性低)

4、缓存雪崩优化

5、热点 key

重建热点 key

6、bigkey(胃寒:数据倾斜,超时足额,)

要求:

发现及删除注意事项:

四、扩散问题: redis 为啥单线程模型会达到每秒万级别的处理能力?

作者:PHP Zendo
出处:http://blog.phpzendo.com/?p=508

51Reboot 2019 最新课程招生信息

Python 零基础入门课程
此课程为面授班和网络班,一共 15 个课时,每周上一个全天,历时4个月。附加:录播视频+笔记+答疑2019-6月份开课

Python 自动化运维进阶课程
此课程为面授班和网络班,一共 15 个课时,每周上一个全天,历时4个月。附加:录播视频+笔记+答疑2019-4月份开课

Docker+K8s 课程
此课程为网络班,一共 150个课时,每周上一个全天,历时4个月。附加:录播视频+笔记+答疑现已开课
现在报名即可享受早鸟价

golang 课程

早报名可享受早鸟价
想要详细了解和报名的同学可以扫码添加好友私聊


image
上一篇下一篇

猜你喜欢

热点阅读