国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn)

這篇具有很好參考價值的文章主要介紹了高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一,場景概述:

在高并發(fā)的環(huán)境下,比如淘寶,京東不定時的促銷活動,大量的用戶訪問會導致數(shù)據(jù)庫的性能下降,進而有可能數(shù)據(jù)庫宕機從而不能產(chǎn)生正常的服務,一般一個系統(tǒng)最大的性能瓶頸,就是數(shù)據(jù)庫的io操作,如果發(fā)生大量的io那么他的問題也會隨之而來。從數(shù)據(jù)庫入手也是調(diào)優(yōu)性價比最高的切入點。因此需要對我們的程序進行優(yōu)化.一般采取兩種方案:

①從數(shù)據(jù)庫自身出發(fā):優(yōu)化sql,通過分析sql給sql建立索引,優(yōu)化查詢效率

②盡量避免直接查詢數(shù)據(jù)庫:使用緩存來實現(xiàn)

此文主要以緩存來解決高并發(fā)的效率問題來闡述,工欲善其事必先利其器,我們從原理和實戰(zhàn)兩方面入手來完成優(yōu)化

二,原理

1.緩存的基本使用流程

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

如圖所示:用戶發(fā)起請求到達服務器,處理業(yè)務的同時,如果涉及到持久層,會經(jīng)歷以下幾個步驟:

①首先到達緩存查詢,查看緩存是否存在

②如果存在,則直接返回

③如果不存在,則前往數(shù)據(jù)庫查詢

④將DB查詢到的結(jié)果返回給客戶端,同時將查詢到的結(jié)果放入緩存一份

⑤再次查詢,直接從緩存里面即可拿到對應的數(shù)據(jù).

但是在高并發(fā)的情況下,大量的請求過來又會導致一系列問題的產(chǎn)生,因此針對不同的問題,我們又有不同的解決方案,詳情如下:

2.緩存產(chǎn)生的問題以及解決方案

在高并發(fā)條件下,無數(shù)的請求并發(fā)會產(chǎn)生以下問題:

①緩存雪崩

②緩存穿透

③緩存擊穿

............

2.1緩存雪崩

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

我們可以簡單的理解為:由于原有緩存失效,新緩存未到期間(例如:我們設(shè)置緩存時采用了相同的過期時間,在同一時刻出現(xiàn)大面積的緩存過期),所有原本應該訪問緩存的請求都去查詢數(shù)據(jù)庫了,而對數(shù)據(jù)庫CPU和內(nèi)存造成巨大壓力,嚴重的會造成數(shù)據(jù)庫宕機。從而形成一系列連鎖反應,造成整個系統(tǒng)崩潰。

解決方案:

①加鎖

②對于緩存的key隨機的設(shè)置過期時間,保證讓緩存不在同一時間失效

③采用隊列方式保證來保證不會有大量的線程對數(shù)據(jù)庫一次性進行讀寫,從而避免失效時大量的并發(fā)請求落到底層存儲系統(tǒng)上

2.2緩存擊穿

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

如圖所示:緩存穿透指的是對于某個熱點key,在高峰期大量的并發(fā)請求過來的時候,該熱點key正好過期,導致所有的請求一瞬間打在了DB上,從而導致DB宕機或性能下降.

解決方案:

①加鎖

②隊列

2.3緩存穿透

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

如圖所示:緩存穿透指的是,查詢一個不存在的key,緩存為空,同時數(shù)據(jù)庫也為空,相當于做了無用功,意義不大,如果被別人利用,大量的請求null,將會對數(shù)據(jù)庫的性能產(chǎn)生巨大的影響

解決辦法:

①緩存空值,并給空值key設(shè)置小于5分的過期時間

②采用布隆過濾器,將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中,一個一定不存在的數(shù)據(jù)會被這個bitmap攔截掉,從而避免了對底層存儲系統(tǒng)的查詢壓力。

2.4緩存預熱

緩存預熱這個應該是一個比較常見的概念,相信很多小伙伴都應該可以很容易的理解,緩存預熱就是系統(tǒng)上線后,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請求的時候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題!用戶直接查詢事先被預熱的緩存數(shù)據(jù)!

解決辦法

①直接寫個緩存刷新頁面,上線時手工操作下;

②數(shù)據(jù)量不大,可以在項目啟動的時候自動進行加載;

