瑞士军刀Redis
- 慢查询
- pipeline
- 发布订阅
- Bitmap
- HyperLogLog
- GEO
慢查询
声明周期
- 慢查询发生在第三阶段 (执行命令), 其中发送命令和排队导致的响应时延问题并不属于慢查询, 而是由于执行(keys, flushall, flushdb, slow lua script, mutil/exec, operate big value (collection))这些重量级的命令导致的问题.
- 客户端超时不一定是慢查询, 但慢查询是客户端超时的一个可能因素.
- 我们可以使用 slowlog(慢查询)功能找出最耗时的 Redis 命令进行相关的优化,以提升 Redis 的运行速度,慢查询有两个重要的配置项.
两个配置
slowlog-max-len
- 表示慢查询日志的条数
- 慢查询队列是一个先进先出队列, 当队列超过长度将会剔除最先入队的慢查询信息
- 慢查询队列是一个固定长度的队列(可通过配置文件或者命令修改此长度)
- 慢查询队列保存在内存中, 将随着内存的
slowlog-log-slower-than
- 慢查询阈值 (单位: 微秒), 执行超过这个时间的命令将被记录到慢查询日志
- slowlog-log-slower-than = 0, 记录所有命令
- slowlog-log-slower-than < 0, 不记录任何命令
配置方法
默认值
127.0.0.1:6379> config get slowlog-max-len
1) "slowlog-max-len"
2) "128"
127.0.0.1:6379> config get slowlog-log-slower-than
1) "slowlog-log-slower-than"
2) "10000"
修改配置文件重启
- 不推荐, 当首次运行时可以使用此操作, 运行时是支持动态配置的
动态配置
127.0.0.1:6379> config set slowlog-max-len 1000 OK 127.0.0.1:6379> config set slowlog-log-slower-than 1000 OK
慢查询命令
- slowlog get [n] : 获取慢查询队列
- slowlog len : 获取慢查询队列长度
- slowlog reset : 清空慢查询队列
运维经验
slowlog-log-slower-than 不要设置过大, 默认10ms, 通常设置1ms, 通过QPS来确定此参数
slowlog-max-len 不要设置过小 (设置过小不利于慢查询日志分析), 通常设置1000左右
理解命令声明周期
定期持久化慢查询, 因为慢查询记录在内存中(队列长度和内存重启都可能导致慢查询日志丢失), 可以利用slowlog get命令来持久化到硬盘上
Pipeline
1次网络命令通信模型
批量网络命令通信模型
什么是流水线
流水线的作用
注意:
- Redis的命令时间是微秒级别. (网络命令传输是Redis执行效果的瓶颈之一)
- Pipeline每次条数要控制 (网络).
Pipeline - Jedis实现
- 执行10000条命令时:
没有pipeline
使用pipeline
Pipeline与原生M操作
原生M操作
Pipeline
Pipeline使用建议
- 注意每次pipeline携带数据量
- pipeline每次只能作用在一个Redis节点上
- M操作与pipeline区别
发布订阅
角色
- 发布者 (publisher)
- 订阅者 (subscriber)
- 频道 (channel)
模型
- 发布者和订阅者都是一个redis客户端
- 发布者发送一个消息, 订阅该频道的订阅者都可以接受到此消息
- 一个订阅者可以同时订阅多个频道
API
- publish
- unsubscribe
- subscribe
- 其他
publish (发布命令)
API:
publish channel message
演示:
127.0.0.1:6379> publish sohu:tv "helloworld"
(integer) 2
subscribe (订阅)
API:
subscribe [channel] # 一个或多个
演示:
127.0.0.1:6379> subscribe sohu:tv
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "sohu:tv"
3) (integer) 1
1) "message"
2) "sohu:tv"
3) "helloworld"
unsubscribe (取消订阅)
API:
unsubscribe [channel] # 一个或多个
演示:
127.0.0.1:6379> unsubscribe souhu:tv
1) "unsubscribe"
2) "souhu:tv"
3) (integer) 0
其他API
psubscribe [pattern...] # 订阅模式
punsubscribe [pattern...] # 取消指定的订阅模式
pubsub channels # 列出至少有一个订阅者的频道
pubsub numsub [channel...] # 列出给定频道的订阅者数量
消息队列和发布订阅
Bitmap
位图
- Redis可以对存储的数据进行对位操作
- 示例:
127.0.0.1:6379> set hello big
OK
127.0.0.1:6379> getbit hello 0
(integer) 0
127.0.0.1:6379> getbit hello 1
(integer) 1
127.0.0.1:6379> getbit hello 2
(integer) 1
127.0.0.1:6379> getbit hello 3
(integer) 0
API
setbit
API:
# 给位图指定索引设置值
setbit key offset value
演示:
效果:
- 可以做一些独立用户统计的功能
- 如果只设置索引50, 则位图变为:
- 注意: 一般不要在一个很短的位图上突然间做一个很大的偏移量, 会引起一些问题 (注意Redis是一个单线程)
getbit
API:
# 获取位图指定索引的值
getbit key offset
演示:
bitcount
API:
# 获取位图指定范围(start到end, 单位为字节, 如果不能指定就是获取全部)位值为1的个数
bitcount key [start end]
演示:
bitop
API:
# 做多个Bitmap的and(交集), or(并集), not(非), xor(异或)操作并将结果保存在destkey中
bitop op destkey key [key...]
演示:
bitpos
API:
# 计算位图指定范围(start到end, 单位为字节, 如果不能指定就是获取全部)第一个便宜量对应的值等于targetBit的位置
bitpos key targetBit [start] [end]
演示:
127.0.0.1:6379> setbit bitops_key 2 1
(integer) 0
127.0.0.1:6379> setbit bitops_key 4 1
(integer) 0
127.0.0.1:6379> bitcount bitops_key 0 1
(integer) 2
127.0.0.1:6379> bitpos bitops_key 1
(integer) 2
127.0.0.1:6379> bitpos bitops_key 1 3
(integer) -1
独立用户统计
- 1亿用户, 5千万独立
set和Bitmap对比
- 只有10万独立用户
使用经验
- Bitmap的 type = string, 且最大支持512MB
- 注意setbit时的偏移量, 可能有较大消耗
- 位图不是绝对的好, 要根据合理的场景进行使用
HyperLogLog
基于HyperLogLog算法: 极小的空间完成独立数量统计
在Redis中本质还是字符串
三个命令
- pfadd key element [element…] # 向HyperLogLog添加元素
- pfcount key [key…] # 计算HyperLogLog的独立总数
- pfmerge destkey sourcekey [sourcekey…] # 合并多个HyperLogLog
演示
内存消耗 (百万独立用户)
使用经验
是否能够容忍错误? (错误率: 0.81%)
- 例如上述百万条数据做如下操作:
是否需要单条数据?
- HyperLogLog不能够获取单条数据
GEO
- GEO (地理位置信息定位): 存储经纬度, 计算两地距离, 范围计算等
应用场景
5个城市经纬度
API
geoadd
API:
# 增加地理位置信息
geo key longitude latitude member [longitude latitude member...]
演示:
geopos
API:
# 获取地理位置信息
geopos key member [member...]
演示:
geodist
API:
# 获取两个地理位置的距离
# unit: m(米), km(千米), mi(英里), ft(尺)
geodist key member1 member2 [unit]
georadius
API:
示例:
相关说明
- since 3.2 +
- type geoKey = zset
- 没有删除API: 可以利用zset实现删除 zrem key member