日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何解决秒杀的性能问题和超卖的讨论 及防止按钮多次点击

發(fā)布時間:2025/3/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何解决秒杀的性能问题和超卖的讨论 及防止按钮多次点击 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

搶購活動一般會經(jīng)過【預(yù)約】【搶訂單】【支付】這3個大環(huán)節(jié),而其中【搶訂單】這個環(huán)節(jié)是最考驗業(yè)務(wù)提供方的抗壓能力的。

搶訂單環(huán)節(jié)一般會帶來2個問題:

  1、高并發(fā)

  比較火熱的秒殺在線人數(shù)都是10w起的,如此之高的在線人數(shù)對于網(wǎng)站架構(gòu)從前到后都是一種考驗。

  2、超賣

  任何商品都會有數(shù)量上限,如何避免成功下訂單買到商品的人數(shù)不超過商品數(shù)量的上限,這是每個搶購活動都要面臨的難題。

?

二、如何解決?


?

首先,產(chǎn)品解決方案我們就不予討論了。我們只討論技術(shù)解決方案

1、前端

面對高并發(fā)的搶購活動,前端常用的三板斧是【擴容】【靜態(tài)化】【限流】

  A:擴容

  加機器,這是最簡單的方法,通過增加前端池的整體承載量來抗峰值。

  B:靜態(tài)化

  將活動頁面上的所有可以靜態(tài)的元素全部靜態(tài)化,并盡量減少動態(tài)元素。通過CDN來抗峰值。

  C:限流

  一般都會采用IP級別的限流,即針對某一個IP,限制單位時間內(nèi)發(fā)起請求數(shù)量。

  或者活動入口的時候增加游戲或者問題環(huán)節(jié)進行消峰操作。

  D:有損服務(wù)

  最后一招,在接近前端池承載能力的水位上限的時候,隨機拒絕部分請求來保護活動整體的可用性。

?

2、后端

那么后端的數(shù)據(jù)庫在高并發(fā)和超賣下會遇到什么問題呢?主要會有如下3個問題:(主要討論寫的問題,讀的問題通過增加cache可以很容易的解決)

  I: 首先MySQL自身對于高并發(fā)的處理性能就會出現(xiàn)問題,一般來說,MySQL的處理性能會隨著并發(fā)thread上升而上升,但是到了一定的并發(fā)度之后會出現(xiàn)明顯的拐點,之后一路下降,最終甚至?xí)葐蝨hread的性能還要差。

  II:?其次,超賣的根結(jié)在于減庫存操作是一個事務(wù)操作,需要先select,然后insert,最后update -1。最后這個-1操作是不能出現(xiàn)負數(shù)的,但是當(dāng)多用戶在有庫存的情況下并發(fā)操作,出現(xiàn)負數(shù)這是無法避免的。

  III:最后,當(dāng)減庫存和高并發(fā)碰到一起的時候,由于操作的庫存數(shù)目在同一行,就會出現(xiàn)爭搶InnoDB行鎖的問題,導(dǎo)致出現(xiàn)互相等待甚至死鎖,從而大大降低MySQL的處理性能,最終導(dǎo)致前端頁面出現(xiàn)超時異常。

?

針對上述問題,如何解決呢? 我們先看眼淘寶的高大上解決方案:

  I: ?關(guān)閉死鎖檢測,提高并發(fā)處理性能。

  II:修改源代碼,將排隊提到進入引擎層前,降低引擎層面的并發(fā)度。

  III:組提交,降低server和引擎的交互次數(shù),降低IO消耗。

以上內(nèi)容可以參考丁奇在DTCC2013上分享的《秒殺場景下MySQL的低效》一文。在文中所有優(yōu)化都使用后,TPS在高并發(fā)下,從原始的150飆升到8.5w,提升近566倍,非常嚇人!!!

?

不過結(jié)合我們的實際,改源碼這種高大上的解決方案顯然有那么一點不切實際。于是小伙伴們需要討論出一種適合我們實際情況的解決方案。以下就是我們討論的解決方案:

首先設(shè)定一個前提,為了防止超賣現(xiàn)象,所有減庫存操作都需要進行一次減后檢查,保證減完不能等于負數(shù)。(由于MySQL事務(wù)的特性,這種方法只能降低超賣的數(shù)量,但是不可能完全避免超賣)

update number set x=x-1 where (x -1 ) >= 0;

?

解決方案1:

將存庫從MySQL前移到Redis中,所有的寫操作放到內(nèi)存中,由于Redis中不存在鎖故不會出現(xiàn)互相等待,并且由于Redis的寫性能和讀性能都遠高于MySQL,這就解決了高并發(fā)下的性能問題。然后通過隊列等異步手段,將變化的數(shù)據(jù)異步寫入到DB中。

優(yōu)點:解決性能問題

缺點:沒有解決超賣問題,同時由于異步寫入DB,存在某一時刻DB和Redis中數(shù)據(jù)不一致的風(fēng)險。

?

解決方案2:

引入隊列,然后將所有寫DB操作在單隊列中排隊,完全串行處理。當(dāng)達到庫存閥值的時候就不在消費隊列,并關(guān)閉購買功能。這就解決了超賣問題。

優(yōu)點:解決超賣問題,略微提升性能。

缺點:性能受限于隊列處理機處理性能和DB的寫入性能中最短的那個,另外多商品同時搶購的時候需要準(zhǔn)備多條隊列。

?

解決方案3:

將寫操作前移到MC中,同時利用MC的輕量級的鎖機制CAS來實現(xiàn)減庫存操作。

優(yōu)點:讀寫在內(nèi)存中,操作性能快,引入輕量級鎖之后可以保證同一時刻只有一個寫入成功,解決減庫存問題。

缺點:沒有實測,基于CAS的特性不知道高并發(fā)下是否會出現(xiàn)大量更新失敗?不過加鎖之后肯定對并發(fā)性能會有影響。

?

解決方案4:

將提交操作變成兩段式,先申請后確認。然后利用Redis的原子自增操作(相比較MySQL的自增來說沒有空洞),同時利用Redis的事務(wù)特性來發(fā)號,保證拿到小于等于庫存閥值的號的人都可以成功提交訂單。然后數(shù)據(jù)異步更新到DB中。

優(yōu)點:解決超賣問題,庫存讀寫都在內(nèi)存中,故同時解決性能問題。

缺點:由于異步寫入DB,可能存在數(shù)據(jù)不一致。另可能存在少買,也就是如果拿到號的人不真正下訂單,可能庫存減為0,但是訂單數(shù)并沒有達到庫存閥值。

?

三、總結(jié)


?

1、前端三板斧【擴容】【限流】【靜態(tài)化】

2、后端兩條路【內(nèi)存】+【排隊】

?

防止按鈕多次點擊

?

var nn = 0; var tipId; //打印小票調(diào)自動打印 function OrderbyHands() {nn = 10;if (nn === 10) {startPrint();tipId = setInterval("changebtntxt()", 1000); //每隔1秒調(diào)用一次changebtntxt()方法 } } function changebtntxt() {if (nn > 0) {var vv = " 打印小票 (" + nn + ")";$("#btnOrderPrint").prop("disabled", "disabled"); //使按鈕不能被點擊$("#btnOrderPrint").text(vv); //更改按鈕上的文字nn--;}if (nn === 0) {console.info("tipId", tipId);$("#btnOrderPrint").removeAttr("disabled"); //使按鈕能夠被點擊$("#btnOrderPrint").text(" 打印小票 "); //更改按鈕上的文字clearInterval(tipId); //清除循環(huán)事件 }}function startPrint() {var rows = grid_order.getSelecteds();var OrderIds = [];for (var i = 0; i < rows.length; i++) {OrderIds.push(rows[i]["OrderId"]);}if (OrderIds.length == 0) {modal.dangerAlert("請選擇單據(jù)!");return;}if (OrderIds.length > 20) {modal.dangerAlert("一次勾選單據(jù)不能超過20單!");return;}var pendingRequests = {};jQuery.ajaxPrefilter(function (options, originalOptions, jqXHR) {var key = options.url;console.log(key);if (!pendingRequests[key]) {pendingRequests[key] = jqXHR;} else {jqXHR.abort(); //放棄后觸發(fā)的提交//pendingRequests[key].abort(); // 放棄先觸發(fā)的提交 }var complete = options.complete;options.complete = function (jqXHR, textStatus) {pendingRequests[key] = null;if (jQuery.isFunction(complete)) {complete.apply(this, arguments);}};});$.ajax({type: "POST",url: "/Print/GetOrderByHands",datatype: "Json",data: { OrderIds: OrderIds },success: function (data) {if (data.IsSuccess) {orderPrintbyHands(data.Data.PrintOrders);} else {modal.dangerAlert(data.Message);}},error: function (data) {modal.dangerAlert(data.responseText);}}); }

?

參考

http://www.cnblogs.com/yc-755909659/p/3591758.html
http://www.hollischuang.com/archives/931

?

總結(jié)

以上是生活随笔為你收集整理的如何解决秒杀的性能问题和超卖的讨论 及防止按钮多次点击的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。