[原創]商城系統下單庫存管控系列雜記(一)(併發安全和性能基礎認識)

来源:http://www.cnblogs.com/bsfz/archive/2017/11/07/7801980.html
-Advertisement-
Play Games

前言 參與過幾個中小型商城系統的開發,隨著時間的增長,以及對系統的深入研究和測試,發現確實有很多值得推敲和商榷的地方(總有很多重要細節存在缺陷)。基於商城系統,無論規模大小,或者本身是否分佈架構,個人覺得最核心的一環就是下單模塊,而這裡面更相關和棘手的一些設計和問題,大多時候都涉及庫存系統。想想之... ...


商城系統下單庫存管控系列雜記(一)(併發安全和性能基礎認識)   前言   參與過幾個中小型商城系統的開發,隨著時間的增長,以及對系統的深入研究和測試,發現確實有很多值得推敲和商榷的地方(總有很多重要細節存在缺陷)。基於商城系統,無論規模大小,或者本身是否分佈架構,個人覺得最核心的一環就是下單模塊,而這裡面更相關和棘手的一些設計和問題,大多時候都涉及庫存系統。想想之前跟某人的交流,他一句“庫存管控做得好,系統設計就成功了一半”,自己頗有認同。圍繞這個點,結合目前經驗和朋友間的交流(包括近來參閱其他文章提到的點),閑來做些整理記錄,也許不太完整,但總歸希望能有更多啟發,自己往後也會重新揣摩。當然,文中若有不妥,歡迎指正。     正文   談及”下單“,就立刻想起前年參與的一個基於微信的小型商城系統,裡面下單這塊本身談不上複雜,大概可以這樣描述提交過程:用戶提交商品訂單,系統核對用戶提交的訂單,校驗商品(商品價格、優惠折扣、積分等),檢測附屬信息(地址運費等),一切Pass,操作庫存(記錄/預扣),生成訂單及相關聯的明細數據。此時下單Ok,那麼後續則是等待用戶的及時付款了。   然而,看似如此簡單的一個流程,放在併發環境下,就暴露了足夠多的問題。深入進去,首當其衝的就是庫存管控。包括但不限於庫存的扣減方式,如何安全操作,以及減少性能損耗等等。     一、簡單提一提通常的庫存扣除時機選擇:“下單減庫存”和“付款減庫存”   首先表明個人觀點,在大多數業務場景下,個人相對傾向前者——“下單減庫存”。後續大部分解決方案的論述,也都是以這個為主要前提展開。當然,針對去年參與的某微信商城系統(之後用“AutumnBing”作為項目代號),兩種是同時實現的 ——— 商戶可以在管理後臺,指定某商品的庫存扣減方式。   兩者在應用上的一些細節區別:   1.1  下單減庫存:   用戶下單時,後臺進行預扣庫存,當前用戶體驗不錯。但當前用戶若遲遲未付款,這種“弔單”就造成庫存浪費,影響商戶利益,同時也影響了其他用戶的需求購物(除非,能做好一定風控和庫存回滾,後續會有闡述,也是我更傾向的)。   1.2  付款減庫存:   用戶下單後過了幾秒,進行線上支付,結果付款成功了,卻發現庫存已經不足,導致購物失敗,嚴重影響購物體驗。同時,還要考慮扣款的回退造成更多複雜性(除非,允許一定超賣,或者庫存數量“不計” ,另外倘若是秒殺場景,則依然是無法應付)。     二、描述下非併發情況下,針對庫存預扣的(其中)一種抽象流程   2.1  用戶選擇 商品P * 數量N,並提交訂單,系統後臺核心API介面 如SubmitOrder,進行接收處理。   2.1.1 在SubmitOrder中,假定商品P的庫存足夠,將對應商品規格的庫存 -N。   2.1.2 在SubmitOrder中,倘若商品P的庫存已經不足夠,告知下單失敗及原因。   2.2 訂單付款設置有一定的時效,為M分鐘。   2.2.1   在M分鐘內,可以正常付款並流轉後續服務。   2.2.2 超過M分鐘,則當前訂單自動處理為過期(或者直接Close),並將商品P的庫存 +N,從而恢復庫存。   2.3 用戶取消訂單,類似2.2.2,直接將當前訂單狀態改為取消(或者直接Close),並將商品P的庫存 +N,從而恢復庫存。   2.4 用戶申請退款   2.4.1 未發貨,可以直接申請退款,同時將商品P的庫存 +N,從而恢復庫存(Tips:某些極少數現存項目里,存在發貨後才減庫存的設計,那麼無需補足,但這裡不對比論述,否則本流程也會相應調整,也非重點)。   2.4.2 已發貨,可以直接申請退款,但需要發回商品,等待相關處理(手動重新上架,或者補充商品P庫存)。     三、額外說明,在不考慮併發情況,庫存風險管控上的一些附屬問題   商品P若被大量下單,這些訂單中又存在相當大比例的未支付,此時商品P的庫存會被瞬間清空,必定就需要針對這塊的風控檢測。(PS:其實這不是本文闡述的主要方向,但最近剛好在其他平臺看到幾篇相關的文章中有簡單提到以下幾點,既然有一定的關聯性,本人就結合目前的想法,就儘量先拋出來,但不做過多延伸)。   3.1 商品P被同一用戶刻意反覆下單(非併發造成):   可採取在SubmitOrder之前,設置用戶限購以及關聯商品P的訂單待支付核查。同時提供備用的手動黑名單機制。   3.2 商品P被同一IP的多個用戶刷單:   這種情況,首先就有系統的分級檢測風控,譬如第一級是設置驗證碼(針對用戶),第二級是已購買檢測(類似3.1),第三級是庫存閾值報警通知(針對商家),第三級是黑名單攔截(程式攔截和手動攔截)等。其實這在“AutumnBing”項目里並未用到,而截止目前,本人身邊也只有一位朋友提到了相關實際應用,並且是相對簡單粗糙的實現,畢竟這塊程式上能做的只是輔助。   3.3 商品P被不同IP的用戶惡意下單:   比如某些競爭對手非法發起的有網路組織進行團體性惡意拍單,這種類似“DDOS”的洪流(條件類似)已經上升到了另外的高度上去了。除了結合上面的一些輔助手段,目前沒有見過或者聽過有效的處理方式。但值得一提的是,和DDOS場景本身不同的地方,如果這些用戶賬號不停下單,卻未履約,那麼會受到一些凍結處罰(配合時效),這會使得惡意攻擊的成本更高 。     四、闡述關於併發環境中庫存管控的一些案例問題,以及涉及到的相關技術實現細節   庫存扣減,簡單來說,就是在對應的存儲器中(資料庫或者持久緩存)將對應商品的數量減少。 資料庫設計時,一般包含但不限於 商品主表,商品規格表,商品庫存表,商品庫存流水日誌表等等。但這裡為了方便後續闡述,將其簡化為一張表——商品表(PT),該表僅包含兩個欄位——商品主鍵(id)和商品庫存(qty )。   依然以商品P舉例,其主鍵為pid,那麼就是在下單時,將歷史庫存S修改為 S -N。具體到SQL里,原始操作大概是這樣(以SQL SERVER 舉例): update PT set qty = (S - N) where id = pid ;   這是以前的最原始的操作方式,單粒度的看,也沒什麼大礙。然而,放在一個併發環境中,則立馬暴露出諸多問題。   假定在同一時刻,有兩個用戶提交了訂單,一樣的操作,一樣的商品,一樣的數量。那麼最終商品P的庫存數量應該為 S - N - N。而執行上面的SQL,因為併發,導致兩次查詢到歷史庫存均是S(應該至少有一次qty為S - N),則更新完畢後,商品數量最終是 S - N。這種致命性的Bug,也屬於超賣(雖然不會扣為負數),如果放線上上,簡直是一個定時炸彈。   圍繞解決這樣的問題,考慮到併發安全以及併發性能,產生了各種解決方案。大體基於兩種機制:悲觀鎖和樂觀鎖。在諸多場景里,基於每種鎖,都有配套的輔助手段,以及各自不同的側重取捨和相關實現。     考慮到本篇更主要的是做一些基礎鋪墊,也可為對於電商系統不太瞭解的朋友做一些相關引導,第一篇 ,暫告一段落。第二篇 —— 商城系統下單庫存管控系列雜記(二) ,本人將找個專門的時間寫,可能會篇幅上長很多,內容上緊接第四點,將會談及較多的重要細節,以及相關應用實現,到時再進行具體延伸,以及其他擴展討論。     End.    
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • vim 插入模式 a 游標後 A 行尾 o 游標所在行下一行 O 游標所在行上一行 i 游標前 I 行首 s 刪除游標所在位置的字元併進入插入模式 命令模式 d 刪除 dd 刪除當前行 dgg 刪除游標到文檔首 dG 刪除游標到文檔尾部 d$ 刪除游標到行尾,包括游標所在位置字元 d^ 刪除游標到行 ...
  • 1.使用xshell連接虛擬機,也可直接在虛擬機中敲命令。 以下是xshell上的命令: 首先安裝HTTPD包 [root@one ~]# mount /dev/sr0 /mnt[root@one ~]# yum install httpd重啟服務查看靜態 [root@one ~]# systemc ...
  • 本文將通過場景例子演示,來通俗易懂的講解在複雜的業務邏輯下,如何以最簡練的代碼,最直觀的編寫事務代碼。 通過一系列優化最終達到兩個效果,1.通過代碼塊來控制事務(分散式事務),2.通過委托優化TransactionScope的編碼寫法。 本文需要的知識點:1. Action委托 2. 分散式事務Tr ...
  • 在ABP官網創建一個.Net Core項目編譯完成 1、 發佈網站 2、 IIS新建站點 目錄指向發佈的目錄 3、安裝WindowsHosting IIS安裝伺服器上安裝DotNetCore.X.X.X-WindowsHosting安裝成功後重啟IIS伺服器。根據版本選擇下載 下載地址:https: ...
  • 一、設計目的:讓項目中只顯示一個實例對象 二、設計步驟: 三、項目相關名詞或知識點解釋 此處類類型:如果當前類為SingleCase,則此靜態變數類型也要為SingleCase類型, 即在此處定義的靜態變數的類型要和這個當前類的類型相同 定義單例實例變數時,儘量都用instance(實例)來指代,方 ...
  • 近乎產品的數據訪問是基於輕量級ORM——PetaPoco,哪怕是他們最新的5.2版本也是基於PetaPoco。至於為什麼沒有選用EF這些ORM,感興趣的可以去咨詢他們的產品人員,本文就不詳細說明瞭。 關於近乎源碼下載:www.jinhusns.com ...
  • Asp.Net Web API不可以需要IIS。可以自己在主機上承載一個Web API 創建WebAPI.Server項目 創建一個控制器項目的服務端 在Nuget中添加Microsoft.AspNet.WebApi.SelfHost 創建Model與Controller 首先在服務端添加一個Pro ...
  • 前兩天做一個項目的時候,由於頁面沒有限制TextBox的輸入長度,所以,後臺直接報錯了,超出資料庫最大的長度。 資料庫的長度是按照位元組來計算的,而且不同的編碼格式,漢字占用的位元組長度又不相同,比如,我們用的是UTF8,一個漢字是3個位元組,而預設的Default,一個漢字是2個位元組。 TextBox有 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...