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

redis?lua腳本解決高并發(fā)下秒殺場景

 更新時間:2023年10月07日 15:05:50   作者:光法V3  
這篇文章主要為大家介紹了redis?lua腳本解決高并發(fā)下秒殺場景,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Redis lua腳本解決搶購秒殺場景

秒殺搶購可以說是在分布式環(huán)境下?個?常經(jīng)典的案例,?邊有很多痛點:

1.?并發(fā): 時間極短、瞬間?戶量?,?瞬間的?QPS把系統(tǒng)或數(shù)據(jù)庫直接打死,響應(yīng)失敗,導(dǎo)致與這個系統(tǒng)耦合的系統(tǒng)也GG

目前秒殺的實現(xiàn)方案主要有兩種:

2.超賣: 你只有?百件商品,由于是?并發(fā)的問題,導(dǎo)致超賣的情況

目前秒殺的實現(xiàn)方案主要有兩種:

1.用redis 將搶購信息進(jìn)行存儲。然后再慢慢消費(fèi)。 同時,服務(wù)器給與用戶快速響應(yīng)。

2.用mq實現(xiàn),比如RabbitMQ,服務(wù)器將請求過來的數(shù)據(jù)先讓RabbitMQ存起來,然后再慢慢消費(fèi)掉。

也可以結(jié)合redis與mq的方式,通過redis控制剩余庫存,達(dá)到快速響應(yīng),將滿足條件的購買的訂單先讓RabbitMQ存起來,后續(xù)在慢慢消化。

整體流程

1.服務(wù)器接收到了大量用戶請求過來(1s 2000個請求)。比如傳了用戶信息,產(chǎn)品信息,和購買數(shù)量信息。此時 服務(wù)器采用redis 的lua 腳本 去調(diào)用redis 中間件。lua 腳本的邏輯是減庫存,校驗庫存是否足夠。然后迅速給與服務(wù)器反饋(庫存是否夠,夠返回 1 ,不夠返回 0)。

2.服務(wù)器迅速給與用戶的請求反饋。提示搶購成功.或者搶購失敗

3.搶購成功,將訂單信息放入MQ,其余線程接受到MQ的信息后,將訂單信息存入DB中

4.后面客戶就可以查詢 mysql 的訂單信息了。

架構(gòu)

采用springboot+redis+mysql+myBatis.

數(shù)據(jù)庫

