日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
秒殺系統(tǒng)的架構(gòu)(Golang 實現(xiàn))

12306搶票,極限并發(fā)帶來的思考?

每到節(jié)假日期間,一二線城市返鄉(xiāng)、外出游玩的人們幾乎都面臨著一個問題:搶火車票!雖然現(xiàn)在大多數(shù)情況下都能訂到票,但是放票瞬間即無票的場景,相信大家都深有體會。

尤其是春節(jié)期間,大家不僅使用12306,還會考慮“智行”和其他的搶票軟件,全國上下幾億人在這段時間都在搶票。

“12306服務(wù)”承受著這個世界上任何秒殺系統(tǒng)都無法超越的QPS,上百萬的并發(fā)再正常不過了!筆者專門研究了一下“12306”的服務(wù)端架構(gòu),學(xué)習(xí)到了其系統(tǒng)設(shè)計上很多亮點,在這里和大家分享一下并模擬一個例子:如何在100萬人同時搶1萬張火車票時,系統(tǒng)提供正常、穩(wěn)定的服務(wù)。

一. 大型高并發(fā)系統(tǒng)架構(gòu)

高并發(fā)的系統(tǒng)架構(gòu)都會采用分布式集群部署,服務(wù)上層有著層層負(fù)載均衡,并提供各種容災(zāi)手段(雙火機(jī)房、節(jié)點容錯、服務(wù)器災(zāi)備等)保證系統(tǒng)的高可用,流量也會根據(jù)不同的負(fù)載能力和配置策略均衡到不同的服務(wù)器上。下邊是一個簡單的示意圖:

1.1 負(fù)載均衡簡介

上圖中描述了用戶請求到服務(wù)器經(jīng)歷了三層的負(fù)載均衡,下邊分別簡單介紹一下這三種負(fù)載均衡:

  • OSPF(開放式最短鏈路優(yōu)先)是一個內(nèi)部網(wǎng)關(guān)協(xié)議(Interior Gateway Protocol,簡稱IGP)。OSPF通過路由器之間通告網(wǎng)絡(luò)接口的狀態(tài)來建立鏈路狀態(tài)數(shù)據(jù)庫,生成最短路徑樹,OSPF會自動計算路由接口上的Cost值,但也可以通過手工指定該接口的Cost值,手工指定的優(yōu)先于自動計算的值。OSPF計算的Cost,同樣是和接口帶寬成反比,帶寬越高,Cost值越小。到達(dá)目標(biāo)相同Cost值的路徑,可以執(zhí)行負(fù)載均衡,最多6條鏈路同時執(zhí)行負(fù)載均衡。
  • LVS (Linux VirtualServer),它是一種集群(Cluster)技術(shù),采用IP負(fù)載均衡技術(shù)和基于內(nèi)容請求分發(fā)技術(shù)。調(diào)度器具有很好的吞吐率,將請求均衡地轉(zhuǎn)移到不同的服務(wù)器上執(zhí)行,且調(diào)度器自動屏蔽掉服務(wù)器的故障,從而將一組服務(wù)器構(gòu)成一個高性能的、高可用的虛擬服務(wù)器。
  • Nginx想必大家都很熟悉了,是一款非常高性能的http代理/反向代理服務(wù)器,服務(wù)開發(fā)中也經(jīng)常使用它來做負(fù)載均衡。Nginx實現(xiàn)負(fù)載均衡的方式主要有三種:輪詢、加權(quán)輪詢、ip hash輪詢,下面我們就針對Nginx的加權(quán)輪詢做專門的配置和測試

1.2 Nginx加權(quán)輪詢的演示

Nginx實現(xiàn)負(fù)載均衡通過upstream模塊實現(xiàn),其中加權(quán)輪詢的配置是可以給相關(guān)的服務(wù)加上一個權(quán)重值,配置的時候可能根據(jù)服務(wù)器的性能、負(fù)載能力設(shè)置相應(yīng)的負(fù)載。

下面是一個加權(quán)輪詢負(fù)載的配置,我將在本地的監(jiān)聽3001-3004端口,分別配置1,2,3,4的權(quán)重:

