前段時間在kubernetes中做多副本部署時,發現有些服務中存在定時任務,這樣一來不同副本都會執行這些定時任務,導致任務重複執行,然後找了一下決定使用 Redisson 來做這個,其實現在來看分佈式時鎖相對容易多了,就是在同一時刻去獲取一把鎖,拿到這把鎖就可以進行操作,拿不到就不能操作,這裏 Redisson 是利用在 Redis 存放一個 Key (其實是setNX)來做這個工作。當然定時任務僅僅分佈式鎖運用的一種場景。現在 Redisson 的使用也簡單了很多,官方直接提供了 redisson-spring-boot-starter
,和SpringBoot整合也很方便,下面是集成示例:
1. 引入依賴
注:redisson-spring-data 需要根據項目中使用的 SpringBoot 的版本進行重選,3.11.5 版本默認引用的是 redisson-spring-data-21(即適用於SpringBoot版本爲2.1.x的使用),但項目中我的SpringBoot是2.0.7就不行,需要選用redisson-spring-data-20
,不做這一步啓動會出錯的,具體的pom依賴爲:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-20</artifactId>
<version>3.11.5</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.11.5</version>
<exclusions>
<exclusion>
<artifactId>redisson-spring-data-21</artifactId>
<groupId>org.redisson</groupId>
</exclusion>
</exclusions>
</dependency>
2. 配置
配置方面如果只想試試,直接在application.properties
文件中使用Spring-data-redis的基本配置即可:
spring.redis.database=
spring.redis.host=
spring.redis.port=
spring.redis.password=
當然更全面的配置可以通過spring.redis.redisson.config=classpath:redisson.yaml
的方式以外部配置的方式植入,示例文件如下:
## 1. 雲託管方式(注意名字)
#replicatedServersConfig:
# # 連接空閒超時,默認值10000,如果當前連接池裏的連接數量超過了最小空閒連接數,同時有連接空閒時間超過了該數值,那這些連接將會自動被關閉,並從連接池裏去掉
# idleConnectionTimeout: 10000
# pingTimeout: 1000
# # 連接超時,默認10000,同任何節點建立連接時的等待超時
# connectTimeout: 10000
# # 命令等待超時
# timeout: 3000
# # 命令失敗重試次數,如果命令嘗試次數超過該值仍然不能發送至某個指定的節點時,將拋出錯誤。如果嘗試在此限制之內發送成功,則開始啓用 timeout(命令等待超時) 計時
# retryAttempts: 3
# # 命令重試發送時間間隔
# retryInterval: 1500
# # 當與某個節點的連接斷開時,等待與其重新建立連接的時間間隔
# reconnectionTimeout: 3000
# # 執行失敗最大次數,在某個節點執行相同或不同命令時,連續失敗次數大於該數值時,該節點將被從可用節點列表裏清除,直到 reconnectionTimeout 超時以後再次嘗試
# failedAttempts: 3
# password: 123456
# # 單個連接最大訂閱數量
# subscriptionsPerConnection: 5
# # 客戶端名稱,在Redis節點裏顯示的客戶端名稱
# clientName: null
# # 負載均衡算法類的選擇,多Redis服務節點的環境裏有3種可選:
# # org.redisson.connection.balancer.WeightedRoundRobinBalancer - 權重輪詢調度算法
# # org.redisson.connection.balancer.RoundRobinLoadBalancer - 輪詢調度算法(默認)
# # org.redisson.connection.balancer.RandomLoadBalancer - 隨機調度算法
# loadBalancer: org.redisson.connection.balancer.RoundRobinLoadBalancer
# # slave用於發佈和訂閱連接的最小保持連接數(長連接),默認值1。Redisson內部經常通過發佈和訂閱來實現許多功能。長期保持一定數量的發佈訂閱連接是必須的
# slaveSubscriptionConnectionMinimumIdleSize: 1
# # slave的發佈和訂閱連接池大小,默認50,連接池的連接數量自動彈性伸縮
# slaveSubscriptionConnectionPoolSize: 50
# # slave的最小空閒連接數
# slaveConnectionMinimumIdleSize: 32
# # slave的連接池大小,默認64,連接池的連接數量自動彈性伸縮
# slaveConnectionPoolSize: 64
# # mater的最小空閒連接數
# masterConnectionMinimumIdleSize: 32
# # mater的連接池大小
# masterConnectionPoolSize: 64
# # 讀取操作的負載均衡模式:SLAVE-只在從服務節點裏讀取,MASTER-只在主服務節點裏讀取,MASTER_SLAVE-在主、從服務節點裏都可以讀取
# readMode: "SLAVE"
# # 節點地址,通過host:port的格式來指定雲託管模式的多個Redis集羣節點的地址
# nodeAddresses:
# - "redis://127.0.0.1:6379"
# - "redis://127.0.0.1:6380"
# # 主節點變化掃描間隔時間,對主節點變化節點狀態掃描的時間間隔
# scanInterval: 1000
## 線程池數量,默認=當前處理核數量*2,該線程池數量被所有RTopic對象監聽器,RRemoteService調用者和RExecutorService任務共同共享
#threads: 0
## Netty線程池數量,默認=當前處理核數量*2,該線程池數量是在一個Redisson實例內,被其創建的所有分佈式數據類型和服務,以及底層客戶端所一同共享的線程池裏保存的線程數量
#nettyThreads: 0
## 編碼,Redisson的對象編碼類是用於將對象進行序列化和反序列化,以實現對該對象在Redis裏的讀取和存儲,默認JsonJacksonCodec
#codec: org.redisson.codec.JsonJacksonCodec
## 傳輸模式,可選:NIO(默認)、EPOLL(需要依賴裏有netty-transport-native-epoll包 Linux)、KQUEUE(需要依賴裏有 netty-transport-native-kqueue包(macOS)
#transportMode:"NIO"
# 1. 單節點
#singleServerConfig:
# idleConnectionTimeout: 10000
# pingTimeout: 1000
# connectTimeout: 10000
# timeout: 3000
# retryAttempts: 3
# retryInterval: 1500
# reconnectionTimeout: 3000
# failedAttempts: 3
# password: 123456
# subscriptionsPerConnection: 5
# clientName: null
# address: "redis://127.0.0.1:6379"
# subscriptionConnectionMinimumIdleSize: 1
# subscriptionConnectionPoolSize: 50
# connectionMinimumIdleSize: 32
# connectionPoolSize: 64
# database: 5
## dnsMonitoring: false
## dnsMonitoringInterval: 5000
#threads: 0
#nettyThreads: 0
#codec: !<org.redisson.codec.JsonJacksonCodec> {}
#transportMode: NIO
# 2. 主從節點
masterSlaveServersConfig:
idleConnectionTimeout: 10000
pingTimeout: 1000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
reconnectionTimeout: 3000
failedAttempts: 3
password: 123456
subscriptionsPerConnection: 5
clientName: null
loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
slaveSubscriptionConnectionMinimumIdleSize: 1
slaveSubscriptionConnectionPoolSize: 50
slaveConnectionMinimumIdleSize: 32
slaveConnectionPoolSize: 64
masterConnectionMinimumIdleSize: 32
masterConnectionPoolSize: 64
readMode: "SLAVE"
slaveAddresses:
- "redis://127.0.0.1:6380"
masterAddress: "redis://127.0.0.1:6379"
database: 0
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
"transportMode": "NIO"
3. 使用
在使用redisson客戶端時,就不需要再去配置jedis或者lettuce相關參數了,同樣具備RedisTemplate
可以使用
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Autowired
RedissonClient redissonClient;
public void testRedisson() {
// 獲取可重入鎖
RLock rLock = redissonClient.getLock("test-lock");
try {
// 如果該線程無法獲取鎖將會不斷嘗試,但至多2s,如果仍未獲取,返回false
// 如果該線程獲取鎖了,這個鎖將會在redis中存活60s,返回true
boolean lock = rLock.tryLock(2, 60, TimeUnit.SECONDS);
if (lock) {
System.out.println("get lock success!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// 利用體用的模板對redis進行操作
redisTemplate.opsForValue().set("test2", buildProject());
}
private Project buildProject() {
Project project = new Project();
project.setId(1);
project.setName("測試");
project.setUserId(111);
project.setCreateTime(new Date());
return project;
}
Redisson 存入的鎖對應的value是一個UUID:線程ID
的形式,具體可到redis中自行查看。