redis源码笔记 slowlog

slowlog是redis提供的进行query分析的工具。它将执行时间长的命令统一以list形式保存在内存之中,使用者可以通过slowlog命令查看这些慢query,从而分析系统瓶颈。

最好的分析笔记是作者的注释,除此之外,会做简要记录。

slowlog.h

 1 /* This structure defines an entry inside the slow log list */
 2 typedef struct slowlogEntry {
 3     robj **argv;                      //记录query参数
 4     int argc;
 5     long long id;       /* Unique entry identifier. */
 6     long long duration; /* Time spent by the query, in nanoseconds. */
 7     time_t time;        /* Unix time at which the query was executed. */
 8 } slowlogEntry;
 9 
10 /* Exported API */
11 void slowlogInit(void);               //在redis.c的initServer函数中被调用,初始化一个list结构,只在系统启动时调用一次
12 void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration);
13 
14 /* Exported commands */
15 void slowlogCommand(redisClient *c);  //slowlog Command将会触发此函数被调用

slowlog.c

  1 #include "redis.h"
  2 #include "slowlog.h"
  3 
  4 /* Slowlog implements a system that is able to remember the latest N
  5  * queries that took more than M microseconds to execute.
  6  *
  7  * The execution time to reach to be logged in the slow log is set
  8  * using the 'slowlog-log-slower-than' config directive, that is also
  9  * readable and writable using the CONFIG SET/GET command.
 10  *
 11  * The slow queries log is actually not "logged" in the Redis log file     //只在内存中保存
 12  * but is accessible thanks to the SLOWLOG command. */
 13 
 14 /* Create a new slowlog entry.
 15  * Incrementing the ref count of all the objects retained is up to
 16  * this function. */
 17 slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) {
 18     slowlogEntry *se = zmalloc(sizeof(*se));
 19     int j;
 20 
 21     se->argc = argc;
 22     se->argv = zmalloc(sizeof(robj*)*argc);
 23     for (j = 0; j < argc; j++) {
 24         se->argv[j] = argv[j];
 25         incrRefCount(argv[j]);
 26     }
 27     se->time = time(NULL);
 28     se->duration = duration;
 29     se->id = server.slowlog_entry_id++;
 30     return se;
 31 }
 32 
 33 /* Free a slow log entry. The argument is void so that the prototype of this
 34  * function matches the one of the 'free' method of adlist.c.
 35  *
 36  * This function will take care to release all the retained object. */
 37 void slowlogFreeEntry(void *septr) {
 38     slowlogEntry *se = septr;
 39     int j;
 40 
 41     for (j = 0; j < se->argc; j++)
 42         decrRefCount(se->argv[j]);
 43     zfree(se->argv);
 44     zfree(se);
 45 }
 46 
 47 /* Initialize the slow log. This function should be called a single time
 48  * at server startup. */
 49 void slowlogInit(void) {
 50     server.slowlog = listCreate();
 51     server.slowlog_entry_id = 0;
 52     listSetFreeMethod(server.slowlog,slowlogFreeEntry);
 53 }
 54 
 55 /* Push a new entry into the slow log.
 56  * This function will make sure to trim the slow log accordingly to the
 57  * configured max length. */
 58 void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) {
 59     if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */
 60     if (duration >= server.slowlog_log_slower_than)
 61         listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration));
 62 
 63     /* Remove old entries if needed. */
 64     while (listLength(server.slowlog) > server.slowlog_max_len)
 65         listDelNode(server.slowlog,listLast(server.slowlog));
 66 }  //该函数在每次命令执行时均被调用,对于非慢速的命令,只有一个分支调用的开销;
 67 
 68 /* Remove all the entries from the current slow log. */
 69 void slowlogReset(void) {
 70     while (listLength(server.slowlog) > 0)
 71         listDelNode(server.slowlog,listLast(server.slowlog));
 72 }
 73 
 74 /* The SLOWLOG command. Implements all the subcommands needed to handle the
 75  * Redis slow log. */ slow long get (count) || slowlog reset || slowlog len
 76 void slowlogCommand(redisClient *c) {
 77     if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"reset")) {
 78         slowlogReset();
 79         addReply(c,shared.ok);
 80     } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"len")) {
 81         addReplyLongLong(c,listLength(server.slowlog));
 82     } else if ((c->argc == 2 || c->argc == 3) &&
 83                !strcasecmp(c->argv[1]->ptr,"get"))
 84     {
 85         long count = 10, sent = 0;
 86         listIter li;
 87         void *totentries;
 88         listNode *ln;
 89         slowlogEntry *se;
 90 
 91         if (c->argc == 3 &&
 92             getLongFromObjectOrReply(c,c->argv[2],&count,NULL) != REDIS_OK)
 93             return;
 94 
 95         listRewind(server.slowlog,&li);
 96         totentries = addDeferredMultiBulkLength(c);
 97         while(count-- && (ln = listNext(&li))) {
 98             int j;
 99 
100             se = ln->value;
101             addReplyMultiBulkLen(c,4);
102             addReplyLongLong(c,se->id);
103             addReplyLongLong(c,se->time);
104             addReplyLongLong(c,se->duration);
105             addReplyMultiBulkLen(c,se->argc);
106             for (j = 0; j < se->argc; j++)
107                 addReplyBulk(c,se->argv[j]);     //返回的消息是一个类似嵌套的结构
108             sent++;
109         }
110         setDeferredMultiBulkLength(c,totentries,sent);
111     } else {
112         addReplyError(c,
113             "Unknown SLOWLOG subcommand or wrong # of args. Try GET, RESET, LEN.");
114     }
115 }
原文地址:https://www.cnblogs.com/liuhao/p/2510725.html