Redis高级实践之————Redis短连接性能优化
摘要: 对于Redis服务,通常我们推荐用户使用长连接来访问Redis,但是由于某些用户在连接池失效的时候还是会建立大量的短连接或者用户由于客户端限制还是只能使用短连接来访问Redis,而原生的Redis在频繁建立短连接的时候有一定性能损耗,本文从源码角度对Redis短连接的性能进行了优化。
1. 问题
通过历史监控我们可以发现用户在频繁使用短连接的时候Redis的cpu使用率有显著的上升
2. 排查
通过扁鹊查看但是Redis的cpu运行情况如下
从扁鹊我们可以看到Redis在freeClient的时候会频繁调用listSearchKey,并且该函数占用了百分30左右的调用量,如果我们可以优化降低该调用,短连接性能将得到具体提升。
3. 优化
通过以上分析我们可以知道Redis在释放链接的时候频繁调用了listSearchKey,通过查看Redis关闭客户端源码如下:
void freeClient(redisClient *c) {
listNode *ln; /* If this is marked as current client unset it */
if (server.current_client == c) server.current_client = NULL; /* If it is our master that's beging disconnected we should make sure
* to cache the state to try a partial resynchronization later.
*
* Note that before doing this we make sure that the client is not in
* some unexpected state, by checking its flags. */
if (server.master && c->flags & REDIS_MASTER) {
redisLog(REDIS_WARNING,"Connection with master lost.");
if (!(c->flags & (REDIS_CLOSE_AFTER_REPLY|
REDIS_CLOSE_ASAP|
REDIS_BLOCKED| REDIS_UNBLOCKED)))
{
replicationCacheMaster(c);
return;
}
} /* Log link disconnection with slave */
if ((c->flags & REDIS_SLAVE) && !(c->flags & REDIS_MONITOR)) {
redisLog(REDIS_WARNING,"Connection with slave %s lost.",
replicationGetSlaveName(c));
} /* Free the query buffer */
sdsfree(c->querybuf);
c->querybuf = NULL; /* Deallocate structures used to block on blocking ops. */
if (c->flags & REDIS_BLOCKED)
unblockClientWaitingData(c);
dictRelease(c->bpop.keys); freeClientArgv(c); /* Remove from the list of clients */
if (c->fd != -) {
ln = listSearchKey(server.clients,c);
redisAssert(ln != NULL);
listDelNode(server.clients,ln);
} /* When client was just unblocked because of a blocking operation,
* remove it from the list of unblocked clients. */
if (c->flags & REDIS_UNBLOCKED) {
ln = listSearchKey(server.unblocked_clients,c);
redisAssert(ln != NULL);
listDelNode(server.unblocked_clients,ln);
}
...
...
...
/* Release other dynamically allocated client structure fields,
* and finally release the client structure itself. */
if (c->name) decrRefCount(c->name);
zfree(c->argv);
freeClientMultiState(c);
sdsfree(c->peerid);
if (c->pause_event > ) aeDeleteTimeEvent(server.el, c->pause_event);
zfree(c);
}
从源码我们可以看到Redis在释放链接的时候遍历server.clients查找到对应的redisClient对象然后调用listDelNode把该redisClient对象从server.clients删除,代码如下:
/* Remove from the list of clients */
if (c->fd != -) {
ln = listSearchKey(server.clients,c);
redisAssert(ln != NULL);
listDelNode(server.clients,ln);
}
查看server.clients为List结构,而redis定义的List为双端链表,我们可以在createClient的时候将redisClient的指针地址保留再freeClient的时候直接删除对应的listNode即可,无需再次遍历server.clients,代码优化如下:
3.1 createClient修改
redisClient *createClient(int fd) {
redisClient *c = zmalloc(sizeof(redisClient)); /* passing -1 as fd it is possible to create a non connected client.
* This is useful since all the Redis commands needs to be executed
* in the context of a client. When commands are executed in other
* contexts (for instance a Lua script) we need a non connected client. */
if (fd != -) {
anetNonBlock(NULL,fd);
anetEnableTcpNoDelay(NULL,fd);
if (server.tcpkeepalive)
anetKeepAlive(NULL,fd,server.tcpkeepalive);
if (aeCreateFileEvent(server.el,fd,AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
close(fd);
zfree(c);
return NULL;
}
}
...
if (fd != -) {
c->client_list_node = listAddNodeTailReturnNode(server.clients,c);
}
return c;
}
3.2 freeClient修改
freeClient修改如下:
/* Remove from the list of clients */
if (c->fd != -) {
if (c->client_list_node != NULL) listDelNode(server.clients,c->client_list_node);
}
3.3 优化结果
在同一台物理机上启动优化前后的Redis,分别进行压测,压测命令如下:
redis-benchmark -h host -p port -k -t get -n -c
其中-k 代表使用短连接进行测试
原生Redis-server结果:
99.74% <= milliseconds
99.78% <= milliseconds
99.84% <= milliseconds
99.90% <= milliseconds
99.92% <= milliseconds
99.94% <= milliseconds
99.99% <= milliseconds
100.00% <= milliseconds
10065.42 requests per second
优化后Redis-server结果
99.69% <= milliseconds
99.72% <= milliseconds
99.80% <= milliseconds
99.82% <= milliseconds
99.86% <= milliseconds
99.89% <= milliseconds
99.94% <= milliseconds
99.96% <= milliseconds
99.97% <= milliseconds
100.00% <= milliseconds
13823.61 requests per second
我们可以看到优化之后的Redis-server性能在短连接多的场景下提升了百分30%以上。
Redis高级实践之————Redis短连接性能优化的更多相关文章
- Redis进阶实践之五Redis的高级特性(转载 5)
Redis进阶实践之五Redis的高级特性 一.引言 上一篇文章写了Redis的特征,使用场景,同时也介绍了Redis的基本数据类型,redis的数据类型是操作redis的基础,这个必须好好的掌握.今 ...
- Redis进阶实践之六Redis Desktop Manager连接Windows和Linux系统上的Redis服务(转载6)
Redis进阶实践之六Redis Desktop Manager连接Windows和Linux系统上的Redis服务 一.引言 今天本来没有打算写这篇文章,但是,今天测试Redis的时候发现了两个问题 ...
- Redis进阶实践之七Redis和Lua初步整合使用(转载 7)
Redis进阶实践之七Redis和Lua初步整合使用 一.引言 Redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运 ...
- Redis进阶实践之四Redis的基本数据类型(转载4)
Redis进阶实践之四Redis的基本数据类型 一.引言 今天正式开始了Redis的学习,如果要想学好Redis,必须先学好Redis的数据类型.Redis为什么会比以前的Memchaed等内存缓存软 ...
- Redis进阶实践之五Redis的高级特性
一.引言 上一篇文章写了Redis的特征,使用场景,同时也介绍了Redis的基本数据类型,redis的数据类型是操作redis的基础,这个必须好好的掌握.今天我们开始介绍一些Redis的高级特性 ...
- Redis进阶实践之六Redis Desktop Manager连接Windows和Linux系统上的Redis服务
一.引言 今天本来没有打算写这篇文章,当初我感觉使用这个工具应该很简单,下载的过程也不复杂,也没有打算记录下来.但是在使用的过程中还是出现了一些问题,为了给第一次使用Redis Desktop Man ...
- Redis进阶实践之七Redis和Lua初步整合使用
一.引言 Redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入到大多数语言当 ...
- Redis进阶实践之四Redis的基本数据类型
一.引言 今天正式开始了Redis的学习,如果要想学好Redis,必须先学好Redis的数据类型.Redis为什么会比以前的Memchaed等内存缓存软件使用的更频繁,适用范围更广呢?就是因为R ...
- redis在实践中的一些常见问题以及优化思路
1.fork耗时导致高并发请求延时 RDB和AOF的时候,其实会有生成RDB快照,AOF rewrite,耗费磁盘IO的过程,主进程fork子进程 fork的时候,子进程是需要拷贝父进程的空间内存页表 ...
随机推荐
- React Native学习笔记-1:JSC profiler is not supported.
新建React-Native工程,直接编译运行报错,控制台错误信息如下: 2016-02-22 16:49:47.317 [info][tid:com.facebook.React.JavaScrip ...
- HDU 5724:Chess(博弈 + 状压)
http://acm.hdu.edu.cn/showproblem.php?pid=5724 Chess Problem Description Alice and Bob are playing ...
- [Unity3D]MonoBehaviour函数介绍
原文地址: http://www.cocos2dev.com/?p=486 Unity中的脚本都是继承自MonoBehaviour. 一.基础函数: 创建脚本就默认的update.start方法:(这 ...
- HDU-1042 N!
首先明白这是大数问题,大数问题大多采用数组来实现.如何进位.求余等.比如1047 (Integer Inquiry): 对于1042问题 计算10000以内数的阶乘,因为10000的阶乘达到35660 ...
- 【转】在Eclipse中配置tomcat
转载地址: http://kin111.blog.51cto.com/738881/163096 为了在Eclipse中进行struts2的测试,才发现自己机器上的Eclipse没有集成Tomcat, ...
- 表单校验组件ValidForm
10.1使用入门 1.引入css 请查看下载文件中的style.css,把里面Validform必须部分复制到你的css中 (文件里这个注释 "/*==========以下部分是Validf ...
- 2016 Al-Baath University Training Camp Contest-1 C
Description Rami went back from school and he had an easy homework about bitwise operations (and,or, ...
- Linux 性能监控、测试、优化工具
Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...
- Springmvc整合tiles框架简单入门示例(maven)
Springmvc整合tiles框架简单入门示例(maven) 本教程基于Springmvc,spring mvc和maven怎么弄就不具体说了,这边就只简单说tiles框架的整合. 先贴上源码(免积 ...
- Maven项目的目录结构+maven的安装与配置
1.首先下载maven,然后配置环境变量,在MyEclipse里面配置maven 2.配置maven的pom.xml文件 3.下载和更新资源 右击项目,有一个Maven4Myeclipse,里面有三个 ...