最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Redis解決高并發(fā)方案及思路解讀

 更新時(shí)間:2023年03月31日 09:08:06   作者:WINGZINGLIU  
這篇文章主要介紹了使用Redis解決高并發(fā)方案及思路,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

NoSQL

Not Only SQL的簡(jiǎn)稱。NoSQL是解決傳統(tǒng)的RDBMS在應(yīng)對(duì)某些問(wèn)題時(shí)比較乏力而提出的。

即非關(guān)系型數(shù)據(jù)庫(kù),它們不保證關(guān)系數(shù)據(jù)的ACID特性,數(shù)據(jù)之間一般沒有關(guān)聯(lián),在擴(kuò)展上就非常容易實(shí)現(xiàn),并且擁有較高的性能。

Redis

redis是nosql的典型代表,也是目前互聯(lián)網(wǎng)公司的必用技術(shù)。

redis是鍵值(Key-Value)存儲(chǔ)數(shù)據(jù)庫(kù),主要會(huì)使用到哈希表。大多數(shù)時(shí)候是直接以緩存的形式被使用,使得請(qǐng)求不直接訪問(wèn)到磁盤,所以效率方面是很不錯(cuò)的,完全能滿足中小型企業(yè)的使用需求。

常用數(shù)據(jù)類型

  • 字符串string
  • 散列hash
  • 列表list
  • 集合sets
  • 有序集合sort set

使用頻率上string和hash會(huì)高一些,各個(gè)類型有各自的操作命令,無(wú)非增刪改查,具體的命令后面我會(huì)整理一份。

痛點(diǎn)

web應(yīng)用在眾多請(qǐng)求同時(shí)發(fā)生時(shí),可能會(huì)導(dǎo)致數(shù)據(jù)讀取、存儲(chǔ)上出現(xiàn)錯(cuò)誤,即發(fā)生臟讀、臟數(shù)據(jù)生成。

在分布式項(xiàng)目下,會(huì)出現(xiàn)更多的問(wèn)題。

思路

并發(fā)時(shí),本質(zhì)其實(shí)就是多個(gè)請(qǐng)求同時(shí)進(jìn)來(lái)了,沒辦法正確的去進(jìn)行處理。

可以將所有的請(qǐng)求放在 一個(gè)隊(duì)列,讓請(qǐng)求們按照一個(gè)順序,挨個(gè)進(jìn)來(lái)執(zhí)行業(yè)務(wù)邏輯。目前成熟的解決方案就是使用消息隊(duì)列,下次我會(huì)整理一篇消息隊(duì)列處理高并發(fā)的;

還有一個(gè)方法是直接將并行轉(zhuǎn)為串行,Java提供了synchronized,即同步,不過(guò)這個(gè)在效率要求比較苛刻的地方 或者 分布式項(xiàng)目下還是不太合適的方案,這里就引出了使用redis來(lái)實(shí)現(xiàn)分布式鎖,從而解決并發(fā)問(wèn)題。

分布式鎖

在分布式項(xiàng)目中,使用一個(gè)唯一、通用、效率高的標(biāo)識(shí),來(lái)表示上鎖和解鎖。

redis實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,即對(duì)一個(gè)key是否存在來(lái)表示是否上鎖、是否解鎖。

以string類型舉例:

Integer stock = goodsMapper.getStock();
if (stock > 0) {
? ? stock =- 1;
? ? goodsMapper.updateStock(stock);
}

以上是最簡(jiǎn)單的秒殺偽代碼,我們嘗試用redis實(shí)現(xiàn)分布式鎖。

// 這里是錯(cuò)誤代碼,只是一個(gè)思考過(guò)程,請(qǐng)耐心看完哦
String key = "REDIS_DISTRIBUTION_LOCKER"; // 分布式鎖名稱
String value = jedisUtils.get(key);
if (value != null) { // 未上鎖
? ? // wingzingliu
? ? jedisUtils.set(key, 1); // 上鎖
? ? Integer stock = goodsMapper.getStock();
? ? if (stock > 0) {
? ? ? ? stock =- 1;
? ? ? ? goodsMapper.updateStock(stock);
? ? ? ? jedisUtils.del(key); // 釋放鎖
? ? }
}

