当前位置: 首页 > redis, 分布式系统, 缓存系统 > 正文

Redis核心解读–Slow Log

关键字:
1 星2 星3 星4 星5 星 (2 次投票, 评分: 5.00, 总分: 5)
Loading ... Loading ...
baidu_share

Slow Log简介
Redis Slow Log是用来记录长命令执行的情况。它使用两个配置参数slowlog-log-slower-than和slowlog-max-len来指定长命令执行时间和Slow Log的最大长度。这里的执行时间不包括与客户端交互的时间,Redis因为是单线程异步的,而命令的执行是阻塞的所以很容易可以得出一个命令的执行时间。slowlog-log-slower-than 1000000指的就是1秒。
Slow log相关结构定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define SLOWLOG_ENTRY_MAX_STRING 128
 
/* This structure defines an entry inside the slow log list */
typedef struct slowlogEntry {
    robj **argv;
    int argc;
    long long id;       /* Unique entry identifier. */
    long long duration; /* Time spent by the query, in nanoseconds. */
    time_t time;        /* Unix time at which the query was executed. */
} slowlogEntry;
 
void slowlogInit(void);
void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration);
struct redisServer {
    ……
    list *slowlog;                  /* SLOWLOG list of commands */
    long long slowlog_entry_id;     /* SLOWLOG current entry ID */
    long long slowlog_log_slower_than; /* SLOWLOG time limit (to get logged) */
    unsigned long slowlog_max_len;     /* SLOWLOG max number of items logged */
    ……
}

slowlogEntry显然就是一条记录,为了避免异常的Slow Log挤占过多的内存,这里用SLOWLOG_ENTRY_MAX_ARGC和SLOWLOG_ENTRY_MAX_STRING指定了最长的命令参数和最长字符串长度。 在server这个Redis全局变量中有4个成员与Slow Log有关。

Slow Log实现
初始化Slow Log,在Redis Server启动时调用。

1
2
3
4
5
void slowlogInit(void) {
    server.slowlog = listCreate();
    server.slowlog_entry_id = 0;
    listSetFreeMethod(server.slowlog,slowlogFreeEntry);
}

slowlogPushEntryIfNeeded就是Slow Log的插入接口,Redis命令调用的核心函数就是call(),在call()中,当启动Slow Log时,每次都会调用slowlogPushEntryIfNeeded()检测是否需要记录这条命令。通过配置文件指定的时间长度跟目前命令执行时间作比较来决定是否插入。

1
2
3
4
5
6
7
8
9
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));
 
    /* Remove old entries if needed. */
    while (listLength(server.slowlog) > server.slowlog_max_len)
        listDelNode(server.slowlog,listLast(server.slowlog));
}

slowlogCreateEntry用于创建一个Slow Log Entry,对于过长的命令参数和过长的参数字符串长度都会被省略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) {
    slowlogEntry *se = zmalloc(sizeof(*se));
    int j, slargc = argc;
 
    if (slargc > SLOWLOG_ENTRY_MAX_ARGC) slargc = SLOWLOG_ENTRY_MAX_ARGC;
    se->argc = slargc;
    se->argv = zmalloc(sizeof(robj*)*slargc);
    for (j = 0; j < slargc; j++) {
         if (slargc != argc && j == slargc-1) {
            se->argv[j] = createObject(REDIS_STRING,
                sdscatprintf(sdsempty(),"... (%d more arguments)",
                argc-slargc+1));
        } else {
            /* Trim too long strings as well... */
            if (argv[j]->type == REDIS_STRING &&
                argv[j]->encoding == REDIS_ENCODING_RAW &&
                sdslen(argv[j]->ptr) > SLOWLOG_ENTRY_MAX_STRING)
            {
                sds s = sdsnewlen(argv[j]->ptr, SLOWLOG_ENTRY_MAX_STRING);
 
                s = sdscatprintf(s,"... (%lu more bytes)",
                    (unsigned long)
                    sdslen(argv[j]->ptr) - SLOWLOG_ENTRY_MAX_STRING);
                se->argv[j] = createObject(REDIS_STRING,s);
            } else {
                se->argv[j] = argv[j];
                incrRefCount(argv[j]);
            }
        }
    }
    se->time = time(NULL);
    se->duration = duration;
    se->id = server.slowlog_entry_id++;
    return se;
}

本文固定链接: http://www.chepoo.com/redis-analysis-solw-log.html | IT技术精华网

Redis核心解读–Slow Log:等您坐沙发呢!

发表评论