全球领先的redis客户端:SFedis
零、背景
这个客户端起源于我们一个系统的生产问题。
一、问题的发生
在我们的生产环境上发生了两次redis服务端连接数达到上限(我们配置的单节点连接数上限为8000)导致无法创建连接的情况。由于这个系统生产环境的redis集群的tps达到百万级,所以发生了这个情况的后果是非常严重的,有的业务会发生缓存穿透的情况,有的业务会直接报错。
二、问题分析
在生产环境上每个redis节点的tps上限在50000左右,我们监控redis的slowlog的阀值设置为0.1ms,也就是说如果服务端慢到10000tps时就会触发报警,但在问题发生当时并没有报警。实际上这是我们的一个失误:如果redis一个服务节点是独享一个cpu核的,那么按照redis的机制是可以推测出slowlog是不可能会有“慢”的结果的。那么如果慢一定不是在redis本身的处理上,有可能是塞在epoll上或者网络上。但我们并没有发现有任何地方有异常(包括网络)。
我们并没有查到故障发生在哪里,但故障的确就发生了,这是很离奇的。
最后我们只能进行了推测:正常情况下整个集群的速度是非常快的。监控设置的0.1ms的阀值虽然看起来是非常快(万分之一秒),但和正常情况下的平均响应时长来说还是慢了5倍的差距。也就是说,我们检测每一个地方都没有看到问题,可能只是因为检测的标准以及检测工具的能力(精确度)的问题。比如说:平时单节点平均处理能力在0.02ms每个命令,但当慢(无论慢在哪里)到0.05ms的时候我们是没能监控出来的,而实际上这个时候问题已经发生了。假设网络因未知原因卡了一秒钟,那么就会有几十万到一百万个请求塞在网络上,客户端因请求还没有返回,新的请求就会向连接池申请新的连接,如果服务端没有保留足够的buffer来处理瞬间多出来的请求,那么很有可能在这个时候发生一个雪崩效应——连接数瞬间达到上限。
三、临时解决
当时在故障处理时,我们采取了比较粗爆但有效的办法:减少客户端的数量。我们停掉了相关服务的一半节点,使所有运行节点的线程池即使全部打满也不会达到redis服务端的上限,这样当业务消费一段时间后,请求降下来了,再启动被关掉的服务。
当天晚上我们对redis集群进行了扩容,保留了更大的buffer,使应对异常冲击的能力提高一些。
这些只是临时的解决方案,治标不治本的。所以还是需要更进一步研究更好的解决方案。
这里需要说明一点:为什么服务可以停掉一半?如果服务停掉了一半,前端的请求会不会把服务的cpu打满,导致服务挂掉呢?
这里是因为:
1.服务端对所有的rest/http接口以及rpc接口都做了隔离限流,每任何一个接口超过一定的并发之后,后面的请求就会马上报错,保证服务的安全。
2.用户端是移动App,在移动端我们对所有重要业务做了统一的重试机制,如果没有传上来的,可以在一定时间之后再次重试。
所以这里服务端减少服务能力的情况下,并不会导致严重的业务问题,但是会使业务数据上传变慢一些。
四、原理分析
当时我们的客户端用的是jedis,连接的管理用的是jedis自带的。
因为redis服务端的每个节点的数据是不同的,所以在长时间的调用下,每个客户端一定会访问到每个服务端节点。这样的话,服务端每个节点的连接数就并不取决于服务端集群的大小,而取决于客户端集群的大小。
如下图所示:如果客户端有2个,每个客户端的连接池上限是40个连接,那么无论服务端是多少个节点,每个节点的连接数量的上限应该是40*2=80个。
那么问题来了:服务端的每个节点处理能力是有限的,连接数过多是没有意义的,如果每个服务端的连接上限是10000个,每个客户端的连接池上限是100个,那么在理论上要保证连接安全,客户端的节点数上限是10000/100=100个。但如果我们需要更大的业务处理能力(业务应用集群的节点数需要超过100个)的情况下,怎么办呢?
五、一个想法
从理论上说,1个连接是可以达到一个网卡的带宽极限的,那么是否有可能做到每个redis客户端只有一个连接,却可以达到原来n多个连接一样的性能(甚至更好)呢?
六、研究业界现有方案
带着问题,我们用了两个月时间来研究测试各种业界公认的成熟方案(除了当时正在用的jedis客户端之外,还研究了twemproxy、Codis、redis 4.0 (cluster)、redisson),发现这些方案并没有让我们满意。下面说一下我们为什么不选择这些方案:
twemproxy:代理并不能完全解决连接数的问题,它只能让连接数少一些,而且代理大约有20%的性能损耗。
Codis:1.代理和twemproxy的差不多,也不能完全解决连接数的问题;2.Codis新版本没有节点失效的检测的能力;3.整个方案的部署比较麻烦。4.在增加节点时,集群会自动迁移数据(当然,这个不能说是缺点,但如果整个集群的内存达到几个T的情况下,内存的数据迁移会有什么后果不好预料(迁移数据导致网络塞住怎么办?迁移数据时服务会中段多长时间?))。
Redis cluster:1.必须做主备,当主备都挂了的情况下,不能自动摘除节点;2.在增加节点时,集群会自动迁移数据——这一点和Codis一样——我们宁可缓存穿透,也不希望他迁移数据(如果实现了一致性hash,那么会穿透的数据还是很少的——比如:如果我们服务已经有了100个节点,再加一个节点最多只会导致1%的数据失效);
redisson:这个客户端用了nio机制,在异步操作的情况下的确会大大减少连接数,并且异步的性能非常好(极端的情况下,有可能是jedis的十倍)。但在同步的情况下就没那么乐观,还是需要多个连接才能勉强追得上jedis的速度。如果我们改用redisson的异步形式,则需要改业务代码,这是很难接受的——不过这里我认为是redisson的开发者们对代码的优化没有做到极致,因为在基础原理上nio可以达到的程度绝对可以比现在的redisson更好。
另外,如果采用短连接的形式的话,对性能的影响比较大,所以我们也不想牺牲长连接的优势。
既然找不到已经实现好的成熟方案,那么我们是否可以自己实现一个呢?
七、自己开发
目标很清晰:一个“新的jedis”,但每个客户端在连接每个服务节点时只连一个连接,最重要的是性能绝不可以比jedis差。
虽然目标很清晰,并且在基础原理上是可以达到的,但具体的技术细节确并不容易。目标是我定的,但我给不出在技术细节上的实现方案,后来我们部门内的一个码神想到了一个很好的实现方案。
具体原理是这样的:
1.redis的通信协议是tcp,这就提供了异步请求的基础——如果是同步的网络请求,客户端就需要等待服务端的响应,那么在等待这段时间里,带宽是空着的,这样要打满带宽就必然需要多个连接,所以,如果我们需要用一个连接打满带宽就必然需要用异步。
2.redis的命令协议上是没有在发送与接收之间建立对应关系的(没有msg_id之类的属性),这如果不停的发送与接收命令,应该如何告诉业务哪个接收到的数据属于应用事例的哪个线程呢?这里我们找到了一个很巧妙的对应关系:顺序。redis服务端是单线程的,那么服务端先接收到的命令必然先返回,同时,tcp协议又是保证顺序的,这就决定了我们可以用“顺序”做为“发”与“收”之间的对应协议。
3.为了不修改业务,我们必须用“新的原理”来实现“老的接口”,老接口都是同步操作的,那么这里的阻塞动作就一定要在客户端框架中来实现了。这里就要用到Future了。
最终的实现结果是:我们自己实现的新redis客户端框架SFedis访问每个服务节点只用1个连接,却比业界广泛使用的Jedis用多个连接还要快一点。
我们现在还没有实现异步接口,如果我们真的实现了异步接口,那么估计比redisson还要快。
另:在十一月的新书《决战618》我看到书中有写到京东也有用nio实现自己的redis客户端来解决连接数的问题,不过书中只有一句话讲这个,完全没有任何细节。
八、结果展示
我们有两个服务共用一个redis集群,下图是其中一个服务上线后的连接数监控图:
这里可以看到:一个服务上线之后的几天比上线前的几天,redis连接数直接腰斩了。
下图是另一个服务也上线之后的连接数监控图:
可以看到在第二个服务上线之后,连接数已经完全不再波动了(这里千万别误会:后面三天的线是平的,不代表没有服务。服务是正常运行的,而且运行得很健康),这里连接数停留在应用实例的个数上(58个)。
这里声明一下:这个系统是有做灰度的,在生产上有多个环境在跑不同的版本,上面的两个截图是一个小环境上线前后的监控情况,所以节点数比较少,只有58个。而且这个小环境在性能上留的buffer是比较充足的,所以平时的redis连接数也不高。在大的生产环境上这个图会显得更猛一些。
九、开源计划
目前这个客户端还没有开源,但开源已在计划之中。后续开源之后会公布出来。
十、人员招募
我们团队正在招人,岗位有:Android开发、Java后台开发、架构师、测试。欢迎大家推荐或自荐!
简历请发我邮箱:zhouyou@sf-express.com
全球领先的redis客户端:SFedis的更多相关文章
- StackExchange.Redis客户端读写主从配置,以及哨兵配置。
今天简单分享一下StackExchange.Redis客户端中配置主从分离以及哨兵的配置. 关于哨兵如果有不了解的朋友,可以看我之前的一篇分享,当然主从复制文章也可以找到.http://www.cnb ...
- c#实现redis客户端(一)
最近项目使用中要改造redis客户端,看了下文档,总结分享一下. 阅读目录: 协议规范 基础通信 状态命令 set.get命令 管道.事务 总结 协议规范 redis允许客户端以TCP方式连接,默认6 ...
- 使用StackExchange.Redis客户端进行Redis访问出现的Timeout异常排查
问题产生 这两天业务系统在redis的使用过程中,当并行客户端数量达到200+之后,产生了大量timeout异常,典型的异常信息如下: Timeout performing HVALS Parser2 ...
- Redis客户端之Spring整合Jedis,ShardedJedisPool集群配置
Jedis设计 Jedis作为推荐的java语言redis客户端,其抽象封装为三部分: 对象池设计:Pool,JedisPool,GenericObjectPool,BasePoolableObjec ...
- 从零开始写redis客户端(deerlet-redis-client)之路——第一个纠结很久的问题,restore引发的血案
引言 正如之前的一篇博文,LZ最近正在从零开始写一个redis的客户端,主要目的是为了更加深入的了解redis,当然了,LZ也希望deerlet客户端有一天能有一席之地.在写的过程当中,LZ遇到了一个 ...
- Redis 客户端配置及示例
一.redis自定义配置节点 <configSections> <section name ="RedisConfig" type="Amy.Toolk ...
- Redis客户端Java服务接口封装
最近在学习Redis并集成到Spring中去,发现Spring的RedisTemplate并不好用,还没有MongoTemplate好用. 而且发现Jedis和ShardedJedis的方法非常多,覆 ...
- "Redis客户端连接数一直降不下来"的有关问题解决
[线上问题] "Redis客户端连接数一直降不下来"的问题解决 前段时间,上线了新的 Redis缓存(Cache)服务,准备替换掉 Memcached. 为什么要将 Memcach ...
- spring整合redis客户端及缓存接口设计(转)
一.写在前面 缓存作为系统性能优化的一大杀手锏,几乎在每个系统或多或少的用到缓存.有的使用本地内存作为缓存,有的使用本地硬盘作为缓存,有的使用缓存服务器.但是无论使用哪种缓存,接口中的方法都是差不多. ...
随机推荐
- 【充分利用你的Azure】将Azure用作云计算平台(1)
本文将围绕几个步骤来讲. 因为本人是MSP,微软送了150刀的额度给我随便使用.这篇文章是要讲将Azure用作云计算平台,对于我来说,我是做机器学习的,那么Azure就要有机器学习的平台. 本文的目的 ...
- hdu4705 Y 2013 Multi-University Training Contest 10
Y Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submis ...
- Linux下将Apache(httpd)新增为系统服务及开机自启动
1. 查看一下/etc/init.d/下是否存在httpd这个服务 ls /etc/init.d/ | grep httpd 如果没有执行下一步 2.将自己安装目录下的apachect1复制到该目录下 ...
- Android ListView getViewTypeCount 的返回值问题解决
最近在学慕课网上的一个实战课程,期间有一个智能聊天机器人模块. 聊天界面通过 ListView 显示,用 Adapter 加载.一般来说,单对单的聊天,两者发出的话分别列在聊天页面的左右两边.所以,在 ...
- MongoDB学习教程(2)-常用命令
1.MongoDB 创建数据库 use DATABASE_NAME,如果数据库不存在,则创建数据库,否则切换到指定数据库. > use test_0902 switched to db test ...
- HDU5661 Claris and XOR
我们求二进制是怎么求的呢:先看看二进制的每一位代表多大:.......32 16 8 4 2 1 假如n=10, ..... 32>n ,不要. 16>n,不要. 8<=n,要,然后 ...
- BZOJ-4915-简单的数字题
Description 对任意的四个不同的正整数组成的集合A={a_1,a_2,a_3,a_4 },记S_A=a_1+a_2+a_3+a_4,设n_A是满足a_i+a_j (1 ≤i<j≤4)| ...
- 【特效】给元素循环添加class
经常会遇到给元素循环添加class的效果,例如下面这个图 每个模块的背景色和图标都不相同,但是呢,模块的数量又不确定,说不定有几十个,那我不能设计几十个图标吧,所以,可以做成每9个一循环,也就是第10 ...
- 【学习】如何制作手机端html模板(REM的实际应用)
以前制作手机页面时,总是很迷茫,不知从何着手,页面也不知如何处理.会用一些百分比啊,媒体查询啊,还有就是目测了,但是各种手机端的屏幕适配是个老大难的问题,没有做到百分百兼容的.自从发现了rem这个好东 ...
- win10 UWP 标题栏后退
设置里,标题栏有后退按钮 在win平板,可以有后退键,手机也有 pc可以在标题栏 在OnLaunched //最后 Windows.UI.Core.SystemNavigationManager.Ge ...