基于上一篇博客,用阻塞隊列實現異步下單

在上一篇博客中,我們介紹了如何利用 Redis 和 Lua 腳本來高效處理秒殺活動中的高并發請求,保證用戶體驗。本文將進一步優化秒殺系統,通過引入阻塞隊列實現異步下單,從而提高系統的整體性能和穩定性。

引言

秒殺活動往往伴隨著極高的并發請求,對系統的性能和穩定性提出了巨大挑戰。同步處理訂單請求可能導致數據庫壓力過大,影響系統響應時間。為了緩解這一問題,我們可以采用異步下單的方式,將訂單請求先放入阻塞隊列,由后臺線程逐一處理,從而降低數據庫的瞬時壓力。

方案設計

基本思路

  1. 用戶發起秒殺請求,先通過 Redis Lua 腳本進行資格判斷。
  2. 通過 Lua 腳本判斷用戶是否有購買資格,并扣減庫存。
  3. 將訂單信息放入阻塞隊列中,由后臺線程異步處理訂單創建和數據庫操作。
  4. 返回訂單 ID 給用戶。

具體實現

Lua 腳本

Lua 腳本的邏輯保持不變,繼續用于判斷秒殺資格和扣減庫存。

Java 代碼

在 Java 代碼中,我們通過阻塞隊列實現異步下單,并利用 Redisson 分布式鎖來確保訂單操作的線程安全。

@Service
@Slf4j
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService seckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate RedissonClient redissonClient;private static final DefaultRedisScript<Long> SECKILL_SCRIPT;static {SECKILL_SCRIPT = new DefaultRedisScript<>();SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));SECKILL_SCRIPT.setResultType(Long.class);}private BlockingQueue<VoucherOrder> orderTasks = new ArrayBlockingQueue<>(1024 * 1024);private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();@PostConstructprivate void init() {SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());}private class VoucherOrderHandler implements Runnable {@Overridepublic void run() {while (true) {try {VoucherOrder voucherOrder = orderTasks.take();handleVoucherOrder(voucherOrder);} catch (Exception e) {log.error("創建訂單失敗", e);}}}}private void handleVoucherOrder(VoucherOrder voucherOrder) {Long userId = voucherOrder.getUserId();RLock lock = redissonClient.getLock("lock:order:" + userId);boolean isLock = lock.tryLock();if (!isLock) {log.error("不允許重復下單");return;}try {proxy.crateVoucherOrder(voucherOrder);} finally {lock.unlock();}}private IVoucherOrderService proxy;@Overridepublic Result seckillVoucher(Long voucherId) {Long userId = UserHolder.getUser().getId();Long result = stringRedisTemplate.execute(SECKILL_SCRIPT,Collections.emptyList(),voucherId.toString(), userId.toString());int r = result.intValue();if (r != 0) {return Result.fail(r == 1 ? "庫存不足" : "不能重復下單");}VoucherOrder voucherOrder = new VoucherOrder();long orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);voucherOrder.setUserId(userId);voucherOrder.setVoucherId(voucherId);orderTasks.add(voucherOrder);proxy = (IVoucherOrderService) AopContext.currentProxy();return Result.ok(orderId);}@Override@Transactionalpublic void crateVoucherOrder(VoucherOrder voucherOrder) {Long userId = voucherOrder.getUserId();int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();if (count > 0) {log.error("不允許重復下單!");return;}boolean success = seckillVoucherService.update().setSql("stock = stock - 1").eq("voucher_id",voucherOrder.getVoucherId()).gt("stock", 0).update();if (!success) {log.error("庫存不足!");return;}save(voucherOrder);}
}

代碼詳解

  1. 初始化阻塞隊列和線程池

    • 使用 BlockingQueueExecutorService 實現一個單線程的訂單處理機制,在服務初始化時啟動訂單處理線程。
  2. 秒殺請求處理

    • 用戶發起秒殺請求時,首先通過 Lua 腳本判斷秒殺資格和扣減庫存。
    • 如果有購買資格,將訂單信息放入阻塞隊列中。
  3. 訂單處理線程

    • 訂單處理線程從阻塞隊列中取出訂單,并在獲取到用戶鎖后創建訂單,防止同一用戶重復下單。
  4. 事務處理

    • 在訂單處理方法中使用事務管理,確保訂單創建和庫存扣減的原子性。

