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

10萬(wàn)QPS高并發(fā)請(qǐng)求,如何防止重復(fù)下單

數(shù)據(jù)庫(kù) MySQL
當(dāng)業(yè)務(wù)量暴增的話,MySQL單機(jī)磁盤容量會(huì)撐爆。并且,我們知道數(shù)據(jù)庫(kù)連接數(shù)是有限的。在高并發(fā)的場(chǎng)景下,大量請(qǐng)求訪問數(shù)據(jù)庫(kù),MySQL單機(jī)是扛不住的!高并發(fā)場(chǎng)景下,會(huì)出現(xiàn)too many connections報(bào)錯(cuò)。

前言 

大家好,我是田螺。

星球粉絲分享了一道面試題:10萬(wàn)QPS高并發(fā)請(qǐng)求,如何防止重復(fù)下單。本文田螺哥從面試的角度,跟大家一起探討一下,從前端到后端,全鏈路,一層層遞進(jìn)探討!

1. 前端攔截 

首先因?yàn)槭?0萬(wàn)QPS的高并發(fā)請(qǐng)求,我們要保護(hù)好系統(tǒng),那就是盡可能減少用戶無(wú)效請(qǐng)求。

1.1 按鈕置灰

很多用戶搶票、搶購(gòu)、搶紅包等時(shí)候,為了提高搶中的概率,都是瘋狂點(diǎn)擊按鈕。會(huì)觸發(fā)多次請(qǐng)求,導(dǎo)致重復(fù)下單。

因此,在用戶點(diǎn)擊過搶購(gòu)按鈕后,我們可以給按鈕置灰,不讓用戶重復(fù)點(diǎn)擊。

const submitButton = document.getElementById('submit-order');
submitButton.disabled = true;  // 禁用按鈕
// 提交訂單的異步操作
submitOrder().then(response => {
  submitButton.disabled = false;  // 請(qǐng)求完成后恢復(fù)按鈕
}).catch(error => {
  submitButton.disabled = false;  // 請(qǐng)求失敗也恢復(fù)按鈕
});

如果你的系統(tǒng)希望設(shè)計(jì)得友好一點(diǎn),可以前端提示個(gè)文案,比如:已經(jīng)收到你的請(qǐng)求,請(qǐng)耐心等待搶購(gòu)結(jié)果。

1.2 Token機(jī)制

  • 前端加載頁(yè)面的時(shí)候,獲取一個(gè)全局唯一標(biāo)記的token,如UUID。
  • 在表單提交時(shí),用該Token來標(biāo)識(shí)該請(qǐng)求。每次請(qǐng)求都附帶該Token,后端驗(yàn)證Token是否唯一。如果已提交過該Token的請(qǐng)求,則直接返回錯(cuò)誤或無(wú)效響應(yīng),防止重復(fù)提交。

2.后端設(shè)計(jì) 

2.1 NGINX 限流

請(qǐng)求從前端到后端,首先是先到nginx ,我們可以在nginx做一下限流。

因?yàn)橛行┯脩舨粦押靡?,通過腳本繞過前端,瘋狂請(qǐng)求。這類用戶的IP和用戶ID,我們都可以做一下限流的限制的。

一個(gè)Nginx限流配置:

http {
    # 核心配置:IP+用戶ID雙因子限流 (按業(yè)務(wù)需求二選一)
    
    ## 選項(xiàng)1:基礎(chǔ)版(純IP限制)
    limit_req_zone $binary_remote_addr zone=order_base:10m rate=3r/m;  # 每IP每分鐘3次

    ## 選項(xiàng)2:增強(qiáng)版(IP+用戶ID,需前端傳遞UserID)
    limit_req_zone $binary_remote_addr$http_user_id zone=order_enhanced:20m rate=5r/m;

    server {
        listen 80;
        server_name tianluoboy.com;

        # 訂單提交接口
        location = /v1/order/create {
            # 啟用限流(示例用增強(qiáng)版)
            limit_req zone=order_enhanced burst=3 nodelay;  
            
            # 返回429時(shí)強(qiáng)制JSON響應(yīng)
            error_page 429 @toofast;
            location @toofast {
                default_type application/json;
                return 200 '{"code":429,"msg":"操作過于頻繁,請(qǐng)稍后再試"}';
            }

            # 反向代理到業(yè)務(wù)服務(wù)器
            proxy_pass http://order_backend;
        }

        # 其他接口不限流
        location / {
            proxy_pass http://default_backend;
        }
    }
}

2.2 網(wǎng)關(guān)(Spring Cloud Gateway)

網(wǎng)關(guān)層可以做的事情很多,比如

Token 校驗(yàn):在網(wǎng)關(guān)層攔截請(qǐng)求,驗(yàn)證 Token 是否在 Redis 中存在.

// 偽代碼示例:網(wǎng)關(guān)過濾器校驗(yàn) Token
if (redis.get(token) != null) {
    return error("重復(fù)請(qǐng)求");
} else {
    redis.setex(token, 60, "1"); // Token 有效期 60 秒
    //請(qǐng)求到后臺(tái)
    passToBackend();
}

當(dāng)然,網(wǎng)關(guān)也可以做限流的:

  • 令牌桶算法:通過Redis + Lua 實(shí)現(xiàn)集群級(jí)限流(如 redis-cell 模塊)。
  • 用戶維度限流:基于用戶 ID或設(shè)備指紋限制并發(fā)請(qǐng)求數(shù)。

網(wǎng)關(guān)層可以做一下請(qǐng)求排隊(duì):

  • 對(duì)高并發(fā)請(qǐng)求放到消息隊(duì)列,削峰填谷(如 Kafka/RabbitMQ)

圖片圖片

2.3 冪等設(shè)計(jì)

下單業(yè)務(wù)接口,我們一般要做冪等的。

一般用唯一索引做冪等設(shè)計(jì)。

唯一索引:比如使用用戶ID + 商品ID + 時(shí)間戳組合生成唯一訂單號(hào)。

一般的冪等處理就是這樣啦,如下:

圖片圖片

2.4 分庫(kù)分表

分庫(kù)分表:按用戶 ID 分片,分散寫壓力,避免單表成為瓶頸。

當(dāng)業(yè)務(wù)量暴增的話,MySQL單機(jī)磁盤容量會(huì)撐爆。并且,我們知道數(shù)據(jù)庫(kù)連接數(shù)是有限的。在高并發(fā)的場(chǎng)景下,大量請(qǐng)求訪問數(shù)據(jù)庫(kù),MySQL單機(jī)是扛不住的!高并發(fā)場(chǎng)景下,會(huì)出現(xiàn)too many connections報(bào)錯(cuò)。

所以高并發(fā)的系統(tǒng),需要考慮拆分為多個(gè)數(shù)據(jù)庫(kù),來抗住高并發(fā)的毒打。而假如你的單表數(shù)據(jù)量非常大,存儲(chǔ)和查詢的性能就會(huì)遇到瓶頸了,如果你做了很多優(yōu)化之后還是無(wú)法提升效率的時(shí)候,就需要考慮做分表了。一般千萬(wàn)級(jí)別數(shù)據(jù)量,就需要分表,每個(gè)表的數(shù)據(jù)量少一點(diǎn),提升SQL查詢性能。

2.5 分布式鎖

既然是防止重復(fù)下單,一般都需要加Redis分布式鎖的。

// 偽代碼:Redisson 分布式鎖
RLock lock = redisson.getLock("order:lock:" + userId);
if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
    try {
        createOrder();
    } finally {
        lock.unlock();
    }
}

2.6 樂觀鎖兜底

如果分布式鎖失效了呢?怎么辦呢?

我們可以加數(shù)據(jù)庫(kù)樂觀鎖兜底。比如

  • 在數(shù)據(jù)訂單表中添加 version 字段,每次更新都version+1,更新時(shí)校驗(yàn)版本號(hào)
  • 通過原子操作 UPDATE ... SET versinotallow=version+1 WHERE order_id=xx AND versinotallow=old_version實(shí)現(xiàn)

2.7 日志與監(jiān)控

要打印好日志,和做好監(jiān)控指標(biāo),如果發(fā)現(xiàn)日志或者監(jiān)控異常,可以快速介入排查~

打印日志也有坑:

圖片圖片

有需要的伙伴可以購(gòu)買我的踩坑專欄哈:血與淚的教訓(xùn),盤點(diǎn)我工作七年所踩的坑(更新到90篇啦~)

2.8 核對(duì)數(shù)據(jù)

我們要做好核對(duì)數(shù)據(jù),比如做個(gè)定時(shí)任務(wù),核對(duì)訂單數(shù)據(jù)和交易金額是否對(duì)得上,如果發(fā)現(xiàn)數(shù)據(jù)異常,就人工快速介入排查和修復(fù)。

責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2024-08-06 08:13:26

2022-09-03 23:18:46

Order服務(wù)負(fù)載均衡

2022-04-18 10:54:49

券系統(tǒng)緩存 RedisMySQL

2021-06-17 09:32:39

重復(fù)請(qǐng)求并發(fā)請(qǐng)求Java

2012-04-24 09:30:57

淘寶開發(fā)

2024-06-06 08:46:37

2025-02-28 00:03:22

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

2018-09-20 09:33:38

單機(jī)QPSRedis

2024-10-31 09:04:20

Spring高并發(fā)

2021-10-28 09:36:12

高并發(fā)數(shù)據(jù)實(shí)踐

2022-11-11 07:34:43

2024-08-05 09:29:00

前端接口請(qǐng)求

2025-06-23 08:23:04

2020-12-21 09:57:33

無(wú)鎖緩存并發(fā)緩存

2022-11-15 07:39:48

2022-11-17 07:43:13

2023-10-07 08:54:28

項(xiàng)目httpPost對(duì)象

2024-10-08 11:21:11

2025-02-14 03:00:00

點(diǎn)贊
收藏

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

主站蜘蛛池模板: 国产精品1区2区3区 欧美 中文字幕 | 91免费电影| 成人av鲁丝片一区二区小说 | 成人高清视频在线观看 | 欧美日韩精品免费 | 特a毛片| 91免费小视频 | 福利二区 | 91婷婷韩国欧美一区二区 | 91久久精品一区二区二区 | 欧美精品一区二区三区蜜桃视频 | 国产最好的av国产大片 | 日日噜噜夜夜爽爽狠狠 | 一区二区三区国产精品 | 欧美综合在线观看 | 亚洲精品一区二区三区中文字幕 | 亚洲国产精品久久 | 亚洲一区二区精品视频 | 国产精品国产三级国产aⅴ中文 | 男人天堂免费在线 | 成人三级在线播放 | 特黄毛片| 久色一区 | 国产精品毛片一区二区在线看 | 国产成人精品亚洲日本在线观看 | 国产一级片在线观看视频 | 国产日产精品一区二区三区四区 | 一级黄色毛片免费 | 国产精品性做久久久久久 | 日韩一区二区三区av | 韩日免费视频 | 91精品国产色综合久久不卡蜜臀 | 成人做爰www免费看 午夜精品久久久久久久久久久久 | 日本激情一区二区 | 国产男女精品 | 波多野结衣中文字幕一区二区三区 | 95国产精品 | 狠狠色综合欧美激情 | 国产1页 | 亚洲天堂免费在线 | 国产精品欧美一区喷水 |