1、Redis 数据类型解析
- 字符串:基于简单动态字符串,时间复杂度为 O(1)。
- 哈希:基于哈希表,将字段(field)和值(value)映射到哈希表中。时间复杂度为 O(1),除了 HGETALL、HKEYS、HVALS等获取所有字段或值的操作时为 O(N)。
- 列表:基于双向链表和压缩列表两种数据结构实现的,大多数列表操作的时间复杂度是O(1),因为都是从头尾插入数据或者删除数据。但在某些情况下,比如在执行LRANGE、LINSERT、LREM等操作时,时间复杂度可能会变为O(N),其中 N 是列表的长度。
- 双向链表:数据量多时,需要频繁插入与删除(一般都是头尾插入或者删除),占用内存高。
- 压缩列表:数据量少时,插入与删除效率取决于插入的位置决定,占用内存低。
- 集合:基于哈希表,大多数集合操作的时间复杂度是O(1),但在某些情况下,比如在执行SMEMBERS、SDIFF、SINTER、SUNION等操作时,时间复杂度可能会变为O(N),其中 N 是所有集合中元素的总数
- 有序集合:基于跳跃表和哈希表两种数据结构。
- 跳跃表:存储有序元素,高效执行范围查询,时间复杂度 O(log N)。
- 哈希表:维护成员到分值的映射关系, 快速查找特定成员对应的分值,时间复杂度 O(1)
- HyperLogLog(基数估计算法):基于哈希表和位图实现的。
- 哈希表:存储计数器的信息,每个桶(bucket)对应一个哈希值,时间复杂度 0(1)
- 位图:将哈希值映射到位图中的相应位,位图的长度即为哈希表中的桶数。
2、PHP 使用 Redis
下载 Redis 拓展, 在配置文件中开启拓展。地址: https://github.com/phpredis/phpredis/releases
// 实例化 Redis 类
$redis = new \Redis();
- 字符串
// set 写入
$redis->set('key1', 'value1');
// get 读取
$redis->get('key1');
// mset 批量写入
$redis->mset(['key1' => 'value1', 'key2', 'value2']);
// mget 批量读取
$redis->mget(['key1','key2','key3']);
// setex 写入(过期时间,秒), 常用于分布式锁
$redis->setex('key1', 600, 'value1');
// incr 自增
$redis->incr('key1');
// decr 自减
$redis->decr('key1');
// del 删除一个或多个键值
$redis->del ('key1', 'key2');
- 哈希
// 写入
$redis->hset('obj', 'key1', 'value1');
// 读取
$redis->hget('obj', 'key1');
// 批量写入
$redis->hMSet('obj', ['key1' => 'value1', 'key2' => 'value2']);
// 批量读取
$redis->hMGet('obj', ['key1', 'key2', 'key3']);
// 读取键值所有值
$redis->hVals('obj');
- 列表
// lpush 一个或多个值插入(头部)
$redis->lPush('list', 'value1', 'value2');
// rpush 一个或多个值插入(尾部)
$redis->rPush ('list', 'value1', 'value2');
// rpop 移除列表最后一个元素
$redis->rPop('list');
// lpop 移除列表第一个元素
$redis->lPop('list');
// 阻塞 移除列表最后一个元素(配合lpush,一般用于消息队列)
// 当使用消息队列时,一般为单独的 PHP 文件,cli 命令执行,守护进程。
$timeOut = 100; // 设置为0时表示不断开
$redis->brPop('list', $timeOut);
// 阻塞 移除列表第一个元素
$timeOut = 100; // 设置为0时表示不断开
$redis->blPop('list', $timeOut);
- 集合
// 插入一个或多个成员
$redis->sAdd('key', 'value1', 'value2')
// 获取成员数
$redis->sCard('key')
// 判断是否存在某个成员
$redis->sIsMember('key','value1')
- 有序集合
// 插入一个或多个值
$redis->zAdd('k', 'scope1', 'member1', 'scope2', 'member2');
// 获取成员数
$redis->zCard('k');
// 成员加上指定分数 +3
$redis->zIncrby ('k', 'scope', 'member1');
- HyperLogLog
// 添加元素
$redis->pfAdd('key', ['hyper1', 'hyper2'])
// 返回 test_hyper 计数值(唯一值计数)
$redis->pfCount('key')
$redis->pfCount(['key1', 'key2'])
-
订阅发布
// 注意事项
// 此文件代码一般是写在业务逻辑里面传递参数
// 生产者 product.php(无密码,若存在密码则需要 $redis->auth('password') 方法验证)
$redis = new Redis();
$redis->connect("127.0.0.1",6379);
$redis->publish('channel',json_encode([
'name' => '张三',
'age' => 48
], JSON_UNESCAPED_UNICODE));
// 注意事项
// 此脚本 cli 命令执行(php customer.php), 注意依赖文件的导入
// 需要守护进程(可以使用 supervisor), 防止异常情况导致脚本挂掉
// 消费者 customer.php
ini_set('default_socket_timeout', -1);
$redis = new \Redis();
$redis = initRedis($redis);
while(true){
try{
$redis->subscribe(['channel'],function ($instance, $channelName, $message){
$message = json_decode($message, true);
var_dump(message);
});
sleep(1);
}catch(\Throwable $e){
$redis = initRedis($redis);
}
}
/**
* 初始化 Redis 连接
* @param \Redis $redis
* @return \Redis
* */
function initRedis($redis){
$redis->connect("127.0.0.1",6379);
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
return $redis;
}