• 八方資訊網歡迎您!
    八方資訊網>科技>正文

    架構成長之路:分布式秒殺系統之如何防止單個用戶重復秒殺下單?!

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

    電子交易的一個很基本的問題,就是避免用戶下重復訂單。用戶明明想買一次,結果一看下了兩個單。如果沒有及時發現,就會帶來額外的物流成本和扯皮。對商家的信譽也不好看。

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

    為啥會下重了呢?

    原因1:客戶端bug

    比如下單的按鍵在點按之后,在沒有收到服務器請求之前,按鍵的狀態沒有設為已禁用狀態,還可以被按。又或者,在觸摸屏下,用戶手指的點按可能被手機操作系統識別為多次點擊。

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

    原因2: 超時

    用戶的設備與服務器之間可能是不穩定的網路。這樣一個下單請求過去,返回不一定回得來。超時最大的問題是: 從用戶的角度,他無法確定下單的請求是還沒到服務器,還是已經到了服務器但是返回丟失了。——用戶無法區分到底這個單下了還是沒下

    這樣在等待一個超時后,UI可能會提示用戶下單超時,請重復再試。

    架構成長之路:分布式秒殺系統之如何防止單個用戶重復秒殺下單?

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

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

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

    用冪等防止重復訂單

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

    客戶端的流程

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

    架構成長之路:分布式秒殺系統之如何防止單個用戶重復秒殺下單?

    下單的客戶端流程

    后端數據表設計

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

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

    下單的實現

    在實現下單邏輯時,基于該dedup_key實現一個"create-or-get"語義的下單接口——簡單說就是

    如果帶有指定dedup_key的訂單已經存在,則直接返回;否則,用該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 ...
    }
    }

    這時,這段下單代碼總是能返回一個訂單(除非發生一些DB掛了之類的錯誤),要么是新創建的,要么就是一個已經存在的單。注意,最好在訂單里增加一個屬性(比如例子中用“duplicated”)來表示這個訂單是這次新生成的,還是因為冪等而直接返回的。這樣前端可以有針對性的對這兩種情況提示不同的文案。

    技術搞定冪等就足夠了嗎?

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

    比如,在客戶端緩存一個表,記錄所有沒有確認結果的訂單。

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

    架構成長之路:分布式秒殺系統之如何防止單個用戶重復秒殺下單?

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

    如果用戶想重試,可以繼續用表中對應記錄的dedup key重新發起下單。

    這樣不是絕對準確的,僅僅是盡量的減少用戶誤操作的可能性。當然,在產品設計上可以能出于用戶交互簡化,不一定真的會這樣做。這就需要其他機制來配合,比如“通知”。

    通知

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

    另外一種手段就是,服務器端實時掃描用戶的下單數據,一旦發現可能的重單,就立刻通知客服主動聯系用戶,及時處理問題。

    如果還攔不住……

    經過層層阻攔,可能還是會有用戶誤操作,直到收到兩份商品才發現下重了。此時就得依靠運營/客服的支持了。提供用戶申訴的手段,讓用戶提出哪些訂單是重復的,并且由銷售系統店家、商品提供者和買家三方共同根據用戶操作的記錄來協商如何處理。我們需要讓技術幫助讓這種人工處理的幾率盡量小。因為每次處理都會耗費較大的人工成本,和一些運營費用(比如賠款、小禮品等等)。

    這么麻煩,有必要嗎?

    這要分業務場景,對于很多電商來講可能不是必要的。因為從用戶下單到訂單被審核處理進入到發貨階段需要一定的時間(可能是半小時~1小時),并且一定是支付成功后才會開始進行下一步流程。在這個時間段,用戶大概率能從網絡錯誤中恢復過來,自行區分是否下重了。配合客服主動提示,會極大的降低出問題的概率。

    但是對于理財服務來說,這種去重就非常必要了。因為

    • “下單+支付”。用戶購買理財往往是“下單+支付”一起執行,不可以單獨下單/單獨支付
    • 用戶的入金可能很大。例如數萬,數十萬
    • 準確性丟失。如果一旦下重了,有可能影響用戶的投資資金配置的準確性。
    • 撤銷難。部分理財產品存在下單不可撤銷的問題;或者即便撤銷,資金也無法立刻回款。等到回款,可能這個購入機會就錯過去了。例如對于基金交易,錯過1個交易日,價格就會發生變動。

    基于這些特性,在理財產品中,就要竭盡全力的去重。

    結論

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

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

    本文介紹的原理也不僅僅適用于防止下重復訂單,而是可以應用到任何需要“創建一個不應該重復資源”的場景,比如“向用戶發一條通知”,“觸發一次不能重復的批處理任務!

    本文為企業推廣,本網站不做任何建議,僅提供參考,作為信息展示!

    推薦閱讀:資訊中國

    網友評論
    請登錄后進行評論| 0條評論

    請文明發言,還可以輸入140

    您的評論已經發表成功,請等候審核

    小提示:您要為您發表的言論后果負責,請各位遵守法紀注意語言文明

    回到首頁 回到頂部
    八方資訊網 關于我們| 聯系我們| 招聘信息| XML地圖| 網站地圖TXT
    免責聲明:八方資訊網所有文字、圖片、視頻、音頻等資料均來自互聯網,不代表本站贊同其觀點,本站亦不為其版權負責。相關作品的原創性、文中陳述文字以及內容數據龐雜本站無法一一核實,如果您發現本網站上有侵犯您的合法權益的內容,請聯系我們,本網站將立即予以刪除!
    Copyright © 2012-2019 http://www.quan28.cn, All rights reserved.
    主站蜘蛛池模板: 国产精品免费αv视频| 久久91精品久久91综合| 99视频在线观看精品| 久久国产精品一区| 亚洲国产精品久久久久| 精品一区二区三区免费毛片爱| 好湿好大硬得深一点动态图91精品福利一区二区 | 人人妻人人澡人人爽人人精品| 久99久无码精品视频免费播放| 久久久九九有精品国产| 精品调教CHINESEGAY| 亚洲国产精品人人做人人爱| 精品国产91久久久久久久a| 亚洲国产成人久久精品动漫| 91探花福利精品国产自产在线| 亚洲精品无码久久久久去q| 欧美ppypp精品一区二区| 国产精品女同一区二区久久| 91精品国产自产在线观看| 国产精品一区二区久久| 国产a∨精品一区二区三区不卡| 色久综合网精品一区二区| 一本久久精品一区二区| 四虎国产精品永免费| 久久乐国产精品亚洲综合| 国产一区二区精品尤物| 国产精品久久久久久久午夜片| 亚洲国产精品久久久久| 四虎精品影院永久在线播放| 丝袜美腿国产精品视频一区 | 亚洲国产精品成人午夜在线观看| 国产在线精品一区二区夜色| 国产精品永久久久久久久久久| 国产精品丝袜久久久久久不卡| 国产高清日韩精品欧美激情| 国产精品videossex白浆| 99在线精品免费视频| 亚洲精品高清国产一久久| 91嫩草亚洲精品| 精品乱码久久久久久久| 日韩精品无码专区免费播放|