首頁(yè)技術(shù)文章正文

java高并發(fā):如何解決秒殺的高并發(fā)?[java培訓(xùn)]

更新時(shí)間:2020-03-15 來(lái)源:黑馬程序員 瀏覽量:

一、什么是高并發(fā)

高并發(fā)(High Concurrency)是互聯(lián)網(wǎng)分布式系統(tǒng)架構(gòu)設(shè)計(jì)中必須考慮的因素之一,它通常是指,通過(guò)設(shè)計(jì)保證系統(tǒng)能夠同時(shí)并行處理很多請(qǐng)求。高并發(fā)相關(guān)常用的一些指標(biāo)有響應(yīng)時(shí)間(Response Time),吞吐量(Throughput),每秒查詢率QPS(Query Per Second),并發(fā)用戶數(shù)等。推薦了解黑馬程序員java培訓(xùn)課程

響應(yīng)時(shí)間:系統(tǒng)對(duì)請(qǐng)求做出響應(yīng)的時(shí)間。例如系統(tǒng)處理一個(gè)HTTP請(qǐng)求需要200ms,這個(gè)200ms就是系統(tǒng)的響應(yīng)時(shí)間。

吞吐量:?jiǎn)挝粫r(shí)間內(nèi)處理的請(qǐng)求數(shù)量。

QPS:每秒響應(yīng)請(qǐng)求數(shù)。在互聯(lián)網(wǎng)領(lǐng)域,這個(gè)指標(biāo)和吞吐量區(qū)分的沒(méi)有這么明顯。

并發(fā)用戶數(shù):同時(shí)承載正常使用系統(tǒng)功能的用戶數(shù)量。例如一個(gè)即時(shí)通訊系統(tǒng),同時(shí)在線量一定程度上代表了系統(tǒng)的并發(fā)用戶數(shù)。

二、什么是秒殺

秒殺場(chǎng)景一般會(huì)在電商網(wǎng)站舉行一些活動(dòng)或者節(jié)假日在12306網(wǎng)站上搶票時(shí)遇到。對(duì)于電商網(wǎng)站中一些稀缺或者特價(jià)商品,電商網(wǎng)站一般會(huì)在約定時(shí)間點(diǎn)對(duì)其進(jìn)行限量銷售,因?yàn)檫@些商品的特殊性,會(huì)吸引大量用戶前來(lái)?yè)屬?gòu),并且會(huì)在約定的時(shí)間點(diǎn)同時(shí)在秒殺頁(yè)面進(jìn)行搶購(gòu)。

此種場(chǎng)景就是非常有特點(diǎn)的高并發(fā)場(chǎng)景,如果不對(duì)流量進(jìn)行合理管控,肆意放任大流量沖擊系統(tǒng),那么將導(dǎo)致一系列的問(wèn)題出現(xiàn),比如一些可用的連接資源被耗盡、分布式緩存的容量被撐爆、數(shù)據(jù)庫(kù)吞吐量降低,最終必然會(huì)導(dǎo)致系統(tǒng)產(chǎn)生雪崩效應(yīng)。

一般來(lái)說(shuō),大型互聯(lián)網(wǎng)站通常采用的做法是通過(guò)擴(kuò)容、動(dòng)靜分離、緩存、服務(wù)降級(jí)及限流五種常規(guī)手段來(lái)保護(hù)系統(tǒng)的穩(wěn)定運(yùn)行。

三、如何解決秒殺的高并發(fā)

1. 限流

在討論為什么需要限流之前,我們先聊一聊生活中那些隨處可見(jiàn)的限流場(chǎng)景。

例如上下班高峰期,大量人群涌入地鐵站,會(huì)造成嚴(yán)重?fù)矶?,原本從站廳到站臺(tái)最多只需花費(fèi)5分鐘左右的時(shí)間,卻在被限流管制下被迫花費(fèi)30分鐘或更久才能順利進(jìn)入站臺(tái)。

java高并發(fā)解決方案01

java高并發(fā)解決方案02


上面兩張圖片就展示了地鐵擁擠的場(chǎng)景,如果這所有的人全部涌入站臺(tái),那么會(huì)造成更多的人無(wú)法上車,所以采取了管制之后,我們可以讓人們通過(guò)地面和站廳層的雙重排隊(duì)等待,減輕站臺(tái)的壓力,保證每一位乘客最終都能順利的上車。

在電商系統(tǒng)的秒殺中,也會(huì)有大批量的用戶同時(shí)涌入,鑒于只有少部分用戶能夠秒殺成功,所以要限制大部分流量,只允許少部分流量進(jìn)入服務(wù)后端。

