结合redis设计与实现的redis源码学习-25-慢查询日志(slowlog)
来源:互联网 发布:mac文件管理在哪里 编辑:程序博客网 时间:2024/06/05 14:54
Redis的慢查询日志功能用于记录执行时间超过给定时长的命令请求,用户可以通过这个功能产生的日志来监控和优化查询速度。
服务器配置有两个和慢查询日志相关的选项:
-1、slowlog-log-slower-than选项指定执行时间超过多少微妙的命令会被记录到日志上。
-2、slowlog-max-len选项指定服务器最多保存多少条慢查询日志。
服务器使用先进先出的方式保存多条慢查询日志,当达到设置的最大值时,服务器在添加一条新的慢查询日志之前,会先将最旧的一条删除。
一、慢查询记录的保存
struct redisServer{ long long slowlog_entry_id;//下一条慢查询日志的ID list *slowlog;//保存了所有慢查询日志的链表 long long slowlog_log_slower_than;//服务器配置的保存日志的命令执行时间 unsigned long slowlog_max_len;//服务器配置的最大日志长度}
其中链表保存的每个节点都是一个结构体:
typedef struct slowlogEntry{ long long id;//唯一标识符 time_t time;//命令执行的时间 long long duration;//执行命令消耗的时间,以微妙为单位 robj **argv;//命令与参数 int argc;//命令与参数的数量}
二、添加新日志
在每次执行命令之前和之后,程序都会记录微妙格式的当前UNIX时间戳,这两个时间戳之间的差就是服务器执行命令所耗费的时长,服务器会将这个时长作为参数之一传给slowlogPushEntryIfNeeded函数,负责检查是否需要为这次执行的命令创建慢查询日志。
看代码
slowlog.h
#define SLOWLOG_ENTRY_MAX_ARGC 32#define SLOWLOG_ENTRY_MAX_STRING 128/* Exported API 导出的API*/void slowlogInit(void);void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration);/* Exported commands 导出的命令*/void slowlogCommand(client *c);
slowlog.c
#include "server.h"#include "slowlog.h"/* Create a new slowlog entry.创建一个日志条目 * Incrementing the ref count of all the objects retained is up to this function. 增加保留的所有对象的引用计数器取决于此功能*/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(OBJ_STRING, sdscatprintf(sdsempty(),"... (%d more arguments)", argc-slargc+1)); } else { /* Trim too long strings as well... 截取太长的字符串*/ if (argv[j]->type == OBJ_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(OBJ_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;}/* Free a slow log entry. The argument is void so that the prototype of this function matches the one of the 'free' method of adlist.c.释放一个日志条目,这个参数是无效的,所以这个函数的原型与adlist.c的free方法中的一个匹配 This function will take care to release all the retained object. 这个函数小心的释放所有保留的对象*/void slowlogFreeEntry(void *septr) { slowlogEntry *se = septr; int j; for (j = 0; j < se->argc; j++) decrRefCount(se->argv[j]); zfree(se->argv); zfree(se);}/* Initialize the slow log. This function should be called a single time at server startup. 初始化慢查询日志,这个函数只会在服务器启动时调用*/void slowlogInit(void) { server.slowlog = listCreate(); server.slowlog_entry_id = 0; listSetFreeMethod(server.slowlog,slowlogFreeEntry);}/* 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)); /* Remove old entries if needed. 如果超过最大长度,删除最旧的*/ while (listLength(server.slowlog) > server.slowlog_max_len) listDelNode(server.slowlog,listLast(server.slowlog));}/* Remove all the entries from the current slow log. 释放所有日志条目*/void slowlogReset(void) { while (listLength(server.slowlog) > 0) listDelNode(server.slowlog,listLast(server.slowlog));}/* The SLOWLOG command. Implements all the subcommands needed to handle the Redis slow log. 执行慢查询日志的相关命令*/void slowlogCommand(client *c) { if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"reset")) { slowlogReset(); addReply(c,shared.ok); } 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) != C_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."); }}
阅读全文
0 0
- 结合redis设计与实现的redis源码学习-25-慢查询日志(slowlog)
- 结合redis设计与实现的redis源码学习-8.1-object.c(对象实现)
- 结合redis设计与实现的redis源码学习-17-发布与订阅(pubsub.c)
- 结合redis设计与实现的redis源码学习-1-内存分配(zmalloc)
- 结合redis设计与实现的redis源码学习-2-SDS(简单动态字符串)
- 结合redis设计与实现的redis源码学习-4-dict(字典)
- 结合redis设计与实现的redis源码学习-5-skiplist(跳跃表)
- 结合redis设计与实现的redis源码学习-6-intset(整数集合)
- 结合redis设计与实现的redis源码学习-7-ziplist(压缩列表)
- 结合redis设计与实现的redis源码学习-8.0-object(对象)
- 结合redis设计与实现的redis源码学习-10-hyperloglog(基数统计)
- 结合redis设计与实现的redis源码学习-8.2-t_string(字符串键)
- 结合redis设计与实现的redis源码学习-8.3-t_list.c(列表键)
- 结合redis设计与实现的redis源码学习-14-事件(ae.c/ae_epoll.c)
- 结合redis设计与实现的redis源码学习-15-TCP网络连接(anet.c)
- 结合redis设计与实现的redis源码学习-16-事务(multi.c)
- 结合redis设计与实现的redis源码学习-18-网络连接库(networking.c)
- 结合redis设计与实现的redis源码学习-19-服务器(server.c)
- 梯度原理
- AutoCAD .Net 使用 DrawJig 来动态地移动、旋转、缩放多个图元
- poj_1679_判断最小生成树是否唯一
- 《JAVA编程技巧1001条》第340条:数学函数 ARCSIN;
- 梆梆加固之防内存dump分析
- 结合redis设计与实现的redis源码学习-25-慢查询日志(slowlog)
- AutoCAD .Net 外部参照 XRef
- 缓存,什么意思?
- Jackson传输map中含有float数据的一个小坑
- Errors occured, no packages were upgraded. ⇒ ERROR: Failed to install packages to new root.
- EasyUiDatagrid打印
- 数据结构与算法学习之(三):线性表(下)
- bzoj2693jzptab莫比乌斯反演
- leetcode 529. Minesweeper 扫雷游戏 + 经典的DFS深度优先遍历