Redis 作为一个开源的 (BSD) 基于内存的高性能存储系统, 已经被各大互联网公司广泛使用, 并且有着诸多的应用场景. 本篇文章将基于 PHP 来详细讲解 Redis 在 web 项目中的主要应用与实践.
缓存
这里所介绍的缓存是指可以丢失或过期的数据. 常用的命令有 set, hset, get, hget, 使用 Redis 作为缓存时需要注意一下几个问题:
由于 Redis 的可用内存是有限的, 不能容忍 Redis 内存的无限增长, 建议设置 maxmemory 最大内存.
在开启 maxmemory 的情况下, 可以启用 lru 机制, 设置 key 的 expire, 当到达 Redis 最大内存时, Redis 会根据最近最少用算法对 key 进行自动淘汰.
Redis 的持久化策略和 Redis 故障恢复时间是一个博弈的过程, 如果你希望在发生故障时能够尽快恢复, 应该启用 dump 备份机制, 但这样需要更多的可用内存空间来进行持久化. 如果能够容忍 Redis 漫长的故障恢复时间, 可以使用 AOF 持久化机制, 同时关闭 dump 机制, 这样不需要额外的内存空间.
存储
在 Web 项目中, Redis 可存储读写非常频繁的数据来缓解 MySQL 等数据库的压力. Redis 如果作为存储系统的话, 为了防止数据丢失, 持久化必须开启.
典型场景
计数器
- $queueKey = "queue";
- // 生产者
- $Redis->rpush($queueKey, $data)
- // 消费者
- while (true) {
- $data = $Redis->lpop($queueKey);
- if (null === $data) {
- usleep(100000);
- continue;
- }
- // 业务逻辑
- ...
- }
- $queueKey = "queue";
- // 生产消息
- // 消费时间, 这里设置为 1 小时候
- $consumeTimestamp = time() + 3600;
- // $data 需要添加随机串前缀(or 后缀), 防止出现重复 member 被丢弃
- $data = $data . md5(uniqid(rand(), true));
- $Redis->zadd($queueKey, $consumeTimestamp, $data);
- // 消费消息
- while (tue) {
- $arrData = $Redis->zrangebyscore($queueKey, 0, time());
- if (!$arrData) {
- usleep(100000);
- continue;
- }
- // 业务逻辑
- foreach ($arrData as $data) {
- $data = substr($data, 0, strlen($data) - 32);
- // 消费 $data
- }
- }
- $lockStatus = $Redis->setnx($lockKey, 1);
- if (1 === $lockStatus) {
- // 加锁成功, 为锁设置超时时间
- $Redis->expire($lockKey, 300);
- // 进行后续操作
- } elseif (0 === $lockStatus) {
- // 加锁失败
- } else {
- // 其他异常
- }
- $lockStatus = $this->Redis->set($lockKey, 1, "EX", 30, "NX");
- if ("OK" === $lockStatus) {
- // 加锁成功, 可进行后续操作
- // 业务逻辑执行完毕, 释放锁
- $this->Redis->del($lockKey);
- } elseif (null === $lockStatus) {
- // 加锁失败
- }
- $lockToken = md5(uniqid(rand(), true));
- // 此处超时时间根据具体业务逻辑配置
- $expire = rand(280, 320);
- $lockStatus = $this->Redis->set($lockKey, $lockToken, "EX", $expire, "NX");
- if ("OK" === $lockStatus) {
- // 加锁成功, 可进行后续操作
- // 业务逻辑执行完毕, 释放锁
- // 删除锁之前需要判断是否是自己上的锁
- $currentToken = $this->Redis->get($lockKey);
- if ($currentToken === $lockToken) {
- $this->Redis->del($lockKey);
- }
- } elseif (null === $lockStatus) {
- // 加锁失败
- }
- $arrPostsKey = [
- //...
- ];
- $arrPostsViewNum = $Redis->mget($arrPostsKey);
- // 存储数据
- $sortKey = "sort_key";
- $Redis->zadd($sortKey, 100, "tom");
- $Redis->zadd($sortKey, 80, "Jon");
- $Redis->zadd($sortKey, 59, "Lilei");
- $Redis->zadd($sortKey, 87, "Hanmeimei");
- // 获取排行
- // 由大到小排序
- $arrRet = $Redis->zrevrange($sortKey, 0, -1, true);
- // 由小到大排序
- $arrRet = $Redis->zrange($sortKey, 0, -1, true);
来源: https://juejin.im/post/5c695972e51d4501333ff190