慢查詢?nèi)罩?/p>
記錄最新的N條執(zhí)行時(shí)間超過M毫秒的命令。慢查詢?nèi)罩颈4嬖趦?nèi)存中,而不是文件中,這保證了慢查詢?nèi)罩镜男省?/p>
1.慢查詢?nèi)罩镜臈l目定義
/* This structure defines an entry inside the slow log list */
/*
* 慢查詢?nèi)罩? */
typedef struct slowlogEntry {
// 命令與命令參數(shù)
robj **argv;
// 命令與命令參數(shù)的數(shù)量
int argc;
// 唯一標(biāo)識(shí)符
long long id; /* Unique entry identifier. */
// 執(zhí)行命令消耗的時(shí)間,以微秒為單位
// 注釋里說的 nanoseconds 是錯(cuò)誤的
long long duration; /* Time spent by the query, in nanoseconds. */
// 命令執(zhí)行時(shí)的時(shí)間,格式為 UNIX 時(shí)間戳
time_t time; /* Unix time at which the query was executed. */
} slowlogEntry;
2.服務(wù)器和慢查詢有關(guān)的定義
/* slowlog */
// 保存了所有慢查詢?nèi)罩镜逆湵? list *slowlog; /* SLOWLOG list of commands */
// 下一條慢查詢?nèi)罩镜?nbsp;ID
long long slowlog_entry_id; /* SLOWLOG current entry ID */
// 服務(wù)器配置 slowlog-log-slower-than 選項(xiàng)的值
long long slowlog_log_slower_than; /* SLOWLOG time limit (to get logged) */
// 服務(wù)器配置 slowlog-max-len 選項(xiàng)的值
unsigned long slowlog_max_len; /* SLOWLOG max number of items logged */
服務(wù)器的慢查詢存儲(chǔ)在一個(gè)list中,list中的每一項(xiàng)都是一條慢查詢?nèi)罩荆^新的日志總是保存在隊(duì)首。慢查詢?nèi)罩局斜4婷畹膱?zhí)行參數(shù)和執(zhí)行時(shí)間,如果超出系統(tǒng)限制,參數(shù)和日志可能被截?cái)唷?/p>
3.慢查詢支持的客戶端操作
GET:獲取某條或者全部慢查詢?nèi)罩?/p>
RESET:清空慢查詢?nèi)罩?/p>
LEN:慢查詢?nèi)罩镜臄?shù)量
4.慢查詢?nèi)罩镜膽?yīng)用
redis每執(zhí)行一條命令,就會(huì)記錄命令的開始時(shí)間和結(jié)束時(shí)間,由此計(jì)算命令的執(zhí)行時(shí)間。并發(fā)命令以及命令的執(zhí)行時(shí)間傳遞給slowlogPushEntryIfNeeded,由slowlogPushEntryIfNeeded決定是否生成慢查詢?nèi)罩尽?/p>
/* Call() is the core of Redis execution of a command */
// 調(diào)用命令的實(shí)現(xiàn)函數(shù),執(zhí)行命令
void call(redisClient *c, int flags)
{
//獲取命令的執(zhí)行時(shí)間
/* Log the command into the Slow log if needed, and populate the
* per-command statistics that we show in INFO commandstats. */
// 如果有需要,將命令放到 SLOWLOG 里面
if (flags & REDIS_CALL_SLOWLOG && c->cmd->proc != execCommand)
slowlogPushEntryIfNeeded(c->argv,c->argc,duration);
}
5.slowlogPushEntryIfNeeded的實(shí)現(xiàn)
判斷系統(tǒng)標(biāo)志位,并把慢查詢?nèi)罩炯尤氲椒?wù)器的慢查詢鏈表中
/* Push a new entry into the slow log.
*
* 如果參數(shù) duration 超過服務(wù)器設(shè)置的上限時(shí)間,
* 那么將一個(gè)新條目以 FIFO 順序推入到慢查詢?nèi)罩局小? *
* This function will make sure to trim the slow log accordingly to the
* configured max length.
*
* 根據(jù)服務(wù)器設(shè)置的最大日志長(zhǎng)度,可能會(huì)對(duì)日志進(jìn)行截?cái)啵╰rim)
*/
void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) {
// 慢查詢功能未開啟,直接返回
if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */
// 如果執(zhí)行時(shí)間超過服務(wù)器設(shè)置的上限,那么將命令添加到慢查詢?nèi)罩? if (duration >= server.slowlog_log_slower_than)
// 新日志添加到鏈表表頭
listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration));
/* Remove old entries if needed. */
// 如果日志數(shù)量過多,那么進(jìn)行刪除
while (listLength(server.slowlog) > server.slowlog_max_len)
listDelNode(server.slowlog,listLast(server.slowlog));
}