Redis實現-優惠卷秒殺(基礎版本)

在這里插入圖片描述

(一)全局唯一ID

一、全局ID生成器

在這里插入圖片描述
可以看到在優惠卷訂單表中的主鍵id并沒有設置Auto increment自增長
在這里插入圖片描述
假如未來訂單量達到數億單,單表無法保存如此多數據,就需要對其進行分表存儲(分布式)。假如每張表都采用自增長,各自從1開始自增,那么這個id就一定會出現重復,而從業務角度考慮,訂單id都應當是獨立且唯一的,那么也就會出現危險。也就需要去用到全局ID生成器。
在這里插入圖片描述

  1. 唯一性
    Redis當中的String數據結構有一種自增且唯一特性的命令increm。因為Redis是獨立于MySQL數據庫之外的,無論有幾個不同數據庫幾張不同的表,Redis都只有一個,這時當所有人來訪問Redis時,它的自增ID一定是唯一的。
  2. 高可用
    將來講解Redis的集群方案、主從方案、哨兵方案都可以確保Redis的高可用性。
  3. 高性能
    Redis的數據就是存儲在內存當中,是以高性能著稱的。
  4. 遞增性
    Redis的自增方案就能保證數據的遞增性、連續性。
  5. 安全性
    假如Redis直接采用這種低端自增方案,那么就會與MySQL數據庫一樣不存在安全性(因為太容易被猜測出規律),所以在使用increm全局自增ID時不能直接把這個數值用來當作ID,而是拼接其他信息來減弱規律性。
    在這里插入圖片描述
    為了提高數據庫性能,id會采用數值類型(也就是java中的Long型)。時間戳用于增加ID復雜性,長度為31位是因為將來要以秒為單位,定義一個初始時間至當下時間的時間差,31位能夠存儲21億個單位,也就是接近69年,已經足夠我們使用了。假如在一秒內生成多個訂單需要生成多個ID,那么就會去自增后面的32位序列號,也就是Redis自增的值。
  • Redis并不是全局唯一ID的唯一實現方案,還會有很多其他的方案。

二、Redis實現全局唯一ID

在這里插入圖片描述
在這里插入圖片描述

  1. 為什么需要引入一個keyPrefix參數:
    該ID的生成策略是基于Redis自增長的,而我們也需要有一個key來對應該值,不同業務會有不同的key也就不能都去使用同一個自增長ID,也就是需要有一個前綴來區分不同業務。
  2. id生成策略也就是我們的核心業務-生成時間戳與序列號
    在這里插入圖片描述
  3. 為什么需要在key中拼接動態日期字符串:
    若將key值寫死,那么就代表整個業務永遠采用同一個key來做自增長,也就是說無論該業務是經歷了多少年,使用的永遠是同一個key值,隨著業務逐漸發展,值會越來越大。而我們知道,Redis中該自增值的上限是2的64次方,雖然該值看似足夠大永遠不會觸及,但是它也是永遠存在這個上限的,而且在key的生成策略當中用于記錄序列號的值只有32個bit,這個值是很有可能被超過的。所以說我們不能永遠使用同一個key,可以考慮在key值中拼接上當天的日期值,這樣可以實現每天刷新value值上限,同時也更方便統計每天的記錄數量。
  4. 為什么要將timestamp左移并且與count值進行或運算
    因為我們要想生成的全局id的最后32位都應當為從Redis當中得到的自增值,而當前僅有的是時間戳值,所以我們需要將時間戳值左移32位來空出擺放自增值的空間。并且因為或運算的效果是只要當前位置上的數字不為0即可直接賦值,所以這里與count值進行或運算就是相當于將count值直接賦值到序列號位的數字上,就能實現一個拼接的效果。

三、單元測試

測試在并發情況下生成id的性能以及值的情況,并且記錄運行時間,因為使用的線程池是異步的,需要用CountDownLatch來記錄每一條線程的執行時間并打印總耗費時間。
在這里插入圖片描述
在這里插入圖片描述
最終得到生成的全局ID以及總耗費時間,并且可以在Redis中查看到生成的id個數達30000個:
在這里插入圖片描述
在這里插入圖片描述

四、總結

