第七節 使用者商城搶單併發實戰(流量削峰實戰)

2021-09-19 19:15:00 字數 2618 閱讀 7507

資料庫有一張商品表,庫存量是100。現在有1000個消費者準備開搶這100個庫存。

t_product表維護商品編號與商品庫存剩餘數量。編號no123321的這種商品的庫存量有100個。

t_product_record維護搶到商品的使用者id。理論上t_product錶開搶後的 記錄數量應該是100條(共有100個人搶到了商品)。

我們使用執行緒池建立1000個執行緒,模擬一千個人同時開搶。 

構造的一千個執行緒,同時運算元據庫,可能將庫存表的total欄位變成負的。

在下面的實測過程中,發現了100庫存最終變成了-4,這是有問題的。

其中的核心原因是:在搶單方法中,既有讀資料庫操作,又有寫資料庫操作。a執行緒從資料庫查到的product的庫存數量是1,b執行緒同樣是查到了是1。結果兩個執行緒都執行了更新庫存減一的操作,那麼庫存量就變成了 -1 了。實際情況會更糟糕。

下面是有問題的**。

/**

* 搶單方法實現

** @param userid 搶單使用者id

*/@override

public void robbingproduct(int userid) 搶單成功", userid);

} else 搶單失敗", userid);}}

併發出現的問題,一般情況下,可以從sql角度**角度中介軟體角度來解決。

sql優化

在更新庫存的**後面,追加and total > 0 

追加的這個total大於0的條件非常重要。在mysql資料庫中,它會讓我們的t_product表的庫存total欄位,更新到0為止。

update t_product set total = total - 1 where productno = #

and total > 0

select * from `t_product` where productno = #

and total > 0

**優化

int updateresult = productdao.updateproduct(product_no);
在sql優化中,如果total>0條件不成立,也就是說庫存量total欄位的值已經到了0。

因此,當上述**的執行結果的返回值是0的時候,說明更新失敗,資料庫中total欄位已經為0,商品已經被搶光。

product product = productdao.selectproductbyno(product_no);

if (product != null && product.gettotal() > 0) 搶單成功", userid);

} else 搶單失敗", userid);

}} else 搶單失敗", userid);

}

優化後效果:

最後乙個問題是,如果併發量實在太大,會給我的應用程式帶來非常大的壓力。

首先因為頻繁建立物件,對我們的堆記憶體造成壓力。gc需要頻繁銷毀物件,對gc的壓力也很大。

其次對資料庫的壓力也很大。

解決辦法就是,把使用者的搶單請求傳送到rabbitmq訊息中介軟體中。因為rabbitmq是乙個訊息佇列,佇列會按照先進先出的特點進行操作。rabbitmq伺服器一般部署在另外乙個電腦上,所以就把這個併發壓力轉移到了另外電腦的rabbitmq伺服器上,而不是我們的搶單應用程式。

使用rabbitmq的最主要變化就是:以前搶單操作請求直接由我們搶單應用程式執行,現在請求被轉移到了rabbitmq伺服器中。rabbitmq伺服器把接收到的搶單請求進行排隊,最後由rabbitmq伺服器把搶單請求**到我們的搶單應用程式,這樣的好處就是避免我們的搶單應用程式短時間直接處理大量請求。rabbitmq伺服器主要作用是減緩搶單應用程式的併發壓力,相當於在我們的搶單程式之前加了一道請求緩衝區。

配置後的效果預覽

rabbitmq伺服器的整合,也可參考上一節:第六節 springboot整合rabbitmq綜合運用(ssm框架整合rabbitmq)

閱讀更多:從頭開始學rabbimtmq目錄貼

第七節 指標

go語言有指標這一概念。直接上 func pointtest 定義int型別的值a,並且賦值為3 定義int型別指標變數p,並且取a的位址賦值給p 輸出a和p 控制台 3 0xc00000a0a8 3 process finished with exit code 0 a的值為3,p為a在記憶體中的...

第七節 覆蓋虛介面

有時候我們需要表達一種抽象的東西,它是一些東西的概括,但我們又不能真正的看到它成為乙個實體在我們眼前出現,為此物件導向的程式語言便有了抽象類的概念。c 作為乙個物件導向的語言,必然也會引入抽象類這一概念。介面和抽象類使您可以建立元件互動的定義。通過介面,可以指定元件必須實現的方法,但不實際指定如何實...

第七節 結構體

1,下面程式是執行結果是?include include struct stu void fun struct stu p intmain1 fun students 1 system pause return0 2,喝汽水,1瓶汽水1元,2個空瓶可以換一瓶汽水,給20元,可以多少汽水 程式設計實現...