目录
- Slowlog概述
- Slowlog源码简析
- Slowlog测试
Slowlog概述
slowlog是指那些执行时间超过某个指定时间的查询,这里的执行时间不包括对磁盘的I/O操作、与客户端的连接等额外开销,只包含对内存数据的操作时间。Redis提供了以下两个配置来管理slowlog
# 超时时间阈值设定,单位微妙
slowlog-log-slower-than 10000
# 可存储的慢日志条数
slowlog-max-len 128
slowlog-log-slower-than用于指定超时时间的阈值,超过该值的操作会被认为是慢查询,Redis会为其生成一条对应的慢日志存储在内存中。同时为了防止慢日志占用过多内存空间,通过slowlog-max-len可以限定内存中可存储的慢日志的最大条数,当超出最大条数后,根据FIFO规则,会将最早的slowlog删除。
Slowlog源码简析
slowlog.h定义了慢日志对应的结构体信息
#define SLOWLOG_ENTRY_MAX_ARGC 32 /* 每条慢查询日志最多记录32个查询参数 */
#define SLOWLOG_ENTRY_MAX_STRING 128 /* 每个查询参数最长只记录128个字符 */
/* This structure defines an entry inside the slow log list */
typedef struct slowlogEntry {
robj **argv; /* 参数信息 */
int argc; /* 参数个数 */
long long id; /* 日志ID: Unique entry identifier. */
long long duration; /* 命令执行时间: Time spent by the query, in microseconds. */
time_t time; /* 日志创建时间:Unix time at which the query was executed. */
} slowlogEntry;
/* Exported API */
void slowlogInit(void);
void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration);
/* Exported commands */
void slowlogCommand(client *c);
slowlog.c中定义了具体的流程,以下是部分源码
/* Initialize the slow log. This function should be called a single time
* at server startup. */
void slowlogInit(void) {
server.slowlog = listCreate(); /* 创建一个list列表 */
server.slowlog_entry_id = 0; /* 日志ID从0开始 */
listSetFreeMethod(server.slowlog,slowlogFreeEntry); /* 指定慢查询日志list空间的释放方法 */
}
/* Push a new entry into the slow log.
* This function will make sure to trim the slow log accordingly to the
* configured max length. */
void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) {
if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */ /* 负数表示禁用 */
if (duration >= server.slowlog_log_slower_than) /* 如果执行时间 > 指定阈值*/
listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration)); /* 创建一个slowlogEntry对象,添加到列表首部*/
/* Remove old entries if needed. */
while (listLength(server.slowlog) > server.slowlog_max_len) /* 如果列表长度 > 指定长度 */
listDelNode(server.slowlog,listLast(server.slowlog)); /* 移除列表尾部元素 */
}
Slowlog测试
step1:为了方便测试,这里临时设置时间阈值为1微妙,长度限制为3条。任意执行几条命令,比如mset、keys *、slowlog get等
从结果可以看出,有三条命令执行时间都超过了1微妙,都生成了对应的slowlog。而且slowlog get打印输出的信息和slowlogEntry结构体相对应。
对于命令01config set...由于其执行时间<10ms(在执行命令02之前时间阈值为10ms),所以没有生成慢日志。对于命令5slowlog get,其执行时间其实是超过了1纳秒的,之所以没有打印出来,是因为slowlog get在返回给客户端信息之后才会生成慢日志并存储进内存。step2验证了这一点
step2:继续执行任意命令,比如一个sadd,然后再执行slowlog get。
结果说明ID等于0和1的慢日志已经被删除;对于key长度>128的,在记录日志时进行了截取;代表上次slowlog get命令的慢日志被打印出来了。
Slowlog应用
-
慢查询时间阈值默认为10ms,依官方介绍来看10毫秒确实算慢了,生产环境中可以适当的调低该值,比如1~5毫秒。
-
由于慢查询日志列表的FIFO规则,为了防止日志丢失的情况,生产环境中可以定期执行 slowlog get命令将慢查询日志持久化到文件或DB中,然后通过可视化工具进行查询。同时为了防止在高并发情况下慢日志数量瞬间达到规定上限,在尚未持久化就已经丢失的情况,可以调大slow-max-len,比如1000。