③定時刷新緩存;

2.5緩存更新

除了緩存服務器自帶的緩存失效策略之外(Redis默認的有6種策略可供選擇),我們還可以根據(jù)具體的業(yè)務需求進行自定義的緩存淘汰,常見的策略有兩種:

①定時去清理過期的緩存;

②當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。

兩者各有優(yōu)劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜!具體用哪種方案,可以根據(jù)自己的應用場景來權(quán)衡。

2.6、緩存降級

當訪問量劇增、服務出現(xiàn)問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然需要保證服務還是可用的,即使是有損服務。系統(tǒng)可以根據(jù)一些關(guān)鍵數(shù)據(jù)進行自動降級,也可以配置開關(guān)實現(xiàn)人工降級。降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結(jié)算)。

總結(jié):針對于上面提到的問題不同的場景有不同的解決方案,一般情況下,我們選擇加鎖的方式來完成對緩存產(chǎn)生問題的優(yōu)化,鎖的選擇有多種:

①本地鎖(不能解決集群下產(chǎn)生的問題)

②分布式鎖(redis,zookeper,數(shù)據(jù)庫鎖)

以下將采用加鎖的方式分別闡述解決緩存帶來的問題

三,準備工作

3.1創(chuàng)建springboot工程,導入redis的依賴

springboot版本選擇2.3.6.RELEASE

<!--?redis?-->????????<dependency>????????????<groupId>org.springframework.boot</groupId>????????????<artifactId>spring-boot-starter-data-redis</artifactId>????????</dependency>
????????<!--?spring2.X集成redis所需common-pool2-->????????<dependency>????????????<groupId>org.apache.commons</groupId>????????????<artifactId>commons-pool2</artifactId>????????????<version>2.6.0</version>????????</dependency>????????<dependency>????????????<groupId>org.springframework.boot</groupId>????????????<artifactId>spring-boot-starter-web</artifactId>????????</dependency>

3.2添加配置文件并創(chuàng)建啟動類(略)

redis:????host:?192.168.17.166????port:?6379????database:?0????timeout:?1800000????password:????lettuce:??????pool:????????max-active:?20?#最大連接數(shù)????????max-wait:?-1????#最大阻塞等待時間(負數(shù)表示沒限制)????????max-idle:?5????#最大空閑????????min-idle:?0?????#最小空閑

3.3配置類 ?

@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 序列號key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}

四,實戰(zhàn)模擬

4.1不加鎖帶來的問題

num的值為0,提前在redis客戶端里面存儲

創(chuàng)建controller和service

 

啟動測試:

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

單獨的測試,每次發(fā)請求都沒有問題,但是如果面對大量的請求呢,又會發(fā)生什么問題呢?

使用ab工具進行壓測

在linux里面安裝yum?-y?install?httpd-tools

測試5000個請求,每次請求100個會是什么情況呢?

預想值:5000

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

實際值:148

為什么呢?

原因是多個線程搶占同一資源,會有不同的線程在同一時刻搶占到同一個值,來回的切換修改,導致了,數(shù)據(jù)不一致的問題

如何解決:上鎖,加入synchronized關(guān)鍵字,再次進行測試

4.2本地鎖

synchonized又叫同步鎖,它通過持有同步監(jiān)視器對象來判斷是否自動上鎖還是解鎖.

①實例方法:同步監(jiān)視器是this

②靜態(tài)方法:同步監(jiān)視器是類.class

③同步代碼塊:同步監(jiān)視器是括號里面的內(nèi)容