CREATE TABLE `tb_product` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `product_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'id',
   `price` decimal(65,18) NOT NULL DEFAULT '0',
   `available_qty` bigint NOT NULL DEFAULT '0' COMMENT '發(fā)行數(shù)量',
  `title` varchar(1024) NOT NULL DEFAULT '',
   `end_time` bigint NOT NULL DEFAULT '0',
  `start_time` bigint NOT NULL DEFAULT '0',
  `created` bigint NOT NULL DEFAULT '0',
  `updated` bigint NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

pom依賴

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

lua 腳本

1.減少庫存,校驗庫存是否充足

2.庫存數(shù)量回滾:

核心業(yè)務(wù)代碼展示

1.加載lua腳本

private final static DefaultRedisScript<Long> deductRedisScript = new DefaultRedisScript();
    private final static DefaultRedisScript<Long> increaseRedisScript = new DefaultRedisScript();   
//加載lua腳本
    @PostConstruct
    void init() {
        //加載削減庫存lua腳本
        deductRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/fixedDeductInventory.lua")));
        deductRedisScript.setResultType(Long.class);
        //加載庫存回滾lua腳本
        increaseRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/fixedIncreaseInventory.lua")));
        increaseRedisScript.setResultType(Long.class);
    }

2.添加庫存到redis

注意點:在使用redis集群時,lua腳本中存在多個key時,可以通過hash tag這個方法將不同key的值落在同一個槽位上,hash tag 是通過{}這對括號括起來的字符串,如果下列中{fixed:" + data.getProductId() + "} 作為tag,確保同一個產(chǎn)品的信息都在同一個槽位。

@Resource(name = "fixedCacheRedisTemplate")
    private RedisTemplate<String, Long> fixedCacheRedisTemplate;
public void ProductToOngoing(Product data, Long time) {
         //設(shè)置數(shù)量
            long number = data.getAvailableQty();
            fixedCacheRedisTemplate.opsForHash().putIfAbsent("{fixed:" + data.getProductId() + "}-residue_stock_" + data.getRecordId(),
                    "{fixed:" + data.getProductId() + "}-residueStock" , number);
            String statusKey = "fixed_product_sold_status_"+ data.getRecordId();
            long timeout = data.getEndTime() - data.getStartTime();
              //添加產(chǎn)品出售狀態(tài)
            fixedCacheRedisTemplate.opsForValue().set(statusKey, 1L, data.getEndTime() - data.getStartTime(), TimeUnit.MILLISECONDS);
    }

3.下單&庫存校驗

//檢查庫存
public boolean checkFixedOrderQty(Long userId, Long productId, Long quantity, Long overTime) {
        Boolean pendingOrder = false;
        String userKey = "";
        try {
            //校驗是否開始
            String statusKey = "fixed_product_sold_status_" + productId;
            Long fixedStartStatus = fixedCacheRedisTemplate.opsForValue().get(statusKey);
            if (fixedStartStatus == null || fixedStartStatus != 1L) {
                //報錯返回,商品未開售
                throw new WebException(ResultCode.SALE_HAS_NOT_START);
            }
              //檢查庫存數(shù)量
            Long number = deductInventory(productId, quantity);
            if (number != 1L) {
                log.warn("availbale num is null:{} {}", productId, number);
                throw new WebException(ResultCode.AVAILABLE_AMOUNT_INSUFFICIENT);
            }
            return true;
        } catch (Exception e) {
            log.warn("checkFixedOrderQty error:{}", e.getMessage(), e);
            throw e;
        }
    }
//下單
 public void createOrder(Long userId, Long productId, BigDecimal price, Long quantity){
     boolean check = checkFixedOrderQty(userId, productId, quantity);
        try {
            if (check) {
                //添加MQ等待下單,后續(xù)收到推送的線程保存靠DB中
                CreateCoinOrderData data = new CreateCoinOrderData();
                data.setUserId(userId);
                data.setProductId(productId);
                data.setPrice(price);
                data.setQuantity(quantity);
                rabbitmqProducer.sendMessage(1, JSONObject.toJSONString(data));
            }
        } catch (Exception e) {
            //發(fā)生異常,庫存需要回滾
            increaseInventory(recordId, quantity, 1L);
            throw e;
        }
 }
    //庫存回填
    public Long increaseInventory(Long productId, Long num) {
        try {
            // 構(gòu)建keys信息,代表hash值中所需要的key信息
            List<String> keys = Arrays.asList("{fixed:" + productId + "}-residue_stock_"+ recordId, "{fixed:" + productId + "}-residueStock");
            // 執(zhí)行腳本
            Object result = fixedCacheRedisTemplate.execute(increaseRedisScript, keys, num);
            log.info("increaseInventory productId :{} num:{}  result:{}", productId, num, result);
            return (Long) result;
        } catch (Exception e) {
            log.warn("increaseInventory error productId:{}  num:{}", productId, num);
        }
        return 0L;
    }

以上就是redis lua腳本解決高并發(fā)下秒殺場景的詳細(xì)內(nèi)容,更多關(guān)于redis lua高并發(fā)秒殺的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Redis之BigKey與HotKey問題詳解

    Redis之BigKey與HotKey問題詳解

    在Redis的實際使用過程中,BigKey和 HotKey是兩個常見且可能導(dǎo)致嚴(yán)重性能問題的問題,它們可能導(dǎo)致 Redis 實例響應(yīng)變慢、內(nèi)存使用不均、甚至服務(wù)不可用,下面就來介紹一下這兩個的問題
    2026-02-02
  • 在Redis中如何保存時間序列數(shù)據(jù)詳解

    在Redis中如何保存時間序列數(shù)據(jù)詳解

    與發(fā)生時間相關(guān)的一組數(shù)據(jù),就是時間序列數(shù)據(jù),這些數(shù)據(jù)的特點是沒有嚴(yán)格的關(guān)系模型,記錄的信息可以表示成鍵和值的關(guān)系,這篇文章主要給大家介紹了關(guān)于在Redis中如何保存時間序列數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • redis三種高可用方式部署的實現(xiàn)

    redis三種高可用方式部署的實現(xiàn)

    這篇文章主要介紹了redis三種高可用方式部署的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Redis主從復(fù)制問題和擴(kuò)容問題的解決思路

    Redis主從復(fù)制問題和擴(kuò)容問題的解決思路

    這篇文章主要介紹了Redis主從復(fù)制問題和擴(kuò)容問題的解決思路,其中擴(kuò)容問題的解決思路來自Redis作者,需要的朋友可以參考下
    2014-06-06
  • redis的bigkey掃描腳本深入介紹

    redis的bigkey掃描腳本深入介紹

    這篇文章主要給大家介紹了關(guān)于redis的bigkey掃描腳本的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • redis遠(yuǎn)程連接不上的解決辦法

    redis遠(yuǎn)程連接不上的解決辦法

    本文主要介紹了redis遠(yuǎn)程連接不上的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式)

    ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式)

    這篇文章主要介紹了ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式),需要的朋友可以參考下
    2018-03-03
  • Redis從基礎(chǔ)到Stream消息隊列實戰(zhàn)指南

    Redis從基礎(chǔ)到Stream消息隊列實戰(zhàn)指南

    Redis是一個高性能內(nèi)存數(shù)據(jù)庫,支持字符串、哈希、列表等數(shù)據(jù)結(jié)構(gòu),5.0版本新增Stream類型,提供消息隊列功能,支持消費(fèi)者組和消息確認(rèn),本文介紹Redis從基礎(chǔ)到Stream消息隊列實戰(zhàn)指南,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Redis如何實現(xiàn)計數(shù)統(tǒng)計

    Redis如何實現(xiàn)計數(shù)統(tǒng)計

    這篇文章主要介紹了Redis如何實現(xiàn)計數(shù)統(tǒng)計方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Redis緩存雪崩的物種解決方案

    Redis緩存雪崩的物種解決方案

    在高并發(fā)系統(tǒng)中,Redis作為核心緩存組件,通常扮演著重要的"守門員"角色,當(dāng)大量緩存同時失效時,會導(dǎo)致請求如洪水般直接涌向數(shù)據(jù)庫,造成數(shù)據(jù)庫瞬間壓力劇增甚至宕機(jī),這種現(xiàn)象被形象地稱為"緩存雪崩",本文給大家介紹了Redis緩存雪崩的5種應(yīng)對措施,需要的朋友可以參考下
    2025-04-04

最新評論

军事| 饶阳县| 宁化县| 黄龙县| 荔波县| 礼泉县| 方正县| 宜良县| 抚顺县| 凭祥市| 安图县| 资阳市| 宁城县| 乳山市| 汉阴县| 茌平县| 惠东县| 湘潭县| 织金县| 昆明市| 闻喜县| 磴口县| 广昌县| 六枝特区| 平乡县| 盘山县| 玉山县| 鹤山市| 房产| 辽阳市| 永年县| 昭觉县| 郧西县| 五常市| 鄯善县| 门头沟区| 塘沽区| 九龙坡区| 紫金县| 临漳县| 阿坝县|