这里写自定义目录标题
<?php
/*
* Redis - set:集合类型与结构
* 每个集合最多可以存储 232 - 1 个元素(40多亿)
* 类型与list列表相似,都可以存储多个字符串元素的集合,但和list不同的是不允许重复额元素,而且set集合中的元素是没有顺序的,不存在元素下标。
*
*redis的set类型是使用哈希表构造的,因此复杂度是O(1),它支持集合内的增删改查,并且支持多个集合间的交集、并集、差集操作。可以利用这些集合操作,解决程序开发过程当中很多数据集合间的问题。
*
* set 使用哈希表结构:
* 1 数字元素少于513个的时候使用Intset(整数集合)集合的内部实现,以减少内存的使用。
* 2 数字元素大于512 或者 元素为字符串,则使用哈希表 作为集合的内部实现
* */
//基础函数
sadd();//添加元素,格式是:sadd set的key item的项值,item项可以有多个
smembers();//获取集合中所有元素,格式是:smembers set的key
sismember();//判断元素是否在集合中,格式是:sismember set的key item的项值
srem();//删除元素,格式是:srem set的key item项的值
scard();//获取集合中元素的个数,格式是:scard set的key
srandmember()//随机获取集合中的元素,格式是:srandmember set的key[数量]。(数量为正数时,会随机获取这么多个不重复的元素;如果数量大于集合元素个数,返回全部;如果数量为负,会随机获取这么多个元素,可能有重复。)
spop()//弹出元素,格式是:spop set的key
smove();//移动元素。格式是:smove 源set的key 目的set的key item项的值 (ps:一次只能移动一个item)
sdiff();//差集,返回在第一个set里面而不在后面任何一个set里面的项。格式是:sdiff set的key 用来比较的多个set的key
sdiffstore();//差集并保留结果,格式是:sdiffstore 存放结果的set的key set的key 用来比较的多个set的key
sinter();//交集,返回多个set里面都有的项。格式是:sinter 多个set的key
sinterstore();//交集并保留结果。格式是:sinterstore 存放结果的key 多个set的key
sunion();//并集。格式是:sunion 多个set的key
sunionstore();//并集并保留结果。格式是:sunionstore 存放结果的set的key 多个set的key
/*
应用案例 1 商品筛选
商城不同属性的产品ID集合 如:电脑的内存8G 一个集合,16G 一个集合等待,前段界面筛选的时候获取对应的集合ID ,并集/交集/差集 取出ID集合 再根据ID集合查询数据
应用案例 2 抽奖
使用 srandmember/spop 随机获取奖品
这两个命令功能非常相似,都是从集合中返回一个元素值。不同的是,sRandMember不会从集合中删除返回的元素,但是sPop会删除。这两个命令可以分别实现不同的抽奖算法。
比如,集合中有100个元素,值从数字1到数字100.我们定义抽到的是数字1的话,即表示中奖。
使用sRandMember的话,不管之前抽过多少次,下次抽中的概率都是1%。而使用sPop的话,则每次抽中的概率都不一样。第一个人抽中概率是1%,当第一个人没抽中的话,第二个人抽中概率就是1/99,以此类推。
应用案例 3
好友/关注/粉丝/感兴趣的人集合
a. sinter命令可以获得A和B两个用户的共同好友
b. sismember命令可以判断A是否是B的好友
c. scard命令可以获取好友数量
c. 关注时,smove命令可以将B从A的粉丝集合转移到A的好友集合
应用案例 4 随机展示
通常,app首页的展示区域有限,但是又不能总是展示固定的内容,
一种做法是先确定一批需要展示的内容,再从中随机获取。
如下图所示,酷狗音乐K歌擂台赛当日的打擂歌曲共29首,首页随机展示5首;
昨日打擂金曲共200首,首页随机展示30首。
应用案例 5 黑名单/白名单
经常有业务出于安全性方面的考虑,需要设置用户黑名单、ip黑名单、设备黑名单等,set类型适合存储这些黑名单数据,sismember命令可用于判断用户、ip、设备是否处于黑名单之中。
*/
/*
redis 慢查询
许多存储系统(例如MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阈值,就将这条命令的相关信息(例如:发生时间、耗时、命令的详细信息)记录下来,Redis也提供了类似的功能。
redis 命令的执行时间(排除tcp通讯和排挡等候等等耗时,只是Redis内部执行的时间)的时长,
时长以微秒计算(1秒=1000毫妙,1毫妙=1000微秒)
设置参数:
slowlog-log-slower-than:指定执行时间超过多少微秒(1秒等于1000000微秒) 的命令请求会被记录到日志上
slowlog-max-len:指定服务器最多保存多少条慢查询操作
设置命令:
CONFIG SET slowlog-log-slower-than num
CONFIG SET slowlog-max-len num
查看慢查询命令:
SLOWLOG GET
慢查询日志的添加和删除
当慢查询的条数达到最大值时,采用先进先出的方式删除最老的记录,所以可以 使用工具vc-redis-sniffer,从redis中抓取慢日志。保存起来 方便分析
*/
/*
Redis pipeline管道命令:
客户端与Redis服务器之间TCP通讯是有耗时的,如果大量的一组设置 如 给list/zset/set 添加大量的元素,就会有通讯间耗时比较多,这时候利用pipeline管道,把这一组命令都放入管道中,一次性的提交到服务器中,服务器处理完成在一次性的返回结果,从而节省了大量的通讯时间。
注意:使用通道的一组命令是不存在因果关系的,因为他们几乎是同时执行,不可能在客户端中做任何的前后因果关系逻辑判断处理。
特点:高内聚低耦合,
优点:
1 通过打包命令,一次性执行,可以节省 连接->发送命令->返回结果 所产生的往返时间,
减少的I/O的调用次数。
缺点:
1.前先缓存起所有命令的处理结果。这样就有一个内存的消耗。
2 是责任链模式,这个模式的缺点是,每次它对于一个输入都必须从链头开始遍历(参考Http Server处理请求就能明白),这确实存在一定的性能损耗。
3 不保证原子性,如果要求原子性的,不推荐使用 pipeline
*/
$redisObj = new \Redis();
$redisObj->connect('127.0.0.1', 6379);
$time_start = microtime(true);
$mcKey = "lpush:normal";
for ($i = 0; $i < 20000; $i++)
{
$redisObj->lPush($mcKey, $i);
}
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "逐条写模式耗时: {$time}\n";
// =======================================
$time_start = microtime(true);
$redisObj->multi(Redis::PIPELINE);
unset($time, $time_end, $mcKey);
$mcKey = "lpush:pipeline";
for ($i = 0; $i < 20000; $i++)
{
$redisObj->lPush($mcKey, $i);
}
$redisObj->exec();
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "pipeline 模式运行耗时:{$time}\n";