??@Override????public?synchronized??void?testRedisRefresh()?{????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????String?value?=?redisTemplate.opsForValue().get("num");????????//校驗????????if(StringUtils.isEmpty(value)){????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????return;????????}????????//存在將num轉(zhuǎn)換為int????????int?num?=?Integer.parseInt(value);????????//存入緩存????????redisTemplate.opsForValue().set("num",String.valueOf(++num));????}

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

可以看到,此時的結(jié)果正確,這是因為我們使用了synchronized給方法上了同步鎖,那么我的方法每次只處理一個線程的請求,其余方法只能在外面等著,當我的一個線程處理完,自動釋放鎖之后,其他方法才會依次進入,這樣就可以保證原子性.

但是,為了減少服務器的性能,會將服務器搭建集群,那么本地鎖還能夠適用嗎,我們拭目以待.

搭建同樣的8206,8216,8226三個微服務,使用gatway網(wǎng)關(guān)統(tǒng)一訪問測試:

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

可以看到數(shù)據(jù)再次出現(xiàn)了不一致,導致出現(xiàn)這種情況的原因在于我們的三個微服務有三把鎖,三把鎖同時工作,

每個線程占到的鎖不一樣,因此會導致數(shù)據(jù)不一致的情況.

本地鎖只能鎖住同一工程內(nèi)的資源,在分布式系統(tǒng)里面都存在局限性。

解決這個問題的辦法在于給集群的程序設(shè)置一把鎖,此時需要分布式鎖。

4.3分布式鎖

4.3.1分布式鎖的解決方案

隨著業(yè)務發(fā)展的需要,原單體單機部署的系統(tǒng)被演化成分布式集群系統(tǒng)后,由于分布式系統(tǒng)多線程、多進程并且分布在不同機器上,這將使原單機部署情況下的并發(fā)控制鎖策略失效,單純的Java?API并不能提供分布式鎖的能力。為了解決這個問題就需要一種跨JVM的互斥機制來控制共享資源的訪問,這就是分布式鎖要解決的問題!

分布式鎖主流的實現(xiàn)方案:

  1. 基于數(shù)據(jù)庫實現(xiàn)分布式鎖

  2. 基于緩存(Redis等)

  3. 基于Zookeeper

每一種分布式鎖解決方案都有各自的優(yōu)缺點:

  1. 性能:redis最高

  2. 可靠性:zookeeper最高

這里,我們基于redis實現(xiàn)分布式鎖。

4.3.2redis實現(xiàn)分布式鎖

在redis中可以通過setnx來對一個key上鎖,通過刪除這個key來解鎖,因此基于redis的這個特性我們可以將它做成全局分布式鎖

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

(1)版本一

修改service代碼如下所示

?@Override????public???void?testRedisRefresh()?{????????//鎖定key????????Boolean?absent?=?redisTemplate.opsForValue().setIfAbsent("lock",?"111");????????if?(absent){????????????//處理業(yè)務????????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????????String?value?=?redisTemplate.opsForValue().get("num");????????????//校驗????????????if(StringUtils.isEmpty(value)){????????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????????return;????????????}????????????//存在將num轉(zhuǎn)換為int????????????int?num?=?Integer.parseInt(value);????????????//存入緩存????????????redisTemplate.opsForValue().set("num",String.valueOf(++num));????????}else{????????????//未拿到鎖等待????????????try?{????????????????Thread.sleep(100);????????????}?catch?(InterruptedException?e)?{????????????????e.printStackTrace();????????????}????????????//自旋????????????this.testRedisRefresh();????????}
????}

再次啟動三個微服務測試

通過測試發(fā)現(xiàn)結(jié)果為5000,與預想的結(jié)果值一樣

再次分析:

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

(2)版本二,優(yōu)化

基于2.6.1版本之后的特性我們在使用java執(zhí)行setnx的時候可以給key設(shè)置一個過期時間

?@Override????public???void?testRedisRefresh()?{????????//鎖定key????????Boolean?absent?=?redisTemplate.opsForValue().setIfAbsent("lock",?"111",3L,TimeUnit.SECONDS);????????if?(absent){????????????//處理業(yè)務????????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????????String?value?=?redisTemplate.opsForValue().get("num");????????????//校驗????????????if(StringUtils.isEmpty(value)){????????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????????return;????????????}????????????//存在將num轉(zhuǎn)換為int????????????int?num?=?Integer.parseInt(value);????????????//存入緩存????????????redisTemplate.opsForValue().set("num",String.valueOf(++num));
????????????//釋放鎖???????????redisTemplate.delete("lock");????????}else{????????????//未拿到鎖等待????????????try?{????????????????Thread.sleep(100);????????????????//自旋????????????????this.testRedisRefresh();????????????}?catch?(InterruptedException?e)?{????????????????e.printStackTrace();????????????}
????????}

????}

測試發(fā)現(xiàn)依然沒問題,再次分析

問題:可能會釋放其他服務器的鎖。

