- 最新动态
- 功能总览
- 服务公告
- 产品介绍
- 计费说明
- 快速入门
- 用户指南
- 最佳实践
- API参考
- SDK参考
-
常见问题
- 实例类型/版本
- 实例特性
- 安全性
-
客户端和网络连接
- DCS实例支持公网访问吗?
- Redis连接失败问题排查和解决
- DCS实例是否支持跨VPC访问?
- Redis公网访问所需弹性IP是否收费?
- Redis连接时报错:“(error) NOAUTH Authentication required”。
- 客户Http的Server端关闭导致Redis访问失败
- 客户端出现概率性超时错误
- 使用Jedis连接池报错如何处理?
- 如何使用Redis-desktop-manager访问Redis实例?
- 使用SpringCloud时出现ERR Unsupported CONFIG subcommand怎么办?
- 客户端无法使用域名连接DCS缓存实例时如何处理?
- 本地环境是否可以连接缓存实例?
- 使用Redis实例的发布订阅(pubsub)有哪些注意事项?
- Redis 3.0实例公网开关被关闭是什么原因?
- 使用短连接访问Redis出现“Cannot assign requested address”错误
- 连接池选择及Jedis连接池参数配置建议
- 如何解决Lettuce 6.x版本客户端使用DCS实例兼容性问题?
- 应该选择域名还是IP地址连接Redis实例?
- 主备实例的只读地址是连接到主节点还是备节点?
-
Redis使用
- 是否支持CPU架构的变更?
- 实例是否支持变更可用区
- Redis实例能否修改VPC和子网?
- 实例是否支持自定义或修改端口?
- 实例是否支持修改访问地址?
- 实例无法删除是什么原因?
- 集群实例启动时间过长是什么原因?
- 使用redis_exporter出错怎么办?
- 什么是预留内存,如何配置预留内存?
- 创建的缓存实例为什么可使用内存比实例规格少一些?
- Redis 3.0 Proxy集群不支持redisson分布式锁的原因
- DCS Redis有没有后台管理软件?
- DCS缓存实例的数据被删除后,能否找回?
- 为什么实例实际可用内存比申请规格小而且已使用内存不为0?
- 如何查看Redis内存占用量
- Cluster集群实例容量和性能未达到瓶颈,但某个分片容量或性能已过载是什么原因?
- 访问Redis报OOM错误提示
- 不同编程语言如何使用Cluster集群客户端
- 使用Cluster的Redis集群时建议配置合理的超时时间
- 读取redis数据报超时错误
- hashtag的原理、规则及用法示例
- Redis key丢失是什么原因
- 重启实例后缓存数据会保留吗?
- 如何确认实例是单DB还是多DB
- Proxy集群开启多DB的使用限制及操作方式
- 如何创建多DB的Proxy集群实例?
- 扩容缩容与实例升级
-
数据备份/导出/迁移
- DCS实例是否兼容低版本Redis迁移到高版本
- 不同类型的操作系统间进行数据传递和操作,需要注意什么?
- 源Redis使用了多DB,能否迁移数据到集群实例?
- 源Redis迁移到集群实例中有哪些限制和注意事项?
- 在线迁移需要注意哪些?
- 在线迁移能否做到完全不中断业务?
- 在线迁移实例源端报“Disconnecting timedout slave”和“overcoming of output buffer limits”
- 如何导出Redis实例数据?
- 使用Rump工具迁移数据,命令执行后无报错,但Redis容量无变化
- 是否支持控制台导出RDB格式的Redis备份文件?
- 缓存实例备份文件如何存放?备份文件的数量是否有限制?
- Redis在线数据迁移是迁移整个实例数据么?
- AOF文件在什么情况下会被重写
- Redis迁移失败有哪些常见原因?
- 一个数据迁移能迁移到多个目标实例么?
- 怎么放通SYNC和PSYNC命令?
- 迁移或导入备份数据时,相同的Key会被覆盖吗?
- Cluster集群实例使用内置key且跨slot的Lua脚本时迁移失败
- 迁移故障处理
- 数据迁移失败问题排查
- Memcached如何迁移?
- 是否支持Memcached和Redis之间实例数据的迁移?
- 大Key/热Key分析/过期Key扫描
- Redis命令
- 监控告警
- 主备倒换
- 创建实例和权限
- Memcached使用
- 故障排除
- 视频帮助
- 文档下载
- 通用参考
链接复制成功!
优化Jedis连接池
方案概述
JedisPool是Jedis客户端的连接池,合理设置JedisPool资源池参数能够有效地提升Redis性能与资源利用率。本文档将对JedisPool的使用和资源池的参数配置提供详细的说明和配置建议。
JedisPool使用方法
以Jedis 5.1.3为例,其Maven依赖如下:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>5.1.3</version> </dependency>
Jedis使用Apache Commons-pool2对资源池进行管理,在定义JedisPool时需设置关键参数GenericObjectPoolConfig(资源池)。该参数的使用示例如下,其中的参数的说明请参见JedisPool参数说明。
GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig(); jedisPoolConfig.setMaxTotal(...); jedisPoolConfig.setMaxIdle(...); jedisPoolConfig.setMinIdle(...); jedisPoolConfig.setMaxWaitMillis(...);
JedisPool的初始化方法如下:
// redisHost为Redis实例的连接IP, redisPort为Redis实例连接端口,redisPassword为Redis实例的连接密码,timeout是连接超时/读写超时。 JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, timeout, redisPassword); // 执行命令如下 Jedis jedis = null; try { jedis = jedisPool.getResource(); // 具体的命令 jedis.set("key", "value"); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { // 在JedisPool模式下,Jedis会被归还给资源池 if (jedis != null) jedis.close(); }
JedisPool参数说明
Jedis连接是连接池中JedisPool管理的资源,JedisPool保证资源在一个可控范围内,并保障线程安全。使用合理的GenericObjectPoolConfig配置能够提升Redis的服务性能,降低资源开销。表1及表2提供了一些重要参数的说明及配置建议。
参数 |
说明 |
默认值 |
建议 |
---|---|---|---|
maxTotal |
资源池中的最大连接数。 |
8 |
请参见关键参数配置建议。 |
maxIdle |
资源池允许的最大空闲连接数。 |
8 |
请参见关键参数配置建议。 |
minIdle |
资源池允许的最小空闲连接数。 |
0 |
请参见关键参数配置建议。 |
blockWhenExhausted |
当资源池用尽后,调用者是否要等待。
只有当值为true时,设置的maxWaitMillis才会生效。 |
true |
建议使用默认值。 |
maxWaitMillis |
当资源池连接用尽后,调用者的最大等待时间(单位:毫秒)。 值为-1表示一直等待。 |
-1 |
建议设置具体的最大等待时间。 |
testOnBorrow |
向资源池借用连接时是否做连接有效性检测(ping)。检测到的无效连接将会被移除。
|
false |
业务量很大时候建议设置为false,减少一次ping的开销。 |
testOnReturn |
向资源池归还连接时是否做连接有效性检测(ping)。检测到的无效连接将会被移除。
|
false |
业务量很大时候建议设置为false,减少一次ping的开销。 |
jmxEnabled |
是否开启JMX监控。
|
true |
建议开启,请注意应用本身也需要开启。 |
空闲Jedis对象检测由表2中的参数组合完成。
名称 |
说明 |
默认值 |
建议 |
---|---|---|---|
testWhileIdle |
是否在空闲资源监测时通过ping命令监测连接有效性,无效连接将被销毁。 |
false |
true |
timeBetweenEvictionRunsMillis |
空闲资源的检测周期(单位:毫秒)。 值为-1表示不检测。 |
-1 |
建议设置,周期自行选择,也可以默认也可以使用下方JedisPoolConfig 中的配置。 |
minEvictableIdleTimeMillis |
资源池中资源的最小空闲时间(单位:毫秒),达到此值后空闲资源将被移除。 |
1,800,000(即30分钟) |
可根据自身业务决定,一般默认值即可,也可以考虑使用下方JedisPoolConfig中的配置。 |
numTestsPerEvictionRun |
做空闲资源检测时,每次检测资源的个数。 |
3 |
可根据自身应用连接数进行微调,设置为-1时,表示对所有连接做空闲监测。 |
为了方便使用,Jedis提供了JedisPoolConfig,它继承了GenericObjectPoolConfig在空闲检测上的一些设置。
public class JedisPoolConfig extends GenericObjectPoolConfig { public JedisPoolConfig() { setTestWhileIdle(true); setMinEvictableIdleTimeMillis(60000); setTimeBetweenEvictionRunsMillis(30000); setNumTestsPerEvictionRun(-1); }}
可以在org.apache.commons.pool2.impl.BaseObjectPoolConfig中查看全部默认值。
关键参数配置建议
- maxTotal设置建议
合理设置maxTotal(最大连接数)需要考虑的因素较多,如:
- 业务希望的Redis并发量。
- 客户端执行命令时间。
- Redis资源,例如Redis分片数。
- maxTotal不能超过Redis的最大连接数(查看Redis的最大连接数请参考查看或修改实例最大连接数)。
- 资源开销,例如虽然希望控制空闲连接,但又不希望因为连接池中频繁地释放和创建连接造成不必要的开销。
假设一次命令时间,即borrow|return resource加上Jedis执行命令(含网络耗时)的平均耗时约为1ms,一个连接的QPS大约是1s/1ms = 1000,而业务期望的单个Redis的QPS是50000(业务总的QPS/Redis分片个数),那么理论上需要的资源池大小(即MaxTotal)是50000 / 1000 = 50。
但事实上在理论值基础上,还要预留一些资源,所以maxTotal可以比理论值大一些。这个值不是越大越好,一方面连接太多会占用客户端和服务端资源,另一方面对于Redis这种高QPS的服务器,如果出现大命令的阻塞,即使设置再大的资源池也无济于事。
- maxIdle和minIdle设置建议
maxIdle是业务需要的最大连接数,maxTotal是为了给出余量,所以maxIdle不要设置得过小,否则会有new Jedis(新连接)开销,而minIdle是为了控制空闲资源检测。
连接池的最佳性能是maxTotal=maxIdle,这样就避免了连接池伸缩带来的性能干扰。如果您的业务存在突峰访问,建议设置这两个参数的值相等;如果并发量不大或者maxIdle设置过高,则会导致不必要的连接资源浪费。
您可以根据实际总QPS和调用Redis的客户端规模整体评估每个节点所使用的连接池大小。
- 使用监控获取合理值
在实际环境中,比较可靠的方法是通过监控来尝试获取参数的最佳值。可以考虑通过JMX等方式实现监控,从而找到合理值。
常见报错
- 资源不足
下面两种情况均属于无法从资源池获取到资源。此类异常的原因不一定是资源池不够大,请参见关键参数设置建议中的分析。建议从网络、资源池参数设置、资源池监控(如果对JMX监控)、代码(例如没执行jedis.close())、慢查询、DNS等方面进行排查。
- 超时:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool …Caused by: java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject
- blockWhenExhausted为false时,资源池用尽后不会等待资源释放:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool …Caused by: java.util.NoSuchElementException: Pool exhausted at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject
- 超时:
- 预热JedisPool
由于一些原因(如超时时间设置较小等),项目在启动成功后可能会出现超时。JedisPool定义最大资源数、最小空闲资源数时,不会在连接池中创建Jedis连接。初次使用时,池中没有资源使用则会先新建一个new Jedis,使用后再放入资源池,该过程会有一定的时间开销,所以建议在定义JedisPool后,以最小空闲数量为基准对JedisPool进行预热,示例如下:
List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle()); for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) { Jedis jedis = null; try { jedis = pool.getResource(); minIdleJedisList.add(jedis); jedis.ping(); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { } } for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) { Jedis jedis = null; try { jedis = minIdleJedisList.get(i); jedis.close(); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { } }