什么是redis?
Redis是一种可基于内存亦可持久化的日志型、Key-Value数据库,支持的存储类型非常丰富,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。(具体介绍请参照百度百科)
为什么快?
纯ANSI C编写。
所有数据均存放在内存中,当然不包括持久化。
不依赖第三方类库,没有像memcached那样使用libevent。
Redis多样的数据结构,每种结构只做自己爱做的事,当然比数据库只有Table,MongogoDB只有JSON一种结构快了。
Redis支持的功能:
所有数据都在内存中。
五种数据结构:String / Hash / List / Set / Ordered Set。
数据过期时间支持。
不完全的事务支持。
服务端脚本:使用Lua Script编写,作用类似存储过程。
PubSub:捞过界的消息一对多发布订阅功能,起码Redis-Sentinel在使用它。
持久化:支持定期导出内存的RDB与 记录写操作日志的Append Only File两种模式。
Replication:Master-Slave模式,Master可连接多个只读Slave。
Fail-Over:Redis-Sentinel节点负责监控Master节点。
动态配置:所有参数可用命令行动态配置不需重启,2.8版可以重新写回配置文件中,对云上的大规模部署非常合适。
如何使用?
Redis包下载地址:http://download.csdn.net/detail/litao0942051021/9675872
Redis环境配置推荐博文:http://www.cnblogs.com/yjmyzz/p/redis-cluster-turotial.html
Redis命令学习推荐网址:http://doc.redisfans.com/
redis性能
这里讨论的性能是直接通过shell来进行测试的,跟使用Java Driver提供的Jedis是完全不同的。后面将讨论Jedis的性能。在此大概说一下Driver的选择有哪些?各个Driver好像只有Jedis比较活跃,也是Java里redis官方唯一推荐的。另外还有Spring Data Redis封装的JedisTemplate,主要负责从池中获取与归还Jedis实例,处理异常。这个封装并不太必要,因为Jedis已足够简单。综合来说,Java中使用Jedis就足够了,自己封装一下异常处理就ok了。
那么又回来说redis的性能,使用redis自带的redis-benchmark命令测试。
单个客户端处理10w条set操作,处理数据大小为100字节,得到的TPS在11000左右。
同样的参数,把客户端的连接增加到4,处理数据40万条,处理速度能够达到95000次/s。
把客户端连接增大到50,100,每个连接处理10万条数据,得到的处理速度差不多,接近100000次/s。
以上测试均关闭了redis持久化功能。需要注意的是redis是单线程架构。
下面看看Jedis性能如何,从理论上看,Jedis毕竟是用Java语言写的,性能自然不能跟以上情况比。
测试环境:单台redis服务器,端口号7020。Redis配置使用默认配置。
测试用例:使用序列化后的Authcode对象进行set和get操作
测试内容:开启多个线程,分别统计执行10万次set和get操作消耗的时间。
测试结果:
开启1条线程对10万条数据进行set得到的结果
每秒也有1万多的处理速度。
开启4条线程同时处理40万条
也就是每秒3.3万左右。
开启16条线程处理160万条操作,得到结果为4万次/s。
60条线程呢?结果为3.8万次/s,可见,Jedis的极限也差不多到这里了。
以上是set操作,下面再看看get,理论上应该要快些:
单线程处理速度为10526次/s
4线程处理速度为4万/s
16线程处理速度为4.7万/s
60线程处理速度为3.8万/s
最后也就是想说明,Jedis不可能达到跟不用任何Driver的redis一样高的性能,Jedis在set上最高4万/s,get最高5万多/s,该数值依赖具体的硬件运行环境。
Redis优化
正视网络往返时间。
MSet/LPush/ZAdd等都支持一次输入多个Key。
PipeLining模式 可以一次输入多个指令。在Jedis的实现里,所有指令先在本地的buffer中存着,直到调用sync。
更快的是Lua Script模式,还可以包含逻辑,直接在服务端又get又set的。
发现执行缓慢的命令,可配置执行超过多少时间的指令算是缓慢指令(默认10毫秒,不含IO时间),可以用slowlog get 指令查看(默认只保留最后的128条)。单线程的模型下,一个请求占掉10毫秒是件大事情,注意设置和显示的单位为微秒。
CPU永远是瓶颈,但top看到单个CPU 100%时,就是垂直扩展的时候了。
持久化对性能的影响很大,如果不需要就关掉。
要熟悉各指令的复杂度,不过只要不是O(N)一个超大集合,都不用太担心。
Redis集群
以上的测试都只是针对单台redis服务器性能做的比较。那么下面将对集群环境进行讨论。
什么是集群?
集群软件一般根据侧重的方向和试图解决的问题分为三大类
高性能计算集群(HPC)
将计算任务分配到不同计算节点来提高整体计算能力,主要应用于科学计算领域。这种集群是并行计算的基础,处理能力与真正超级并行机相等,并具有优良的性价比。常见于科研机构,企业环境很少用到。
负载均衡集群 (LBC)
这种集群的核心是把业务的负载流量尽可能平均合理分摊到集群各个节点。
这种集群系统会计算应用负载或网络流量负载,非常适合于提供静态内容网站。每个节点都可以处理一部分负载,并且可以根据节点负载进行动态平衡,以保持负载平衡。对于网络流量,负载均衡算法还可以根据每个节点不同的可用资源或网络的特殊环境来进行优化。
高可用性集群 (HAC)
侧重于提高系统的可用性,它通过集成硬件和软件的容错性来实现整体服务的高可用。如果群集中的某个节点发生了故障,那么将由另外的节点代替它。即使多个节点发生故障,整个系统环境也保证用户能够访问。
为什么要用集群?
这个问题很重要,这对后期优化的整体把握有一定的帮助。要明白redis集群是一种HAC集群。Redis3.0的提出就是为了解决redis高可用的问题,而且是以牺牲了单台redis的性能为代价来提高了容灾能力。
首先,单台的redis内存毕竟有限,如果数据量大,很难满足需求。其次,满足高可用要求,具有一定的容灾能力。
当前比较流行的redis集群方案有三种:twemproxy,codis,redis cluster
Twemproxy是目前用得最广泛,也是最成熟的方案。
Codis是国内豌豆荚做的开源方案,有很友好的运维管理界面。
Redis cluster是redis官网发布的redis3.0包含的集群方案,才发布不久,有一些bug,不够成熟。
关于这三种方案的比较,可以看相关博文:http://www.wtoutiao.com/a/2288780.html
集群性能
下面将用我们项目中自己封装的redis客户端分别对twemproxy和codis,单台redis的性能做比较,希望对后续redis的优化提供参考和帮助。
首先说明自己封装的redis跟java提供的Jedis的区别,之前说过Jedis提供的功能已经足够了,我们封装的redis只是对连接池的获取和归还,还有异常处理做了添加,没有影响Jedis的性能,我在测试中也证实过这一点。唯一影响性能的地方就是我们项目中使用的序列化功能,我尝试过不同的序列化方式,但是性能提升的效果不明显,所以也没再深究。(有关protostuff序列化的使用可以参考博文:http://blog.csdn.net/litao0942051021/article/details/53068493)
下面是单台redis和tw代理的性能对比:
测试环境:一个twemproxy服务器,两个redis服务器构成twemproxy集群,端口号为22121;单台redis服务器,端口号7020。Redis配置使用默认配置。
测试用例:使用序列化后的Authcode对象进行set和get操作
测试内容:开启4个线程,分别统计执行10万次set和get操作消耗的时间。
单台redis执行Set操作所耗时间 单台redis执行get操作所耗时间
Twemproxy集群执行set操作所耗时间 Twemproxy集群执行get操作所耗时间
也就是说40万条操作,单台redis set速度为3.3万/s,get速度为4.4万/s;tw代理set速度为1.8万/s,get速度为2.2万/s。
下面是tw代理和codis对比:
测试环境:一个twemproxy服务器,两个redis服务器构成twemproxy集群,端口号为22121;4个redis服务器以master-slave形式构成2组codis group,codis proxy端口号19000。Redis配置使用默认配置。
测试用例:使用序列化后的Authcode对象进行set和get操作
测试内容:开启4个线程,分别统计执行10万次set和get操作消耗的时间。
twemproxy set操作 get操作
codis set操作 get操作
也就是说codis在集群规模很小的情况下,其实性能不如tw代理,规模上去了才能显示出codis的性能优势,不过codis提供的dashboard集群管理界面非常友好,而且可以很容易的扩容。
该文档是我在做redis优化的一些心得,当然这里所说的内容只是我工作中的一个子集,很多细节回忆不起来了。测试可能不够严谨,但是反应了很多问题,对redis优化方案能够提供一定程度上的参考。希望对后面从事redis优化的同事提供学习上的帮助。
另外可以参考有关redis的常识,博文http://www.lxway.com/508104094.htm
最后说一下redis所谓的长连接和连接池:
长连接是指:一个连接上连续发送多个数据包,不用每个数据包都去创建一个连接。一般数据库的连接用长连接。
短连接是指:通讯双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。WEB网站的http服务一般都用短链接。
Jedispool会跟redis服务器维持多个连接,每个连接redis客户端都可以连续发送多次请求,而且每个请求都是同一个socket连接。也就是说连接池分配的连接就是长连接。而且我们项目的redis客户端具备重连机制,所以从系统的角度来讲redis客户端也算是一个长连接。
来源:CSDN
作者:AvalonLT
链接:https://blog.csdn.net/litao0942051021/article/details/53068493