在這里插入圖片描述

(二)實現優惠卷秒殺下單

一、添加優惠卷

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

二、實現秒殺下單

在這里插入圖片描述
在這里插入圖片描述
優惠卷訂單表:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

(三)超賣問題

一、庫存超賣問題分析

假設數據庫中某優惠券的庫存為100張,當我們使用jmeter調用200個線程來進行并發購買優惠券時會發現執行異常率為45%,也就是說有超過100條線程執行成功了,數據庫中優惠券庫存也變為負數,說明此時出現了超賣問題。
在這里插入圖片描述

(1)執行流程分析
  1. 正常邏輯
    在這里插入圖片描述
  2. 交叉執行
    在這里插入圖片描述
(2)解決方案

悲觀鎖與樂觀鎖并不是一種真正的鎖,而是一種鎖的設計理念
在這里插入圖片描述

  1. 悲觀鎖
    悲觀鎖認為一定會出現線程安全問題,因此會在操作數據之前先去獲取鎖,來確保所有線程串行執行,減少并發情況。但是這也代表它的性能并不是很好,因為所有線程都是一個一個去執行的,不適合高并發場景。
  2. 樂觀鎖
    樂觀鎖認為不一定會出現線程安全問題(認為出現問題的概率比較低),因此不會直接加鎖,而是會在線程對數據做修改時去判斷在這之前是否有別的線程已經對數據進行修改。也就是當我們查詢到數據庫中數據且將要對其做修改之前,會去檢查當前被修改的數據是否與一開始查詢到的數據相同,若不同則說明有別人已經對該數據進行修改了,會有線程安全問題,此時可以去重試或拋異常。它的性能會比悲觀鎖強很多,核心就是要去判斷數據是否被修改。
(3)樂觀鎖
  1. 版本號法
    版本號法也就是給數據加上一個版本,在多線程并發時基于版本號來判斷是否被修改過,每當數據做一次修改,版本號就會加一。要想判斷一個數據是否被修改過,就是要判斷它的版本號是否有變化。
    在這里插入圖片描述
  2. CAS法
    直接將目標修改的數據值作為比較值,替代版本號的作用
    在這里插入圖片描述

二、樂觀鎖解決超賣問題

  1. 樂觀鎖實現邏輯與業務邏輯的沖突問題
    在樂觀鎖中要求對數據修改前原數據不能發生變化,而在當前業務中僅要求庫存大于0即可,樂觀鎖與業務的邏輯差異會導致線程異常率增大,也就是實際扣減成功率太低了,所以要對其進行優化。
    在這里插入圖片描述
    在這里插入圖片描述
  2. 最終代碼修改情況
    在這里插入圖片描述
    再次執行測試,發現線程異常率達50%,也就是正好賣空全部庫存
    在這里插入圖片描述
    在這里插入圖片描述
  3. 總結
    在這里插入圖片描述

(四)一人一單

一、一人一單功能實現

在這里插入圖片描述
在這里插入圖片描述
但是此時的業務邏輯并不完美,因為此時一人一單的邏輯與之前下單的邏輯相同,都是先查詢再判斷,這使得同樣會出現多個線程穿插執行的情況,導致出現超賣,也就是并發安全問題。
之前提到的樂觀鎖是在更新數據時去使用的,這里是需要去插入數據,所以不能直接去判斷數據是否有被修改過,而是要去判斷數據是否存在,也就只能去使用悲觀鎖。

(1)具體改造流程
  1. 封裝方法
    在這里插入圖片描述
    在這里插入圖片描述
  2. 根據用戶id進行加鎖并且通過獲取代理對象來開啟createVoucherOrder方法的事務
    在這里插入圖片描述
    引入依賴并添加注解去暴露代理對象
    在這里插入圖片描述
    在這里插入圖片描述
  3. 測試
    在這里插入圖片描述
    在這里插入圖片描述

二、集群下的線程并發安全問題

