Jedis客户端连接Redis(Java)
本章节介绍使用Jedis客户端连接Redis实例的方法。更多的客户端的使用方法请参考Redis客户端。
在springboot类型的项目中,spring-data-redis中已提供了对jedis、lettuce的集成适配。另外,在springboot1.x中默认集成的是jedis,springboot2.x中改为了lettuce,因此在springboot2.x及更高版本中集成使用jedis,需要对已集成的lettuce组件依赖进行排包。
Springboot版本不得低于2.3.12.RELEASE,Jedis版本不得低于3.10.0。
前提条件
- 已成功创建Redis实例,且状态为“运行中”。创建Redis实例的操作请参考购买Redis实例。
- 查看并获取待连接Redis实例的IP地址/域名和端口。具体步骤请参见查看和修改DCS实例基本信息。
- 连接实例前确保客户端与Redis实例之间网络互通,具体请参考连接Redis网络要求。
Pom配置
<!-- 引入spring-data-redis组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!--spring boot 2.0之后默认lettuce客户端, 使用jedis时需要排包--> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <!-- 引入jedis依赖包 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${jedis.version}<version> </dependency>
基于application.properties配置
- 单机、主备、读写分离、Proxy集群实例配置
#redis host spring.redis.host=<host> #redis 端口号 spring.redis.port=<port> #redis 数据库下标 spring.redis.database=0 #redis 密码 spring.redis.password=<password> #redis 读写超时 spring.redis.timeout=2000 #是否开启连接池 spring.redis.jedis.pool.enabled=true #连接池的最小连接数 spring.redis.jedis.pool.min-idle=50 #连接池的最大空闲连接数 spring.redis.jedis.pool.max-idle=200 #连接池的最大连接数 spring.redis.jedis.pool.max-active=200 #连接池耗尽后获取连接的最大等待时间,默认-1表示一直等待 spring.redis.jedis.pool.max-wait=3000 #空闲连接逐出的检测周期,默认为60S spring.redis.jedis.pool.time-between-eviction-runs=60S
- Cluster集群实例配置
#redis cluster节点连接信息 spring.redis.cluster.nodes=<ip:port>,<ip:port>,<ip:port> #redis cluster密码 spring.redis.password=<password> #redis cluster访问最大重定向次数 spring.redis.cluster.max-redirects=3 #redis 读写超时 spring.redis.timeout=2000 #是否开启连接池 spring.redis.jedis.pool.enabled=true #连接池的最小连接数 spring.redis.jedis.pool.min-idle=50 #连接池的最大空闲连接数 spring.redis.jedis.pool.max-idle=200 #连接池的最大连接数 spring.redis.jedis.pool.max-active=200 #连接池耗尽后获取连接的最大等待时间,默认-1表示一直等待 spring.redis.jedis.pool.max-wait=3000 #空闲连接逐出的检测周期,默认为60S spring.redis.jedis.pool.time-between-eviction-runs=60S
基于Bean方式配置
- 单机、主备、读写分离、Proxy集群实例配置
import java.time.Duration; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import redis.clients.jedis.JedisPoolConfig; @Configuration public class RedisConfiguration { @Value("${redis.host}") private String redisHost; @Value("${redis.port:6379}") private Integer redisPort = 6379; @Value("${redis.database:0}") private Integer redisDatabase = 0; @Value("${redis.password:}") private String redisPassword; @Value("${redis.connect.timeout:3000}") private Integer redisConnectTimeout = 3000; @Value("${redis.read.timeout:2000}") private Integer redisReadTimeout = 2000; @Value("${redis.pool.minSize:50}") private Integer redisPoolMinSize = 50; @Value("${redis.pool.maxSize:200}") private Integer redisPoolMaxSize = 200; @Value("${redis.pool.maxWaitMillis:3000}") private Integer redisPoolMaxWaitMillis = 3000; @Value("${redis.pool.softMinEvictableIdleTimeMillis:1800000}") private Integer redisPoolSoftMinEvictableIdleTimeMillis = 30 * 60 * 1000; @Value("${redis.pool.timeBetweenEvictionRunsMillis:60000}") private Integer redisPoolBetweenEvictionRunsMillis = 60 * 1000; @Bean public RedisConnectionFactory redisConnectionFactory(JedisClientConfiguration clientConfiguration) { RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(); standaloneConfiguration.setHostName(redisHost); standaloneConfiguration.setPort(redisPort); standaloneConfiguration.setDatabase(redisDatabase); standaloneConfiguration.setPassword(redisPassword); return new JedisConnectionFactory(standaloneConfiguration, clientConfiguration); } @Bean public JedisClientConfiguration clientConfiguration() { JedisClientConfiguration clientConfiguration = JedisClientConfiguration.builder() .connectTimeout(Duration.ofMillis(redisConnectTimeout)) .readTimeout(Duration.ofMillis(redisReadTimeout)) .usePooling().poolConfig(redisPoolConfig()) .build(); return clientConfiguration; } private JedisPoolConfig redisPoolConfig() { JedisPoolConfig poolConfig = new JedisPoolConfig(); //连接池的最小连接数 poolConfig.setMinIdle(redisPoolMinSize); //连接池的最大空闲连接数 poolConfig.setMaxIdle(redisPoolMaxSize); //连接池的最大连接数 poolConfig.setMaxTotal(redisPoolMaxSize); //连接池耗尽后是否需要等待,默认true表示等待。当值为true时,setMaxWait才会生效 poolConfig.setBlockWhenExhausted(true); //连接池耗尽后获取连接的最大等待时间,默认-1表示一直等待 poolConfig.setMaxWaitMillis(redisPoolMaxWaitMillis); //创建连接时校验有效性(ping),默认false poolConfig.setTestOnCreate(false); //获取连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销 poolConfig.setTestOnBorrow(true); //归还连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销 poolConfig.setTestOnReturn(false); //是否开启空闲连接检测,如为false,则不剔除空闲连接 poolConfig.setTestWhileIdle(true); //连接空闲多久后逐出,空闲时间>该值,并且空闲连接>最大空闲数时直接逐出 poolConfig.setSoftMinEvictableIdleTimeMillis(redisPoolSoftMinEvictableIdleTimeMillis); //关闭根据MinEvictableIdleTimeMillis判断逐出 poolConfig.setMinEvictableIdleTimeMillis(-1); //空闲连接逐出的检测周期,默认为60S poolConfig.setTimeBetweenEvictionRunsMillis(redisPoolBetweenEvictionRunsMillis); return poolConfig; } }
- Cluster集群实例配置
import java.time.Duration; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import redis.clients.jedis.JedisPoolConfig; @Configuration public class RedisConfiguration { @Value("${redis.cluster.nodes}") private String redisClusterNodes; @Value("${redis.password:}") private String redisPassword; @Value("${redis.connect.timeout:3000}") private Integer redisConnectTimeout = 3000; @Value("${redis.read.timeout:2000}") private Integer redisReadTimeout = 2000; @Value("${redis.pool.minSize:50}") private Integer redisPoolMinSize = 50; @Value("${redis.pool.maxSize:200}") private Integer redisPoolMaxSize = 200; @Value("${redis.pool.maxWaitMillis:3000}") private Integer redisPoolMaxWaitMillis = 3000; @Value("${redis.pool.softMinEvictableIdleTimeMillis:1800000}") private Integer redisPoolSoftMinEvictableIdleTimeMillis = 30 * 60 * 1000; @Value("${redis.pool.timeBetweenEvictionRunsMillis:60000}") private Integer redisPoolBetweenEvictionRunsMillis = 60 * 1000; @Bean public RedisConnectionFactory redisConnectionFactory(JedisClientConfiguration clientConfiguration) { RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(); List<RedisNode> clusterNodes = new ArrayList<>(); for (String clusterNodeStr : redisClusterNodes.split(",")) { String[] nodeInfo = clusterNodeStr.split(":"); clusterNodes.add(new RedisNode(nodeInfo[0], Integer.valueOf(nodeInfo[1]))); } clusterConfiguration.setClusterNodes(clusterNodes); clusterConfiguration.setPassword(redisPassword); clusterConfiguration.setMaxRedirects(3); return new JedisConnectionFactory(clusterConfiguration, clientConfiguration); } @Bean public JedisClientConfiguration clientConfiguration() { JedisClientConfiguration clientConfiguration = JedisClientConfiguration.builder() .connectTimeout(Duration.ofMillis(redisConnectTimeout)) .readTimeout(Duration.ofMillis(redisReadTimeout)) .usePooling().poolConfig(redisPoolConfig()) .build(); return clientConfiguration; } private JedisPoolConfig redisPoolConfig() { JedisPoolConfig poolConfig = new JedisPoolConfig(); //连接池的最小连接数 poolConfig.setMinIdle(redisPoolMinSize); //连接池的最大空闲连接数 poolConfig.setMaxIdle(redisPoolMaxSize); //连接池的最大连接数 poolConfig.setMaxTotal(redisPoolMaxSize); //连接池耗尽后是否需要等待,默认true表示等待。当值为true时,setMaxWait才会生效 poolConfig.setBlockWhenExhausted(true); //连接池耗尽后最大等待时间,默认-1表示一直等待 poolConfig.setMaxWaitMillis(redisPoolMaxWaitMillis); //创建连接时校验有效性(ping),默认false poolConfig.setTestOnCreate(false); //获取连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销 poolConfig.setTestOnBorrow(true); //归还连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销 poolConfig.setTestOnReturn(false); //是否开启空闲连接检测,如为false,则不剔除空闲连接 poolConfig.setTestWhileIdle(true); //连接空闲多久后逐出,当空闲时间>该值,并且空闲连接>最大空闲数时直接逐出 poolConfig.setSoftMinEvictableIdleTimeMillis(redisPoolSoftMinEvictableIdleTimeMillis); //关闭根据MinEvictableIdleTimeMillis判断逐出 poolConfig.setMinEvictableIdleTimeMillis(-1); //空闲连接逐出的检测周期,默认为60s poolConfig.setTimeBetweenEvictionRunsMillis(redisPoolBetweenEvictionRunsMillis); return poolConfig; } }
SSL连接配置(可选配置)
当实例开启了SSL,通过SSL连接实例时,请使用以下内容替换基于Bean方式配置中的JedisClientConfiguration构造方法clientConfiguration()。Redis实例支持SSL的情况请参考配置Redis SSL数据加密传输。
@Bean public JedisClientConfiguration clientConfiguration() throws Exception { JedisClientConfiguration.JedisClientConfigurationBuilder configurationBuilder = JedisClientConfiguration.builder() .connectTimeout(Duration.ofMillis(redisConnectTimeout)) .readTimeout(Duration.ofMillis(redisReadTimeout)); configurationBuilder.usePooling().poolConfig(redisPoolConfig()); configurationBuilder.useSsl().sslSocketFactory(getTrustStoreSslSocketFactory()); return configurationBuilder.build(); } private SSLSocketFactory getTrustStoreSslSocketFactory() throws Exception{ //加载自定义路径下的ca证书,可结合具体业务配置 CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate ca; try (InputStream is = new FileInputStream("./ca.crt")) { ca = cf.generateCertificate(is); } //创建keystore String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca); //创建TrustManager TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); //创建SSLContext SSLContext context = SSLContext.getInstance("TLS"); context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); return context.getSocketFactory(); }
参数明细
参数 |
默认值 |
说明 |
---|---|---|
hostName |
localhost |
连接Redis实例的IP地址/域名。 |
port |
6379 |
连接端口号。 |
database |
0 |
数据库下标,默认0。 |
password |
- |
连接Redis实例的密码。 |
参数 |
说明 |
---|---|
clusterNodes |
cluster节点连接信息,需节点IP、Port。 |
maxRedirects |
cluster访问最大重定向次数。 |
password |
连接密码。 |
参数 |
默认值 |
说明 |
---|---|---|
minIdle |
- |
连接池的最小连接数。 |
maxIdle |
- |
连接池的最大空闲连接数。 |
maxTotal |
- |
连接池的最大连接数。 |
blockWhenExhausted |
true |
连接池耗尽后是否需要等待,默认true表示等待,false表示不等待。当值为true时,设置maxWaitMillis才会生效。 |
maxWaitMillis |
-1 |
连接池耗尽后获取连接的最大等待时间,单位:毫秒。默认-1表示一直等待。 |
testOnCreate |
false |
创建连接时校验有效性(ping),false:不校验,true:校验。 |
testOnBorrow |
false |
获取连接时校验有效性(ping),false:不校验,true:校验。业务量大时建议设置为false减少开销。 |
testOnReturn |
false |
归还连接时校验有效性(ping),false:不校验,true:校验。业务量大时建议设置为false减少开销。 |
testWhileIdle |
false |
是否开启空闲连接检测,如为false,则不剔除空闲连接,建议值:true。 |
softMinEvictableIdleTimeMillis |
1800000 |
连接空闲多久后逐出,(空闲时间>该值 && 空闲连接>最大空闲数)时直接逐出,单位:毫秒。 |
minEvictableIdleTimeMillis |
60000 |
根据minEvictableIdleTimeMillis时间判断逐出,单位:毫秒。建议值:-1,表示关闭该策略,改用softMinEvictableIdleTimeMillis策略。 |
timeBetweenEvictionRunsMillis |
60000 |
空闲连接逐出的检测周期,单位:毫秒。 |
参数 |
默认值 |
说明 |
---|---|---|
connectTimeout |
2000 |
连接超时时间,单位:毫秒。 |
readTimeout |
2000 |
请求等待响应的超时时间,单位:毫秒。 |
poolConfig |
- |
池化配置,具体请参见JedisPoolConfig。 |
DCS实例配置建议
- 连接池配置
以下计算方式只适用于一般业务场景,建议根据业务情况做适当调整适配。
连接池的大小没有绝对的标准,建议根据业务流量进行合理配置,一般连接池大小的参数计算公式如下:
- 最小连接数 =(单机访问Redis QPS)/(1000ms / 单命令平均耗时)
- 最大连接数 =(单机访问Redis QPS)/(1000ms / 单命令平均耗时)* 150%
举例:某个业务应用的QPS为10000左右,每个请求需访问Redis10次,即每秒对Redis的访问次数为100000次,同时该业务应用有10台机器,计算如下:
单机访问Redis QPS = 100000 / 10 = 10000
单命令平均耗时 = 20ms(Redis处理单命令耗时为5~10ms,遇到网络抖动按照15~20ms来估算)
最小连接数 =(10000)/(1000ms / 20ms)= 200
最大连接数 =(10000)/(1000ms / 20ms)* 150% = 300