#配置負(fù)載均衡
upstream load_rule {
server 127.0.0.1:3001 weight=1;
server 127.0.0.1:3002 weight=2;
server 127.0.0.1:3003 weight=3;
server 127.0.0.1:3004 weight=4;
}
...
server {
listen 80;
server_name load_balance.com www.load_balance.com;
location / {
proxy_pass http://load_rule;
}
}

我在本地/etc/hosts目錄下配置了 www.load_balance.com的虛擬域名地址,接下來使用Go語言開啟四個http端口監(jiān)聽服務(wù),下面是監(jiān)聽在3001端口的Go程序,其他幾個只需要修改端口即可:

package mainimport (  "net/http"
"os"
"strings")func main() {
http.HandleFunc("/buy/ticket", handleReq)
http.ListenAndServe(":3001", nil)
}//處理請求函數(shù),根據(jù)請求將響應(yīng)結(jié)果信息寫入日志func handleReq(w http.ResponseWriter, r *http.Request) {
failedMsg := "handle in port:"
writeLog(failedMsg, "./stat.log")
}//寫入日志func writeLog(msg string, logPath string) {
fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) defer fd.Close()
content := strings.Join([]string{msg, "\r\n"}, "3001")
buf := []byte(content)
fd.Write(buf)
}

我將請求的端口日志信息寫到了./stat.log文件當(dāng)中,然后使用ab壓測工具做壓測:

ab -n 1000 -c 100 http://www.load_balance.com/buy/ticket

統(tǒng)計日志中的結(jié)果,3001-3004端口分別得到了100、200、300、400的請求量,這和我在nginx中配置的權(quán)重占比很好的吻合在了一起,并且負(fù)載后的流量非常的均勻、隨機(jī)。具體的實現(xiàn)大家可以參考nginx的upsteam模塊實現(xiàn)源碼,這里推薦一篇文章:Nginx 中 upstream 機(jī)制的負(fù)載均衡

https://www.kancloud.cn/digest/understandingnginx/202607

二.秒殺搶購系統(tǒng)選型

回到我們最初提到的問題中來:火車票秒殺系統(tǒng)如何在高并發(fā)情況下提供正常、穩(wěn)定的服務(wù)呢?

從上面的介紹我們知道用戶秒殺流量通過層層的負(fù)載均衡,均勻到了不同的服務(wù)器上,即使如此,集群中的單機(jī)所承受的QPS也是非常高的。如何將單機(jī)性能優(yōu)化到極致呢?

要解決這個問題,我們就要想明白一件事:通常訂票系統(tǒng)要處理生成訂單、減扣庫存、用戶支付這三個基本的階段,我們系統(tǒng)要做的事情是要保證火車票訂單不超賣、不少賣,每張售賣的車票都必須支付才有效,還要保證系統(tǒng)承受極高的并發(fā)。

這三個階段的先后順序改怎么分配才更加合理呢?我們來分析一下:

2.1 下單減庫存

當(dāng)用戶并發(fā)請求到達(dá)服務(wù)端時,首先創(chuàng)建訂單,然后扣除庫存,等待用戶支付。

這種順序是我們一般人首先會想到的解決方案,這種情況下也能保證訂單不會超賣,因為創(chuàng)建訂單之后就會減庫存,這是一個原子操作。

但是這樣也會產(chǎn)生一些問題

第一就是在極限并發(fā)情況下,任何一個內(nèi)存操作的細(xì)節(jié)都至關(guān)影響性能,尤其像創(chuàng)建訂單這種邏輯,一般都需要存儲到磁盤數(shù)據(jù)庫的,對數(shù)據(jù)庫的壓力是可想而知的;

第二是如果用戶存在惡意下單的情況,只下單不支付這樣庫存就會變少,會少賣很多訂單,雖然服務(wù)端可以限制IP和用戶的購買訂單數(shù)量,這也不算是一個好方法。

2.2 支付減庫存

如果等待用戶支付了訂單在減庫存,第一感覺就是不會少賣。但是這是并發(fā)架構(gòu)的大忌,因為在極限并發(fā)情況下,用戶可能會創(chuàng)建很多訂單,當(dāng)庫存減為零的時候很多用戶發(fā)現(xiàn)搶到的訂單支付不了了,這也就是所謂的“超賣”。也不能避免并發(fā)操作數(shù)據(jù)庫磁盤IO

2.3 預(yù)扣庫存