結論

通過引入阻塞隊列實現異步下單,我們有效地減少了數據庫的瞬時壓力,提高了系統的整體性能和穩定性。這種方法不僅適用于秒殺活動,還可以推廣到其他高并發場景,如搶購、促銷活動等。希望本文對您理解和實現高并發系統有所幫助。

可能出現的問題

我在一次批量用一千個線程去搶優惠卷的時候發現,優惠卷沒有搶完,初步判斷是阻塞隊列的大小過小,內存的限制問題。

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

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

相關文章

ArmSoM-Sige7/5/1 和樹莓派5規格比較

引言 在當今快速發展的嵌入式系統領域&#xff0c;選擇一款性能強大、功能豐富的開發板對于項目的成功至關重要。本文將介紹并比較 Sige7、Sige5、Raspberry Pi 5 和 Sige1 這四款開發板的關鍵規格和特性&#xff0c;幫助開發者和愛好者選擇最適合其需求的平臺。 ArmSoM-Sige…

使用模板方法設計模式封裝 socket 套接字并實現Tcp服務器和客戶端 簡單工廠模式設計

文章目錄 使用模板方法設計模式封裝套接字使用封裝后的套接字實現Tcp服務器和客戶端實現Tcp服務器實現Tcp客戶端 工廠模式 使用模板方法設計模式封裝套接字 可以使用模塊方法設計模式來設計套接字 socket 的封裝 模板方法&#xff08;Template Method&#xff09;設計模式是一…

【深度學習】深度學習基礎

李宏毅深度學習筆記 局部極小值與鞍點 鞍點其實就是梯度是零且區別于局部極小值和局部極大值的點。 鞍點的叫法是因為其形狀像馬鞍。鞍點的梯度為零&#xff0c;但它不是局部極小值。我們把梯度為零的點統稱為臨界點&#xff08;critical point&#xff09;。損失沒有辦法再下…

使用Flink CDC實現 Oracle數據庫數據同步(非SQL)

文章目錄 前言一、開啟歸檔日志二、創建flinkcdc專屬用戶2.1 對于Oracle 非CDB數據庫&#xff0c;執行如下sql2.2 對于Oracle CDB數據庫&#xff0c;執行如下sql 三、指定oracle表、庫級啟用四、使用flink-connector-oracle-cdc實現數據庫同步4.1 引入pom依賴4.1 Java主代碼4.1…

Docker Desktop 簡易操作指南 (Windows, macOS, Linux)

1. 下載最新版本 Docker Desktop https://www.docker.com/products/docker-desktop/ 2.啟動 Docker Desktop 3.常用命令&#xff08;在 cmd 或 Terminal 中執行&#xff09; #列出所有鏡像&#xff08;Images&#xff09; docker images #列出所有容器&#xff08;Containers&…

OpenSSL/3.3.0: error:0A00018A:SSL routines::dh key too small

php curl解決辦法: curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, ‘DEFAULTSECLEVEL1’); python 解決辦法: from twisted.internet.ssl import AcceptableCiphers from scrapy.core.downloader import contextfactory contextfactory.DEFAULT_CIPHERS AcceptableCiphers.from…

CSS 核心知識點 - grid

思維導圖 參考網址: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_grid_layout 一、什么是 grid&#xff1f; CSS Grid布局是在CSS3規范中引入的一種新的布局方式&#xff0c;旨在解決傳統布局方法&#xff08;如浮動、定位、表格布局&#xff09;存在的許多問題。C…

Spring Boot 集成 MyBatis-Plus 總結

Spring Boot 集成 MyBatis-Plus 總結 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在Java開發中&#xff0c;Spring Boot以其簡潔和高效的特點&#xff0c;…

Oh My Zsh Git 插件

以下是一些常見的別名和它們對應的 Git 命令&#xff1a; g: gitga: git addgaa: git add --allgapa: git add --patchgau: git add --updategb: git branchgba: git branch -agbd: git branch -dgbda: git branch --no-color --merged | command grep -vE “^(||*|\s*(main|m…

第十九站:Java鈦藍——區塊鏈技術的新探索

在區塊鏈技術的新探索中&#xff0c;Java作為一門成熟的編程語言&#xff0c;正在通過Hyperledger Fabric和Web3j等技術實現其在區塊鏈領域的應用。以下是對這些技術的簡要介紹和如何使用Java源代碼與它們進行交互的講解。 Hyperledger Fabric Hyperledger Fabric是一個由Lin…

