介绍使用同一VPC内弹性云主机ECS上的Redisson连接Redis实例的方法。更多的客户端的使用方法请参考Redis客户端。
在springboot类型的项目中,spring-data-redis中提供了对jedis、lettuce的适配,但没有提供对redisson组件的适配。为了能够在springboot中集成redisson,redisson侧主动提供了适配springboot的组件:redisson-spring-boot-starter。
注意:在springboot1.x中默认集成的是jedis,springboot2.x中改为了lettuce。
说明
如果创建Redis实例时设置了密码,使用Redisson客户端连接Redis时,需要配置密码进行连接,建议不要将明文密码硬编码在代码中。
连接单机、主备、Proxy集群实例需要使用Redisson的SingleServerConfig配置对象中的useSingleServer方法,Cluster集群实例需要使用ClusterServersConfig对象中的useClusterServers方法。
前提条件
- 已成功申请Redis实例,且状态为“运行中”。
- 查看并获取待连接Redis实例的IP地址和端口。
具体步骤请参见查看实例信息。
- 已创建弹性云主机,创建弹性云主机的方法,请参见《弹性云主机用户指南》。
- 如果弹性云主机为Linux系统,该弹性云主机必须已经安装java编译环境。
- Pom配置
<!-- 引入spring-data-redis组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <!-- 因springboot2.x中默认集成了lettuce,因此需要排掉该依赖 --> <exclusion> <artifactId>lettuce-core</artifactId> <groupId>io.lettuce</groupId> </exclusion> </exclusions> </dependency> <!-- 引入redisson对springboot的集成适配包 --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>${redisson.version}</version> </dependency>
基于Bean方式配置
因springboot中没有提供对redisson的适配,在application.properties配置文件自然也没有对应的配置项,只能通过基于Bean的方式注入。
- 单机实例配置
import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.Config; import org.redisson.config.SingleServerConfig; import org.redisson.spring.data.connection.RedissonConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedisConfiguration { @Value("${redis.address}") private String redisAddress; @Value("${redis.password:}") private String redisPassword; @Value("${redis.database:0}") private Integer redisDatabase = 0; @Value("${redis.connect.timeout:3000}") private Integer redisConnectTimeout = 3000; @Value("${redis.connection.idle.timeout:10000}") private Integer redisConnectionIdleTimeout = 10000; @Value("${redis.connection.ping.interval:1000}") private Integer redisConnectionPingInterval = 1000; @Value("${redis.timeout:2000}") private Integer timeout = 2000; @Value("${redis.connection.pool.min.size:50}") private Integer redisConnectionPoolMinSize; @Value("${redis.connection.pool.max.size:200}") private Integer redisConnectionPoolMaxSize; @Value("${redis.retry.attempts:3}") private Integer redisRetryAttempts = 3; @Value("${redis.retry.interval:200}") private Integer redisRetryInterval = 200; @Bean public RedissonConnectionFactory redissonConnectionFactory(Config redissonSingleServerConfig) { return new RedissonConnectionFactory(redissonSingleServerConfig); } @Bean public Config redissonSingleServerConfig() { Config redissonConfig = new Config(); SingleServerConfig serverConfig = redissonConfig.useSingleServer(); serverConfig.setAddress(redisAddress); serverConfig.setConnectionMinimumIdleSize(redisConnectionPoolMinSize); serverConfig.setConnectionPoolSize(redisConnectionPoolMaxSize); serverConfig.setDatabase(redisDatabase); serverConfig.setPassword(redisPassword); serverConfig.setConnectTimeout(redisConnectTimeout); serverConfig.setIdleConnectionTimeout(redisConnectionIdleTimeout); serverConfig.setPingConnectionInterval(redisConnectionPingInterval); serverConfig.setTimeout(timeout); serverConfig.setRetryAttempts(redisRetryAttempts); serverConfig.setRetryInterval(redisRetryInterval); redissonConfig.setCodec(new JsonJacksonCodec()); return redissonConfig; } }
- 主备、读写分离实例配置
import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.Config; import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.ReadMode; import org.redisson.config.SubscriptionMode; import org.redisson.spring.data.connection.RedissonConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedisConfiguration { @Value("${redis.master.address}") private String redisMasterAddress; @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.connection.idle.timeout:10000}") private Integer redisConnectionIdleTimeout = 10000; @Value("${redis.connection.ping.interval:1000}") private Integer redisConnectionPingInterval = 1000; @Value("${redis.timeout:2000}") private Integer timeout = 2000; @Value("${redis.master.connection.pool.min.size:50}") private Integer redisMasterConnectionPoolMinSize = 50; @Value("${redis.master.connection.pool.max.size:200}") private Integer redisMasterConnectionPoolMaxSize = 200; @Value("${redis.retry.attempts:3}") private Integer redisRetryAttempts = 3; @Value("${redis.retry.interval:200}") private Integer redisRetryInterval = 200; @Bean public RedissonConnectionFactory redissonConnectionFactory(Config redissonMasterSlaveServersConfig) { return new RedissonConnectionFactory(redissonMasterSlaveServersConfig); } @Bean public Config redissonMasterSlaveServersConfig() { Config redissonConfig = new Config(); MasterSlaveServersConfig serverConfig = redissonConfig.useMasterSlaveServers(); serverConfig.setMasterAddress(redisMasterAddress); serverConfig.setDatabase(redisDatabase); serverConfig.setPassword(redisPassword); serverConfig.setMasterConnectionMinimumIdleSize(redisMasterConnectionPoolMinSize); serverConfig.setMasterConnectionPoolSize(redisMasterConnectionPoolMaxSize); serverConfig.setReadMode(ReadMode.MASTER_SLAVE); serverConfig.setSubscriptionMode(SubscriptionMode.MASTER); serverConfig.setConnectTimeout(redisConnectTimeout); serverConfig.setIdleConnectionTimeout(redisConnectionIdleTimeout); serverConfig.setPingConnectionInterval(redisConnectionPingInterval); serverConfig.setTimeout(timeout); serverConfig.setRetryAttempts(redisRetryAttempts); serverConfig.setRetryInterval(redisRetryInterval); redissonConfig.setCodec(new JsonJacksonCodec()); return redissonConfig; } }
- Proxy集群实例配置
import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.Config; import org.redisson.config.SingleServerConfig; import org.redisson.spring.data.connection.RedissonConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedisConfiguration { @Value("${redis.address}") private String redisAddress; @Value("${redis.password:}") private String redisPassword; @Value("${redis.database:0}") private Integer redisDatabase = 0; @Value("${redis.connect.timeout:3000}") private Integer redisConnectTimeout = 3000; @Value("${redis.connection.idle.timeout:10000}") private Integer redisConnectionIdleTimeout = 10000; @Value("${redis.connection.ping.interval:1000}") private Integer redisConnectionPingInterval = 1000; @Value("${redis.timeout:2000}") private Integer timeout = 2000; @Value("${redis.connection.pool.min.size:50}") private Integer redisConnectionPoolMinSize; @Value("${redis.connection.pool.max.size:200}") private Integer redisConnectionPoolMaxSize; @Value("${redis.retry.attempts:3}") private Integer redisRetryAttempts = 3; @Value("${redis.retry.interval:200}") private Integer redisRetryInterval = 200; @Bean public RedissonConnectionFactory redissonConnectionFactory(Config redissonProxyServerConfig) { return new RedissonConnectionFactory(redissonProxyServerConfig); } @Bean public Config redissonProxyServerConfig() { Config redissonConfig = new Config(); SingleServerConfig serverConfig = redissonConfig.useSingleServer(); serverConfig.setAddress(redisAddress); serverConfig.setConnectionMinimumIdleSize(redisConnectionPoolMinSize); serverConfig.setConnectionPoolSize(redisConnectionPoolMaxSize); serverConfig.setDatabase(redisDatabase); serverConfig.setPassword(redisPassword); serverConfig.setConnectTimeout(redisConnectTimeout); serverConfig.setIdleConnectionTimeout(redisConnectionIdleTimeout); serverConfig.setPingConnectionInterval(redisConnectionPingInterval); serverConfig.setTimeout(timeout); serverConfig.setRetryAttempts(redisRetryAttempts); serverConfig.setRetryInterval(redisRetryInterval); redissonConfig.setCodec(new JsonJacksonCodec()); return redissonConfig; } }
- Cluster集群实例配置
import java.util.List; import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.ClusterServersConfig; import org.redisson.config.Config; import org.redisson.config.ReadMode; import org.redisson.config.SubscriptionMode; import org.redisson.spring.data.connection.RedissonConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedisConfiguration { @Value("${redis.cluster.address}") private List<String> redisClusterAddress; @Value("${redis.cluster.scan.interval:5000}") private Integer redisClusterScanInterval = 5000; @Value("${redis.password:}") private String redisPassword; @Value("${redis.connect.timeout:3000}") private Integer redisConnectTimeout = 3000; @Value("${redis.connection.idle.timeout:10000}") private Integer redisConnectionIdleTimeout = 10000; @Value("${redis.connection.ping.interval:1000}") private Integer redisConnectionPingInterval = 1000; @Value("${redis.timeout:2000}") private Integer timeout = 2000; @Value("${redis.retry.attempts:3}") private Integer redisRetryAttempts = 3; @Value("${redis.retry.interval:200}") private Integer redisRetryInterval = 200; @Value("${redis.master.connection.pool.min.size:50}") private Integer redisMasterConnectionPoolMinSize = 50; @Value("${redis.master.connection.pool.max.size:200}") private Integer redisMasterConnectionPoolMaxSize = 200; @Bean public RedissonConnectionFactory redissonConnectionFactory(Config redissonClusterServersConfig) { return new RedissonConnectionFactory(redissonClusterServersConfig); } @Bean public Config redissonClusterServersConfig() { Config redissonConfig = new Config(); ClusterServersConfig serverConfig = redissonConfig.useClusterServers(); serverConfig.setNodeAddresses(redisClusterAddress); serverConfig.setScanInterval(redisClusterScanInterval); serverConfig.setPassword(redisPassword); serverConfig.setMasterConnectionMinimumIdleSize(redisMasterConnectionPoolMinSize); serverConfig.setMasterConnectionPoolSize(redisMasterConnectionPoolMaxSize); serverConfig.setReadMode(ReadMode.MASTER); serverConfig.setSubscriptionMode(SubscriptionMode.MASTER); serverConfig.setConnectTimeout(redisConnectTimeout); serverConfig.setIdleConnectionTimeout(redisConnectionIdleTimeout); serverConfig.setPingConnectionInterval(redisConnectionPingInterval); serverConfig.setTimeout(timeout); serverConfig.setRetryAttempts(redisRetryAttempts); serverConfig.setRetryInterval(redisRetryInterval); redissonConfig.setCodec(new JsonJacksonCodec()); return redissonConfig; } }
参数明细
Config参数
参数 | 默认值 | 说明 |
---|---|---|
codec | org.redisson.codec.JsonJacksonCodec | 编码格式,内置了JSON/Avro/Smile/CBOR/MsgPack等编码格式 |
executor | null | 功能同上,不设置该参数时,会根据threads参数初始化一个线程池 |
nettyThreads | cpu核数 * 2 | 连接redis-server的tcp channel使用的线程池,所有channel共享该连接池,映射到netty即Bootstrap.group(...) |
eventLoopGroup | null | 功能同上,不设置该参数时,会根据nettyThreads参数初始化一个EventLoopGroup,用于底层tcpchannel使用 |
transportMode | TransportMode.NIO | 传输模式,可选有NIO、EPOLL(需额外引包)、KQUEUE(需额外引包) |
lockWatchdogTimeout | 30000 | 监控锁的看门狗超时时间,单位:毫秒。用于分布式锁场景下未指定leaseTimeout参数时,采用该值为默认值 |
keepPubSubOrder | true | 是否按照订阅发布消息的顺序来接收,如能接受并行处理消息,建议设置为false |
单机实例-SingleServerConfig参数
参数 | 默认值 | 说明 |
---|---|---|
address | - | 节点连接信息,ip:port |
database | 0 | 选择使用的数据库编号 |
connectionMinimumIdleSize | 32 | 连接每个分片主节点的最小连接数 |
connectionPoolSize | 64 | 连接每个分片主节点的最大连接数 |
subscriptionConnectionMinimumIdleSize | 1 | 连接目标节点的用于发布订阅的最小连接数 |
subscriptionConnectionPoolSize | 50 | 连接目标节点的用于发布订阅的最大连接数 |
subcriptionPerConnection | 5 | 每个订阅连接上的最大订阅数量 |
connectionTimeout | 10000 | 连接超时时间,单位:毫秒 |
idleConnectionTimeout | 10000 | 空闲连接的最大回收时间,单位:毫秒 |
pingConnectionInterval | 30000 | 检测连接可用心跳,单位:毫秒,建议值:3000ms |
timeout | 3000 | 请求等待响应的超时时间,单位:毫秒 |
retryAttemps | 3 | 发送失败的最大重试次数 |
retryInterval | 1500 | 每次重试的时间间隔,单位:毫秒,建议值:200ms |
clientName | null | 客户端名称 |
主备、读写分离、Proxy集群实例MasterSlaveServersConfig参数
参数 | 默认值 | 说明 |
---|---|---|
masterAddress | - | 主节点连接信息,ip:port |
slaveAddresses | - | 从节点连接信息列表,Set<ip:port> |
readMode | SLAVE | 读取模式,默认读流量分发到从节点,可选值:MASTER、SLAVE、MASTER_SLAVE;建议MASTER |
loadBalancer | RoundRobinLoadBalancer | 负载均衡算法,在readMode为SLAVE、MASTER_SLAVE时生效,均衡读流量分发 |
masterConnectionMinimumIdleSize | 32 | 连接每个分片主节点的最小连接数 |
masterConnectionPoolSize | 64 | 连接每个分片主节点的最大连接数 |
slaveConnectionMinimumIdleSize | 32 | 连接每个分片每个从节点的最小连接数,如readMode=MASTER,该配置值将失效 |
slaveConnectionPoolSize | 64 | 连接每个分片每个从节点的最大连接数,如readMode=MASTER,该配置值将失效 |
subscriptionMode | SLAVE | 订阅模式,默认只在从节点订阅,可选值:SLAVE、MASTER;建议采用MASTER |
subscriptionConnectionMinimumIdleSize | 1 | 连接目标节点的用于发布订阅的最小连接数 |
subscriptionConnectionPoolSize | 50 | 连接目标节点的用于发布订阅的最大连接数 |
subcriptionPerConnection | 5 | 每个订阅连接上的最大订阅数量 |
connectionTimeout | 10000 | 连接超时时间,单位:毫秒 |
idleConnectionTimeout | 10000 | 空闲连接的最大回收时间,单位:毫秒 |
pingConnectionInterval | 30000 | 检测连接可用心跳,单位:毫秒,建议值:3000ms |
timeout | 3000 | 请求等待响应的超时时间,单位:毫秒 |
retryAttemps | 3 | 发送失败的最大重试次数 |
retryInterval | 1500 | 每次重试的时间间隔,单位:毫秒,建议值:200ms |
clientName | null | 客户端名称 |
Cluster集群实例-ClusterServersConfig参数
参数 | 默认值 | 说明 |
---|---|---|
nodeAddress | - | 集群节点的地址连接信息,每个节点采用ip:port方式,多个节点连接信息用英文逗号隔开 |
password | null | 集群登录密码 |
scanInterval | 1000 | 定时检测集群节点状态的时间间隔,单位:毫秒 |
readMode | SLAVE | 读取模式,默认读流量分发到从节点,可选值:MASTER、SLAVE、MASTER_SLAVE;建议修改为MASTER |
loadBalancer | RoundRobinLoadBalancer | 负载均衡算法,在readMode为SLAVE、MASTER_SLAVE时生效,均衡读流量分发 |
masterConnectionMinimumIdleSize | 32 | 连接每个分片主节点的最小连接数 |
masterConnectionPoolSize | 64 | 连接每个分片主节点的最大连接数 |
slaveConnectionMinimumIdleSize | 32 | 连接每个分片每个从节点的最小连接数,如readMode=MASTER,该配置值将失效 |
slaveConnectionPoolSize | 64 | 连接每个分片每个从节点的最大连接数,如readMode=MASTER,该配置值将失效 |
subscriptionMode | SLAVE | 订阅模式,默认只在从节点订阅,可选值:SLAVE、MASTER;建议采用MASTER |
subscriptionConnectionMinimumIdleSize | 1 | 连接目标节点的用于发布订阅的最小连接数 |
subscriptionConnectionPoolSize | 50 | 连接目标节点的用于发布订阅的最大连接数 |
subcriptionPerConnection | 5 | 每个订阅连接上的最大订阅数量 |
connectionTimeout | 10000 | 连接超时时间,单位:毫秒 |
idleConnectionTimeout | 10000 | 空闲连接的最大回收时间,单位:毫秒 |
pingConnectionInterval | 30000 | 检测连接可用心跳,单位:毫秒,建议值:3000 |
timeout | 3000 | 请求等待响应的超时时间,单位:毫秒 |
retryAttemps | 3 | 发送失败的最大重试次数 |
retryInterval | 1500 | 每次重试的时间间隔,单位:毫秒,建议值:200 |
clientName | null | 客户端名称 |
DCS实例配置建议
- 读取模式(readMode)
建议采用MASTER,即Master节点承担所有的读写流量,一方面避免数据因主从同步时延带来的一致性问题;另一方面,如果从节点故障,配置值=SLAVE,所有读请求会触发报错;配置值=MASTER_SLAVE,部分读请求会触发异常。读报错会持续failedSlaveCheckInterval(默认180s)时间,直至从可用节点列表中摘除。
如需读写流量分流处理,DCS服务提供了针对读写流量分流的读写分离实例类型,通过在中间架设代理节点实现读写流量分发,遇到从节点故障时,自动切流至主节点,对业务应用无感知,且故障感知时间窗口远小于redisson内部的时间窗口。
- 订阅模式(subscriptionMode)
建立采用MASTER,原理同上。
- 连接池配置
说明以下计算方式只适用于一般业务场景,建议根据业务情况做适当调整适配。
连接池的大小没有绝对的标准,建议根据业务流量进行合理配置,一般连接池大小的参数计算公式如下:
最小连接数=(单机访问Redis QPS)/(1000ms / 单命令平均耗时)
最大连接数=(单机访问Redis QPS)/(1000ms / 单命令平均耗时)* 150%
举例:某个业务应用的QPS为10000左右,每个请求需访问Redis10次,即每秒对Redis的访问次数为100000次,同时该业务应用有10台机器,计算如下:
单机访问Redis QPS = 100000 / 10 = 10000
单命令平均耗时 = 20ms(Redis处理单命令耗时为510ms,遇到网络抖动按照1520ms来估算)
最小连接数 =(10000)/(1000ms / 20ms)= 200
最大连接数 =(10000)/(1000ms / 20ms)* 150% = 300
- 重试配置
redisson中支持重试配置,主要是如下两个参数,建议根据业务情况配置合理值,一般重试次数为3,重试间隔为200ms左右。
retryAttemps:配置重试次数
retryInterval:配置重试时间间隔
说明在redisson中,部分API通过借助LUA的方式实现,性能表现上偏低,建议使用jedis客户端替换redisson。