慢查询分析
所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阈值,就将这条命令的相关信息(例如:发生时间、耗时、命令的详细信息)记录下来。
- 生命周期:发送命令 -> 命令排队 -> 执行命令 -> 返回结果
- 慢查询发生在第 3 阶段
- 客户端超时不一定是慢查询,但慢查询是客户端超时的一个可能因素
- 两个配置参数
slowlog-max-len
:保存慢查询的队列最大长度,默认值128slowlog-log-slower-than
:慢查询阈值(单位:微秒),表示执行时间大于多少时被记录为慢查询,设为 0 表示记录所有命令,小于 0 表示不记录任何命令,默认值10000(10毫秒)修改配置方式
- 一种是修改配置文件
- 另一种是使用 config set 命令动态修改,例如:
config set slowlog-max-len 256 config set slowlog-log-slower-than 1000
- 慢查询命令
- 虽然慢查询日志是存放在 Redis 内存列表中的,但是 Redis 并没有暴露这个列表的键,而是通过一组命令来实现对慢查询日志的访问和管理。
slowlog get [n]
:获取慢查询队列slowlog len
:获取慢查询队列当前长度slowlog reset
:清空慢查询队列- 慢查询日志结构:
- 运维经验
slowlog-log-slower-than 不要设置过大
,默认 10ms,通常设置 1msslowlog-max-len 不要设置过小
,通常设置 1000 左右- 理解命令的
生命周期
,慢查询只记录命令执行时间,并不包括命令排队或网络传输时间 - 定期
持久化
慢查询日志,由于慢查询日志是一个先进先出的队列,也就是说如果慢查询比较多的情况下,可能会丢失部分慢查询命令。
pipeline(流水线)
Redis 提供了批量操作命令(例如 mget、mset 等),有效地节约 RTT(Round Trip Time,往返时间)。但大部分命令是不支持批量操作的,例如要执行 n 次 hgetall 命令,并没有 mhgetall 命令存在,需要消耗 n 次 RTT。
Pipeline(流水线)机制能改善上面这类问题,它能
将一组 Redis 命令进行组装,通过一次 RTT 传输给 Redis,再将这组 Redis 命令的执行结果按顺序返回给客户端
。
- 注意
- pipeline 每次条数要控制(网络请求)
- pipeline 批量执行命令,
目的是节省多次 IO 往返的时间
- pipeline 每次只能作用在一个 Redis 节点上
- pipeline的使用
- 没有 pipeline,大概需要 50s
Jedis jedis = new Jedis("127.0.0.1", 6379);
for(int i = 0; i < 10000; i++){
jedis.hset("hashkey:" + i, "field" + i, "value" + i);
}
- 使用pipeline:大概需要0.7s
Jedis jedis = new Jedis("127.0.0.1", 6379);
for(int i = 0; i < 100; i++){
Pipeline pipeline = jedis.pipelined();
for(int j = 0; j < 100; j++){
pipeline.hset("hashkey:" + j, "field" + j, "value" + j);
}
pipeline.syncAndReturnAll();
}
- 原生批量命令与 Pipeline 对比
- 原生批量命令是原子操作,Pipeline 是非原子操作
- 原生批量命令是一个命令对应多个 key,Pipeline 支持多个命令
- 原生批量命令是 Redis 服务端支持实现的,而 Pipeline 需要服务端和客户端的共同实现
事务与 Lua
为了保证多条命令组合的原子性,Redis 提供了简单的事务功能以及集成 Lua 脚本来解决这个问题。
- 事务
- Redis 提供了简单的事务功能,将一组需要一起执行的命令放到
multi 和 exec
两个命令之间。 - multi 命令代表事务开始,exec 命令代表事务结束,他们之间的命令是原子顺序执行的。
- 注意,Redis 并不支持回滚功能。
- Lua
- Redis 将 Lua 作为脚本语言可帮助开发者定制自己的 Redis 命令。
- 在 Redis 中执行 Lua 脚本有两种方法:
eval 和 evalsha
- Lua 脚本功能为 Redis 开发和运维人员带来三个好处:
- Lua 脚本在 Redis 中是
原子执行
的,执行过程中间不会插入其他命令 - Lua 脚本可以帮助开发和运维人员创造出自己
定制的命令
,并可以将这些命令常驻在 Redis 内存中,实现复用的效果 - Lua 脚本可以将多条命令一次性打包,有效地
减少网络开销
- Lua 脚本在 Redis 中是
- Redis 提供了 4 个命令实现对 Lua 脚本的管理
script load
:用于将 Lua 脚本加载到 Redis 内存中script exists
:判断 Lua 脚本是否已经加载到内存中script flush
:用于清除 Redis 内存已经加载的所有 Lua 脚本script kill
:用于杀掉正在执行的 Lua 脚本
BitMaps(位图)
Redis 提供了 Bitmaps 这个“数据结构”可以实现对位的操作。
- 数据结构模型
- 本身不是一种数据结构,实际上它就是
字符串
,但是它可以对字符串的位进行操作 - BitMaps 单独提供了一套命令,所以在 Redis 中使用 BitMaps 和使用字符串的方法不太相同。
- API
setbit key offset value
:给位图指定索引设置值,第 offset 位设置成 value,value 只能是 0 或 1getbit key offset
:获取某一位的值bitcount key [start end]
:获取位图指定范围(start 到 end,单位为字节,不指定表示获取所有)位值为1的个数bitop op destkey key [key...]
:做多个 Bitmap 的 and(交集),or(并集),not(非),xor(异或)操作,并将结果保存到 destkey 中bitops key targetBit [start] [end]
:计算位图指定范围(start 到 end,单位为字节,如果不指定就是获取全部)第一个偏移量对应的值等于 targetBit 的位置。
- 使用经验
- 位图实际类型就是 string,最大 512MB
- 注意 setbit 时的偏移量,可能有较大耗时
Hyperloglog
- 数据结构模型
- 并不是一种新的数据结构,实际类型也是
字符串类型
,而是一种基数算法,通过 Hyperloglog 可以利用极小的内存空间完成独立总数的统计
,数据集可以是 IP、Email、ID 等。
- API
pfadd key element [element ...]
:向 Hyperloglog 添加元素pfcount key [key ...]
:计算 Hyperloglog 的独立总数pfmerge destkey sourcekey [sourcekey ...]
:合并多个 Hyperloglog
- 使用经验
- 是否能够容忍错误?Redis 官方给出的数字是 0.81% 的失误率
- 是否需要单条语句?这里是无法取出单条语句
- 使用场景可以是统计一些用户数,而且可以接受一个很小的误差
发布订阅
Redis 提供了基于“发布/订阅”模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道(channel)发布消息,订阅该频道的每个客户端都可以收到该消息。
- API
publish channel message
:向 channel 频道发布 message 消息,返回结果是订阅者数subscribe [channel]
:可订阅一个或多个频道unsubscribe [channel]
:取消订阅psubscribe [pattern...]
:订阅模式punsubscribe [pattern...]
:退订指定的模式pubsub channels
:列出至少有一个订阅者的频道pubsub numsub [channel...]
:列出给定频道的订阅者数量pubsub numpat
:列出被订阅模式的数量
- 使用场景
- 聊天室、公告牌、服务之间利用消息解耦都可以使用发布订阅模式。
GEO(地理信息定位)
Redis 提供的 GEO 功能,支持存储地理位置信息用来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。
- API
geoadd key lng lat member [lng lat member ...]
:增加地理位置信息geopos key member [member ...]
:获取地理位置信息geodist key member1 member2 [unit]
:获取两个地理位置的距离,unit:m(米),km(千米),mi(英里),ft(尺)georadius
:获取地理位置信息
- 说明
- GEO 数据类型是 zset,Redis 间所有地理位置信息的 geohash 存放在 zset 中。
- GEO 没有提供删除命令,直接使用 zset 命令就行:zrem key member
来源:《Redis 开发与运维》第 3 章 小功能大用处