介紹使(shi)用同一VPC內彈性云主機ECS上的Redisson連(lian)接(jie)Redis實(shi)例的方法。更多的客戶端的使(shi)用方法請參(can)考。
在springboot類型的(de)(de)項目中,spring-data-redis中提(ti)供(gong)了(le)對、的(de)(de)適配,但沒有提(ti)供(gong)對redisson組(zu)件的(de)(de)適配。為了(le)能夠在springboot中集成,redisson側主動提(ti)供(gong)了(le)適配springboot的(de)(de)組(zu)件:。
注意:在springboot1.x中默(mo)認集成的是jedis,springboot2.x中改為了(le)lettuce。
說明
?如果創建Redis實例時(shi)(shi)設置(zhi)了密(mi)碼(ma),使(shi)用Redisson客戶(hu)端連(lian)接(jie)(jie)Redis時(shi)(shi),需要(yao)配置(zhi)密(mi)碼(ma)進行(xing)連(lian)接(jie)(jie),建議不(bu)要(yao)將(jiang)明文密(mi)碼(ma)硬(ying)編碼(ma)在代碼(ma)中(zhong)。
連接單機、主備、Proxy集群實(shi)例需要(yao)使用Redisson的(de)SingleServerConfig配置對象中(zhong)的(de)useSingleServer方法,Cluster集群實(shi)例需要(yao)使用ClusterServersConfig對象中(zhong)的(de)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的適(shi)配,在application.properties配置文件自(zi)然也沒有對應的配置項,只(zhi)能通過基于Bean的方式注(zhu)入。
- 單機實例配置
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參數(shu)
| 參數 | 默認值 | 說明 |
|---|---|---|
| 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 | 客戶端名稱 |
主備、讀(du)寫分離、Proxy集(ji)群實(shi)例(li)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集(ji)群實例-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)
建(jian)議(yi)采用(yong)MASTER,即Master節點承擔(dan)所有的讀(du)寫流量,一(yi)方面避免數(shu)據因主從(cong)(cong)同(tong)步(bu)時延帶來的一(yi)致性問題;另一(yi)方面,如果(guo)從(cong)(cong)節點故(gu)障(zhang),配置(zhi)值=SLAVE,所有讀(du)請(qing)求(qiu)會觸發報錯;配置(zhi)值=MASTER_SLAVE,部分(fen)讀(du)請(qing)求(qiu)會觸發異常。讀(du)報錯會持續(xu)failedSlaveCheckInterval(默認180s)時間,直至(zhi)從(cong)(cong)可用(yong)節點列表中摘除。
如需讀寫流(liu)量分(fen)(fen)流(liu)處理,DCS服務提供(gong)了針對讀寫流(liu)量分(fen)(fen)流(liu)的(de)讀寫分(fen)(fen)離實例類型(xing),通過(guo)在中間(jian)架設代理節(jie)點(dian)實現讀寫流(liu)量分(fen)(fen)發,遇到從節(jie)點(dian)故障(zhang)時(shi),自動切(qie)流(liu)至(zhi)主節(jie)點(dian),對業務應用(yong)無感知,且故障(zhang)感知時(shi)間(jian)窗口(kou)遠小于redisson內部的(de)時(shi)間(jian)窗口(kou)。
- 訂閱模式(subscriptionMode)
建立采用MASTER,原理(li)同上。
- 連接池配置
說明以下計算方式只適(shi)用于一般業(ye)務場景,建(jian)議根據業(ye)務情(qing)況做適(shi)當(dang)調整(zheng)適(shi)配。
連接(jie)池(chi)的(de)(de)大小(xiao)沒有絕對的(de)(de)標準,建議根據業(ye)務(wu)流量進(jin)行合理配置,一(yi)般連接(jie)池(chi)大小(xiao)的(de)(de)參數計算公式如下:
最小連接數=(單(dan)機(ji)訪問(wen)Redis QPS)/(1000ms / 單(dan)命(ming)令平均(jun)耗(hao)時(shi))
最大連接數=(單(dan)機訪問Redis QPS)/(1000ms / 單(dan)命令(ling)平(ping)均耗時)* 150%
舉例:某(mou)個(ge)業(ye)(ye)務應用(yong)的QPS為(wei)10000左右,每個(ge)請(qing)求需訪問Redis10次,即每秒對Redis的訪問次數(shu)為(wei)100000次,同(tong)時該業(ye)(ye)務應用(yong)有(you)10臺機器,計算如(ru)下:
單機訪(fang)問Redis QPS = 100000 / 10 = 10000
單命(ming)令平均耗(hao)時 = 20ms(Redis處(chu)理單命(ming)令耗(hao)時為510ms,遇到網絡(luo)抖動按(an)照1520ms來(lai)估算)
最小(xiao)連接數 =(10000)/(1000ms / 20ms)= 200
最大(da)連(lian)接數 =(10000)/(1000ms / 20ms)* 150% = 300
- 重試配置
redisson中(zhong)支(zhi)持重試配置(zhi),主(zhu)要是如(ru)下兩(liang)個參數(shu),建議根據業務情況配置(zhi)合理(li)值,一般重試次數(shu)為3,重試間(jian)隔為200ms左右。
retryAttemps:配(pei)置重試次數(shu)
retryInterval:配(pei)置重試時間(jian)間(jian)隔(ge)
說明在redisson中,部分API通過借(jie)助LUA的方式實現,性能表現上(shang)偏低,建議使(shi)用jedis客戶端(duan)替換redisson。