限流可以采用限制服務(wù)器的連接等待數(shù)量以及等待時(shí)間,每次只放行少量用戶,讓更多的用戶處于假排隊(duì)的狀態(tài)。

例如tomcat的配置:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxThreads="800" acceptCount="1000"/>

其中最后兩個(gè)參數(shù)意義如下:

maxThreads:tomcat起動(dòng)的最大線程數(shù),即同時(shí)處理的任務(wù)個(gè)數(shù),默認(rèn)值為200

acceptCount:當(dāng)tomcat起動(dòng)的線程數(shù)達(dá)到最大時(shí),接受排隊(duì)的請(qǐng)求個(gè)數(shù),默認(rèn)值為100

這兩個(gè)值如何起作用,請(qǐng)看下面三種情況

情況1:接受一個(gè)請(qǐng)求,此時(shí)tomcat起動(dòng)的線程數(shù)沒(méi)有到達(dá)maxThreads,tomcat會(huì)起動(dòng)一個(gè)線程來(lái)處理此請(qǐng)求。

情況2:接受一個(gè)請(qǐng)求,此時(shí)tomcat起動(dòng)的線程數(shù)已經(jīng)到達(dá)maxThreads,tomcat會(huì)把此請(qǐng)求放入等待隊(duì)列,等待空閑線程。

情況3:接受一個(gè)請(qǐng)求,此時(shí)tomcat起動(dòng)的線程數(shù)已經(jīng)到達(dá)maxThreads,等待隊(duì)列中的請(qǐng)求個(gè)數(shù)也達(dá)到了acceptCount,此時(shí)tomcat會(huì)直接拒絕此次請(qǐng)求,返回connection refused。

2. 頁(yè)面靜態(tài)化

首先我們可以使用Freemarker對(duì)頁(yè)面進(jìn)行靜態(tài)化,讓用戶減少跟后端服務(wù)器之間的交互。這樣就能降低服務(wù)器的壓力,如果條件允許我們可以采用CDN加速。

Freemarker的原理如下圖,模板+數(shù)據(jù)通過(guò)Freemarker可以生成靜態(tài)頁(yè)面。

java高并發(fā)解決方案03


CDN是將源站內(nèi)容分發(fā)至最接近用戶的節(jié)點(diǎn),使用戶可就近取得所需內(nèi)容,提高用戶訪問(wèn)的響應(yīng)速度和成功率。

例如下圖:北京網(wǎng)民會(huì)自動(dòng)訪問(wèn)到離自己最近并且速度最快的服務(wù)器的資源。

java高并發(fā)解決方案04

3. 引入Redis

限流和靜態(tài)化都是為了減輕服務(wù)器后端的壓力,但是最終用戶的請(qǐng)求還是會(huì)落到服務(wù)器中,為了增加用戶的體驗(yàn)度,我們也應(yīng)加快相應(yīng)速度。后端代碼和數(shù)據(jù)庫(kù)之間的交互會(huì)降低相應(yīng)速度,所以我們可以采用Redis來(lái)進(jìn)行數(shù)據(jù)的高速讀取。

Redis是一款極其優(yōu)秀的內(nèi)存級(jí)別的NoSql數(shù)據(jù)庫(kù),單線程下讀寫速度能達(dá)到5w/s。所以我們?cè)诤芏嗲闆r下都能利用Redis去解決高速讀取的問(wèn)題。

特別是庫(kù)存量的超賣現(xiàn)象,我們可以在開始秒殺的時(shí)候,把總的庫(kù)存量存入Redis中,每當(dāng)用戶來(lái)?yè)屬?gòu)時(shí),利用String類型的decr方法去減一,如果減一成功就視認(rèn)為搶夠成功,并把用戶和商品信息存入Redis的訂單條目中,當(dāng)最終搶購(gòu)結(jié)束時(shí),我們?cè)僖徊裄edis的訂單信息存入到數(shù)據(jù)庫(kù)中。

代碼參考:

# 設(shè)置總的待搶購(gòu)數(shù)量為1000000
set amount 1000000;
# 搶購(gòu) 數(shù)量減一
decr amount
# 把用戶信息存入到搶購(gòu)成功的集合中,由商品ID命名來(lái)區(qū)分
lpush 用戶ID 商品ID

四、總結(jié)

通過(guò)上述3種方案可以解決大部分場(chǎng)景下的秒殺問(wèn)題,當(dāng)然高并發(fā)下也會(huì)出現(xiàn)更多的意外的狀況,那么我們可以針對(duì)自己的業(yè)務(wù),資源的調(diào)度進(jìn)行更多方位的嘗試,找到最適合自己的解決方案。

猜你喜歡:
Java進(jìn)階之JVM垃圾回收機(jī)制視頻教程

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!