更新时间:2024-10-24 GMT+08:00

Jedis客户端连接Redis(Java)

本章节介绍使用Jedis客户端连接Redis实例的方法。更多的客户端的使用方法请参考Redis客户端

在springboot类型的项目中,spring-data-redis中已提供了对jedislettuce的集成适配。另外,在springboot1.x中默认集成的是jedis,springboot2.x中改为了lettuce,因此在springboot2.x及更高版本中集成使用jedis,需要对已集成的lettuce组件依赖进行排包。

Springboot版本不得低于2.3.12.RELEASE,Jedis版本不得低于3.10.0

前提条件

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();
}

参数明细

表1 RedisStandaloneConfiguration参数

参数

默认值

说明

hostName

localhost

连接Redis实例的IP地址/域名。

port

6379

连接端口号。

database

0

数据库下标,默认0。

password

-

连接Redis实例的密码。

表2 RedisClusterConfiguration参数

参数

说明

clusterNodes

cluster节点连接信息,需节点IP、Port。

maxRedirects

cluster访问最大重定向次数。

password

连接密码。

表3 JedisPoolConfig参数

参数

默认值

说明

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

空闲连接逐出的检测周期,单位:毫秒。

表4 JedisClientConfiguration参数

参数

默认值

说明

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