Redis使用经验
Posted maxytj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis使用经验相关的知识,希望对你有一定的参考价值。
官方文档:http://redis.io/documentation
三、应用场景
Redis适合存储Key-Value形式的数据,因为是直接内存读写,效率很高,在开发中一般有两种场景使用它。
1.作为缓存使用
把redis作为一个只读的或者读多写少的缓存存储器,目标是提供高速的缓存读写,注重性能而不需要考虑数据是否会丢失的问题,这种情况下可以直接关闭RDB和AOF存储选项,以提高性能。
2.作为数据库使用
当需要一个既能高速读写又能保障数据安全的数据库时,redis也能满足。当我们需要100%数据安全的时候,需要开启AOF的逐个写入,它的性能会比较差;当我们需要99.9%的数据安全时,可采用主备模式来实现,主机提供读写不做持久化存储,备机开启AOF存储,保障数据安全。主备数据同步是实时的,主备之间切换会丢失一到几毫秒的数据。原则上应尽量保持主机不宕机以避免切换。
四、集群设计
Redis的集群主要目的是增强服务的吞吐量,在redis中由于存储的都是key-value的数据结构,因此它的集群主要是针对key进行分片,不同的key路由到不同的服务器上去,来实现简单的分片集群。
4.主备切换机制
每组主备服务器配置一个vip,同时用keeplived实现热切换,当主机宕机后vip从主机指向备机,该备机变为新的主机,关闭AOF,原主机修复后启动变为备机,开启AOF。
5.数据分片技术
数据分片可以在客户端或服务端实现。
数据分片即是对key进行分片,首先对key采用一致性哈希算法进行计算,算出key存在于的区间,区间映射到不同的节点,然后再进行存储。
节点区间的映射支持两种方式,一种是基于已配置的主机的顺序,另外一种是为每个配置的主机命名。如果采用了基于主机顺序的方式,则读取和写入的配置必须保持相同的顺序,否则会导致分片失效。如果采用了命名的方式,那么在读取和写入要保持相同的名字,否则也会导致分片失效。建议采用主机顺序的方式,简单容易移植。
下面是一个基于主机顺序分片的例子,在spring中配置jedis2.7的时需要注意构造函数的参数类型,看下面红色高亮的参数,JedisShardInfo提供了10个构造函数,如果不指定 constructor-arg的类型,默认为String, 会调用到另外一个构造函数,它会把timeout参数当成分片主机的命名,导致对已经导入的数据不能正确的分片路由。
<bean id = "shardedJedisPool" class = "redis.clients.jedis.ShardedJedisPool">
<constructor-arg index="0" ref="jedisPoolConfig"/>
<constructor-arg index="1">
<list>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg index="0" value="${redis.a.host}"/>
<constructor-arg index="1" value="${redis.a.port}"/>
<constructor-arg index="2" value="${redis.timeout}" type="int"/>
</bean>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg index="0" value="${redis.b.host}"/>
<constructor-arg index="1" value="${redis.b.port}"/>
<constructor-arg index="2" value="${redis.timeout}" type="int"/>
</bean>
</list>
</constructor-arg>
</bean>
6.预分片实现集群扩展
Redis集群存在的一个弊端,就是当需要扩展物理服务器的时候,会发现无法对一个现有的redis实例的已存在的数据重新分片。为此我们可以采取预分片技术,即先在一台物理主机上启动多个节点,需要扩展的时候把一些节点直接迁移到另外的物理机器上,即可实现扩展。
7.并发写入问题
当Redis作为数据库使用的时候,在大数据量和大并发量下需要考虑写操作并发的问题。Redis没有提供锁机制,需要用一些手段自己实现。自己写并发锁需要考虑锁的时效问题,超时后自动释放锁。
在单一键值并发写入不大的情况下,可以从程序上优化,尽可能的避免读写间隔过长,如果同一键值读写间隔能控制在毫秒级的话,可以不用考虑锁。如果读写间隔过长,可以在写入之前再次读取,合并最新结果后再写入。
五、数据导入
有两种数据导入的方式:
第一种是用重定向的方式,将命令集中到一个文件中,然后定向输出到redis-cli。这种方式的弊端是不能执行分片导入。
第二种方式是调用jedis客户端使用程序导入数据。
六、数据备份恢复
调用client端的save命令,执行成功后备份rdb文件。
如果只配置AOF,重启时加载AOF文件恢复数据;
如果同时配置了RBD和AOF,启动是只加载AOF文件恢复数据;
如果只配置RBD,启动是加载dump文件恢复数据。
七、服务器配置
8.增加最大连接数
1.修改操作系统句柄最大数:ulimit -n 50000
2.修改配置文件中客户端最大连接数量:maxclients 10000
9.过期数据内存回收
3.当Redis中存在过期数据时,最好设置最大内存,过期的数据不会释放内存,达到最大内存时根据回收策略执行过期数据回收。
4.也可以通过定期执行keys命令手动回收。
5.计算带有过期数据的实际的dbsize的命令:
a)./redis-cli keys "*" | wc -l
10.RDB模式
6.默认配置时开启了RDB模式的,当达到条件的时候系统会自动执行将内存快照存储到磁盘上。当数据变更太快的时候建议关掉RDB模式(save配置下增加 save ""),因为不断地存储快照将导致Redis无响应或响应时间变大。启用了RDB模式后,最大内存最好不要超过系统可用内存的50%。
7.Rdb模式下如果宕机的话默认配置下会丢失最大60秒或者10000条数据。这个是可以配置的,如果希望数据更安全可以调整参数。
11.AOF模式
8.默认配置时关闭了AOF模式的,AOF模式是将接受的命令持久化到硬盘文件,因此执行效率更高,不会消耗太多的系统性能。但是重新启动要加载很多历史命令,速度非常慢。建议在主备模式下备机启用AOF模式。
9.AOF模式下,如果需要保证数据绝对安全则可以设置 appendfsync always,即每次请求均要写入AOF数据文件,这种方式下效率非常低。如果要求不高,可以采用默认值 appendfsync everysec,宕机后最多丢失1秒数据。
八、Jedis
12.客户端调用
10.客户端调用要使用连接池,重用连接提高性能,注意连接用完要关闭。
11.单节点采用:redis.clients.jedis.JedisPoolConfig
12.集群采用: redis.clients.jedis.ShardedJedisPool
批量数据处理要使用pipeline
单节点采用:redis.clients.jedis.Pipeline
集群采用: redis.clients.jedis.ShardedJedisPipeline
九、性能测试
测试的场景是通过Java代码调用Jedis客户端实现和Redis集群通信。通过对一组双节点组成(64G内存+ 6核CPU4个)的集群进行测试后,得出如下结论:
读取性能很高,3亿数据量,最多承受4000个线程的压力,每秒10000的并发下平均响应时间6毫秒。
写入性能稍差,最多承受500个线程的压力,1000万的数据量,每秒5000的并发下平均响应时间1-2毫秒。
主备模式下,某些请求瞬间的响应比较大,最大为300到600毫秒之间,主备复制对主机的瞬时影响是存在的。备机开启aof的情况下,最大响应时间也会偏大。
详情可以参考下面的压力测试结果,双击打开,测试代码参考第八章的java工程。
十、Redis监控
编写shell脚本监控redis服务器CPU和内存使用情况、负载以及检测redis是否假死、主从切换等,通过统一通知及时发送报警短信。短信发送功能的jar包由短信厅提供,具体项目实施须自行解决。
以上是关于Redis使用经验的主要内容,如果未能解决你的问题,请参考以下文章
使用Python客户端(redis-py)连接Redis--华为云DCS for Redis使用经验