我们在使用Redis时,总会碰到一些redis-server端CPU及内存占用比较高的问题。下面以几个实际案例为例,来讨论一下在使用Redis时容易忽视的几种情形。
一、短连接导致CPU高
某用户反映QPS不高,从监控看CPU确实偏高。既然QPS不高,那么redis-server自身很可能在做某些清理工作或者用户在执行复杂度较高的命令,经排查无没有进行key过期删除操作,没有执行复杂度高的命令。
上机器对redis-server进行perf分析,发现函数listSearchKey占用CPU比较高,分析调用栈发现在释放连接时会频繁调用listSearchKey,且用户反馈说是使用的短连接,所以推断是频繁释放连接导致CPU占用有所升高。
1、对比实验
下面使用redis-benchmark工具分别使用长连接和短连接做一个对比实验,redis-server为社区版4.0.10。
1)长连接测试
使用10000个长连接向redis-server发送50w次ping命令:
./redis-benchmark -h host -p port -t ping -c 10000 -n 500000 -k
1(k=1表示使用长连接,k=0表示使用短连接)
最终QPS:
PING_INLINE: 92902.27 requests per second
PING_BULK: 93580.38 requests per second
对redis-server分析,发现占用CPU最高的是readQueryFromClient,即主要是在处理来自用户端的请求。
2)短连接测试
使用10000个短连接向redis-server发送50w次ping命令:
./redis-benchmark -h host -p port -t ping -c 10000 -n 500000 -k 0
最终QPS:
PING_INLINE: 15187.18 requests per second
PING_BULK: 16471.75 requests per second
对redis-server分析,发现占用CPU最高的确实是listSearchKey,而readQueryFromClient所占CPU的比例比listSearchKey要低得多,也就是说CPU有点“不务正业”了,处理用户请求变成了副业,而搜索list却成为了主业。所以在同样的业务请求量下,使用短连接会增加CPU的负担。
从QPS上看,短连接与长连接差距比较大,原因来自两方面:
-
每次重新建连接引入的网络开销。
-
释放连接时,redis-server需消耗额外的CPU周期做清理工作。(这一点可以尝试从redis-server端做优化)
2、Redis连接释放
我们从代码层面来看下redis-server在用户端发起连接释放后都会做哪些事情,redis-server在收到用户端的断连请求时会直接进入到freeClient。
void freeClient(client *c) {
listNode *ln;
/* .........*/
/* Free the query buffer */
sdsfree(c->querybuf);
sdsfree(c->pending_querybuf);
c->querybuf = NULL;
/* Deallocate structures used to block on blocking ops. */
if (c->flags & CLIENT_BLOCKED) unblockClient(c);
dictRelease(c->bpop.keys);
/* UNWATCH all the keys */
unwatchAllKeys(c);
listRelease(c->watched_keys);
/* Unsubscribe from all the pubsub channels */
pubsubUnsubscribeAllChannels(c,0);
pubsubUnsubscribeAllPatterns(c,0);
dictRelease(c->pubsub_channels);
listRelease(c->pubsub_patterns);
/* Free data structures. */
listRelease(c-&