以上代碼可能會(huì)出現(xiàn)一個(gè)問(wèn)題,就是當(dāng)同時(shí)多個(gè)請(qǐng)求進(jìn)來(lái),某次多個(gè)請(qǐng)求都拿到value為空,線程A進(jìn)入if 走到// wingzingliu這里的時(shí)候,還未上鎖,其他請(qǐng)求也進(jìn)來(lái)了,這樣就會(huì)出現(xiàn)臟數(shù)據(jù)了。

這里的代碼問(wèn)題就是出在沒有考慮原子性問(wèn)題。

所以我們要使用到redis的一個(gè)setNx命令,本質(zhì)也是設(shè)置值,但是這是一個(gè)原子操作,執(zhí)行之后會(huì)返回是否設(shè)置成功。

redis> SETNX job "programmer" ? ?# job 設(shè)置成功
(integer) 1
?
redis> SETNX job "code-farmer" ? # 嘗試覆蓋 job ,失敗
(integer) 0
?
redis> GET job ? ? ? ? ? ? ? ? ? # 沒有被覆蓋
"programmer"

重點(diǎn)關(guān)注 當(dāng)有值時(shí),會(huì)失敗,返回0。所以我們的代碼會(huì)改造成以下這個(gè)樣子。

// 這里是錯(cuò)誤代碼,只是一個(gè)思考過(guò)程,請(qǐng)耐心看完哦
String key = "REDIS_DISTRIBUTION_LOCKER"; // 分布式鎖名稱
Long result = jedisUtils.setNx(key, 1);
if (result > 0) { // 上鎖成功,進(jìn)入邏輯
? ? // wingzingliu1
? ? Integer stock = goodsMapper.getStock();
? ? if (stock > 0) {
? ? ? ? stock =- 1;
? ? ? ? goodsMapper.updateStock(stock);
?
? ? ? ? System.out.println("購(gòu)買成功!");
? ? } else {
? ? ? ? System.out.println("沒有庫(kù)存了!");
? ? }
? ? // wingzingliu2
? ? jedisUtils.del(key); // 釋放鎖
}

以上我們就可以保證原子性,能正確的按照順序去處理。

可是還有一個(gè)隱藏的問(wèn)題,就是當(dāng)某個(gè)線程執(zhí)行上鎖成功后,在wingzingliu1到wingzingliu2之間時(shí),程序拋異常了,那么程序終止了,就無(wú)法釋放鎖,其他線程也都進(jìn)不來(lái)了。

解決方案是加上try catch finally塊,在finally里面去釋放鎖。

可是那如果是宕機(jī)呢?上鎖之后宕機(jī)了,finally里面的依然不會(huì)執(zhí)行,鎖沒有得到釋放,不手動(dòng)處理的情況下,以后所有線程也無(wú)法進(jìn)入。

所以引入了redis的過(guò)期時(shí)間,到了某個(gè)時(shí)間自動(dòng)解鎖。

// 這里是不夠完善的代碼,請(qǐng)耐心看完哦
try {
? ? String key = "REDIS_DISTRIBUTION_LOCKER"; // 分布式鎖名稱
? ? Long result = jedisUtils.setNx(key, 1, 30); // 假設(shè)處理邏輯需要20s左右,設(shè)置了30秒自動(dòng)過(guò)期
? ? if (result > 0) { // 上鎖成功,進(jìn)入邏輯
? ? ? ? Integer stock = goodsMapper.getStock();
? ? ? ? if (stock > 0) {
? ? ? ? ? ? stock =- 1;
? ? ? ? ? ? goodsMapper.updateStock(stock);
?
? ? ? ? ? ? System.out.println("購(gòu)買成功!");
? ? ? ? } else {
? ? ? ? ? ? System.out.println("沒有庫(kù)存了!");
? ? ? ? }
? ? }
} catch (Exception e) {
? ??
} finally {
? ? jedisUtils.del(key); // 釋放鎖
}

