Redis - 慢查询
Redis 的慢查询日志功能用于记录执行时间超过给定时长的命令请求,用户可以通过这个功能产生的日志来监视和优化查询速度。
服务配置慢查询参数:
-
slowlog-log-slower-than 选项指定执行时间超过多少微秒(1秒等于 1000000 微秒)的命令请求会被记录到日志上
举例,如果这个选项值为100,那么执行时间超过100微秒的命令就会被记录到慢查询日志,如果这个选项为500,那么执行时间超过500微秒的命令就会被记录到慢查询日志
-
slowlog-max-len 选项指定服务器最多保存多少条慢查询日志
服务器使用先进先出的方式保存多条慢查询日志,当服务器储存的慢查询日志数量等于 slowlog-max-len 选项的值时,服务器在添加一跳新的慢查询日志之前,会先将最旧的一跳慢查询日志删除。
让我们看一下慢查询日志功能的例子,首先用 CONFIG_SET 命令将 slowlog-log-slower-than 选项的值设为0微秒,这样 Redis 服务器执行的任何命令都会被记录到慢查询日志中,接着将 slowlog-max-len 选项的值设为 5,让服务器最多只保存 5 条慢查询日志
redis> CONFIG SET slowlog-log-slower-than 0
OK
redis> CONFIG SET slowlog-max-len 5
OK
接着, 我们用客户端发送几条命令请求:
redis> SET msg "hello world"
OK
redis> SET number 10086
OK
redis> SET database "Redis"
OK
然后使用 SLOWLOG GET 命令查看服务器所保存的慢查询日志:
redis> SLOWLOG GET
1) 1) (integer) 4 # 日志的唯一标识符(uid)
2) (integer) 1378781447 # 命令执行时的 UNIX 时间戳
3) (integer) 13 # 命令执行的时长,以微秒计算
4) 1) "SET" # 命令以及命令参数
2) "database"
3) "Redis"
2) 1) (integer) 3
2) (integer) 1378781439
3) (integer) 10
4) 1) "SET"
2) "number"
3) "10086"
3) 1) (integer) 2
2) (integer) 1378781436
3) (integer) 18
4) 1) "SET"
2) "msg"
3) "hello world"
4) 1) (integer) 1
2) (integer) 1378781425
3) (integer) 11
4) 1) "CONFIG"
2) "SET"
3) "slowlog-max-len"
4) "5"
5) 1) (integer) 0
2) (integer) 1378781415
3) (integer) 53
4) 1) "CONFIG"
2) "SET"
3) "slowlog-log-slower-than"
4) "0"
如果这时再执行一条 SLOWLOG GET 命令,那么我们将看到,上一次执行的 SLOWLOG GET命令已经被记录到慢查询日志中,而最旧的、编号为 0 的慢查询日志已经被删除,服务器的慢查询日志数量仍然为5条
redis> SLOWLOG GET
1) 1) (integer) 5
2) (integer) 1378781521
3) (integer) 61
4) 1) "SLOWLOG"
2) "GET"
2) 1) (integer) 4
2) (integer) 1378781447
3) (integer) 13
4) 1) "SET"
2) "database"
3) "Redis"
3) 1) (integer) 3
2) (integer) 1378781439
3) (integer) 10
4) 1) "SET"
2) "number"
3) "10086"
4) 1) (integer) 2
2) (integer) 1378781436
3) (integer) 18
4) 1) "SET"
2) "msg"
3) "hello world"
5) 1) (integer) 1
2) (integer) 1378781425
3) (integer) 11
4) 1) "CONFIG"
2) "SET"
3) "slowlog-max-len"
4) "5"
慢查询记录保存
服务器状态中包含来几个和慢查询日志功能有关的属性:
struct redisServer {
// ...
// 下一条慢查询日志的 ID
long long slowlog_entry_id;
// 保存了所有慢查询日志的链表
list *slowlog;
// 服务器配置 slowlog-log-slower-than 选项的值
long long slowlog_log_slower_than;
// 服务器配置 slowlog-max-len 选项的值
unsigned long slowlog_max_len;
// ...
};
slowlog_entry_id 属性初始值为 0,每当创建一条新的慢查询日志时,这个属性的值就会用作新日志的 id 值,之后程序会对这个属性的值增一。
比如说,在创建第一条慢查询日志时,slowlog_entry_id 的值 0 会成为第一条慢查询日志的 ID,而之后服务器会对这个属性的值增一,当服务器再创建新的慢查询日志的时候,slowlog_entry_id 的值 1 就会成为第二条慢查询日志的 ID,然后服务器再次对这个属性的值增一,以此类推。
slowlog 链表保存了服务器中的所有慢查询日志,链表中的每个节点都保存了一个 slowlogEntry 结构,每个 slowlogEntry 结构代表一条慢查询日志:
typedef struct slowlogEntry {
// 唯一标识符
long long id;
// 命令执行时的时间,格式为 UNIX 时间戳
time_t time;
// 执行命令消耗的时间,以微秒为单位
long long duration;
// 命令与命令参数
robj **argv;
// 命令与命令参数的数量
int argc;
} slowlogEntry;
举例:对于以下慢查询日志来说
1) (integer) 3
2) (integer) 1378781439
3) (integer) 10
4) 1) "SET"
2) "number"
3) "10086"
下图展示的就是该日志所对应的 slowlogEntry 结构
下图展示了服务器状态中,和慢查询功能有关的属性:
- slowlog_entry_id 的值为 6 , 表示服务器下条慢查询日志的 id 值将为 6
- slowlog 链表包含了 id 为 5 至 1 的慢查询日志, 最新的 5 号日志排在链表的表头, 而最旧的 1 号日志排在链表的表尾, 这表明 slowlog 链表是使用插入到表头的方式来添加新日志的
- slowlog_log_slower_than 记录了服务器配置 slowlog-log-slower-than 选项的值 0 , 表示任何执行时间超过 0 微秒的命令都会被慢查询日志记录
- slowlog-max-len 属性记录了服务器配置 slowlog-max-len 选项的值 5 , 表示服务器最多储存五条慢查询日志