從上邊兩種方案的考慮,我們可以得出結(jié)論:只要創(chuàng)建訂單,就要頻繁操作數(shù)據(jù)庫IO。那么有沒有一種不需要直接操作數(shù)據(jù)庫IO的方案呢,這就是預(yù)扣庫存。先扣除了庫存,保證不超賣,然后異步生成用戶訂單,這樣響應(yīng)給用戶的速度就會快很多;

那么怎么保證不少賣呢?用戶拿到了訂單,不支付怎么辦?我們都知道現(xiàn)在訂單都有有效期,比如說用戶五分鐘內(nèi)不支付,訂單就失效了,訂單一旦失效,就會加入新的庫存,這也是現(xiàn)在很多網(wǎng)上零售企業(yè)保證商品不少賣采用的方案。

訂單的生成是異步的,一般都會放到MQ、kafka這樣的即時消費(fèi)隊列中處理,訂單量比較少的情況下,生成訂單非???,用戶幾乎不用排隊。

三. 扣庫存的藝術(shù)

從上面的分析可知,顯然預(yù)扣庫存的方案最合理。我們進(jìn)一步分析扣庫存的細(xì)節(jié),這里還有很大的優(yōu)化空間,庫存存在哪里?怎樣保證高并發(fā)下,正確的扣庫存,還能快速的響應(yīng)用戶請求?

在單機(jī)低并發(fā)情況下,我們實現(xiàn)扣庫存通常是這樣的:

為了保證扣庫存和生成訂單的原子性,需要采用事務(wù)處理,然后取庫存判斷、減庫存,最后提交事務(wù),整個流程有很多IO,對數(shù)據(jù)庫的操作又是阻塞的。這種方式根本不適合高并發(fā)的秒殺系統(tǒng)。

接下來我們對單機(jī)扣庫存的方案做優(yōu)化:本地扣庫存。我們把一定的庫存量分配到本地機(jī)器,直接在內(nèi)存中減庫存,然后按照之前的邏輯異步創(chuàng)建訂單。改進(jìn)過之后的單機(jī)系統(tǒng)是這樣的:

這樣就避免了對數(shù)據(jù)庫頻繁的IO操作,只在內(nèi)存中做運(yùn)算,極大的提高了單機(jī)抗并發(fā)的能力。但是百萬的用戶請求量單機(jī)是無論如何也抗不住的,雖然nginx處理網(wǎng)絡(luò)請求使用epoll模型,c10k的問題在業(yè)界早已得到了解決。

但是linux系統(tǒng)下,一切資源皆文件,網(wǎng)絡(luò)請求也是這樣,大量的文件描述符會使操作系統(tǒng)瞬間失去響應(yīng)。上面我們提到了nginx的加權(quán)均衡策略,我們不妨假設(shè)將100W的用戶請求量平均均衡到100臺服務(wù)器上,這樣單機(jī)所承受的并發(fā)量就小了很多。

然后我們每臺機(jī)器本地庫存100張火車票,100臺服務(wù)器上的總庫存還是1萬,這樣保證了庫存訂單不超賣,下面是我們描述的集群架構(gòu):

問題接踵而至,在高并發(fā)情況下,現(xiàn)在我們還無法保證系統(tǒng)的高可用,假如這100臺服務(wù)器上有兩三臺機(jī)器因為扛不住并發(fā)的流量或者其他的原因宕機(jī)了。那么這些服務(wù)器上的訂單就賣不出去了,這就造成了訂單的少賣。

要解決這個問題,我們需要對總訂單量做統(tǒng)一的管理,這就是接下來的容錯方案。服務(wù)器不僅要在本地減庫存,另外要遠(yuǎn)程統(tǒng)一減庫存。有了遠(yuǎn)程統(tǒng)一減庫存的操作,我們就可以根據(jù)機(jī)器負(fù)載情況,為每臺機(jī)器分配一些多余的“buffer庫存”用來防止機(jī)器中有機(jī)器宕機(jī)的情況。我們結(jié)合下面架構(gòu)圖具體分析一下:

我們采用Redis存儲統(tǒng)一庫存,因為Redis的性能非常高,號稱單機(jī)QPS能抗10W的并發(fā)。在本地減庫存以后,如果本地有訂單,我們再去請求redis遠(yuǎn)程減庫存,本地減庫存和遠(yuǎn)程減庫存都成功了,才返回給用戶搶票成功的提示,這樣也能有效的保證訂單不會超賣。

