《redis设计与实现》第四部分 (第23章 慢查询日志)

23.0 慢查询日志

主要的功能:记录执行时间超过给定时长的命令请求,可以用这个功能产生的日志来监视和优化查询速度

  • 两个选项:时间和最多保存的条目
    • slowlog-log-slower-than 执行时间超过多少微秒的命令记录到日志
    • slowlog-max-len指定服务器最多保存多少条查询日志(先进先出,如果日志条目满了,最早的一条会被删除)
  • example one
127.0.0.1:6379> config set slowlog-max-len 5
OK
127.0.0.1:6379> config set slowlog-log-slower-than 0
OK
127.0.0.1:6379> set name "wang wang"
OK
127.0.0.1:6379> set sex "girl"
OK
127.0.0.1:6379> set age "30"
OK
127.0.0.1:6379> set year "2020"
OK
127.0.0.1:6379> set family "four"
OK
127.0.0.1:6379> slowlog get
1) 1) (integer) 10
   2) (integer) 1603691289
   3) (integer) 9
   4) 1) "set"
      2) "family"
      3) "four"
   5) "127.0.0.1:54133"
   6) ""
2) 1) (integer) 9
   2) (integer) 1603691281
   3) (integer) 30
   4) 1) "set"
      2) "year"
      3) "2020"
   5) "127.0.0.1:54133"
   6) ""
3) 1) (integer) 8
   2) (integer) 1603691267
   3) (integer) 34
   4) 1) "set"
      2) "age"
      3) "30"
   5) "127.0.0.1:54133"
   6) ""
4) 1) (integer) 7
   2) (integer) 1603691243
   3) (integer) 25
   4) 1) "set"
      2) "sex"
      3) "girl"
   5) "127.0.0.1:54133"
   6) ""
5) 1) (integer) 6
   2) (integer) 1603691234
   3) (integer) 959
   4) 1) "set"
      2) "name"
      3) "wang wang"
   5) "127.0.0.1:54133"
   6) ""
  • example two
    • 再输入slowlog get,能看到上一次的slowlog get已经被记录到了慢查询日志中,最旧的那条日志已经被删除了
127.0.0.1:6379> slowlog get
1) 1) (integer) 11
   2) (integer) 1603691298
   3) (integer) 66
   4) 1) "slowlog"
      2) "get"
   5) "127.0.0.1:54133"
   6) ""
2) 1) (integer) 10
   2) (integer) 1603691289
   3) (integer) 9
   4) 1) "set"
      2) "family"
      3) "four"
   5) "127.0.0.1:54133"
   6) ""
3) 1) (integer) 9
   2) (integer) 1603691281
   3) (integer) 30
   4) 1) "set"
      2) "year"
      3) "2020"
   5) "127.0.0.1:54133"
   6) ""
4) 1) (integer) 8
   2) (integer) 1603691267
   3) (integer) 34
   4) 1) "set"
      2) "age"
      3) "30"
   5) "127.0.0.1:54133"
   6) ""
5) 1) (integer) 7
   2) (integer) 1603691243
   3) (integer) 25
   4) 1) "set"
      2) "sex"
      3) "girl"
   5) "127.0.0.1:54133"
   6) ""

23.1 慢查询记录的保存

  • 服务器状态中包含了几个和慢查询日志功能有关的属性
//code0 server.h
struct redisServer {
    /* General */
    pid_t pid;                  /* Main process pid. */
    char *configfile;           /* Absolute config file path, or NULL */
    char *executable;           /* Absolute executable file path. */
    // ...
    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 */
    //...
}
  • slowlog_entry_id的初始值位0,每次新创建一条新的慢查询日志时,这个属性的值会被用作新日志的id值,之后程序会对这个属性的值增一。
  • slowlog链表表示了服务器中的所有的慢查询日志,链表的每一个节点保存了slowlogEntry结构,最新的在表头,新的日志总是添加到表头
//code1 slowlog.h
/* 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 microseconds. */
    //命令执行时的时间(start time)
    time_t time;        /* Unix time at which the query was executed. */
    sds cname;          /* Client name. */
    sds peerid;         /* Client network address. */
} slowlogEntry;

23.2 慢查询日志的阅览和删除

  • SLOWLOG GET命令:获取日志
  • SLOWLOG LEN命令:获取日志长度
  • SLOGLOG RESET命令:清空日志
//code2 slowlog.c
/* 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,"help")) {
        const char *help[] = {
"GET [count] -- Return top entries from the slowlog (default: 10)."
"    Entries are made of:",
"    id, timestamp, time in microseconds, arguments array, client IP and port, client name",
"LEN -- Return the length of the slowlog.",
"RESET -- Reset the slowlog.",
NULL
        };
        addReplyHelp(c, help);
    } else 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 = addReplyDeferredLen(c);
        while(count-- && (ln = listNext(&li))) {
            int j;

            se = ln->value;
            addReplyArrayLen(c,6);
            addReplyLongLong(c,se->id);
            addReplyLongLong(c,se->time);
            addReplyLongLong(c,se->duration);
            addReplyArrayLen(c,se->argc);
            for (j = 0; j < se->argc; j++)
                addReplyBulk(c,se->argv[j]);
            addReplyBulkCBuffer(c,se->peerid,sdslen(se->peerid));
            addReplyBulkCBuffer(c,se->cname,sdslen(se->cname));
            sent++;
        }
        setDeferredArrayLen(c,totentries,sent);
    } else {
        addReplySubcommandSyntaxError(c);
    }
}

23.2 添加新日志

  • 执行命令之前和之后,会记录微秒格式的UNIX时间戳,时间差就是服务器执行命令耗费的时间
  • 服务器会将这个时间差传给slowlogPushEntryIfNeeded,负责检查是否需要为这次命令创建慢查询日志
    • 如果需要新创建一条慢查询日志,调用slowlogCreateEntry函数(创建一条新的慢查询日志,且将server.slowlog_entry_id++)
/* 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(client *c, 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(c,argv,argc,duration));

    /* Remove old entries if needed. */
    while (listLength(server.slowlog) > server.slowlog_max_len)
        listDelNode(server.slowlog,listLast(server.slowlog));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值