以上是比較完善的分布式鎖了,但是還有一個(gè)小瑕疵,就是假設(shè)某一次請(qǐng)求A處理的很慢,預(yù)計(jì)20s但是跑了35s,到了30s的時(shí)候鎖過(guò)期了,其他請(qǐng)求就自然進(jìn)來(lái)了。

這不僅僅會(huì)導(dǎo)致一次并行,當(dāng)請(qǐng)求A處理完時(shí),依然會(huì)執(zhí)行釋放鎖,這實(shí)際上是下一個(gè)線程上的鎖。以此類推,整個(gè)并發(fā)控制就亂了。

理論上可以設(shè)置一個(gè)更大的key過(guò)期時(shí)間,但是并不是最好的解決方案。這里就引出一個(gè)概念:鎖續(xù)命。

鎖續(xù)命

如其名,給鎖續(xù)命。實(shí)現(xiàn)就是 當(dāng)鎖快過(guò)期的時(shí)候,去延長(zhǎng)鎖的時(shí)間。假設(shè)一個(gè)30s的鎖,每個(gè)10s去檢測(cè)一下,鎖是否還在 如果在就重新延長(zhǎng)至30s。這樣就避免掉了上面的這個(gè)可能出現(xiàn)的問(wèn)題。

這里使用一個(gè)定時(shí)任務(wù),周期性的調(diào)用即可。

擴(kuò)展

剛剛對(duì)key設(shè)置的value是1,其實(shí)能使用請(qǐng)求ID來(lái)進(jìn)行保存,這樣就能知道鎖是由哪個(gè)請(qǐng)求上的,在解鎖的時(shí)候 也可以避免解鎖了其他線程上的鎖。具體由前端傳遞,或者由服務(wù)端以某種規(guī)則生成都可以。

結(jié)語(yǔ)

至此我們就使用redis,一步一步的解決了在分布式項(xiàng)目下的并發(fā)問(wèn)題。redis不是唯一的解決方案,但是對(duì)于大部分互聯(lián)網(wǎng)公司來(lái)說(shuō),是一個(gè)很成熟、性能不錯(cuò)、便捷的方案。

