简言

1. 总所周知,redis以高性能著称,官方号称QPS可以达到10万次

2. 如果我们做实验,即便是执行最简单的set,get命令,也难以达到官方号称的性能,原因在于没有使用管道(pipe)

3. 不使用管道的时候,由于每个命令都要经过一个完整的网络来回才能得到结果,执行N个命令就要等待N个网络来回时间,效率很低

4. 使用管道的时候,redis服务器并没有任何改变,仍然是顺序处理每一个命令。是redis客户端做的一个技巧,发出一个命令后不再等待它返回,而是接着发送下一条命令,直到全部发送完。接收的时候也是等待所有命令都返回了才一次性返回给用户。整个过程只有一个网络来回,可以极大的提高效率

5. 总结:简单的set, get命令,使用管道可以提高效率800%左右

实验如下图(执行了3次,可以看到同样是执行了10W次set命令,使用管道时耗时620ms左右,不使用管道时耗时4900ms左右

redis管道的使用_redis

完整代码链接

管道使用代码如下(该函数为管道的封装,笔者使用的是C++, 第三方库为hiredis)

// 使用管道运行一批命令(命令列表,回复列表)
bool CRedisClient::PipeCommand(vector<string>& commands, vector<CAutoRedisReply>& replys)
{
REDIS_SAFE_ACCESS

// 参数检测
if (commands.size()==0 || replys.size()==0 || (commands.size() != replys.size()))
{
ERROR("CRedisClient::PipeCommand(), params err, commands.size()=%ld, replys.size()=%ld", commands.size(), replys.size());
return false;
}

bool bSuc = connect();
if (!bSuc)
{
ERROR("CRedisClient::PipeCommand(), connect failed");
return false;
}

// 所有命令
for (size_t i=0;i<commands.size();i++)
{
redisAppendCommand(m_redisCtx, commands[i].c_str());
}

// 所有回复
for (size_t i=0;i<commands.size();i++)
{
redisReply* pReply = NULL;
redisGetReply(m_redisCtx,(void**)(&pReply));

// 由于命令的返回各种各样,无法准确判断结果是否真的正确,所以这里认为没出错即认为正常
if (pReply == NULL || pReply->type == REDIS_REPLY_ERROR)
{
ERROR("CRedisClient::PipeCommand(), get reply error, command=%s, pReply->type=%d, pReply->str=%s", commands[i].c_str(), pReply->type, pReply->str);
return false;
}

replys[i].set(pReply);
}

return true;
}