Redis 高级应用

270 阅读1分钟

分布式锁

  • 适用场景: 秒杀
$rand = rand(); // 设置一个随机数作为标签

// 第三个参数: 过期时间类型, EX 指秒数, PX 指毫秒数
// 第五个参数: NX 指不存在此 key 时才 set, XX 相反
$lock = $redis->set('lock', $rand, 'EX', 5, 'NX');
if ($lock) {
    // ... 业务逻辑

    if ($redis->get('lock') == $rand) { // 当值匹配时才解锁, 防止 A 任务时间过长导致 B 解锁 A
        $redis->del(['lock']);
    }
}

分布式锁不宜用于时间过长的任务

位图

  • 适用场景: 签到

HyperLogLog

  • 适用场景: 统计 UV

布隆过滤器

  • 适用场景: 推送新闻, 检查垃圾邮件地址, 爬虫 URL 地址去重, 解决缓存穿透问题
过滤前总数: 5 -> 过滤 ( 已推送的新闻 || 垃圾邮件地址 || 已爬 url ) -> 过滤后总数: 2 

不精确, 过滤器认为过滤列表有时却可能没有, 认为没有时则一定没有, 如垃圾邮件误报

Redis-Cell

  • 适用场景: 限流
// 扩展 https://github.com/brandur/redis-cell

// 参数 3: 总允许请求次数 -1
// 参数 4和参数 5: 每 60 秒完全请求完毕 30 个, 影响 **漏斗变空剩余时间**
// 参数 6: 每次使用额度, 默认 1
$response = $redis->executeRaw(['cl.throttle', 'test', 15, 30, 60, 1]);

print_r([
    '是否允许请求' => $response[0] ? '否' : '是',
    '总允许请求次数' => $response[1] . ' 次',
    '剩余可请求次数' => $response[2] . ' 次',
    '下一次允许请求时间' => $response[3] == -1 ? '即时' : $response[3] . ' 秒后',
    '漏斗变空剩余时间' => $response[4] . ' 秒后',
]);

GeoHash

  • 适用场景: 附近的人

scan

  • 适用场景: 匹配 key
// 参数 6: 不是指返回的结果量, 而是遍历的字节槽位数量
$redis->executeRaw(['scan', 0, 'match', '*keyword*', 'count', 10]);