
# Jedis客户端连接Redis（Java）
本章节介绍使用Jedis客户端连接Redis实例的方法。更多的客户端的使用方法请参考[Redis客户端](https://redis.io/clients)。
在Springboot类型的项目中，spring-data-redis中已提供了对[Jedis](https://github.com/redis/jedis)、[Lettuce](https://github.com/lettuce-io/lettuce-core)的集成适配。另外，在Springboot 1.x中默认集成的是Jedis，Springboot 2.x中改为Lettuce。因此，如需在Springboot 2.x及更高版本中集成使用Jedis，需要对已集成的Lettuce组件依赖进行排包。
#### 约束与限制
Springboot版本不得低于2.3.12.RELEASE，Jedis版本不得低于[3.10.0](https://github.com/redis/jedis/releases/tag/v3.10.0)。
如果是Redis 7.0实例，请使用[5.0.0](https://github.com/redis/jedis/releases/tag/v5.0.0)及以上版本Jedis客户端，推荐[5.1.1](https://github.com/redis/jedis/releases/tag/v5.1.1)及以上版本。
#### 前提条件
- 已成功创建Redis实例，且状态为"运行中"。创建Redis实例的操作请参考[购买Redis实例](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0713002.html)。
- 查看并获取待连接Redis实例的IP地址/域名和端口。具体步骤请参见[查看和修改DCS实例基本信息](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0312016.html)。当客户端公网访问Redis时，请参考[开启Redis公网访问并获取公网访问地址](https://support.huaweicloud.com/usermanual-dcs/dcs_03_0011.html)，获取实例公网访问地址及端口。
- 连接实例前确保客户端与Redis实例之间网络互通，具体请参考[连接Redis网络要求](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0312007.html)。
 
#### 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配置
Springboot版本不同，配置也不同。Springboot 2.x和Springboot 3.x的配置参考如下。
- [Springboot 2.x配置]
- [Springboot 3.x配置]
- 单机、主备、读写分离、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
  ```
  
 
- 单机、主备、读写分离、Proxy集群实例配置
  ```
  #redis host
  spring.data.redis.host=<host>
  #redis 端口号
  spring.data.redis.port=<port>
  #redis 数据库下标
  spring.data.redis.database=0
  #redis 密码
  spring.data.redis.password=<password>
  #redis 读写超时
  spring.data.redis.timeout=2000
  #是否开启连接池
  spring.data.redis.jedis.pool.enabled=true
  #连接池的最小连接数
  spring.data.redis.jedis.pool.min-idle=50
  #连接池的最大空闲连接数
  spring.data.redis.jedis.pool.max-idle=200
  #连接池的最大连接数
  spring.data.redis.jedis.pool.max-active=200
  #连接池耗尽后获取连接的最大等待时间，默认-1表示一直等待
  spring.data.redis.jedis.pool.max-wait=3000
  #空闲连接逐出的检测周期，默认为60s
  spring.data.redis.jedis.pool.time-between-eviction-runs=60s
  ```
  
- Cluster集群实例配置
  ```
  #redis cluster节点连接信息
  spring.data.redis.cluster.nodes=<ip:port>,<ip:port>,<ip:port>
  #redis cluster密码
  spring.data.redis.password=<password>
  #redis cluster访问最大重定向次数
  spring.data.redis.cluster.max-redirects=3
  #redis 读写超时
  spring.data.redis.timeout=2000
  #是否开启连接池
  spring.data.redis.jedis.pool.enabled=true
  #连接池的最小连接数
  spring.data.redis.jedis.pool.min-idle=50
  #连接池的最大空闲连接数
  spring.data.redis.jedis.pool.max-idle=200
  #连接池的最大连接数
  spring.data.redis.jedis.pool.max-active=200
  #连接池耗尽后获取连接的最大等待时间，默认-1表示一直等待
  spring.data.redis.jedis.pool.max-wait=3000
  #空闲连接逐出的检测周期，默认为60s
  spring.data.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数据加密传输](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-023129.html)。
```
@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();
}
```
#### 参数明细
表1RedisStandaloneConfiguration参数 
| 参数       | 默认值       | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|:---|:---|:---|
| hostName | localhost | 连接Redis实例的IP地址/域名。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| port     | 6379      | 连接端口号。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| database | 0         | 数据库下标，默认0。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| password | -         | 连接Redis实例的密码。如果实例已开启免密访问，无需输入实例的访问密码**。** 忘记密码或需要重置密码请参见[重置缓存实例密码](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0312039.html#dcs-ug-0312039__section7753521111)。 - 如果使用创建Redis实例时自定义的密码（即实例默认账号的密码），请将其修改为实际密码。  - 如果使用实例创建的ACL账号连接，实例的密码需要配置为"账号名称:账号密码"，即**{username:password}** 。创建或查看ACL账号，请参见[配置Redis ACL访问账号](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-221220.html)。   |
   
表2RedisClusterConfiguration参数 
| 参数           | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|:---|:---|
| clusterNodes | Cluster节点连接信息，需节点IP、Port。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| maxRedirects | Cluster访问最大重定向次数。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| password     | 连接Redis实例的密码。如果实例已开启免密访问，无需输入实例的访问密码**。** 忘记密码或需要重置密码请参见[重置缓存实例密码](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0312039.html#dcs-ug-0312039__section7753521111)。 - 如果使用创建Redis实例时自定义的密码（即实例默认账号的密码），请将其修改为实际密码。  - 如果使用实例创建的ACL账号连接，实例的密码需要配置为"账号名称:账号密码"，即**{username:password}** 。创建或查看ACL账号，请参见[配置Redis ACL访问账号](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-221220.html)。   |
   
 表3JedisPoolConfig参数 
| 参数                             | 默认值     | 说明                                                                                              |
|:---|:---|:---|
| 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   | 空闲连接逐出的检测周期，单位：毫秒。                                                                              |
   
表4JedisClientConfiguration参数 
| 参数             | 默认值  | 说明                                                                |
|:---|:---|:---|
| connectTimeout | 2000 | 连接超时时间，单位：毫秒。                                                     |
| readTimeout    | 2000 | 请求等待响应的超时时间，单位：毫秒。                                                |
| poolConfig     | -    | 池化配置，具体请参见[JedisPoolConfig]。 |
   
#### DCS实例配置建议
- 连接池配置
  ![](https://support.huaweicloud.com/usermanual-dcs/public_sys-resources/note_3.0-zh-cn.png)
  以下计算方式只适用于一般业务场景，建议根据业务情况做适当调整适配。
  连接池的大小没有固定标准，建议根据业务流量合理配置，一般连接池大小的参数计算公式如下：
  - 最小连接数 =（单机访问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
  
 
#### 相关文档
- [Redis连接失败问题排查和解决](https://support.huaweicloud.com/trouble-dcs/dcs-trouble-0715001.html)
- [使用Jedis连接池报错如何处理？](https://support.huaweicloud.com/dcs_faq/dcs-faq-0427009.html)
- [连接池选择及Jedis连接池参数配置建议](https://support.huaweicloud.com/dcs_faq/dcs-faq-211230001.html)
 
