畫秒殺系統流程圖

秒殺系統流程圖

在這里插入圖片描述

秒殺系統關鍵點

  1. 高并發處理:
  • 使用網關(如 Nginx)進行流量限流,避免過載。
  • 分布式鎖或 Redis 原子操作控制并發。
  1. 活動狀態檢查:
  • Redis 存儲活動狀態(如 seckill:activity:1:status),快速判斷活動是否進行中。
  1. 用戶資格校驗:
  • Redis Set 記錄參與用戶(如 seckill:activity:1:users),檢查是否重復參與。
  • 示例: SADD seckill:activity:1:users user123 和 SISMEMBER。
  1. 庫存扣減(Redis Lua 腳本):
  • 為什么用 Lua 腳本?
    • 保證原子性,避免并發超賣。
    • 減少網絡往返,提高性能。
  • Redis Key: seckill:activity:1:stock(庫存)。
  • Lua 腳本示例:
local stock_key = KEYS[1]
local current_stock = tonumber(redis.call('GET', stock_key) or 0)
if current_stock <= 0 thenreturn -1  -- 庫存不足
end
redis.call('DECR', stock_key)
return current_stock - 1  -- 返回剩余庫存
  • Java 調用 Lua 腳本(Spring Boot + Redis):
@Autowired
private StringRedisTemplate redisTemplate;public boolean deductStock(String activityId) {String stockKey = "seckill:activity:" + activityId + ":stock";String script = "local stock_key = KEYS[1] " +"local current_stock = tonumber(redis.call('GET', stock_key) or 0) " +"if current_stock <= 0 then return -1 end " +"redis.call('DECR', stock_key) " +"return current_stock - 1";Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),Collections.singletonList(stockKey));return result != null && result >= 0;
}
  1. 訂單生成:
  • 異步隊列(如 RabbitMQ、Kafka)處理訂單生成,減輕數據庫壓力。
  • 示例: 將 {userId, activityId, timestamp} 發送到隊列。
  1. 數據庫寫入:
  • 異步任務消費隊列,批量插入訂單到 MySQL。
  • 避免實時寫庫導致瓶頸。
  1. 防超賣:
  • Redis Lua 腳本確保庫存不減為負。
  • 數據庫加樂觀鎖(如 UPDATE stock SET count = count - 1 WHERE id = ? AND count > 0)。
  1. 返回響應:
  • 扣減成功后立即返回“秒殺成功”,后續操作異步完成。

完整流程偽代碼

@RestController
public class SeckillController {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate RabbitTemplate rabbitTemplate;@PostMapping("/seckill/{activityId}")public String seckill(@PathVariable String activityId, @RequestParam String userId) {// 1. 檢查活動狀態String status = redisTemplate.opsForValue().get("seckill:activity:" + activityId + ":status");if (!"ongoing".equals(status)) {return "活動未開始或已結束";}// 2. 檢查用戶資格if (redisTemplate.opsForSet().isMember("seckill:activity:" + activityId + ":users", userId)) {return "已參與秒殺";}// 3. 扣減庫存 (Lua 腳本)if (!deductStock(activityId)) {return "庫存不足";}// 4. 標記用戶參與redisTemplate.opsForSet().add("seckill:activity:" + activityId + ":users", userId);// 5. 異步生成訂單rabbitTemplate.convertAndSend("seckill-queue", new OrderMessage(userId, activityId, System.currentTimeMillis()));return "秒殺成功";}
}

補充:

redis減扣后 減扣 MySQL 庫存方案

1. 異步減扣 MySQL 庫存(推薦)