在這里插入圖片描述

  1. 正常執行情況
    在這里插入圖片描述
  2. 交叉執行情況(出現并發問題)
    在這里插入圖片描述
    會導致插入了兩次訂單
  3. 加入互斥鎖的執行情況
    在這里插入圖片描述
    產生線程安全問題的原因:
    在集群部署模式或分布式系統下,每一臺服務都會有一個獨立的JVM,而每個JVM當中都會存在獨立的鎖監視器去維護互斥鎖,導致了每臺服務中都有一個線程是能獲取到互斥鎖的,也就會發生并行運行,就可能出現線程安全問題。

解決辦法:讓多個JVM只能使用同一把鎖,也就是實現跨進程的分布式鎖

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80940.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80940.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80940.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++STL——哈希表封裝:實現高效unordered_map與unordered_set

文章目錄 用哈希表封裝unordered_map和unordered_set改進底層框架迭代器實現實現思路迭代器框架迭代器重載operator哈希表中獲取迭代器位置 哈希表的默認成員函數修改后的哈希表的代碼封裝至上層容器 用哈希表封裝unordered_map和unordered_set 在前面我們已經學過如何實現哈希…

虹科應用 | 探索PCAN卡與醫療機器人的革命性結合

隨著醫療技術的不斷進步,醫療機器人在提高手術精度、減少感染風險以及提升患者護理質量方面發揮著越來越重要的作用。醫療機器人的精確操作依賴于穩定且高效的數據通信系統,虹科提供的PCAN四通道mini PCIe轉CAN FD卡,正是為了滿足這一需求而設…

Yolov8的詳解與實戰-深度學習目標檢測

Yolov8的詳解與實戰- 文章目錄 摘要 模型詳解 C2F模塊 Loss head部分 模型實戰 訓練COCO數據集 下載數據集 COCO轉yolo格式數據集(適用V4,V5,V6,V7,V8) 配置yolov8環境 訓練 測試 訓練自定義數據集 Labelme…

scons user 3.1.2

前言 感謝您抽出時間閱讀有關 SCons 的內容。SCons 是一款下一代軟件構建工具,或者稱為 make 工具,即一種用于構建軟件(或其他文件)并在底層輸入文件發生更改時使已構建的軟件保持最新狀態的軟件實用程序。 SCons 最顯著的特點是…

Java的多線程筆記

創建一個線程的方法有多種,比如可以繼承Thread類或者實現Runnable接口,結論是實現Runnable接口比前者更加優越。 二者代碼對比 Java 不支持多繼承,如果你繼承了 Thread 類,就不能再繼承其他類,實現 Runnable 接口后&am…

PDF Base64格式字符串轉換為PDF文件臨時文件

需求描述: 在對接電子病歷系統與河北CA,進行免密文件簽章的時候,兩者系統入參不同,前者是pdf文件,base64格式;后者要求File類型的PDF文件。 在業務中間層開發時,則需要接收EMR側提供的base64格式…

代碼隨想錄訓練營第二十三天| 572.另一顆樹的子樹 104.二叉樹的最大深度 559.N叉樹的最大深度 111.二叉樹的最小深度

572.另一顆樹的子樹: 狀態:已做出 思路: 這道題目當時第一時間不是想到利用100.相同的樹思路來解決,而是先想到了使用kmp,不過這個題目官方題解確實是有kmp解法的,我使用的暴力解法,kmp的大致思…

【RabbitMq C++】消息隊列組件

RabbitMq 消息隊列組件 1. RabbitMq介紹2. 安裝RabbitMQ3. 安裝 RabbitMQ 的 C客戶端庫4. AMQP-CPP 庫的簡單使用4.1 使用4.1.1 TCP 模式4.1.2 擴展模式 4.2 常用類與接口介紹4.2.1 Channel4.3.2 ev 5. RabbitMQ樣例編寫5.1 發布消息5.2 訂閱消息 1. RabbitMq介紹 RabbitMq - …

鴻蒙NEXT開發動畫案例8