React.js 全面解析:從基礎到實戰案例

引言&#xff1a; React.js&#xff0c;由Facebook推出并維護的開源JavaScript庫&#xff0c;以其組件化思想、虛擬DOM技術和聲明式編程風格&#xff0c;成為構建用戶界面的首選工具之一。本文將系統性地介紹React的基礎概念、核心特性&#xff0c;并通過實際案例展示基礎屬性…

DataWhale-吃瓜教程學習筆記(四)

學習視頻&#xff1a;第3章-二分類線性判別分析_嗶哩嗶哩_bilibili 西瓜書對應章節&#xff1a; 3.4 文章目錄 - 算法原理- 損失函數推導-- 異類樣本中心盡可能遠-- 同類樣本方差盡可能小-- 綜合 知識點補充 - 二范數二范數&#xff08;2-norm&#xff09;詳解定義幾何意義性質…

vue3中省市區聯動在同一個el-form-item中咋么設置rules驗證都不為空的效果

在開發中出現如下情況&#xff0c;在同一個el-form-item設置了省市區三級聯動的效果 <el-form-item label"地區" prop"extraProperties.Province"><el-row :gutter"20"><el-col :span"12"><el-select v-model&qu…

OpenHarmony開發實戰:HDF驅動開發流程

概述 HDF&#xff08;Hardware Driver Foundation&#xff09;驅動框架&#xff0c;為驅動開發者提供驅動框架能力&#xff0c;包括驅動加載、驅動服務管理、驅動消息機制和配置管理。并以組件化驅動模型作為核心設計思路&#xff0c;讓驅動開發和部署更加規范&#xff0c;旨在…

Unity3D Excel表格數據處理模塊詳解

一、引言 在Unity3D開發中&#xff0c;我們經常需要處理大量的數據&#xff0c;這些數據可能是游戲配置、角色屬性、道具信息等。Excel表格作為一種常見的數據存儲方式&#xff0c;具有結構清晰、易于編輯的特點&#xff0c;因此被廣泛應用于游戲開發中。本文將詳細介紹如何在…

四川赤橙宏海商務信息咨詢有限公司抖音開店靠譜嗎?

在數字化浪潮席卷全球的今天&#xff0c;電商行業正以前所未有的速度發展。而在這個大潮中&#xff0c;四川赤橙宏海商務信息咨詢有限公司憑借其專業的團隊和前瞻性的戰略眼光&#xff0c;專注于抖音電商服務&#xff0c;為廣大商家提供了一站式解決方案&#xff0c;成為了行業…

面經-常用框架

1.Spring 1.1什么是Spring框架&#xff1f; Spring 是?種輕量級開發框架&#xff0c;旨在提?開發?員的開發效率以及系統的可維護性。 Spring 的 6 個特征:核?技術&#xff0c;測試&#xff0c;數據訪問&#xff0c;Web?持&#xff0c;集成&#xff0c;語? 1.2列舉?些重…

Ubuntu20.04安裝LibTorch并完成高斯濺射環境搭建

0. 簡介 最近受到優刻得的使用邀請&#xff0c;正好解決了我在大模型和自動駕駛行業對GPU的使用需求。UCloud云計算旗下的Compshare的GPU算力云平臺。他們提供高性價比的4090 GPU&#xff0c;按時收費每卡2.6元&#xff0c;月卡只需要1.7元每小時&#xff0c;并附帶200G的免費…

接口自動化測試-項目實戰

什么是接口自動化測試&#xff1a;使用工具或代碼代替人對接口進行測試 測試項目結構&#xff08;python包&#xff09; 1、接口api包 2、script:業務腳本 3、data:數據 4、config.py :配置文件 5、reporter:報告 錯誤問題&#xff1a; 1、未打印任何東西。添加pip ins…

走馬燈封裝

走馬燈功能需求&#xff1a; 支持定時切換&#xff1b;支持左右按鈕切換&#xff08;根據鼠標是否在切換組件內展示和隱藏左右切換按鈕&#xff09;&#xff1b;支持底部標識切換&#xff1b; 走馬燈 完整代碼如下&#xff1a; /*** class 走馬燈*/import react, { Compone…