Redis高级特性初识
慢查询
客户端请求的生命周期
客户端发送命令
入队列
执行命令(慢查询在这一阶段)
返回客户端
(客户端超时,不一定是慢查询,慢查询只是客户端超时的一个可能)
配置
slowlog-max-len,固定长度
slowlog-log-slower-than,慢查询阈值(单位微秒)
=0,记录所有命令
<0,不记录任何命令
#1. 第一次开启配置
config get slowlog-max-len = 128
config get slowlog-log-slower-than = 10000
#2. 修改默认配置重启
#3. 动态配置
config set slowlog-max-len = 128
config set slowlog-log-slower-than = 10000
API
慢查询会把命令放在内存中
slowlog get [n]:获取慢查询队列
slowlog len :获取慢查询队列长度
slowlog reset:清空慢查询队列
定期持久化查询
TIPS
slowlog-max-len 不要设置的过大,默认为10ms,通常设置为1ms
slowlog-log-slower-than 不要设置过小,通常设置为1000左右
理解命令生命周期
pipeline
流水线
n次通信时间=n次命令时间+n次网络时间
使用pipeline:1次网络+n次命令
客户端实现
maven:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
没有使用pipeline
Jedis jedis = new Jedis('127.1',6379);
for(int i=0;i<10000;i++){
jedis.hset("hashkey:"+i,"field"+i,"value"+i);
}
使用pipeline
Jedis jedis = new Jedis('127.1',6379);
for(int i=0;i<100;i++){
Pipeline pipeline = jedis.pipelined();
for(int j=i*100;j<(i+1)*100;j++){
pipeline.hset("hashkey:"+i,"field"+i,"value"+i);
}
pipeline.syncAndRetuenAll();
}
与原生M操作对比
M操作是原子的,而pipeline命令在队列中会被拆分为很多子命令,不是原子的
TIPS
注意每次pipeline携带数据量
pipeline每次只能作用在一个redis节点上
M操作与pipeline的区别
发布订阅
角色
发布者
订阅者
频道
通信模型
发布者向一个频道发布消息
订阅者可以订阅多个频道
订阅者不能收到他订阅之前的消息
API
pushlish channel message,返回订阅者个数
subscribe [channel] ,订阅一个或多个
unsubscribe [channel] ,取消一个或多个订阅
psubscribe [pattern] ,订阅指定的模式
punsubscribe [pattern],退订指定的模式
pubsub channels,列出至少有一个订阅者的频道
pubsub numsub [channel…],列出给定频道的订阅者数量
发布订阅与消息队列
发布订阅会让所有的客户端都受到消息
消息队列通过阻塞和list达到让多个客户端收到队列中的不同内容
消息队列类似于抢红包
BitMap
因为redis可以直接操作位
API
setbit key offset value,给位图指定索引设置值,返回offset之前的值(不要突然在很小的位图上做很大的偏移量)
getbit key offset,获取位图指定索引的值
bitcount key [start end],获取位图指定范围(start到end,单位为字节,如果不指定就是获取全部)位值为1的个数
bitop op destkey key [key…],做多个Bitmap的and(交),or(并),not(非),xor(异或)操作并将结果保存在destkey中
bitpos key targetBit [start] [end],计算位图指定范围start~end,单位为字节,如果不指定就是获取全部,第一个偏移量对应的值等于targetBit的位置
实战
- 独立用户统计
- 假设1亿总用户, 5千万独立用户用户
如果userid是整形,则使用set实现存储需要 32*50000000=200MB
BitMap:1*1亿=12.5MB
- 如果只有10万独立用户
如果userid是整形,则使用set实现存储需要 32*100000=4MB
BitMap:1*1亿=12.5MB
TIPS
type=string,最大512MB,可能需要拆分
注意setbit偏移量,可能有很大的耗时
位图不是绝对的好,需要在合适的场景使用合适的数据结构
HyperLogLog
基于HypeLogLog算法:可以在极小的空间完成独立数量统计
本质还是字符串
API
pfadd key element [element…],向hyperloglog添加元素
pfcount key [key…],计算hyperloglog的独立总数
pfmerge destkey sourcekey [sourcekey…],合并多个hyperloglog
实战
添加百万独立用户
elements=""
key="2019_03_09:users"
for i in `seq 1 1000000`
do
elements="${elements} uuid-"${i}
if [[$((i%1000)) == 0]]
then
redis-cli pfadd ${key} ${ellements}
elements=""
fi
done
内存消耗为15kb
TIPS
是否能容忍错误?(错误率 0.81%)
是否需要单条数据?(不能)
是否需要很小的内存解决问题?
GEO
GEO是什么
GEO(地理信息定位):存储经纬度,计算两地距离,范围计算
实战
需要计算两地距离,以及需要存储用户的位置的场景
API
geo key longitude latitude member [longitude latitude member…],增加地理位置信息(经纬度,名称)
geopos key member [member …],通过名称获取地理位置信息
geodist key member1 menber2 [m/km/mi(英里)/ft(尺)],获取两个地理位置的距离
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] ,获取指定位置范围内的地理位置的信息集合(O(N+logM), 其中 N 为指定半径范围内的位置元素数量, 而 M 则是被返回位置元素的数量) 代码示例
redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
2) "190.4424"
3) 1) "13.361389338970184"
2) "38.115556395496299"
2) 1) "Catania"
2) "56.4413"
3) 1) "15.087267458438873"
2) "37.50266842333162"
TIPS
since 3.2+
type geoKey = zset
没有删除API,可以使用
zrem key member
Comments