ItGo.me - 专注IT技术分享

首页 > Redis > Redis源码分析(二十一)——慢查日志slow_log

Redis源码分析(二十一)——慢查日志slow_log

时间:2016-08-28来源:网友分享 点击:

slow_log是Redis提供的用于观察系统性能的简单功能。慢查日志对应服务器中的慢查日志链表,将中执行时间超过设定最大时间slog_log_slower_then的命令放到该链表中。 

考虑到效率问题,慢查日志是放在内存而非日志文件中的;另一方面,为了节约内存空间,慢查日志记录的命令数量内增加到设定值后,每加入一条新的命令记录,链表中最旧的命令记录将被删除,同时在记录命令的参数时对那些参数过多或者参数过长的命令参数也作了相应的截断处理。


服务器结构中的慢查日志状态量:

struct redisServer {//**********************list *slowlog;                  /* 记录日志的链表 SLOWLOG list of commands */long long slowlog_entry_id;/* 命令记录节点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 *///*********************}

命令记录结构:

/* 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 nanoseconds. */time_t time;       //命令开始时间 /* Unix time at which the query was executed. */} slowlogEntry;

创建一条命令记录: 注意对参数过多或参数过长的处理,以节约内存空间。

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++) {/* Logging too many arguments is a useless memory waste, so we stop* at SLOWLOG_ENTRY_MAX_ARGC, but use the last argument to specify* how many remaining arguments there were in the original command. */// 当参数的数量超过服务器允许的最大参数数量时,// 用最后一个参数记录省略提示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 &&sdsEncodedObject(argv[j]) &&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;// 设置慢查询 idse->id = server.slowlog_entry_id++;return se;}

慢查日志的记录:

每次命令执行前,Redis有一个参数记录了命令开始执行的时间,当命令执行完毕时,计算当前时间,减去开始时间得到命令的执行时间duration,将duration传入函数slowlogpushEntryIfNeed函数,判断,如果执行时间大等于设定的slog_log_slower_then值,则创建命令节点,追加到慢查日志链表的头部,如果链表长度达到设定值,则从链表尾部(最旧)删除最旧命令记录。

/* Push a new entry into the slow log.** 如果参数 duration 超过服务器设置的上限时间,* 那么将一个新条目以 FIFO 顺序推入到慢查询日志中。** This function will make sure to trim the slow log accordingly to the* configured max length.** 根据服务器设置的最大日志长度,可能会对日志进行截断(trim)*/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));}



SLOWLOG 命令的实现:支持 GET / RESET 和 LEN 参数

void slowlogCommand(redisClient *c) {// 重置if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"reset")) {slowlogReset();addReply(c,);// 返回长度} else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"len")) {addReplyLongLong(c,listLength(server.slowlog));// 获取某条或者全部日志} else if ((c->argc == 2 || c->argc == 3) &&!strcasecmp(c->argv[1]->ptr,"get")){long count = 10, sent = 0;listIter li;void *totentries;listNode *ln;slowlogEntry *se;if (c->argc == 3 &&getLongFromObjectOrReply(c,c->argv[2],&count,NULL) != REDIS_OK)return;// 遍历日志,取出指定数量的日志listRewind(server.slowlog,&li);totentries = addDeferredMultiBulkLength(c);while(count-- && (ln = listNext(&li))) {int j;se = ln->value;addReplyMultiBulkLen(c,4);addReplyLongLong(c,se->id);addReplyLongLong(c,se->time);addReplyLongLong(c,se->duration);addReplyMultiBulkLen(c,se->argc);for (j = 0; j < se->argc; j++)addReplyBulk(c,se->argv[j]);sent++;}setDeferredMultiBulkLength(c,totentries,sent);} else {addReplyError(c,"Unknown SLOWLOG subcommand or wrong # of args. Try GET, RESET, LEN.");}}


Redis源码分析(二十一)——慢查日志slow_log

Redis源码分析(二十一)——慢查日志slow_log  讨论


redis学习String数据类型。

本文摘自:http://www.cnblogs.com/stephen-liu74/archive/2012/03/14/2349815.html 一、概述: 字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数...

(转)Redis 集群方案

根据一些测试整理出来的一份方案: 1. Redis 性能 对于redis 的一些简单测试,仅供参考: 测试环境:Redhat6.2 , Xeon E5520(4核)*2/8G,1000M网卡 Redis 版本:2.6.9 客户端机器使用redis-benchmark 简单GET、...

Redis集群创建报错

Redis集群环境:och163/och164/och165 在执行如下脚本时报错: ./src/ create 10.1.253.163:6379 10.1.253.164:6379 10.1.253.165:6379 /usr/lib/ruby/gems/1.8/gems/redis-3.0.7/lib/redis/:97:in `call': ERR Slot 16011 is already busy (Redis::Com...

slow_log是Redis提供的用于观察系统性能的简单功能。慢查日志对应服务器中的慢查日志链表,将中执行时间超过设定最大时间slog_log_slower_then的命令放到该链表中。 考虑到效率问题,慢查日志是
------分隔线----------------------------