成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

拼多多二面:高并發(fā)場景扣減商品庫存如何防止超賣?

開發(fā) 架構(gòu)
高并發(fā)場景下使用樂觀鎖,一是其他請求拿不到版本號導(dǎo)致線程一直自旋等待中,甚至?xí)档拖到y(tǒng)的性能。二是數(shù)據(jù)庫的性能瓶頸。

數(shù)據(jù)庫扣減

我們先來看下通過數(shù)據(jù)庫方式去實現(xiàn)。

因為要防止它超賣,所以要先把庫存鎖住,避免庫存還剩最后一個時,多個線程同時去扣減成負數(shù)了。

圖片圖片

但是這種方式顯而易見效率非常低下,因為這里加的悲觀鎖,讀請求也被阻塞了,我們知道大部分場景下都是讀多寫少,所以如何優(yōu)化呢?

很快小白想到了,可以通過樂觀鎖的方式實現(xiàn)。

樂觀鎖:事務(wù)不會在讀取數(shù)據(jù)時加鎖,而是繼續(xù)執(zhí)行后續(xù)操作,只有在提交數(shù)據(jù)時才會檢查數(shù)據(jù)是否已經(jīng)被其他事務(wù)修改,通常通過 版本號或時間戳來實現(xiàn)。

我們可以給庫存這條記錄加一個版本號字段 version,在更新庫存時判斷版本號是否一致,這樣也不會阻塞讀請求。

UPDATE product_inventory
SET stock = stock - :quantity,
    version = version + 1
WHERE product_id = :productId
  AND version = :version;

這種方式能滿足一般場景,但是假設(shè)在高并發(fā)的搶購活動下,當(dāng)你壓測時發(fā)現(xiàn) TPS 怎么也提不上來。

高并發(fā)場景下使用樂觀鎖,一是其他請求拿不到版本號導(dǎo)致線程一直自旋等待中,甚至?xí)档拖到y(tǒng)的性能。二是數(shù)據(jù)庫的性能瓶頸。

這時,你在想有沒有其他更好的方式呢?

Redis 扣減

既然數(shù)據(jù)庫無法滿足高并發(fā)性能,我們知道 Redis 單節(jié)點理論能支持幾萬級 TPS,而且我們還可以部署集群多節(jié)點,這樣肯定能滿足了吧。

Redis 如何實現(xiàn)庫存扣減呢?

很快,你想到了,Redis 不是有一個 INCRBY 的命令嗎?可以通過這個實現(xiàn)呀。

INCRBY product:1001:stock -10

但很快,測試時你又發(fā)現(xiàn)了問題,在場景下,這個庫存會被扣成負數(shù),這顯然是不能接受的。

那再加上鎖不就好了嗎,因為是是節(jié)點操作,我們想到通過加分布式鎖的方式。

圖片圖片

同一時刻只有一個線程能獲取到鎖去執(zhí)行扣減,這樣肯定不會超賣了,但這種方式因為只有一個線程能去扣減這個商品的庫存,顯然并發(fā)性能還有待提升。

我們可以不加鎖嗎?但判斷庫存是否大于 0 和扣減庫存是兩個指令,如何保證一致性呢?

Redis Lua 扣減

Lua:Redis 支持在服務(wù)器端執(zhí)行 Lua 腳本時,腳本的所有操作都是原子執(zhí)行的,即腳本中的所有命令要么全部成功,要么全部失敗。

我們可以通過 Lua 的原子性來實現(xiàn),避免加鎖。

先獲取當(dāng)前庫存,判斷是否足夠,如果足夠再進行扣減。

local stock = redis.call('get', KEYS[1])  -- 獲取當(dāng)前庫存
if not stock then
    return nil  -- 如果沒有找到庫存,返回nil
end

if tonumber(stock) >= tonumber(ARGV[1]) then  -- 如果庫存足夠
    redis.call('decrby', KEYS[1], ARGV[1])  -- 扣減庫存
    return tonumber(stock) - tonumber(ARGV[1])  -- 返回扣減后的庫存
else
    return nil  -- 庫存不足,返回nil
end

如果這時老板看商品賣的很好,要后臺調(diào)增庫存怎么辦?

如果要調(diào)增庫存,為了防止多個線程同時調(diào)整庫存出現(xiàn)并發(fā)問題,這里要加分布式鎖,可以通過 SETNX 實現(xiàn)。

/**
     * 增加庫存,使用分布式鎖確保并發(fā)安全
     * @param productId 商品ID
     * @param quantity 增加的數(shù)量
     * @param lockValue 鎖的值,用于解鎖時進行驗證
     * @param lockTimeout 鎖的超時時間
     * @return 是否成功增加庫存
     */
    public boolean increaseInventoryWithLock(String productId, int quantity, String lockValue, int lockTimeout) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 獲取分布式鎖
            String lockKey = "product_lock:" + productId;
            boolean lockAcquired = acquireLock(jedis, lockKey, lockValue, lockTimeout);
            if (lockAcquired) {
                try {
                    // 增加庫存
                    jedis.incrBy("product:" + productId + ":stock", quantity);
                    return true;
                } finally {
                    // 釋放鎖
                    releaseLock(jedis, lockKey, lockValue);
                }
            } else {
                // 如果獲取不到鎖,可以返回 false 或進行重試等操作
                return false;
            }
        }
    }

這樣,你想應(yīng)該就萬無一失了吧。

但是,如果你的商品賣得非常好,Redis 單節(jié)點也扛不住了,針對這種熱點商品怎么辦呢?

Redis 庫存分片

莫慌,別忘了我們 Redis 是多節(jié)點集群部署的,我們?nèi)绻堰@個熱點商品庫存拆分到每個節(jié)點上不就解決了嗎。

怎么拆分呢?

假設(shè)我們 Redis 有 12 個節(jié)點,我們可以把商品庫存緩存 Key 再加個后綴 0,1,2....12 分布到每一個節(jié)點上,扣減時如果發(fā)現(xiàn)當(dāng)前節(jié)點沒庫存了,再扣除下個緩存 key。

當(dāng)然,如果每次都從節(jié)點 1 開始,熱點問題并沒有解決,我們可以設(shè)置一個隨機數(shù)組把順序打散,比如[1,2,......,12],[2,12......,1]。

圖片圖片

這樣避免了該熱點商品的所有請求都打到同一個節(jié)點上的問題了。

責(zé)任編輯:武曉燕 來源: 碼哥跳動
相關(guān)推薦

2022-09-19 09:49:17

MCube網(wǎng)絡(luò)引擎

2025-02-26 08:10:40

2024-07-25 09:05:35

2025-04-14 00:00:00

數(shù)據(jù)庫分布式架構(gòu)分布式鎖?

2021-08-26 08:24:33

高并發(fā)秒殺系統(tǒng)

2024-09-10 10:42:27

2020-09-03 06:33:35

高并發(fā)場景分布式鎖

2024-07-12 11:28:44

2024-11-27 00:20:32

2025-06-27 02:00:00

Spring高并發(fā)庫存

2024-03-11 15:13:22

數(shù)據(jù)庫高并發(fā)

2021-04-12 08:02:12

分布式鎖秒殺高并發(fā)

2024-10-22 16:26:11

2025-03-12 09:36:23

AspectJAOP開發(fā)

2024-10-17 16:58:43

2024-10-15 10:59:18

Spring MVCJava開發(fā)

2025-01-27 00:40:41

2021-06-09 18:52:05

方案設(shè)計庫存數(shù)

2025-02-26 03:00:00

2025-02-28 00:03:22

高并發(fā)TPS系統(tǒng)
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美精品一区二区三区四区 在线 | 国产三级一区二区三区 | 国产一级片一区二区 | 狠狠草视频 | 国产精品不卡 | 成人h视频| 国产精品一区二区在线播放 | 欧美精品第三页 | 国产高清精品在线 | 蜜臀久久99精品久久久久久宅男 | 精品国产一区二区国模嫣然 | 在线视频一区二区三区 | 日韩在线不卡 | 男女视频在线免费观看 | 免费欧美| 国产精品欧美一区二区 | 综合色久 | 午夜视频免费在线观看 | 国产电影精品久久 | 福利视频二区 | 国产精品一区二区久久 | 大陆一级毛片免费视频观看 | 国产三级电影网站 | 亚洲精品欧美精品 | 美女日批免费视频 | 波多野结衣一二三区 | 91色在线| 四虎永久在线精品免费一区二 | 国产成人精品一区二区 | 二区国产 | 在线午夜 | 日韩在线精品视频 | 欧美成人免费在线视频 | 亚洲高清视频一区二区 | 特级黄一级播放 | 一区二区三区视频在线免费观看 | av免费看在线 | 日本一区二区视频 | 亚洲一区二区三区四区五区午夜 | 国产96在线 | 日韩成人影院 |