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 }