還可以使用synchronized(非分布式項(xiàng)目)、mq 、zookeeper等方案去實(shí)現(xiàn)分布式鎖 以 解決高并發(fā)問(wèn)題。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Redis 基礎(chǔ)教程之事務(wù)的使用方法

    Redis 基礎(chǔ)教程之事務(wù)的使用方法

    這篇文章主要介紹了Redis 基礎(chǔ)教程之事務(wù)的使用方法的相關(guān)資料,Redis 事務(wù)可以一次執(zhí)行多個(gè)命令和保證,單獨(dú)的隔離操作和原子操作需要的朋友可以參考下
    2017-08-08
  • Redis緩存降級(jí)的四種策略

    Redis緩存降級(jí)的四種策略

    在高并發(fā)系統(tǒng)架構(gòu)中,Redis作為核心緩存組件扮演著至關(guān)重要的角色,它不僅能夠顯著提升系統(tǒng)響應(yīng)速度,還能有效減輕數(shù)據(jù)庫(kù)壓力,然而,當(dāng)Redis服務(wù)出現(xiàn)故障、性能下降或連接超時(shí)時(shí),如果沒有適當(dāng)?shù)慕导?jí)機(jī)制,可能導(dǎo)致系統(tǒng)雪崩,所以本文給大家介紹了Redis緩存降級(jí)的四種策略
    2025-04-04
  • Redis數(shù)據(jù)結(jié)構(gòu)之跳躍表使用學(xué)習(xí)

    Redis數(shù)據(jù)結(jié)構(gòu)之跳躍表使用學(xué)習(xí)

    這篇文章主要為大家介紹了Redis數(shù)據(jù)結(jié)構(gòu)之跳躍表使用學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Redis分布式緩存的安裝

    Redis分布式緩存的安裝

    這篇文章主要介紹了Redis分布式緩存的安裝,Redis?是一個(gè)開源(BSD許可)的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),它可以用作數(shù)據(jù)庫(kù)、緩存和消息中間件,需要的朋友可以參考下
    2023-05-05
  • 關(guān)于Redis的主從復(fù)制及哨兵問(wèn)題

    關(guān)于Redis的主從復(fù)制及哨兵問(wèn)題

    redis中以master為主機(jī),slave為從機(jī),一個(gè)master可以對(duì)應(yīng)多個(gè)slave,而一個(gè)slave只能對(duì)應(yīng)一個(gè)master,這篇文章主要介紹了Redis的主從復(fù)制及哨兵,需要的朋友可以參考下
    2022-06-06
  • Win10下 Redis啟動(dòng) 錯(cuò)誤1067導(dǎo)致進(jìn)程意外終止的解決方法

    Win10下 Redis啟動(dòng) 錯(cuò)誤1067導(dǎo)致進(jìn)程意外終止的解決方法

    這篇文章主要介紹了Win10下 Redis啟動(dòng) 錯(cuò)誤1067導(dǎo)致進(jìn)程意外終止的完美解決方案,需要的朋友可以參考下
    2018-01-01
  • Redis SETNX命令在Spring Cloud中的分布式鎖用法詳解

    Redis SETNX命令在Spring Cloud中的分布式鎖用法詳解

    在Spring Cloud項(xiàng)目中,使用Java和Redis結(jié)合實(shí)現(xiàn)的分布式鎖可以確保訂單的一致性和并發(fā)控制,通過(guò)合理使用鎖的粒度以及注意事項(xiàng),可以減少死鎖問(wèn)題并提高系統(tǒng)的并發(fā)性能,這篇文章主要介紹了Redis SETNX命令在Spring Cloud中的分布式鎖用法詳解,需要的朋友可以參考下
    2023-10-10
  • Redis 持久化 RDB 與 AOF的執(zhí)行過(guò)程

    Redis 持久化 RDB 與 AOF的執(zhí)行過(guò)程

    本文給大家記錄Redis 持久化RDB 與 AOF的執(zhí)行過(guò)程與配置,通過(guò)內(nèi)部觸發(fā) RDB 場(chǎng)景分析Redis 持久化 RDB的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-11-11
  • redis的hash類型操作方法

    redis的hash類型操作方法

    Hash 是一個(gè) String 類型的 field(字段) 和 value(值) 的映射表,hash 特別適合用于存儲(chǔ)對(duì)象,這篇文章主要介紹了redis的hash類型的詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Redis刪除某個(gè)目錄下的數(shù)據(jù)的實(shí)現(xiàn)

    Redis刪除某個(gè)目錄下的數(shù)據(jù)的實(shí)現(xiàn)

    本文介紹了如何在Redis中刪除指定目錄下的數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-09-09

最新評(píng)論

德清县| 海南省| 奉节县| 太仓市| 陕西省| 玉田县| 黄骅市| 安仁县| 安多县| 镇平县| 松潘县| 白玉县| 丁青县| 砚山县| 宁陕县| 托克逊县| 福州市| 毕节市| 西昌市| 大英县| 峨眉山市| 平南县| 四会市| 海伦市| 万荣县| 陇西县| 彭州市| 泰安市| 托克托县| 阿拉善左旗| 桦川县| 乌恰县| 乐至县| 句容市| 平罗县| 兖州市| 乌兰浩特市| 渭南市| 安乡县| 夏河县| 梁山县|