  • 時機
    • Redis 減庫存成功后,將任務發送到異步隊列(如 RabbitMQ、Kafka),由后臺消費者異步更新 MySQL 庫存。
  • 流程
    1. 用戶發起秒殺請求。
    2. Redis Lua 腳本扣減庫存(原子操作)。
    3. 扣減成功后:
      • 發送消息到隊列(如 {activityId, userId, timestamp})。
      • 返回“秒殺成功”給前端。
    4. 隊列消費者異步處理:
      • 更新 MySQL 庫存表。
      • 生成訂單記錄。
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;@PostMapping("/seckill/{activityId}")
public String seckill(@PathVariable String activityId, @RequestParam String userId) {// Redis 減庫存if (!deductStock(activityId)) {return "庫存不足";}// 異步更新 MySQLrabbitTemplate.convertAndSend("seckill-queue", new OrderMessage(activityId, userId, System.currentTimeMillis()));return "秒殺成功";
}// Lua 腳本扣庫存
private boolean deductStock(String activityId) {String stockKey = "seckill:stock:" + activityId;String script = "local stock = tonumber(redis.call('GET', KEYS[1]) or 0) " +"if stock <= 0 then return 0 end " +"redis.call('DECR', KEYS[1]) " +"return 1";Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),Collections.singletonList(stockKey));return result != null && result == 1;
}// 隊列消費者
@Component
@RabbitListener(queues = "seckill-queue")
public class SeckillConsumer {@Autowiredprivate JdbcTemplate jdbcTemplate;@RabbitHandlerpublic void process(OrderMessage msg) {// 更新 MySQL 庫存String sql = "UPDATE seckill_stock SET stock = stock - 1 WHERE activity_id = ? AND stock > 0";int updated = jdbcTemplate.update(sql, msg.getActivityId());if (updated > 0) {// 插入訂單jdbcTemplate.update("INSERT INTO seckill_order (activity_id, user_id, create_time) VALUES (?, ?, ?)",msg.getActivityId(), msg.getUserId(), msg.getTimestamp());}}
}
優點
  • 高性能: Redis 減庫存后立即返回,MySQL 異步處理,避免實時寫庫瓶頸。
  • 高并發: 適合秒殺場景,減少數據庫壓力。
缺點
  • 數據一致性: Redis 和 MySQL 可能短暫不一致(最終一致性)。
  • 失敗處理: 隊列消費失敗需重試或補償。
  • 適用場景
  • 高并發秒殺,優先保證響應速度。

2. 同步減扣 MySQL 庫存

  • 時機
    • Redis 減庫存成功后,在同一事務中同步更新 MySQL 庫存。
  • 流程
    1. 用戶發起秒殺請求。
    2. Redis Lua 腳本扣減庫存。
    3. 扣減成功后:
    4. 立即更新 MySQL 庫存。
    5. 生成訂單。
    6. 返回“秒殺成功”。
@PostMapping("/seckill/{activityId}")
@Transactional
public String seckill(@PathVariable String activityId, @RequestParam String userId) {// Redis 減庫存if (!deductStock(activityId)) {return "庫存不足";}// 同步更新 MySQLint updated = jdbcTemplate.update("UPDATE seckill_stock SET stock = stock - 1 WHERE activity_id = ? AND stock > 0",activityId);if (updated == 0) {// 回滾 Redis(可選)redisTemplate.opsForValue().increment("seckill:stock:" + activityId);return "庫存不足";}// 插入訂單jdbcTemplate.update("INSERT INTO seckill_order (activity_id, user_id, create_time) VALUES (?, ?, ?)",activityId, userId, System.currentTimeMillis());return "秒殺成功";
}
優點
  • 強一致性: Redis 和 MySQL 庫存保持同步。
  • 簡單: 無需異步隊列。
缺點
  • 性能瓶頸: MySQL 寫操作耗時,影響并發能力。
  • 回滾復雜: 如果 MySQL 更新失敗,需回滾 Redis。
  • 適用場景
  • 低并發場景,或對數據一致性要求極高。

3. 延遲減扣 MySQL 庫存(定時同步)

  • 時機
    • Redis 減庫存后,通過定時任務(如每分鐘)批量同步 MySQL 庫存。
  • 流程
    1. Redis 減庫存。
    2. 記錄每次扣減的日志(如 Redis List seckill:stock:log)。
    3. 定時任務讀取日志,批量更新 MySQL。
  • 實現示例
// 秒殺接口
@PostMapping("/seckill/{activityId}")
public String seckill(@PathVariable String activityId, @RequestParam String userId) {if (!deductStock(activityId)) {return "庫存不足";}// 記錄日志redisTemplate.opsForList().leftPush("seckill:stock:log", activityId + "," + userId + "," + System.currentTimeMillis());return "秒殺成功";
}// 定時任務
@Component
@EnableScheduling
public class StockSyncTask {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate JdbcTemplate jdbcTemplate;@Scheduled(fixedRate = 60000) // 每分鐘public void syncStock() {List<String> logs = redisTemplate.opsForList().range("seckill:stock:log", 0, -1);if (logs != null && !logs.isEmpty()) {Map<String, Integer> stockUpdates = new HashMap<>();for (String log : logs) {String[] parts = log.split(",");String activityId = parts[0];stockUpdates.merge(activityId, 1, Integer::sum);}// 批量更新 MySQLfor (Map.Entry<String, Integer> entry : stockUpdates.entrySet()) {jdbcTemplate.update("UPDATE seckill_stock SET stock = stock - ? WHERE activity_id = ?",entry.getValue(), entry.getKey());}redisTemplate.opsForList().trim("seckill:stock:log", logs.size(), -1); // 清空已處理日志}}
}
優點
  • 性能優化: 批量處理,減少 MySQL 頻繁寫。
  • 容錯: 日志記錄便于排查。
缺點
  • 一致性延遲: MySQL 庫存更新有延遲。
  • 復雜性: 需維護日志和定時任務。
  • 適用場景
  • 中等并發,允許短暫不一致。

選擇依據

方案MySQL減庫存時機一致性性能復雜度適用場景
異步減扣Redis 后異步隊列最終一致高并發秒殺
同步減扣Redis 后立即同步強一致低并發強一致性
延遲減扣Redis 后定時批量延遲一致中等并發可接受延遲

推薦方案