當(dāng)機(jī)器中有機(jī)器宕機(jī)時,因為每個機(jī)器上有預(yù)留的buffer余票,所以宕機(jī)機(jī)器上的余票依然能夠在其他機(jī)器上得到彌補(bǔ),保證了不少賣。

buffer余票設(shè)置多少合適呢,理論上buffer設(shè)置的越多,系統(tǒng)容忍宕機(jī)的機(jī)器數(shù)量就越多,但是buffer設(shè)置的太大也會對redis造成一定的影響。

雖然redis內(nèi)存數(shù)據(jù)庫抗并發(fā)能力非常高,請求依然會走一次網(wǎng)絡(luò)IO,其實搶票過程中對redis的請求次數(shù)是本地庫存和buffer庫存的總量,因為當(dāng)本地庫存不足時,系統(tǒng)直接返回用戶“已售罄”的信息提示,就不會再走統(tǒng)一扣庫存的邏輯,這在一定程度上也避免了巨大的網(wǎng)絡(luò)請求量把redis壓跨,所以buffer值設(shè)置多少,需要架構(gòu)師對系統(tǒng)的負(fù)載能力做認(rèn)真的考量。

四. 代碼演示

Go語言原生為并發(fā)設(shè)計,我采用go語言給大家演示一下單機(jī)搶票的具體流程。

4.1 初始化工作

go包中的init函數(shù)先于main函數(shù)執(zhí)行,在這個階段主要做一些準(zhǔn)備性工作。我們系統(tǒng)需要做的準(zhǔn)備工作有:初始化本地庫存、初始化遠(yuǎn)程redis存儲統(tǒng)一庫存的hash鍵值、初始化redis連接池;

另外還需要初始化一個大小為1的int類型chan,目的是實現(xiàn)分布式鎖的功能,也可以直接使用讀寫鎖或者使用redis等其他的方式避免資源競爭,但使用channel更加高效,這就是go語言的哲學(xué):不要通過共享內(nèi)存來通信,而要通過通信來共享內(nèi)存。

redis庫使用的是redigo,下面是代碼實現(xiàn):

...//localSpike包結(jié)構(gòu)體定義package localSpiketype LocalSpike struct {
LocalInStock int64
LocalSalesVolume int64}
...//remoteSpike對hash結(jié)構(gòu)的定義和redis連接池package remoteSpike//遠(yuǎn)程訂單存儲健值type RemoteSpikeKeys struct {
SpikeOrderHashKey string //redis中秒殺訂單hash結(jié)構(gòu)key
TotalInventoryKey string //hash結(jié)構(gòu)中總訂單庫存key
QuantityOfOrderKey string //hash結(jié)構(gòu)中已有訂單數(shù)量key}//初始化redis連接池func NewPool() *redis.Pool { return &redis.Pool{
MaxIdle: 10000,
MaxActive: 12000, // max number of connections
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", ":6379") if err != nil { panic(err.Error())
} return c, err
},
}
}
...func init() {
localSpike = localSpike2.LocalSpike{
LocalInStock: 150,
LocalSalesVolume: 0,
}
remoteSpike = remoteSpike2.RemoteSpikeKeys{
SpikeOrderHashKey: "ticket_hash_key",
TotalInventoryKey: "ticket_total_nums",
QuantityOfOrderKey: "ticket_sold_nums",
}
redisPool = remoteSpike2.NewPool()
done = make(chan int, 1)
done <- 1}

4.2 本地扣庫存和統(tǒng)一扣庫存

本地扣庫存邏輯非常簡單,用戶請求過來,添加銷量,然后對比銷量是否大于本地庫存,返回bool值:

package localSpike//本地扣庫存,返回bool值func (spike *LocalSpike) LocalDeductionStock() bool{
spike.LocalSalesVolume = spike.LocalSalesVolume + 1
return spike.LocalSalesVolume < spike.LocalInStock
}

注意這里對共享數(shù)據(jù)LocalSalesVolume的操作是要使用鎖來實現(xiàn)的,但是因為本地扣庫存和統(tǒng)一扣庫存是一個原子性操作,所以在最上層使用channel來實現(xiàn),這塊后邊會講。

