国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)

這篇具有很好參考價值的文章主要介紹了微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)

1、秒殺優(yōu)化

1.1 秒殺優(yōu)化-異步秒殺思路

我們來回顧一下下單流程

當用戶發(fā)起請求,此時會請求nginx,nginx會訪問到tomcat,而tomcat中的程序,會進行串行操作,分成如下幾個步驟

1、查詢優(yōu)惠卷

2、判斷秒殺庫存是否足夠

3、查詢訂單

4、校驗是否是一人一單

5、扣減庫存

6、創(chuàng)建訂單

在這六步操作中,又有很多操作是要去操作數(shù)據(jù)庫的,而且還是一個線程串行執(zhí)行, 這樣就會導致我們的程序執(zhí)行的很慢,所以我們需要異步程序執(zhí)行,那么如何加速呢?

在這里筆者想給大家分享一下課程內(nèi)沒有的思路,看看有沒有小伙伴這么想,比如,我們可以不可以使用異步編排來做,或者說我開啟N多線程,N多個線程,一個線程執(zhí)行查詢優(yōu)惠卷,一個執(zhí)行判斷扣減庫存,一個去創(chuàng)建訂單等等,然后再統(tǒng)一做返回,這種做法和課程中有哪種好呢?答案是課程中的好,因為如果你采用我剛說的方式,如果訪問的人很多,那么線程池中的線程可能一下子就被消耗完了,而且你使用上述方案,最大的特點在于,你覺得時效性會非常重要,但是你想想是嗎?并不是,比如我只要確定他能做這件事,然后我后邊慢慢做就可以了,我并不需要他一口氣做完這件事,所以我們應當采用的是課程中,類似消息隊列的方式來完成我們的需求,而不是使用線程池或者是異步編排的方式來完成這個需求

微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)

優(yōu)化方案:我們將耗時比較短的邏輯判斷放入到redis中,比如是否庫存足夠,比如是否一人一單,這樣的操作,只要這種邏輯可以完成,就意味著我們是一定可以下單完成的,我們只需要進行快速的邏輯判斷,根本就不用等下單邏輯走完,我們直接給用戶返回成功, 再在后臺開一個線程,后臺線程慢慢的去執(zhí)行queue里邊的消息,這樣程序不就超級快了嗎?而且也不用擔心線程池消耗殆盡的問題,因為這里我們的程序中并沒有手動使用任何線程池,當然這里邊有兩個難點

第一個難點是我們怎么在redis中去快速校驗一人一單,還有庫存判斷

第二個難點是由于我們校驗和tomct下單是兩個線程,那么我們?nèi)绾沃赖降啄膫€單他最后是否成功,或者是下單完成,為了完成這件事我們在redis操作完之后,我們會將一些信息返回給前端,同時也會把這些信息丟到異步queue中去,后續(xù)操作中,可以通過這個id來查詢我們tomcat中的下單邏輯是否完成了。

微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)

我們現(xiàn)在來看看整體思路:當用戶下單之后,判斷庫存是否充足只需要導redis中去根據(jù)key找對應的value是否大于0即可,如果不充足,則直接結(jié)束,如果充足,繼續(xù)在redis中判斷用戶是否可以下單,如果set集合中沒有這條數(shù)據(jù),說明他可以下單,如果set集合中沒有這條記錄,則將userId和優(yōu)惠卷存入到redis中,并且返回0,整個過程需要保證是原子性的,我們可以使用lua來操作

當以上判斷邏輯走完之后,我們可以判斷當前redis中返回的結(jié)果是否是0 ,如果是0,則表示可以下單,則將之前說的信息存入到到queue中去,然后返回,然后再來個線程異步的下單,前端可以通過返回的訂單id來判斷是否下單成功。

微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)

1.2 秒殺優(yōu)化-Redis完成秒殺資格判斷

需求:

  • 新增秒殺優(yōu)惠券的同時,將優(yōu)惠券信息保存到Redis中

  • 基于Lua腳本,判斷秒殺庫存、一人一單,決定用戶是否搶購成功

  • 如果搶購成功,將優(yōu)惠券id和用戶id封裝后存入阻塞隊列

  • 開啟線程任務,不斷從阻塞隊列中獲取信息,實現(xiàn)異步下單功能

    微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)

VoucherServiceImpl

