網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
Redisson 主從一致性
- 我們先來(lái)說(shuō)一下 Redis 的主從模式,
Redis Master
(主節(jié)點(diǎn))中處理所有發(fā)向 Redis 的寫(xiě)操作(增刪改),Redis Slave
(從節(jié)點(diǎn))只負(fù)責(zé)處理讀操作,主節(jié)點(diǎn)會(huì)不斷將自己的數(shù)據(jù)同步給從節(jié)點(diǎn),確保主從之間的數(shù)據(jù)一致性,但是數(shù)據(jù)同步會(huì)存在一定的延時(shí),主從一致性問(wèn)題就是因?yàn)檠訒r(shí)而導(dǎo)致的 - 比如我們通過(guò)
set lock thread1 nx ex 10
來(lái)獲取鎖,主節(jié)點(diǎn)就會(huì)保存這個(gè)鎖的標(biāo)識(shí) thread1,然后主節(jié)點(diǎn)會(huì)向從節(jié)點(diǎn)進(jìn)行同步,但在同步尚未完成時(shí)時(shí)主節(jié)點(diǎn)發(fā)生故障,Redis 哨兵發(fā)現(xiàn)主節(jié)點(diǎn)宕機(jī)后,客戶端連接會(huì)斷開(kāi),然后從從節(jié)點(diǎn)中選出一個(gè)作為新的主節(jié)點(diǎn),但是由于之前主從同步未完成,即 thread1 這個(gè)鎖已經(jīng)丟失,所以此時(shí) Java 應(yīng)用再來(lái)訪問(wèn)新的主節(jié)點(diǎn)時(shí)就會(huì)發(fā)現(xiàn)鎖失效了,此時(shí)其他線程來(lái)獲取鎖時(shí)也能獲取成功,這時(shí)就可能出現(xiàn)并發(fā)安全問(wèn)題,以上就是主從一致性導(dǎo)致的鎖失效問(wèn)題 - 那么 Redisson 是如何解決上述問(wèn)題的呢?既然導(dǎo)致主從一致性問(wèn)題發(fā)生的主要原因是主從同步延時(shí)問(wèn)題,Redisson 干脆直接舍棄了主從節(jié)點(diǎn),所有 Redis 節(jié)點(diǎn)都是獨(dú)立的節(jié)點(diǎn),相互之間無(wú)任何關(guān)系,都可以做讀寫(xiě)操作。此時(shí),我們想獲取鎖就必須依次向多個(gè) Redis 都去獲取鎖(之前直接向 Master 節(jié)點(diǎn)獲取就可以),多個(gè) Redis 節(jié)點(diǎn)都保存鎖的標(biāo)識(shí),才算獲取成功
- 這樣一來(lái),由于所有節(jié)點(diǎn)都是獨(dú)立的,所以避免了主從一致性問(wèn)題;又由于所有的節(jié)點(diǎn)都保存了鎖標(biāo)識(shí),即使由一個(gè)節(jié)點(diǎn)宕機(jī),其他的節(jié)點(diǎn)也保存有鎖的標(biāo)識(shí),保證了高可用,并且可用性會(huì)隨著節(jié)點(diǎn)的增多而增高
- 此外,我們還以為給這些獨(dú)立的節(jié)點(diǎn)再加上從節(jié)點(diǎn) Slave,即使一個(gè)獨(dú)立節(jié)點(diǎn)宕機(jī)了導(dǎo)致其對(duì)應(yīng)的從節(jié)點(diǎn)變成新的主節(jié)點(diǎn),且節(jié)點(diǎn)上鎖標(biāo)識(shí)丟失了也沒(méi)有關(guān)系,因?yàn)槲覀冎挥性诿恳粋€(gè)節(jié)點(diǎn)都拿到鎖才算成功, 盡管可以在這個(gè)空虛的節(jié)點(diǎn)上獲取到鎖,但在其他節(jié)點(diǎn)上是獲取不到的,最終仍然是失敗,因此只要有任意一個(gè)節(jié)點(diǎn)存貨,其他線程就不可能拿到鎖,就不會(huì)出現(xiàn)鎖失效問(wèn)題。這樣,既保留了主從同步機(jī)制,又確保了 Redis 集群的高可用特性,同時(shí)還避免了主從一致所引發(fā)的鎖失效問(wèn)題,這個(gè)方案就叫做
mutilLock
Java 實(shí)現(xiàn) mutilLock
RedissonConfig.java
package com.hmdp.config; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedissonConfig { @Bean public RedissonClient redissonClient() { // 配置 Config config = new Config(); // 地址 & 密碼 config.useSingleServer().setAddress("redis://ip:端口").setPassword("pwd"); // 創(chuàng)建 RedissonClient 對(duì)象 return Redisson.create(config); } @Bean public RedissonClient redissonClient2() { // 配置 Config config = new Config(); // 地址 & 密碼 config.useSingleServer().setAddress("redis://ip:端口").setPassword("pwd"); // 創(chuàng)建 RedissonClient 對(duì)象 return Redisson.create(config); } @Bean public RedissonClient redissonClient3() { // 配置 Config config = new Config(); // 地址 & 密碼 config.useSingleServer().setAddress("redis://ip:端口").setPassword("pwd"); // 創(chuàng)建 RedissonClient 對(duì)象 return Redisson.create(config); } }
TestRedisson.java
package com.hmdp; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; @Slf4j @SpringBootTest public class TestRedisson { @Resource private RedissonClient redissonClient; @Resource private RedissonClient redissonClient2; @Resource private RedissonClient redissonClient3; private RLock lock; @BeforeEach void setUp() { RLock lock1 = redissonClient.getLock("order"); RLock lock2 = redissonClient2.getLock("order"); RLock lock3 = redissonClient3.getLock("order"); // 創(chuàng)建連鎖 multiLock lock = redissonClient.getMultiLock(lock1, lock2, lock3); } @Test void method1() throws InterruptedException { // 嘗試獲取鎖 boolean isLock = lock.tryLock(1L, TimeUnit.SECONDS); if (!isLock) { log.error("獲取鎖失敗 .... 1"); return; } try { log.info("獲取鎖成功 .... 1"); method2(); log.info("開(kāi)始執(zhí)行業(yè)務(wù) .... 1"); } finally { log.warn("準(zhǔn)備釋放鎖 .... 1"); lock.unlock(); } } void method2() { // 嘗試獲取鎖 boolean isLock = lock.tryLock(); if (!isLock) { log.error("獲取鎖失敗 .... 2"); return; } try { log.info("獲取鎖成功 .... 2"); log.info("開(kāi)始執(zhí)行業(yè)務(wù) .... 2"); } finally { log.warn("準(zhǔn)備釋放鎖 .... 2"); lock.unlock(); } } }
跟蹤源碼,我們發(fā)現(xiàn)只有所有的鎖都獲取成功了才會(huì)返回 true
原文鏈接:https://juejin.cn/post/7135613701951848461
相關(guān)推薦
- 2023-01-13 BatchNorm2d原理、作用及pytorch中BatchNorm2d函數(shù)的參數(shù)使用_python
- 2023-03-22 Python中數(shù)值比較的效率_python
- 2023-01-28 python元組的可變與不可變問(wèn)題_python
- 2022-03-14 命令刪除node_modules
- 2022-04-05 Python中hash加密簡(jiǎn)介及使用方法_python
- 2023-02-15 Python二進(jìn)制轉(zhuǎn)化為十進(jìn)制數(shù)學(xué)算法詳解_python
- 2023-10-16 nginx啟動(dòng)與配置
- 2022-04-08 c++11中std::move函數(shù)的使用_C 語(yǔ)言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支