慢查詢日誌
記錄最新的N條執行時間超過M毫秒的命令。慢查詢日誌保存在內存中,而不是文件中,這保證了慢查詢日誌的效率。
慢查詢日誌的條目定義
/* This structure defines an entry inside the slow log list */
/*
* 慢查詢日誌
*/
typedef struct slowlogEntry {
// 命令與命令參數
robj **argv;
// 命令與命令參數的數量
int argc;
// 惟一標識符
long long id; /* Unique entry identifier. */
// 執行命令消耗的時間,以微秒爲單位
// 註釋裏說的 nanoseconds 是錯誤的
long long duration; /* Time spent by the query, in nanoseconds. */
// 命令執行時的時間,格式爲 UNIX 時間戳
time_t time; /* Unix time at which the query was executed. */
} slowlogEntry;
服務器和慢查詢有關的定義
/* slowlog */
// 保存了全部慢查詢日誌的鏈表
list *slowlog; /* SLOWLOG list of commands */
// 下一條慢查詢日誌的 ID
long long slowlog_entry_id; /* SLOWLOG current entry ID */
// 服務器配置 slowlog-log-slower-than 選項的值
long long slowlog_log_slower_than; /* SLOWLOG time limit (to get logged) */
// 服務器配置 slowlog-max-len 選項的值
unsigned long slowlog_max_len; /* SLOWLOG max number of items logged */
服務器的慢查詢存儲在一個list中,list中的每一項都是一條慢查詢日誌,較新的日誌老是保存在隊首。慢查詢日誌中保存命令的執行參數和執行時間,若是超出系統限制,參數和日誌可能被截斷。
慢查詢支持的客戶端操做
GET:獲取某條或者所有慢查詢日誌
RESET:清空慢查詢日誌
LEN:慢查詢日誌的數量
慢查詢日誌的應用
redis每執行一條命令,就會記錄命令的開始時間和結束時間,由此計算命令的執行時間。併發命令以及命令的執行時間傳遞給slowlogPushEntryIfNeeded,由slowlogPushEntryIfNeeded決定是否生成慢查詢日誌。
/* Call() is the core of Redis execution of a command */
// 調用命令的實現函數,執行命令
void call(redisClient *c, int flags)
{
//獲取命令的執行時間
/* 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);
}
slowlogPushEntryIfNeeded的實現
判斷系統標誌位,並把慢查詢日誌加入到服務器的慢查詢鏈表中
/* 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));
}