@Override
@Transactional
public void addSeckillVoucher(Voucher voucher) {
    // 保存優(yōu)惠券
    save(voucher);
    // 保存秒殺信息
    SeckillVoucher seckillVoucher = new SeckillVoucher();
    seckillVoucher.setVoucherId(voucher.getId());
    seckillVoucher.setStock(voucher.getStock());
    seckillVoucher.setBeginTime(voucher.getBeginTime());
    seckillVoucher.setEndTime(voucher.getEndTime());
    seckillVoucherService.save(seckillVoucher);
    // 保存秒殺庫存到Redis中
    //SECKILL_STOCK_KEY 這個變量定義在RedisConstans中
    //private static final String SECKILL_STOCK_KEY ="seckill:stock:"
    stringRedisTemplate.opsForValue().set(SECKILL_STOCK_KEY + voucher.getId(), voucher.getStock().toString());
}

完整lua表達式

-- 1.參數(shù)列表
-- 1.1.優(yōu)惠券id
local voucherId = ARGV[1]
-- 1.2.用戶id
local userId = ARGV[2]
-- 1.3.訂單id
local orderId = ARGV[3]

-- 2.數(shù)據(jù)key
-- 2.1.庫存key
local stockKey = 'seckill:stock:' .. voucherId
-- 2.2.訂單key
local orderKey = 'seckill:order:' .. voucherId

-- 3.腳本業(yè)務
-- 3.1.判斷庫存是否充足 get stockKey
if(tonumber(redis.call('get', stockKey)) <= 0) then
    -- 3.2.庫存不足,返回1
    return 1
end
-- 3.2.判斷用戶是否下單 SISMEMBER orderKey userId
if(redis.call('sismember', orderKey, userId) == 1) then
    -- 3.3.存在,說明是重復下單,返回2
    return 2
end
-- 3.4.扣庫存 incrby stockKey -1
redis.call('incrby', stockKey, -1)
-- 3.5.下單(保存用戶)sadd orderKey userId
redis.call('sadd', orderKey, userId)
-- 3.6.發(fā)送消息到隊列中, XADD stream.orders * k1 v1 k2 v2 ...
redis.call('xadd', 'stream.orders', '*', 'userId', userId, 'voucherId', voucherId, 'id', orderId)
return 0

當以上lua表達式執(zhí)行完畢后,剩下的就是根據(jù)步驟3,4來執(zhí)行我們接下來的任務了

VoucherOrderServiceImpl

@Override
public Result seckillVoucher(Long voucherId) {
    //獲取用戶
    Long userId = UserHolder.getUser().getId();
    long orderId = redisIdWorker.nextId("order");
    // 1.執(zhí)行l(wèi)ua腳本
    Long result = stringRedisTemplate.execute(
            SECKILL_SCRIPT,
            Collections.emptyList(),
            voucherId.toString(), userId.toString(), String.valueOf(orderId)
    );
    int r = result.intValue();
    // 2.判斷結(jié)果是否為0
    if (r != 0) {
        // 2.1.不為0 ,代表沒有購買資格
        return Result.fail(r == 1 ? "庫存不足" : "不能重復下單");
    }
    //TODO 保存阻塞隊列
    // 3.返回訂單id
    return Result.ok(orderId);
}

1.3 秒殺優(yōu)化-基于阻塞隊列實現(xiàn)秒殺優(yōu)化

VoucherOrderServiceImpl

修改下單動作,現(xiàn)在我們?nèi)ハ聠螘r,是通過lua表達式去原子執(zhí)行判斷邏輯,如果判斷我出來不為0 ,則要么是庫存不足,要么是重復下單,返回錯誤信息,如果是0,則把下單的邏輯保存到隊列中去,然后異步執(zhí)行

//異步處理線程池
private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();