  • 高并發秒殺: 采用異步減扣。
    • Redis 負責實時庫存控制,MySQL 異步更新。
    • 通過隊列解耦,確保高吞吐量。
  • 關鍵點:
    • Redis Lua 腳本保證原子性。
    • 異步任務失敗時,需重試或補償(如記錄失敗日志)。

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

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

相關文章

【js逆向入門】圖靈爬蟲練習平臺 第九題

地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvOS8 f12進入了debugger&#xff0c;右擊選擇一律不在此處暫停&#xff0c; 點擊繼續執行 查看請求信息 查看載荷&#xff0c;2個加密參數&#xff0c;m和tt 查看啟動器&#xff0c;打上斷點 進來 往…

Vue中的狀態管理器Vuex被Pinia所替代-上手使用指南

Pinia.js 是新一代的狀態管理器&#xff0c;由 Vue.js團隊中成員所開發的&#xff0c;因此也被認為是下一代的 Vuex&#xff0c;即 Vuex5.x&#xff0c;在 Vue3.0 的項目中使用也是備受推崇 Pinia.js 有如下特點&#xff1a; 完整的 typescript 的支持&#xff1b;足夠輕量&…

向量數據庫學習筆記(1) —— 基礎概念

一、 嵌入模型 Embedding Models 嵌入模型是將復雜數據&#xff08;如文本、圖像、音頻等&#xff09;轉換為向量表示的機器學習模型 1. 核心概念 嵌入(Embedding)&#xff1a;將高維、非結構化的數據映射到低維、稠密的向量空間 向量表示&#xff1a;輸出固定長度的數值向量…

[NO-WX179]基于springboot+微信小程序的在線選課系統

[NO-WX179]基于springboot微信小程序的在線選課系統 1、管理員角色&#xff08;web端&#xff09;&#xff1a;2、教師角色&#xff08;web端&#xff09;&#xff1a;3、用戶角色&#xff08;小程序或web端&#xff09;&#xff1a;4、部分運行截圖管理端--教師管理管理端--學…

2025年滲透測試面試題總結-某 長亭(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 長亭 一、Spring SpEL表達式注入漏洞 1. 技術原理 2. 利用條件 3. 攻擊方法 4. 防御策略 二、Jav…

conda環境下解決gitk亂碼模糊

關鍵詞 conda、git、gitk、git gui、模糊、linux、亂碼 現象 操作系統&#xff1a;ubuntu24.04 conda版本&#xff1a;25.1.1 正常的終端里gitk顯示不會模糊 但是在conda創建的python虛擬環境中使用gitk&#xff0c;字體開始變得模糊不清 分析 根據deepseek的原因原因分析…

【C++項目實戰】:基于正倒排索引的Boost搜索引擎(1)

1. 項目的相關背景與目標 針對boost網站沒有搜索導航功能&#xff0c;為boost網站文檔的查找提供搜索功能 站內搜索&#xff1a;搜索的數據更垂直&#xff0c;數據量小 類似于cplusplus.com的搜索 2.搜索引擎的相關宏觀原理 3.技術棧和項目環境 技術棧&#xff1a;C/C&am…

汽車高級駕駛輔助系統應用存儲MRAM

高級駕駛輔助系統和先進的互連航空電子技術等應用要求元件能夠承受惡劣的環境條件&#xff0c;并具有較高的耐用性。閃存雖然在某些條件下性能可靠&#xff0c;但在耐用性方面存在局限性&#xff0c;因此無法滿足這些嚴格的要求。 在實時傳感器數據處理或高可靠性通信等對時間…

藍橋-班級活動

問題描述 小明的老師準備組織一次班級活動。班上一共有 n 名 (n 為偶數) 同學&#xff0c;老師想把所有的同學進行分組&#xff0c;每兩名同學一組。為了公平&#xff0c;老師給每名同學隨機分配了一個 n 以內的正整數作為 id&#xff0c;第 i 名同學的 id 為 ai?。 老師希望…

MongoDB 的索引是提高查詢性能的核心機制,類似于傳統關系型數據庫的索引。以下是對 MongoDB 索引的詳細說明:

MongoDB 的索引是提高查詢性能的核心機制&#xff0c;類似于傳統關系型數據庫的索引。以下是對 MongoDB 索引的詳細說明&#xff1a; 一、索引基礎 1. 索引的作用 加速查詢&#xff1a;通過索引快速定位數據&#xff0c;避免全集合掃描&#xff08;COLLSCAN&#xff09;。 排…

深入理解指針(1)(C語言版)

文章目錄 前言一、內存和地址1.1 內存1.2 究竟該如何理解編址 二、指針變量和地址2.1 取地址操作符&2.2 指針變量和解引用操作符*2.2.1 指針變量2.2.2 如何拆解指針類型2.2.3 解引用操作符 2.3 指針變量的大小 三、指針變量類型的意義3.1 指針的解引用3.2 指針-整數3.3 voi…

【視頻】m3u8相關操作

【視頻】郭老二博文之:圖像視頻匯總 1、視頻文件轉m3u8 1.1 常用命令 1)默認只保留 5 個ts文件 ffmpeg -i input.mp4 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls stream1.m3u82)去掉音頻 -an,保留全部ts文件 ffmpeg -i input.mp4 -vf scale=640:480 -an -…