統(tǒng)一扣庫存操作redis,因為redis是單線程的,而我們要實現(xiàn)從中取數(shù)據(jù),寫數(shù)據(jù)并計算一些列步驟,我們要配合lua腳本打包命令,保證操作的原子性:

package remoteSpike
......
const LuaScript = ` local ticket_key = KEYS[1] local ticket_total_key = ARGV[1] local ticket_sold_key = ARGV[2] local ticket_total_nums = tonumber(redis.call('HGET', ticket_key, ticket_total_key)) local ticket_sold_nums = tonumber(redis.call('HGET', ticket_key, ticket_sold_key)) -- 查看是否還有余票,增加訂單數(shù)量,返回結(jié)果值
if(ticket_total_nums >= ticket_sold_nums) then
return redis.call('HINCRBY', ticket_key, ticket_sold_key, 1) end
return 0`
//遠(yuǎn)端統(tǒng)一扣庫存
func (RemoteSpikeKeys *RemoteSpikeKeys) RemoteDeductionStock(conn redis.Conn) bool {
lua := redis.NewScript(1, LuaScript)
result, err := redis.Int(lua.Do(conn, RemoteSpikeKeys.SpikeOrderHashKey, RemoteSpikeKeys.TotalInventoryKey, RemoteSpikeKeys.QuantityOfOrderKey)) if err != nil { return false
} return result != 0}

我們使用hash結(jié)構(gòu)存儲總庫存和總銷量的信息,用戶請求過來時,判斷總銷量是否大于庫存,然后返回相關(guān)的bool值。在啟動服務(wù)之前,我們需要初始化redis的初始庫存信息:

hmset ticket_hash_key "ticket_total_nums" 10000 "ticket_sold_nums" 0

4.3 響應(yīng)用戶信息

我們開啟一個http服務(wù),監(jiān)聽在一個端口上:

package main
...func main() {
http.HandleFunc("/buy/ticket", handleReq)
http.ListenAndServe(":3005", nil)
}

上面我們做完了所有的初始化工作,接下來handleReq的邏輯非常清晰,判斷是否搶票成功,返回給用戶信息就可以了。

package main//處理請求函數(shù),根據(jù)請求將響應(yīng)結(jié)果信息寫入日志func handleReq(w http.ResponseWriter, r *http.Request) {
redisConn := redisPool.Get()
LogMsg := ""
<-done //全局讀寫鎖
if localSpike.LocalDeductionStock() && remoteSpike.RemoteDeductionStock(redisConn) {
util.RespJson(w, 1, "搶票成功", nil)
LogMsg = LogMsg + "result:1,localSales:" + strconv.FormatInt(localSpike.LocalSalesVolume, 10)
} else {
util.RespJson(w, -1, "已售罄", nil)
LogMsg = LogMsg + "result:0,localSales:" + strconv.FormatInt(localSpike.LocalSalesVolume, 10)
}
done <- 1
//將搶票狀態(tài)寫入到log中
writeLog(LogMsg, "./stat.log")
}func writeLog(msg string, logPath string) {
fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) defer fd.Close()
content := strings.Join([]string{msg, "\r\n"}, "")
buf := []byte(content)
fd.Write(buf)
}

前邊提到我們扣庫存時要考慮競態(tài)條件,我們這里是使用channel避免并發(fā)的讀寫,保證了請求的高效順序執(zhí)行。我們將接口的返回信息寫入到了./stat.log文件方便做壓測統(tǒng)計。

4.4 單機(jī)服務(wù)壓測

開啟服務(wù),我們使用ab壓測工具進(jìn)行測試:

ab -n 10000 -c 100 http://127.0.0.1:3005/buy/ticket

下面是我本地低配mac的壓測信息