//在類初始化之后執(zhí)行,因為當這個類初始化好了之后,隨時都是有可能要執(zhí)行的
@PostConstruct
private void init() {
   SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());
}
// 用于線程池處理的任務
// 當初始化完畢后,就會去從對列中去拿信息
 private class VoucherOrderHandler implements Runnable{

        @Override
        public void run() {
            while (true){
                try {
                    // 1.獲取隊列中的訂單信息
                    VoucherOrder voucherOrder = orderTasks.take();
                    // 2.創(chuàng)建訂單
                    handleVoucherOrder(voucherOrder);
                } catch (Exception e) {
                    log.error("處理訂單異常", e);
                }
          	 }
        }
     
       private void handleVoucherOrder(VoucherOrder voucherOrder) {
            //1.獲取用戶
            Long userId = voucherOrder.getUserId();
            // 2.創(chuàng)建鎖對象
            RLock redisLock = redissonClient.getLock("lock:order:" + userId);
            // 3.嘗試獲取鎖
            boolean isLock = redisLock.lock();
            // 4.判斷是否獲得鎖成功
            if (!isLock) {
                // 獲取鎖失敗,直接返回失敗或者重試
                log.error("不允許重復下單!");
                return;
            }
            try {
				//注意:由于是spring的事務是放在threadLocal中,此時的是多線程,事務會失效
                proxy.createVoucherOrder(voucherOrder);
            } finally {
                // 釋放鎖
                redisLock.unlock();
            }
    }
     //a
	private BlockingQueue<VoucherOrder> orderTasks =new  ArrayBlockingQueue<>(1024 * 1024);

    @Override
    public Result seckillVoucher(Long voucherId) {
        Long userId = UserHolder.getUser().getId();
        long orderId = redisIdWorker.nextId("order");
        // 1.執(zhí)行l(wèi)ua腳本
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                voucherId.toString(), userId.toString(), String.valueOf(orderId)
        );
        int r = result.intValue();
        // 2.判斷結(jié)果是否為0
        if (r != 0) {
            // 2.1.不為0 ,代表沒有購買資格
            return Result.fail(r == 1 ? "庫存不足" : "不能重復下單");
        }
        VoucherOrder voucherOrder = new VoucherOrder();
        // 2.3.訂單id
        long orderId = redisIdWorker.nextId("order");
        voucherOrder.setId(orderId);
        // 2.4.用戶id
        voucherOrder.setUserId(userId);
        // 2.5.代金券id
        voucherOrder.setVoucherId(voucherId);
        // 2.6.放入阻塞隊列
        orderTasks.add(voucherOrder);
        //3.獲取代理對象
         proxy = (IVoucherOrderService)AopContext.currentProxy();
        //4.返回訂單id
        return Result.ok(orderId);
    }
     
      @Transactional
    public  void createVoucherOrder(VoucherOrder voucherOrder) {
        Long userId = voucherOrder.getUserId();
        // 5.1.查詢訂單
        int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();
        // 5.2.判斷是否存在
        if (count > 0) {
            // 用戶已經(jīng)購買過了
           log.error("用戶已經(jīng)購買過了");
           return ;
        }

        // 6.扣減庫存
        boolean success = seckillVoucherService.update()
                .setSql("stock = stock - 1") // set stock = stock - 1
                .eq("voucher_id", voucherOrder.getVoucherId()).gt("stock", 0) // where id = ? and stock > 0
                .update();
        if (!success) {
            // 扣減失敗
            log.error("庫存不足");
            return ;
        }
        save(voucherOrder);
 
    }

小總結(jié):

秒殺業(yè)務的優(yōu)化思路是什么?文章來源地址http://www.zghlxwxcb.cn/news/detail-453046.html

  • 先利用Redis完成庫存余量、一人一單判斷,完成搶單業(yè)務
  • 再將下單業(yè)務放入阻塞隊列,利用獨立線程異步下單
  • 基于阻塞隊列的異步秒殺存在哪些問題?
    • 內(nèi)存限制問題
    • 數(shù)據(jù)安全問題

到了這里,關于微服務---Redis實用篇-黑馬頭條項目-優(yōu)惠卷秒殺功能(使用java阻塞隊列對秒殺進行異步優(yōu)化)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Redis項目實戰(zhàn)——優(yōu)惠券秒殺

    Redis項目實戰(zhàn)——優(yōu)惠券秒殺

    如果用MySQL的自增長ID,ID的規(guī)律性太明顯, 會暴漏一些信息 (比如銷量等) 數(shù)據(jù)量太大時一張表存不下,需要多張表,MySQL多張表的自增長都是獨立的, 會出現(xiàn)重復ID 需要一種在分布式系統(tǒng)下可以生成全局唯一ID的工具,必須唯一且遞增 在某項目里,不管數(shù)據(jù)庫的表有多少

    2024年02月10日
    瀏覽(25)
  • Redis:原理速成+項目實戰(zhàn)——Redis實戰(zhàn)7(優(yōu)惠券秒殺+細節(jié)解決超賣、一人一單問題)

    Redis:原理速成+項目實戰(zhàn)——Redis實戰(zhàn)7(優(yōu)惠券秒殺+細節(jié)解決超賣、一人一單問題)

    ?????作者簡介:一位大四、研0學生,正在努力準備大四暑假的實習 ??上期文章:Redis:原理速成+項目實戰(zhàn)——Redis實戰(zhàn)6(封裝緩存工具(高級寫法)緩存總結(jié)) ??訂閱專欄:Redis:原理速成+項目實戰(zhàn) 希望文章對你們有所幫助 這篇文章寫了很久。我自己在邊實現(xiàn)、邊用

    2024年01月24日
    瀏覽(20)
  • 2023黑馬頭條.微服務項目.跟學筆記(三)

    2023黑馬頭條.微服務項目.跟學筆記(三)

    1.自媒體前后端搭建 1.1 后臺搭建 ①:資料中找到heima-leadnews-wemedia.zip解壓 拷貝到heima-leadnews-service工程下,并指定子模塊 執(zhí)行l(wèi)eadnews-wemedia.sql腳本 添加對應的nacos配置 ②:資料中找到heima-leadnews-wemedia-gateway.zip解壓 拷貝到heima-leadnews-gateway工程下,并指定子模塊 添加對應的n

    2024年02月13日
    瀏覽(44)
  • 黑馬點評用rabbitmq實現(xiàn)優(yōu)惠券秒殺下單后的異步操作數(shù)據(jù)庫數(shù)據(jù)

    黑馬點評用rabbitmq實現(xiàn)優(yōu)惠券秒殺下單后的異步操作數(shù)據(jù)庫數(shù)據(jù)

    通過@Bean注入MessageConverter,保證消息的正確傳輸 修改后的代碼 監(jiān)聽器

    2024年04月15日
    瀏覽(25)
  • 黑馬頭條 SpringBoot+SpringCloud+ Nacos等企業(yè)級微服務架構項目

    黑馬頭條 SpringBoot+SpringCloud+ Nacos等企業(yè)級微服務架構項目

    各位爺,完整項目gitee如下,求star heima-leadnews-master: 《黑馬頭條》項目采用的是SpringBoot+springcloud當下最流行的微服務為項目架構,配合spring cloud alibaba nacos作為項目的注冊和配置中心。新課程采用快速開發(fā)的模式,主要解決真實企業(yè)開發(fā)的一些應用場景。詳情請看博客:htt

    2024年02月08日
    瀏覽(27)
  • 《黑馬頭條》SpringBoot+SpringCloud+ Nacos等企業(yè)級微服務架構項目

    《黑馬頭條》SpringBoot+SpringCloud+ Nacos等企業(yè)級微服務架構項目

    各位爺,完整項目gitee如下,求star heima-leadnews-master: 《黑馬頭條》項目采用的是SpringBoot+springcloud當下最流行的微服務為項目架構,配合spring cloud alibaba nacos作為項目的注冊和配置中心。新課程采用快速開發(fā)的模式,主要解決真實企業(yè)開發(fā)的一些應用場景。詳情請看博客:htt

    2024年02月15日
    瀏覽(29)
  • Redis分布式鎖原理之實現(xiàn)秒殺搶優(yōu)惠卷業(yè)務

    Redis分布式鎖原理之實現(xiàn)秒殺搶優(yōu)惠卷業(yè)務

    背景 優(yōu)惠券秒殺有兩個業(yè)務涉及線程并發(fā)問題,第一個是庫存超賣,第二個是一人一單,這就必須采取鎖的方案了。下面根據(jù)優(yōu)惠券秒殺功能一步一步進行展開,利用悲觀鎖、同步鎖、分布式鎖等方案循序漸進解決各種問題。 下單核心思路:當我們點擊搶購時,會觸發(fā)右側(cè)

    2024年02月03日
    瀏覽(19)
  • 新黑馬頭條項目經(jīng)驗(黑馬)

    新黑馬頭條項目經(jīng)驗(黑馬)

    ? ? (1)簡介 Swagger 是一個規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化 RESTful 風格的 Web 服務(API Documentation Design Tools for Teams | Swagger)。 它的主要作用是: 使得前后端分離開發(fā)更加方便,有利于團隊協(xié)作 接口的文檔在線自動生成,降低后端開發(fā)人員編寫接口文檔的負擔

    2024年02月02日
    瀏覽(23)
  • 面試項目-黑馬頭條-項目介紹

    面試項目-黑馬頭條-項目介紹

    B站視頻黑馬頭條視頻學習總結(jié),侵權請聯(lián)系刪除 1.1 項目背景 隨著智能手機的普及,人們更加習慣于通過手機來看新聞。由于生活節(jié)奏的加快,很多人只能利用碎片時間來獲取信息,因此,對于移動資訊客戶端的需求也越來越高。黑馬頭條項目正是在這樣背景下開發(fā)出來。黑

    2024年02月09日
    瀏覽(25)
  • 黑馬頭條項目經(jīng)驗&BUG

    黑馬頭條項目經(jīng)驗&BUG

    同樣是配置文件,但與application.yml有所不同 bootstrap.yml的加載比application.yml早 bootstrap.yml作用范圍更廣,可以被多個應用程序共享(可以在每個服務的application.yml中配置 spring: cloud: config: (name)url ,從而配置bootstrap.yml的位置) bootstrap.yml具有更高的優(yōu)先級,可以覆蓋application.y

    2024年02月14日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包