Pika 目前的线程模型在处理命令的逻辑下只有一个线程池去处理,所有的命令装载在一个 Task 队列中,由线程池中的 worker 线程去处理请求,这样的实现方式导致在请求量比较大的情况下,一些慢命令(mset,mget) 等阻塞了快命令的执行,导致许多慢查询日志的产生,需要支持快命令和慢命令队列的分离,提升 Pika 的性能
设计方案
我们从 Pika 层面和 Codis 层面都做了快慢命令的分离,在 Pika 层面,我们新加了一个 slow-cmd线程池专门处理慢命令,在 Codis 层面,我们,接下来我们以 Pika 和 Codis 两层跟大家介绍一下
voidPikaClientConn::ProcessRedisCmds(const std::vector<net::RedisCmdArgsType>& argvs, bool async, std::string* response){ time_stat_->Reset(); if (async) { auto arg = newBgTaskArg(); // 每个BgTaskArg里面都是一个命令 arg->redis_cmds = argvs; time_stat_->enqueue_ts_ = pstd::NowMicros(); arg->conn_ptr = std::dynamic_pointer_cast<PikaClientConn>(shared_from_this()); /** * If using the pipeline method to transmit batch commands to Pika, it is unable to * correctly distinguish between fast and slow commands. * However, if using the pipeline method for Codis, it can correctly distinguish between * fast and slow commands, but it cannot guarantee sequential execution. */ std::string opt = argvs[0][0]; // 取出命令 pstd::StringToLower(opt); bool is_slow_cmd = g_pika_conf->is_slow_cmd(opt); // 判断是不是慢命令 g_pika_server->ScheduleClientPool(&DoBackgroundTask, arg, is_slow_cmd); // 进行快慢命令分离 return; } BatchExecRedisCmd(argvs); }