This is ApacheBench, Version 2.3 <$Revision: 1826891 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 127.0.0.1 (be patient)Completed 1000 requestsCompleted 2000 requestsCompleted 3000 requestsCompleted 4000 requestsCompleted 5000 requestsCompleted 6000 requestsCompleted 7000 requestsCompleted 8000 requestsCompleted 9000 requestsCompleted 10000 requestsFinished 10000 requestsServer Software:Server Hostname:        127.0.0.1Server Port:            3005Document Path:          /buy/ticketDocument Length:        29 bytesConcurrency Level:      100Time taken for tests:   2.339 secondsComplete requests:      10000Failed requests:        0Total transferred:      1370000 bytesHTML transferred:       290000 bytesRequests per second:    4275.96 [#/sec] (mean)Time per request:       23.387 [ms] (mean)Time per request:       0.234 [ms] (mean, across all concurrent requests)Transfer rate:          572.08 [Kbytes/sec] receivedConnection Times (ms)
min mean[+/-sd] median maxConnect: 0 8 14.7 6 223Processing: 2 15 17.6 11 232Waiting: 1 11 13.5 8 225Total: 7 23 22.8 18 239Percentage of the requests served within a certain time (ms)
50% 18
66% 24
75% 26
80% 28
90% 33
95% 39
98% 45
99% 54
100% 239 (longest request)

根據(jù)指標(biāo)顯示,我單機(jī)每秒就能處理4000+的請求,正常服務(wù)器都是多核配置,處理1W+的請求根本沒有問題。而且查看日志發(fā)現(xiàn)整個服務(wù)過程中,請求都很正常,流量均勻,redis也很正常:

//stat.log
...result:1,localSales:145result:1,localSales:146result:1,localSales:147result:1,localSales:148result:1,localSales:149result:1,localSales:150result:0,localSales:151result:0,localSales:152result:0,localSales:153result:0,localSales:154result:0,localSales:156...

五.總結(jié)回顧

總體來說,秒殺系統(tǒng)是非常復(fù)雜的。我們這里只是簡單介紹模擬了一下單機(jī)如何優(yōu)化到高性能,集群如何避免單點故障,保證訂單不超賣、不少賣的一些策略,完整的訂單系統(tǒng)還有訂單進(jìn)度的查看,每臺服務(wù)器上都有一個任務(wù),定時的從總庫存同步余票和庫存信息展示給用戶,還有用戶在訂單有效期內(nèi)不支付,釋放訂單,補(bǔ)充到庫存等等。

我們實現(xiàn)了高并發(fā)搶票的核心邏輯,可以說系統(tǒng)設(shè)計的非常的巧妙,巧妙的避開了對DB數(shù)據(jù)庫IO的操作,對Redis網(wǎng)絡(luò)IO的高并發(fā)請求,幾乎所有的計算都是在內(nèi)存中完成的,而且有效的保證了不超賣、不少賣,還能夠容忍部分機(jī)器的宕機(jī)。我覺得其中有兩點特別值得學(xué)習(xí)總結(jié):

  • 負(fù)載均衡,分而治之。通過負(fù)載均衡,將不同的流量劃分到不同的機(jī)器上,每臺機(jī)器處理好自己的請求,將自己的性能發(fā)揮到極致,這樣系統(tǒng)的整體也就能承受極高的并發(fā)了,就像工作的的一個團(tuán)隊,每個人都將自己的價值發(fā)揮到了極致,團(tuán)隊成長自然是很大的。
  • 合理的使用并發(fā)和異步。自epoll網(wǎng)絡(luò)架構(gòu)模型解決了c10k問題以來,異步越來被服務(wù)端開發(fā)人員所接受,能夠用異步來做的工作,就用異步來做,在功能拆解上能達(dá)到意想不到的效果,這點在nginx、node.js、redis上都能體現(xiàn),他們處理網(wǎng)絡(luò)請求使用的epoll模型,用實踐告訴了我們單線程依然可以發(fā)揮強(qiáng)大的威力。服務(wù)器已經(jīng)進(jìn)入了多核時代,go語言這種天生為并發(fā)而生的語言,完美的發(fā)揮了服務(wù)器多核優(yōu)勢,很多可以并發(fā)處理的任務(wù)都可以使用并發(fā)來解決,比如go處理http請求時每個請求都會在一個goroutine中執(zhí)行,總之:怎樣合理的壓榨CPU,讓其發(fā)揮出應(yīng)有的價值,是我們一直需要探索學(xué)習(xí)的方向。

網(wǎng)頁名稱:秒殺系統(tǒng)的架構(gòu)(Golang 實現(xiàn))
鏈接URL:http://m.5511xx.com/article/dhgcjeo.html