1.創建空白項目 2.Page文件夾下面新建Spin.ets文件,代碼如下: /*** SpinKit動畫組件 (重構版)* author: CSDN-鴻蒙布道師* since: 2025/05/14*/interface AnimationGroup {indexes: number[];delay: number; }ComponentV2 export struct SpinEight {Re…

MySQL全局優化

目錄 1 硬件層面優化 1.1 CPU優化 1.2 內存優化 1.3 存儲優化 1.4 網絡優化 2 系統配置優化 2.1 操作系統配置 2.2 MySQL服務配置 3 庫表結構優化 4 SQL及索引優化 mysql可以從四個層面考慮優化,分別是 硬件系統配置庫表結構SQL及索引 從成本和優化效果來看&#xf…

vue和springboot交互數據,使用axios【跨域問題】

vue和springboot交互數據,使用axios【跨域問題】 提示:幫幫志會陸續更新非常多的IT技術知識,希望分享的內容對您有用。本章分享的是node.js和vue的使用。前后每一小節的內容是存在的有:學習and理解的關聯性。【幫幫志系列文章】&…

FFMPEG 與 mp4

1. FFmpeg 中的 start_time 與 time_base start_time 流的起始時間戳(單位:time_base),表示第一幀的呈現時間(Presentation Time)。通常用于同步多個流(如音頻和視頻)。 time_base …

AI世界的崩塌:當人類思考枯竭引發數據生態鏈斷裂

AI世界的崩塌:當人類思考枯竭引發數據生態鏈斷裂 ——論過度依賴AI創作對技術進化的反噬 一、數據生態的惡性循環:AI的“自噬危機” 當前AI模型的訓練依賴于人類創造的原始數據——書籍、論文、藝術作品、社交媒體動態等。據統計,2025年全球…

C++【STL】(2)string

C【STL】string用法擴展 1. assign:為字符串賦新值 用于替換字符串內容,支持多種參數形式。 常用形式: // 用另一個字符串賦值 str.assign("Hello World");// 用另一個字符串的子串(從第6個字符開始,取5…

樹莓派4基于Debian GNU/Linux 12 (Bookworm)開啟VNC,使用MobaXterm連接VNC出現黑屏/灰屏問題

1. 開啟樹莓派的VNC服務 啟用VNC服務:通過raspi-config開啟 # 1. 通過 raspi-config 工具開啟 sudo raspi-config選擇 Interface Options → VNC → Yes退出時會自動啟動服務 檢查服務狀態: sudo systemctl status vncserver-x11-serviced正常輸出應顯示…

MongoDB使用x.509證書認證

文章目錄 自定義證書生成CA證書生成服務器之間的證書生成集群證書生成用戶證書 MongoDB配置java使用x.509證書連接MongoDBMongoShell使用證書連接 8.0版本的mongodb開啟復制集,配置證書認證 自定義證書 生成CA證書 生成ca私鑰: openssl genrsa -out ca…

Python爬蟲實戰:研究js混淆加密

一、引言 在當今數字化時代,數據已成為推動各行業發展的核心驅動力。網絡爬蟲作為一種高效的數據采集工具,能夠從互聯網上自動獲取大量有價值的信息。然而,隨著互聯網技術的不斷發展,許多網站為了保護自身數據安全和知識產權,采用了 JavaScript 混淆加密技術來防止數據被…

Java項目層級介紹 java 層級 層次

java 層級 層次 實體層 控制器層 數據連接層 Service : 業務處理類 Repository :數據庫訪問類 Java項目層級介紹 https://blog.csdn.net/m0_67574906/article/details/145811846 在Java項目中,層級結構(Layered Architecture&#xf…

網絡安全頂會——SP 2025 論文清單與摘要

1、"Check-Before-you-Solve": Verifiable Time-lock Puzzles 時間鎖謎題是一種密碼學原語,它向生成者保證該謎題無法在少于T個順序計算步驟內被破解。近年來,該技術已在公平合約簽署和密封投標拍賣等場景中得到廣泛應用。然而,求解…

《100天精通Python——基礎篇 2025 第18天:正則表達式入門實戰,解鎖字符串處理的魔法力量》

目錄 一、認識正則表達式二、正則表達式基本語法2.1 行界定符2.2 單詞定界符2.3 字符類2.4 選擇符2.5 范圍符2.6 排除符2.7 限定符2.8 任意字符2.9 轉義字符2.10 反斜杠2.11 小括號2.11.1 定義獨立單元2.11.2 分組 2.12 反向引用2.13 特殊構造2.14 匹配模式 三、re模塊3.1 comp…