Gleasy的高性能Redis客户端FastRedisClient(二)

声明 本文为Gleasy原创文章,转载请指明引自Gleasy团队博客
第一节 Gleasy自主研发的高性能Redis客户端FastRedisClient(一)
第二节 Gleasy自主研发的高性能Redis客户端FastRedisClient(二)
概要:本文通过引入gleasy线上的问题及解决思路介绍了一种高性能的redis客户端的实现原理及适用场景,以及性能表现

3. 问题的分析
既然问题出在连接池上面,解决问题就应该从连接池入手。采用实验二的方法来改造应用。可是问题立刻就来了:
a. 我们的应用都是基于WEB的应用,Single thread per request,每个请求都是一个线程,在这个请求中还可能访问不止一台redis服务器。
b. 访问并发量大,单台WEB服务器的连接数可以达到3000-4000,如果每个线程一个连接,单是一台WEB服务器就得上千的连接,何况我们的WEB服务器还是几台甚至十几台,将来还可能到几十台,岂不是要有几万连接?
由此可以得出非常悲观的结论,使用每个线程一个连接的方法必不可行。

4. 问题的解决
知道了问题所在,开始另辟蹊径。翻看redis官方资料,发现multi,exec,discard三条命令,很有意思,这三条命令体现的是一种叫做pipeline的技术,即将多条命令封装成单一请求,发送给服务器执行,服务器会在原子性保证这些命令的执行(要么都做,都么都不做,2.2以后版本在pipeline处理方法稍有不同,但不影响主体流程)。那么multi命令的性能如何呢,我们用数学方式来做个假设?

a. 假设一共有100条命令待执行
b. 单条执行,每条需要时间10MS
c. 逐条执行,一共需要时间为100*10MS = 1000MS = 1S
d. 如果使用multi,放到一条请求去执行,假如它的执行时间小于1S,那么就说明,它的性能高于单条命令逐个执行
e. 我们把这个数据乘以5W,即500万条,根据前面实验二的结论(5W/s),逐条执行大概要100S。
f. 我们实验结果与100S相比,将决定着结果的好与坏。

于是做个实验,我们分别插入和读取500万数据,具体结果如下

Redis-shard mset 200线程 (272881/s 272K/s 速度非常惊人)
target/benchtest/bin/TestRedis /data/config/util/config_0_11.properties mset 200 50000*100个key
线程总时间:3409016;平均:0.6818032
实际总时间:18323(18S); 平均:0.0036646

Redis-shard mget 200线程 (470676/s 470K/s 速度极其惊人)
target/benchtest/bin/TestRedis /data/config/util/config_0_11.properties mget 200 50000*100个key
线程总时间:2006452;平均:0.4012904
实际总时间:10623(10S); 平均:0.0021246

结果出来了,写用了18S,是100S的1/5;读用了10S,是100S的1/10。

令人惊讶,事实证明,把100条命令封成一条请求发出去,TPS可以达到270K和470K,是逐条执行的5-6倍和9-10倍。
换言之,我们如果把大量的请求收集起来,变成一条multi请求,发给服务器,不就可以节省大量的时间和开销?基于这个原理,实现了一种称为”快速redis客户端”的JAVA版客户端,具体原理如下:

a. 为每个ip:server:db维护一个本地队列
b. 调用方所有请求都只入队列,然后等待一个唤醒信号(wait)
c. 为每个本地队列,开N条线程(FastRedisClientProxyThread),N等于Cpu核数 1。这N条线程会批量从队列中队出一定数量的请求(比如200,不足200则为实际读取的数量),封装成MULTI命令,发给服务器执行。执行完毕,把结果写入请求结果中,并唤醒等待执行结果的调用线程。
d. 调用方被唤醒,从请求结果中拿到调用结果,继续下一步执行。

5. 性能测试
我们实现的这套客户端,性能究竟如何呢?我们来看以下实验:

redis-shard 10连接
cpu 7-8% 9-12%
root@gleasy cloudredis]# bin/redis-benchmark -t get -h best online casino 192.168.0.11 -p 6680 -d 15 -l 60 -c 200 -b shard
成功:5740491
失败:0
总时间:11999368
最长用时:42
最短用时:0
平均用时:2.090303425264494
min tps:0
max tps:131439
avg tps:94106

cpu 9-12%
[root@gleasy cloudredis]# bin/redis-benchmark -t set -h 192.168.0.11 -p 6680 -d 15 -l 60 -c 200 -b shard
成功:5730516
失败:0
总时间:11999536
最长用时:205
最短用时:0
平均用时:2.093971293335539
min tps:0
max tps:109213
avg tps:93942

怎么解读呢?
通过上述实验,我们可以看到,我们使用了10个redis连接,便可做到了94K读TPS和93K写TPS的给力成绩。而且更给力的是,请求的并发数越大,性能越好,笔者做实验,当并发数达到1000以后,TPS可以达到12W以上。远超原生的REDIS客户端。

6. 线上使用结果
fast redis client上线之后,通过日志明显看到访问redis的请求时间大为减少。而且随着web服务器压力越来越大,请求时间无明显变化,正好验证了当压力越大,该客户端TPS越好的实验结果。

7. 关于源码
GLEASY尚未有足够的精力来维护开源项目,因此该客户端的源码暂未公开。有兴趣的朋友,可以留下联系方式,大家交流切磋。

备注:
a. 本文所有性能测试实验均在相同的硬件环境下进行(CPU i5 4核,16G内存,7200转普通硬盘)
b. 不同硬件环境所做实验结果可能与本文出入很大

此条目发表在 Java技术, 分布式技术, 数据库技术 分类目录。将固定链接加入收藏夹。

Gleasy的高性能Redis客户端FastRedisClient(二)》有 2 条评论

  1. Pingback 引用通告: reids client 高性能 fast

  2. 说:

    你好,能否把源码发来学习和参考一下,谢谢!我的邮箱:zhangnian88123@126.com

发表评论