場景:如果業(yè)務邏輯的執(zhí)行時間是7s。執(zhí)行流程如下

  1. index1業(yè)務邏輯沒執(zhí)行完,3秒后鎖被自動釋放。

  2. index2獲取到鎖,執(zhí)行業(yè)務邏輯,3秒后鎖被自動釋放。

  3. index3獲取到鎖,執(zhí)行業(yè)務邏輯

  4. index1業(yè)務邏輯執(zhí)行完成,開始調(diào)用del釋放鎖,這時釋放的是index3的鎖,?導致index3的業(yè)務只執(zhí)行1s就被別人釋放。

最終等于沒鎖的情況。

解決:setnx獲取鎖時,設(shè)置一個指定的唯一值(例如:uuid);釋放前獲取這個值,判斷是否自己的鎖

(3)版本三優(yōu)化(uuid防止誤刪)

?@Override????public???void?testRedisRefresh()?{????????//設(shè)置唯一表示,防止誤刪除????????String?uuid?=?UUID.randomUUID().toString().replace("-",?"");????????//鎖定key????????Boolean?absent?=?redisTemplate.opsForValue().setIfAbsent("lock",?uuid,3L,TimeUnit.SECONDS);????????if?(absent){????????????//處理業(yè)務????????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????????String?value?=?redisTemplate.opsForValue().get("num");????????????//校驗????????????if(StringUtils.isEmpty(value)){????????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????????return;????????????}????????????//存在將num轉(zhuǎn)換為int????????????int?num?=?Integer.parseInt(value);????????????//存入緩存????????????redisTemplate.opsForValue().set("num",String.valueOf(++num));
????????????????????????//判斷是否是自己的鎖,防誤刪???????????if?(uuid.equals(redisTemplate.opsForValue().get("lock"))){???????????????//釋放鎖???????????????redisTemplate.delete("lock");???????????}????????}else{????????????//未拿到鎖等待????????????try?{????????????????Thread.sleep(100);????????????????//自旋????????????????this.testRedisRefresh();????????????}?catch?(InterruptedException?e)?{????????????????e.printStackTrace();????????????}
????????}

????}

由于刪除操作不具有原子性因此需要再次優(yōu)化

(4)終極版本(使用lua腳本)

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

代碼實現(xiàn):

@Override????public???void?testRedisRefresh()?{????????//①上鎖????????//設(shè)置唯一表示,防止誤刪除????????String?uuid?=?UUID.randomUUID().toString().replace("-",?"");????????//鎖定key????????Boolean?absent?=?redisTemplate.opsForValue().setIfAbsent("lock",?uuid,3L,TimeUnit.SECONDS);????????//②業(yè)務
????????if?(absent){????????????//處理業(yè)務????????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????????String?value?=?redisTemplate.opsForValue().get("num");????????????//校驗????????????if(StringUtils.isEmpty(value)){????????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????????return;????????????}????????????//存在將num轉(zhuǎn)換為int????????????int?num?=?Integer.parseInt(value);????????????//存入緩存????????????redisTemplate.opsForValue().set("num",String.valueOf(++num));

????????//③解鎖????????????????//lua腳本????????????String?script="if?redis.call(\"get\",KEYS[1])?==?ARGV[1]\n"?+????????????????????"then\n"?+????????????????????"????return?redis.call(\"del\",KEYS[1])\n"?+????????????????????"else\n"?+????????????????????"????return?0\n"?+????????????????????"end";????????????????//創(chuàng)建對象????????????DefaultRedisScript<Long>?redisScript?=?new?DefaultRedisScript<>();????????????redisScript.setScriptText(script);????????????redisScript.setResultType(Long.class);????????????//執(zhí)行刪除????????????redisTemplate.execute(redisScript,Arrays.asList("lock",uuid));????????????//④自旋????????}else{????????????//未拿到鎖等待????????????try?{????????????????Thread.sleep(100);????????????????//自旋????????????????this.testRedisRefresh();????????????}?catch?(InterruptedException?e)?{????????????????e.printStackTrace();????????????}
????????}

4.3.3redision實現(xiàn)分布式鎖

(1)概述:Redisson是一個在Redis的基礎(chǔ)上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory?Data?Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務。其中包括(BitSet,?Set,?Multimap,?SortedSet,?Map,?List,?Queue,?BlockingQueue,?Deque,?BlockingDeque,?Semaphore,?Lock,?AtomicLong,?CountDownLatch,?Publish?/?Subscribe,?Bloom?filter,?Remote?service,?Spring?cache,?Executor?service,?Live?Object?service,?Scheduler?service)?Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進使用者對Redis的關(guān)注分離(Separation?of?Concern),從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務邏輯上。

高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn),分布式緩存,緩存,分布式

