您的位置:首页 > 数据库 > Redis

从hiredis使用出core谈谈redis多线程的使用

2014-11-17 20:20 489 查看
转自:http://my.oschina.net/jungleliu0923/blog/202948

摘要 hireedis多线程出core原因

目录[-]

1、情景描述

1.1 使用场景

1.2 初步实现方案

1.3 结果

2、线下复现

2.1 代码

2.2 编译执行

2.3 原因分析

3. 终极解决方案

在实际工作中,我需要使用redis的客户端去连接redis,于是选择了hiredis客户端(公司强推)。 hiRedis 是 Redis 官方指定的 C 语言客户端开发包,支持 Redis 完整的命令集、管线以及事件驱动编程。


1、情景描述

1.1 使用场景

一个epool模型的服务器不断接受外界请求,这个服务器框架给用户预留一个回调函数(多线程),回调函数为用户自己去实现的业务逻辑,其中redis的使用就需要在这个回调函数内部实现。

1.2 初步实现方案

在程序启动的时候,我就初始化redis的连接,获得hiredis句柄。然后把hiredis句柄传入到线程函数里面。让其做相应的业务逻辑。

1.3 结果

很不幸,一次请求都没问题,做压力测试,同时开20个线程访问,程序立即出core。

线上出core如下:

?
当时经过多次尝试。把连接放入到了每个线程中。那么就不会出core了。


2、线下复现

因为不方便公开公司代码,所以我写一个类似的代码来复现这个case。

2.1 代码

代码主要有testredis.cpp和Makefile(自己指定hiredis目录)。用法是 ./redis
-n [num] -h [host] -p [port], n为host数目,多个host用"-"进行分割。

testredis.cpp

?
Makefile

?

2.2 编译执行

?
可以看到出core了

?
虽然出core位置不一致,但是经过查看代码,出core的原因应该是一致的。

2.3 原因分析

从堆栈5可以看到 hiredis.c的1162行出的core,打开hiredis.c

?
可以看到的确在1152行对c->obuf进行了一次free导致出core。

我们分析下调用关系,首先调用redisCommand.

?
然后调用redisvCommand

?
接着调用redisvAppendCommand

?
这里,我们需要care调用__redisAppendCommand.

?
问题出现了。

对于任意一个多线程,他传入的redisContext* c都是一个,那么他们也公用同一个c->obuf,这里很明显,线程数据是耦合的。

当一个线程调用sdsfree c->obuf,其他任意一个线程使用c->obuf都会导致出core. 这也是我所谓的hiredis对多线程支持的不好的地方。


3. 终极解决方案

那么,如果我一定要在多线程中通过hiredis客户端调用redis呢。有没有方案了,答案肯定是有,只不过性能稍差。

原先的做法是先获得hiredis连接句柄,然后把句柄传入到多线程中,让多线程使用。现在改成在线程里面连接获得hiredis句柄,然后再进行使用。当然,代价是对于每个请求,都需要去连接redis服务器,加大了网络开销的同时还加大了redis的请求。

redis是单线程异步模型,hiredis这个客户端看来也只支持单线程。希望后续有redis的相关程序猿来改进相应问题,在hiredis使用多线程需要慎重。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: