• 八方資訊網(wǎng)歡迎您!
    八方資訊網(wǎng)>科技>正文

    架構(gòu)成長(zhǎng)之路:分布式秒殺系統(tǒng)之如何防止單個(gè)用戶重復(fù)秒殺下單?!

    2021-02-18 11:14:23 來源: 閱讀:-

    電子交易的一個(gè)很基本的問題,就是避免用戶下重復(fù)訂單。用戶明明想買一次,結(jié)果一看下了兩個(gè)單。如果沒有及時(shí)發(fā)現(xiàn),就會(huì)帶來額外的物流成本和扯皮。對(duì)商家的信譽(yù)也不好看。

    從技術(shù)上看,這是一個(gè)分布式一致性問題;但實(shí)際上,技術(shù)無法100%解決這類問題,得結(jié)合多種手段綜合處理。這里就來說道說道。

    為啥會(huì)下重了呢?

    原因1:客戶端bug

    比如下單的按鍵在點(diǎn)按之后,在沒有收到服務(wù)器請(qǐng)求之前,按鍵的狀態(tài)沒有設(shè)為已禁用狀態(tài),還可以被按。又或者,在觸摸屏下,用戶手指的點(diǎn)按可能被手機(jī)操作系統(tǒng)識(shí)別為多次點(diǎn)擊。

    嗯,誰能保證客戶端不偶爾出個(gè)什么bug 呢。

    原因2: 超時(shí)

    用戶的設(shè)備與服務(wù)器之間可能是不穩(wěn)定的網(wǎng)路。這樣一個(gè)下單請(qǐng)求過去,返回不一定回得來。超時(shí)最大的問題是: 從用戶的角度,他無法確定下單的請(qǐng)求是還沒到服務(wù)器,還是已經(jīng)到了服務(wù)器但是返回丟失了。——用戶無法區(qū)分到底這個(gè)單下了還是沒下

    這樣在等待一個(gè)超時(shí)后,UI可能會(huì)提示用戶下單超時(shí),請(qǐng)重復(fù)再試。

    架構(gòu)成長(zhǎng)之路:分布式秒殺系統(tǒng)之如何防止單個(gè)用戶重復(fù)秒殺下單?

    原因3: 用戶的App閃退/人工強(qiáng)退,之后重新打開重新下單

    也許可以使用一些技術(shù)手段避免用戶下重單,但是心急的用戶可能會(huì)重啟流程/重啟App/重啟手機(jī)。在這種強(qiáng)制的手段下,任何技術(shù)手段都會(huì)失效——用戶壓根就不讓你的技術(shù)執(zhí)行,你怎么玩?

    在這些條件下,如何避免用戶多下了一筆訂單呢?

    用冪等防止重復(fù)訂單

    在技術(shù)方面,這是一個(gè)分布式一致性的問題,即客戶端和服務(wù)器端對(duì)某個(gè)訂單是否成功/失敗達(dá)成一致。防止重單的關(guān)鍵是使用一個(gè)由客戶端生成的,可用于避免重復(fù)的key,俗稱dedup key(deduplicate key之意)。這個(gè)key可以用任意可以保證全局唯一性的方式生成,比如uuid。客戶端和服務(wù)器需要使用這個(gè)dedup key作為串聯(lián)條件,一起解決去重問題。

    客戶端的流程

    客戶端需要實(shí)現(xiàn)這樣一個(gè)下單界面。用戶點(diǎn)擊【確認(rèn)下單】時(shí),應(yīng)該產(chǎn)生一個(gè)獨(dú)一無二的dedup key,連定訂單數(shù)據(jù)發(fā)送給服務(wù)器端。在服務(wù)器返回之前,該界面應(yīng)該一直等待,直到服務(wù)器響應(yīng)成功/失敗或者超時(shí)發(fā)生(比如15秒后,收不到服務(wù)器響應(yīng))。如果超時(shí)發(fā)生,應(yīng)該向用戶提示是否重試下單或者退出該界面。當(dāng)用戶點(diǎn)擊【重試】時(shí),應(yīng)該用剛剛生成的dedup key來再次發(fā)送下單請(qǐng)求——如果用戶一直不退出這個(gè)流程,每次用戶點(diǎn)擊重試,都應(yīng)該用這個(gè)dedup key來重試下單,直到服務(wù)器正常返回,或者用戶放棄返回。

    架構(gòu)成長(zhǎng)之路:分布式秒殺系統(tǒng)之如何防止單個(gè)用戶重復(fù)秒殺下單?

    下單的客戶端流程

    后端數(shù)據(jù)表設(shè)計(jì)

    后端在訂單數(shù)據(jù)表中,需要增加dedup_key這列,并設(shè)置唯一約束

    create table order(
    # ...
    dedup_key varchar(60) not null comment 'key to pretend order duplication',
    # ...
    unique uniq_dedup_key(dedup_key)
    );

    下單的實(shí)現(xiàn)

    在實(shí)現(xiàn)下單邏輯時(shí),基于該dedup_key實(shí)現(xiàn)一個(gè)"create-or-get"語義的下單接口——簡(jiǎn)單說就是

    如果帶有指定dedup_key的訂單已經(jīng)存在,則直接返回;否則,用該dedup_key下單。

    用偽代碼表示大概是:

    @Transactional
    Order createOrder(Integer userId, String prodCode, Decimal amount, String dedupKey) {
    try {
    String orderId = createOrder(userId, prodCode, amount, deupKey); // insert a new order
    Order order = getOrderById(orderId); // read order from db
    order.setDuplicated(false);
    return order;
    } catch(UniqueKeyViolationException e) {
    // if duplicated order has existed
    Order order = getOrderByDedupKey(dedupKey);
    order.setDuplicated(true);
    return order;
    } catch (Exception e) {
    // hanlde other errors and rollback transaction ...
    }
    }

    這時(shí),這段下單代碼總是能返回一個(gè)訂單(除非發(fā)生一些DB掛了之類的錯(cuò)誤),要么是新創(chuàng)建的,要么就是一個(gè)已經(jīng)存在的單。注意,最好在訂單里增加一個(gè)屬性(比如例子中用“duplicated”)來表示這個(gè)訂單是這次新生成的,還是因?yàn)閮绲榷苯臃祷氐?/strong>。這樣前端可以有針對(duì)性的對(duì)這兩種情況提示不同的文案。

    技術(shù)搞定冪等就足夠了嗎?

    上面的流程沒有考慮一種情況,就是用戶中途強(qiáng)制退出客戶端,或者直接點(diǎn)擊【返回】回到產(chǎn)品頁,重新走下單流程。這個(gè)時(shí)候客戶端就無法判斷用戶到底是想重新下單,還是想第二次下單。此時(shí),可以從產(chǎn)品設(shè)計(jì)上考慮一下。

    比如,在客戶端緩存一個(gè)表,記錄所有沒有確認(rèn)結(jié)果的訂單。

    產(chǎn)品代碼 產(chǎn)品數(shù)量 金額 dedup key 未確認(rèn)訂單1 AAA 1 1000 xxx-yyy-zzz 未確認(rèn)訂單2 BBB 2 500.00 Aaa-bbb-ccc ... 通過這個(gè)表,我們可以一下用戶的意圖。比如,如果用戶重新提交了一筆訂單,其產(chǎn)品代碼、金額與表中記錄的某條完全一致,就可以提示一下用戶:

    架構(gòu)成長(zhǎng)之路:分布式秒殺系統(tǒng)之如何防止單個(gè)用戶重復(fù)秒殺下單?

    提示一下用戶是不是下重了

    如果用戶想重試,可以繼續(xù)用表中對(duì)應(yīng)記錄的dedup key重新發(fā)起下單。

    這樣不是絕對(duì)準(zhǔn)確的,僅僅是盡量的減少用戶誤操作的可能性。當(dāng)然,在產(chǎn)品設(shè)計(jì)上可以能出于用戶交互簡(jiǎn)化,不一定真的會(huì)這樣做。這就需要其他機(jī)制來配合,比如“通知”。

    通知

    一旦服務(wù)器下單成功,可以通過某種通知機(jī)制(如APNS、Websocket)主動(dòng)將訂單推送至客戶端,強(qiáng)行讓客戶端重新拉取最新的訂單信息,并配合“未確認(rèn)訂單”表,以通知Badge/彈框等方式提示用戶剛剛一筆狀態(tài)未知的訂單成功/失敗了。

    另外一種手段就是,服務(wù)器端實(shí)時(shí)掃描用戶的下單數(shù)據(jù),一旦發(fā)現(xiàn)可能的重單,就立刻通知客服主動(dòng)聯(lián)系用戶,及時(shí)處理問題。

    如果還攔不住……

    經(jīng)過層層阻攔,可能還是會(huì)有用戶誤操作,直到收到兩份商品才發(fā)現(xiàn)下重了。此時(shí)就得依靠運(yùn)營(yíng)/客服的支持了。提供用戶申訴的手段,讓用戶提出哪些訂單是重復(fù)的,并且由銷售系統(tǒng)店家、商品提供者和買家三方共同根據(jù)用戶操作的記錄來協(xié)商如何處理。我們需要讓技術(shù)幫助讓這種人工處理的幾率盡量小。因?yàn)槊看翁幚矶紩?huì)耗費(fèi)較大的人工成本,和一些運(yùn)營(yíng)費(fèi)用(比如賠款、小禮品等等)。

    這么麻煩,有必要嗎?

    這要分業(yè)務(wù)場(chǎng)景,對(duì)于很多電商來講可能不是必要的。因?yàn)閺挠脩粝聠蔚接唵伪粚徍颂幚磉M(jìn)入到發(fā)貨階段需要一定的時(shí)間(可能是半小時(shí)~1小時(shí)),并且一定是支付成功后才會(huì)開始進(jìn)行下一步流程。在這個(gè)時(shí)間段,用戶大概率能從網(wǎng)絡(luò)錯(cuò)誤中恢復(fù)過來,自行區(qū)分是否下重了。配合客服主動(dòng)提示,會(huì)極大的降低出問題的概率。

    但是對(duì)于理財(cái)服務(wù)來說,這種去重就非常必要了。因?yàn)?/p>

    • “下單+支付”。用戶購(gòu)買理財(cái)往往是“下單+支付”一起執(zhí)行,不可以單獨(dú)下單/單獨(dú)支付
    • 用戶的入金可能很大。例如數(shù)萬,數(shù)十萬
    • 準(zhǔn)確性丟失。如果一旦下重了,有可能影響用戶的投資資金配置的準(zhǔn)確性。
    • 撤銷難。部分理財(cái)產(chǎn)品存在下單不可撤銷的問題;或者即便撤銷,資金也無法立刻回款。等到回款,可能這個(gè)購(gòu)入機(jī)會(huì)就錯(cuò)過去了。例如對(duì)于基金交易,錯(cuò)過1個(gè)交易日,價(jià)格就會(huì)發(fā)生變動(dòng)。

    基于這些特性,在理財(cái)產(chǎn)品中,就要竭盡全力的去重。

    結(jié)論

    以上所講是處理重復(fù)訂單問題的一般方法。你可以注意到,無論多么好的技術(shù),也不可能100%的攔截所有的可能性,必須依靠技術(shù)+產(chǎn)品設(shè)計(jì)+運(yùn)營(yíng)支持的綜合手段才能解決這類問題。

    另外,本文還沒涉及到關(guān)于訂單支付(支付也可能重復(fù)哦)帶來的進(jìn)一步的復(fù)雜性,也沒有討論在高并發(fā)情況下的性能優(yōu)化,僅僅討論下單本身的問題。所以可以想象一下現(xiàn)實(shí)中的交易業(yè)務(wù)比這里的說的要復(fù)雜得多。

    本文介紹的原理也不僅僅適用于防止下重復(fù)訂單,而是可以應(yīng)用到任何需要“創(chuàng)建一個(gè)不應(yīng)該重復(fù)資源”的場(chǎng)景,比如“向用戶發(fā)一條通知”,“觸發(fā)一次不能重復(fù)的批處理任務(wù)!

    本文為企業(yè)推廣,本網(wǎng)站不做任何建議,僅提供參考,作為信息展示!

    推薦閱讀:資訊中國(guó)

    網(wǎng)友評(píng)論
    請(qǐng)登錄后進(jìn)行評(píng)論| 0條評(píng)論

    請(qǐng)文明發(fā)言,還可以輸入140

    您的評(píng)論已經(jīng)發(fā)表成功,請(qǐng)等候?qū)徍?/p>

    小提示:您要為您發(fā)表的言論后果負(fù)責(zé),請(qǐng)各位遵守法紀(jì)注意語言文明

    回到首頁 回到頂部
    免責(zé)聲明:八方資訊網(wǎng)所有文字、圖片、視頻、音頻等資料均來自互聯(lián)網(wǎng),不代表本站贊同其觀點(diǎn),本站亦不為其版權(quán)負(fù)責(zé)。相關(guān)作品的原創(chuàng)性、文中陳述文字以及內(nèi)容數(shù)據(jù)龐雜本站無法一一核實(shí),如果您發(fā)現(xiàn)本網(wǎng)站上有侵犯您的合法權(quán)益的內(nèi)容,請(qǐng)聯(lián)系我們,本網(wǎng)站將立即予以刪除!
    Copyright © 2012-2019 http://www.quan28.cn, All rights reserved.
    主站蜘蛛池模板: 亚洲线精品一区二区三区 | 国产精品午睡沙发系列| 国产午夜精品久久久久九九| 9999国产精品欧美久久久久久| 九九99精品久久久久久| 亚洲中文久久精品无码| 精品视频久久久久| 久久精品一区二区国产| 欧洲精品久久久av无码电影| 巨大黑人极品VIDEOS精品| 日韩精品久久久久久| 99热亚洲色精品国产88| 亚洲AV无码成人精品区蜜桃| 无码精品人妻一区| 九九精品在线视频| 国产精品视频色视频| 午夜精品在线观看| 精品久久久久久久| 99re这里只有精品6| 精品一区二区三区在线成人| 色欲国产麻豆一精品一AV一免费 | 91麻豆精品国产| 久久er99热精品一区二区| 亚洲精品国产品国语在线| 欧美午夜精品一区二区三区91 | 99久久免费国产精品| 国产在线精品一区二区不卡| 97精品人妻系列无码人妻| 2020国产精品| 国产女人精品视频国产灰线| 欧美肥屁VIDEOSSEX精品| 亚洲AV无码久久精品狠狠爱浪潮| 亚洲精品字幕在线观看| 午夜精品射精入后重之免费观看| 亚洲精品乱码久久久久66| 亚洲午夜国产精品无码| 亚洲国产另类久久久精品| 无码精品A∨在线观看| 久久久一本精品99久久精品88| 国产精品自在线拍国产| 国产精品1024香蕉在线观看|