(2)基本使用

導入依賴

1.導入依賴?service-util
<!--?redisson?--><dependency>???<groupId>org.redisson</groupId>???<artifactId>redisson</artifactId>???<version>3.15.3</version></dependency>

配置redission,加載redis連接數(shù)據(jù)

@Data@Configuration@ConfigurationProperties("spring.redis")public?class?RedissonConfig?{
????private?String?host;
????private?String?password;
????private?String?port;
????private?int?timeout?=?3000;????private?static?String?ADDRESS_PREFIX?=?"redis://";
????/**?????*?自動裝配?????*/????@Bean????RedissonClient?redissonSingle()?{????????Config?config?=?new?Config();
????????if(StringUtils.isEmpty(host)){????????????throw?new?RuntimeException("host?is??empty");????????}????????SingleServerConfig?serverConfig?=?config.useSingleServer()????????????????.setAddress(ADDRESS_PREFIX?+?this.host?+?":"?+?port)????????????????.setTimeout(this.timeout);????????if(!StringUtils.isEmpty(this.password))?{????????????serverConfig.setPassword(this.password);????????}????????return?Redisson.create(config);????}}

(3)實現(xiàn)

@Override????public???void?testRedisRefresh()?{????????//上鎖????????String?skuId="31";????????String?lockKey="lock:"+skuId;????????//獲取鎖????????RLock?lock?=?redissonClient.getLock(lockKey);????????lock.lock();????????//處理業(yè)務????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????String?value?=?redisTemplate.opsForValue().get("num");????????//校驗????????if(StringUtils.isEmpty(value)){????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????return;????????}????????//存在將num轉(zhuǎn)換為int????????int?num?=?Integer.parseInt(value);????????//????????????//存入緩存????????redisTemplate.opsForValue().set("num",String.valueOf(++num));????????//解鎖????????lock.unlock();????}

五,總結(jié)

經(jīng)過分析發(fā)現(xiàn)分布式鎖的實現(xiàn)在一定程度上還是會存在一系列的問題,通過這些問題的解決可以在很大程度的避免數(shù)據(jù)不一致的情況,關(guān)于分布式鎖的實現(xiàn)可以抽取為模板,有業(yè)務場景需要的時候二次修改復用即可.

5.1redis實現(xiàn)分布式鎖四部曲

①上鎖

②判斷true處理業(yè)務

③解鎖(lua腳本)

④自旋

@Override????public???void?testRedisRefresh()?{????????//①上鎖????????//設(shè)置唯一表示,防止誤刪除????????String?uuid?=?UUID.randomUUID().toString().replace("-",?"");????????//鎖定key????????Boolean?absent?=?redisTemplate.opsForValue().setIfAbsent("lock",?uuid,3L,TimeUnit.SECONDS);????????//②業(yè)務
????????if?(absent){????????????//處理業(yè)務????????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????????String?value?=?redisTemplate.opsForValue().get("num");????????????//校驗????????????if(StringUtils.isEmpty(value)){????????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????????return;????????????}????????????//存在將num轉(zhuǎn)換為int????????????int?num?=?Integer.parseInt(value);????????????//存入緩存????????????redisTemplate.opsForValue().set("num",String.valueOf(++num));

????????//③解鎖????????????????//lua腳本????????????String?script="if?redis.call(\"get\",KEYS[1])?==?ARGV[1]\n"?+????????????????????"then\n"?+????????????????????"????return?redis.call(\"del\",KEYS[1])\n"?+????????????????????"else\n"?+????????????????????"????return?0\n"?+????????????????????"end";????????????????//創(chuàng)建對象????????????DefaultRedisScript<Long>?redisScript?=?new?DefaultRedisScript<>();????????????redisScript.setScriptText(script);????????????redisScript.setResultType(Long.class);????????????//執(zhí)行刪除????????????redisTemplate.execute(redisScript,Arrays.asList("lock",uuid));????????????//④自旋????????}else{????????????//未拿到鎖等待????????????try?{????????????????Thread.sleep(100);????????????????//自旋????????????????this.testRedisRefresh();????????????}?catch?(InterruptedException?e)?{????????????????e.printStackTrace();????????????}????????}

5.redission實現(xiàn)分布式鎖三部曲

①上鎖

②業(yè)務邏輯

③解鎖文章來源地址http://www.zghlxwxcb.cn/news/detail-806108.html

?@Override????public???void?testRedisRefresh()?{????????//上鎖????????String?skuId="31";????????String?lockKey="lock:"+skuId;????????//獲取鎖????????RLock?lock?=?redissonClient.getLock(lockKey);????????lock.lock();????????//處理業(yè)務????????//查詢緩存是否存在(預先客戶端設(shè)置num的值為0)????????String?value?=?redisTemplate.opsForValue().get("num");????????//校驗????????if(StringUtils.isEmpty(value)){????????????//不存在(查詢數(shù)據(jù)庫,并且將數(shù)據(jù)存入redis)????????????return;????????}????????//存在將num轉(zhuǎn)換為int????????int?num?=?Integer.parseInt(value);????????//????????????//存入緩存????????redisTemplate.opsForValue().set("num",String.valueOf(++num));????????//解鎖????????lock.unlock();????}

到了這里,關(guān)于高并發(fā)緩存問題分析以及分布式鎖的實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 【go項目-geecache】動手寫分布式緩存 day2 - 單機并發(fā)緩存

    [ Github- geecache ](luckly-0/geecache (github.com)) 收獲總結(jié): 了解接口的使用場景,它和函數(shù)之間的差別和優(yōu)略勢 測試文件要以_test結(jié)尾 系統(tǒng)設(shè)計要嚴謹,要考慮后期的拓展性和維護 ,比如load函數(shù)考慮到了分布式場景 數(shù)據(jù)結(jié)構(gòu)之間的封裝 sync.Mutex 互斥鎖 如果我們要是實現(xiàn)并發(fā)緩存

    2023年04月18日
    瀏覽(21)
  • Redis實戰(zhàn)案例14-分布式鎖的基本原理、不同實現(xiàn)方法對比以及基于Redis進行實現(xiàn)思路

    Redis實戰(zhàn)案例14-分布式鎖的基本原理、不同實現(xiàn)方法對比以及基于Redis進行實現(xiàn)思路

    基于數(shù)據(jù)庫的分布式鎖:這種方式使用數(shù)據(jù)庫的特性來實現(xiàn)分布式鎖。具體流程如下: 獲取鎖:當一個節(jié)點需要獲得鎖時,它嘗試在數(shù)據(jù)庫中插入一個特定的唯一鍵值(如唯一約束的主鍵),如果插入成功,則表示獲得了鎖。 釋放鎖:當節(jié)點完成任務后,通過刪除該唯一鍵

    2024年02月13日
    瀏覽(49)
  • 微服務 - Redis緩存 · 數(shù)據(jù)結(jié)構(gòu) · 持久化 · 分布式 · 高并發(fā)

    微服務 - Redis緩存 · 數(shù)據(jù)結(jié)構(gòu) · 持久化 · 分布式 · 高并發(fā)

    系列目錄 微服務 - 概念 · 應用 · 架構(gòu) · 通訊 · 授權(quán) · 跨域 · 限流 微服務 - Consul集群化 · 服務注冊 · 健康檢測 · 服務發(fā)現(xiàn) · 負載均衡 微服務 - Redis緩存 · 數(shù)據(jù)結(jié)構(gòu) · 持久化 · 分布式 · 高并發(fā) 微服務 - Nginx網(wǎng)關(guān) · 進程機制 · 限流熔斷 · 性能優(yōu)化 · 動態(tài)負載 · 高可用

    2023年04月18日
    瀏覽(23)
  • SpringBoot整合Redis、以及緩存穿透、緩存雪崩、緩存擊穿的理解分布式情況下如何添加分布式鎖 【續(xù)篇】

    SpringBoot整合Redis、以及緩存穿透、緩存雪崩、緩存擊穿的理解分布式情況下如何添加分布式鎖 【續(xù)篇】

    上一篇實現(xiàn)了單體應用下如何上鎖,這一篇主要說明如何在分布式場景下上鎖 上一篇地址:加鎖 需要注意的點是: 在上鎖和釋放鎖的過程中要保證 原子性操作 核心是上鎖和解鎖的過程 關(guān)于解鎖使用腳本參考:SET key value [EX seconds] [PX milliseconds] [NX|XX] 3.1 一個服務按照多個端口同時

    2023年04月10日
    瀏覽(29)
  • 一文拿捏分布式、分布式緩存及其問題解決

    一文拿捏分布式、分布式緩存及其問題解決

    1.集中式 傳統(tǒng)的計算模型通常是集中式的,所有的計算任務和數(shù)據(jù)處理都由 單一的計算機或服務器 完成。然而,隨著數(shù)據(jù)量和計算需求的增加,集中式系統(tǒng)可能會面臨性能瓶頸和可靠性問題。 故而引出了分布式↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    2024年02月07日
    瀏覽(20)
  • 論文-分布式-并發(fā)控制-并發(fā)控制問題的解決方案

    論文-分布式-并發(fā)控制-并發(fā)控制問題的解決方案

    目錄 參考文獻 問題 解法與證明 易讀版本 參考文獻 Dijkstra于1965年發(fā)表文章Solution of a Problem in Concurrent Programming Control,引出并發(fā)系統(tǒng)下的互斥(mutual exclusion)問題,自此開辟了分布式計算領(lǐng)域 Dijkstra在文中給出了基于共享存儲原子性訪問的解決方案只有十多行代碼,但閱讀起來

    2024年02月08日
    瀏覽(34)
  • 分布式緩存:什么是它以及為什么需要它?

    ??隨著網(wǎng)絡的快速發(fā)展,分布式應用變得越來越普遍。這種類型的應用程序需要訪問多個組件和服務,而這些組件可能分散在不同的物理位置上。在這種情況下,由于網(wǎng)絡通信的高延遲和低帶寬,性能問題變得尤為明顯。為解決這一問題,分布式緩存應運而生。 ??簡單的

    2024年02月05日
    瀏覽(31)
  • Redis集群(分布式緩存):詳解持久化、主從同步原理、哨兵機制、Cluster分片集群,實現(xiàn)高并發(fā)高可用

    Redis集群(分布式緩存):詳解持久化、主從同步原理、哨兵機制、Cluster分片集群,實現(xiàn)高并發(fā)高可用

    ? ? ? ? 單機式Redis存在以下問題,因此需要Redis集群化來解決這些問題 ???????Redis數(shù)據(jù)快照,簡單來說就是 把內(nèi)存中的所有數(shù)據(jù)都記錄到磁盤中 。當Redis實例故障重啟后,從 磁盤讀取快照文件,恢復數(shù)據(jù) ??煺瘴募Q為RDB文件,默認是保存在當前運行目錄。 ?? ?(1)

    2024年02月08日
    瀏覽(26)
  • 分布式鎖原理與實戰(zhàn)三:ZooKeeper分布式鎖的原理

    分布式鎖原理與實戰(zhàn)三:ZooKeeper分布式鎖的原理

    ???????? 目錄 ZooKeeper分布式鎖的原理 ZooKeeper的每一個節(jié)點,都是一個天然的順序發(fā)號器。 ZooKeeper節(jié)點的遞增有序性,可以確保鎖的公平 ZooKeeper的節(jié)點監(jiān)聽機制,可以保障占有鎖的傳遞有序而且高效 ZooKeeper的節(jié)點監(jiān)聽機制,能避免羊群效應 分布式鎖的搶占過程 客戶端

    2024年02月08日
    瀏覽(17)
  • 基于Mongodb分布式鎖簡單實現(xiàn),解決定時任務并發(fā)執(zhí)行問題

    我們?nèi)粘i_發(fā)過程,會有一些定時任務的代碼來統(tǒng)計一些系統(tǒng)運行數(shù)據(jù),但是我們應用有需要部署多個實例,傳統(tǒng)的通過配置文件來控制定時任務是否啟動又太過繁瑣,而且還經(jīng)常出錯,導致一些異常數(shù)據(jù)的產(chǎn)生 網(wǎng)上有很多分布式鎖的實現(xiàn)方案,基于redis、zk、等有很多,但

    2023年04月18日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包