AWS CloudWatch 實戰:構建智能監控與自動化運維體系

摘要&#xff1a;本文通過實際案例&#xff0c;詳細講解如何利用AWS CloudWatch實現云端資源的實時監控、日志分析與自動化運維&#xff0c;助力企業提升系統穩定性與運維效率 一、場景痛點分析 某電商平臺遷移至AWS后面臨三大挑戰&#xff1a; 故障響應滯后&#xff1a;服務器…

第一天學爬蟲

閱讀提示&#xff1a;我今天才開始嘗試爬蟲&#xff0c;寫的不好請見諒。 一、準備工具 requests庫&#xff1a;發送HTTP請求并獲取網頁內容。BeautifulSoup庫&#xff1a;解析HTML頁面并提取數據。pandas庫&#xff1a;保存抓取到的數據到CSV文件中。 二、爬取步驟 發送請求…

網絡編程和計算機網絡五層模型的關系

計算機網絡的五層模型&#xff08;應用層、傳輸層、網絡層、鏈路層和物理層&#xff09;為網絡編程提供了基礎框架和通信機制。網絡編程就是在這些層次上實現應用程序之間的通信。 計算機網絡五層模型 &#xff08;1&#xff09;應用層&#xff1a; 作用&#xff1a;應用層是…

知識篇 | Oracle的 TEMP表空間管理和優化

Oracle臨時表空間&#xff08;TEMP&#xff09;是數據庫中用于存儲會話級臨時數據的核心組件&#xff0c;主要用于支持需要中間結果集的操作&#xff08;如排序、哈希連接&#xff09;。其數據在事務結束或會話終止后自動釋放&#xff0c;不持久化存儲。 核心特點&#xff1a;…

重學Java基礎篇—線程池參數優化指南

一、核心參數解析 線程池&#xff08;ThreadPoolExecutor&#xff09;的性能取決于以下關鍵參數&#xff1a; 參數說明corePoolSize核心線程數&#xff0c;即使空閑也不會被回收maximumPoolSize最大線程數&#xff0c;當隊列滿且核心線程忙時創建新線程workQueue任務隊列&…

記一次線上環境JAR沖突導致程序報錯org.springframework.web.util.NestedServletException

一、問題描述 有個文件導入功能&#xff0c;用到了Hutool 的加密解密功能&#xff0c;本地運行完全可以&#xff0c;但是線上報錯&#xff1a;“org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFou…

怎么快速部署Sock5代理到ubuntu云服務器

使用 Dante (推薦) 1. 安裝 Dante bash Copy sudo apt update sudo apt install dante-server -y 2. 配置 Dante 編輯配置文件 /etc/danted.conf&#xff1a; bash Copy sudo nano /etc/danted.conf 替換為以下內容&#xff08;按需修改端口和認證&#xff09;&#…

華為OD機試2025A卷 - 游戲分組/王者榮耀(Java Python JS C++ C )

最新華為OD機試 真題目錄:點擊查看目錄 華為OD面試真題精選:點擊立即查看 題目描述 2020年題: 英雄聯盟是一款十分火熱的對戰類游戲。每一場對戰有10位玩家參與,分為兩組,每組5人。每位玩家都有一個戰斗力,代表著這位玩家的厲害程度。為了對戰盡可能精彩,我們需要…