謝昭陽
(四川大學計算機學院,成都 610065)
高并發(fā)環(huán)境下的限時搶購服務(wù)器性能優(yōu)化方案
謝昭陽
(四川大學計算機學院,成都 610065)
電商平臺中的限時搶購類活動需要處理瞬時高并發(fā)的大量請求,給服務(wù)器后臺架構(gòu)的設(shè)計帶來一些新的問題和挑戰(zhàn)。如何在保證數(shù)據(jù)一致性的情況下提高服務(wù)器的響應(yīng)速度,是該問題的難點所在。提出一套基于消息隊列的方案,并實現(xiàn)整套系統(tǒng),在真實服務(wù)器中測試,得到良好的結(jié)果。
高并發(fā);性能優(yōu)化;限時搶購;電商平臺
越來越多的電商平臺為了吸引用戶消費,推出各種不同形式的促銷活動,其中“限時搶購”是一種比較常見的方式。但是限時搶購類活動需要處理短時間內(nèi)高并發(fā)的大批量請求,給服務(wù)器后臺架構(gòu)的設(shè)計帶來了一些新的問題和挑戰(zhàn)。
“限時搶購”服務(wù)器架構(gòu)設(shè)計需要解決的問題主要有兩點:響應(yīng)速度和數(shù)據(jù)一致性[1]。提高響應(yīng)速度是優(yōu)化的目標,然而,同一時刻的讀和寫的請求可能存在沖突,如果沒有處理好,就會導致數(shù)據(jù)不一致,產(chǎn)生不良后果。如何在保證數(shù)據(jù)一致性的情況下提高服務(wù)器的響應(yīng)速度,是該問題的難點所在。
本文提出一套方案,采用Go語言[2]實現(xiàn)HTTP服務(wù)器,后端訪問Redis數(shù)據(jù)庫[3],使用消息隊列來緩沖請求,分配多worker進行數(shù)據(jù)分發(fā)。實驗表明,該方案部署在3臺服務(wù)器上時,可以在保證100%數(shù)據(jù)一致的情況下,達到4842(單/秒)的穩(wěn)定峰值。
整個系統(tǒng)主要分為三個部分:HTTP響應(yīng)worker池、消息隊列、Redis訪問worker池。當客戶端發(fā)起請求時,系統(tǒng)將從HTTP響應(yīng)worker池中取出一個空閑的worker,用于處理該HTTP請求。如果該請求不需要訪問數(shù)據(jù)庫,則直接返回結(jié)果;否則,將數(shù)據(jù)庫查詢?nèi)蝿?wù)和自身worker_id打包在一起,加入消息隊列中,并阻塞以等待查詢結(jié)果的返回。Redis訪問worker池中的worker在系統(tǒng)運行開始時,就連接并保持了一個和Re-dis服務(wù)器的連接,然后阻塞在消息隊列上。若消息隊列上加入了新的查詢?nèi)蝿?wù),就會觸發(fā)系統(tǒng)從池中調(diào)度一個空閑的worker到隊列中取走任務(wù)。worker拿到任務(wù)后,從已保持的Redis連接向數(shù)據(jù)庫發(fā)出操作指令,然后阻塞在該連接上。數(shù)據(jù)庫操作完成并返回后,Re-dis訪問worker被喚醒,它把結(jié)果交給消息中指定的HTTP響應(yīng)worker,然后繼續(xù)阻塞在消息隊列上,等待下一次被系統(tǒng)調(diào)度。當系統(tǒng)遇到瞬時高并發(fā)的訪問時,大量沒有涉及數(shù)據(jù)庫操作的請求可以直接響應(yīng)。涉及數(shù)據(jù)庫操作的請求會按請求的先后順序依次進入消息隊列等待處理。Redis訪問worker可以持續(xù)不斷地處理隊列中的任務(wù),不必為每一個任務(wù)單獨建立和銷毀連接。根據(jù)實際硬件和網(wǎng)絡(luò)環(huán)境適當?shù)乜刂芌edis訪問worker的數(shù)量,平衡系統(tǒng)開銷和隊列等待時間,以達到最佳性能。
本方案主要采用Go語言實現(xiàn)整個系統(tǒng)。Go語言的標準庫包含一個基礎(chǔ)的HTTP服務(wù)器。為了提高URL解析速度,本文采用基于Trie樹的httprouter作為URL路由器。
Go語言支持一種輕量級線程goroutine,它類似于協(xié)程,在goroutine之間切換成本非常低。此外,為了支持goroutine之間的通信,Go語言提供channel作為內(nèi)置的數(shù)據(jù)類型,并為其配備一些語法層面上的操作。其中一個比較典型的是select關(guān)鍵字,使用時,類似于switch一樣指定若干個case子表達式,也可以指定de-fault語句,其中每個case的條件通常是一個等待chan-nel讀或?qū)懙谋磉_式。當執(zhí)行到select語句時,系統(tǒng)會從就緒的case中不確定地選擇一個執(zhí)行。若此時所有case都未就緒,且沒有指明default,則該select語句所在的goroutine就會阻塞,并交出控制權(quán),系統(tǒng)就會調(diào)度其他goroutine執(zhí)行。當一個select語句指明default時,則遇到?jīng)]有任何case就緒的情況就會直接執(zhí)行de-fault。
本文在實現(xiàn)所提出的方案時,以兩種不同的方式使用channel:一種是用來阻塞HTTP響應(yīng)worker的單值channel,實現(xiàn)信號量的功能;另一種是用來緩沖Re-dis訪問的多值channel,實現(xiàn)消息隊列的功能。當HTTP響應(yīng)worker要請求數(shù)據(jù)庫時,它先會創(chuàng)建一個單值channel,將其和數(shù)據(jù)庫查詢參數(shù)打包,放入消息隊列中,然后等待這個channel傳出數(shù)據(jù)的時候再繼續(xù)執(zhí)行。Redis訪問worker從初始化開始,就嘗試從消息隊列channel中讀取消息。由于一開始消息隊列為空,所以所有Redis訪問worker都阻塞。當隊列channel可以讀取消息時,空閑的worker就會迅速將消息取走。搶到消息的worker執(zhí)行Redis訪問,其余的繼續(xù)阻塞等待。如果Redis查詢結(jié)束,Redis訪問worker就會把結(jié)果通過消息中的單值channel傳遞給相應(yīng)的HTTP響應(yīng)worker,使其繼續(xù)執(zhí)行。
程序中的關(guān)鍵代碼如下:
Redis是一種NoSQL內(nèi)存數(shù)據(jù)庫,存取速度非???。Redis中的數(shù)據(jù)主要以“Key-Value”的方式存儲,Key限定為字符串,Value則有不同數(shù)據(jù)結(jié)構(gòu)可選,例如字符串String、集合Set、哈希表Hash、鏈表List、有序集合Sorted Set等。Redis服務(wù)器內(nèi)嵌Lua腳本解釋器,可以編寫Lua腳本代碼作為預定義批處理操作,由客戶端提供參數(shù),發(fā)起調(diào)用命令“EVAL”或“EVALSHA”以執(zhí)行指定的Lua代碼。Redis保證每個Lua調(diào)用都和內(nèi)置操作一樣具有原子性,當一段Lua腳本代碼在執(zhí)行,不會有其他操作同時運行?;赗edis提供的這個特性,我們把Redis訪問worker的數(shù)據(jù)讀寫操作都封裝到一個Lua腳本中,這樣實現(xiàn),一方面可以保證數(shù)據(jù)的一致性,另一方面又可以使得多次操作合并成一個操作,減少網(wǎng)絡(luò)傳輸開銷和來回傳輸?shù)木W(wǎng)絡(luò)延遲。
由于本文所提出的方案沒有橫向依賴,即各個HTTP服務(wù)器之間不存在直接通信,所以在真實環(huán)境中,可以設(shè)置一臺負載均衡服務(wù)器,并橫向增加HTTP服務(wù)器,以提高整個系統(tǒng)的并發(fā)量。
我們將HTTP服務(wù)器代碼鏡像地部署在3臺雙核CPU、4GB內(nèi)存的服務(wù)器上。另外配置了一臺Redis服務(wù)器,獨立于HTTP服務(wù)器,只負責數(shù)據(jù)存儲與管理。配置額外的服務(wù)器運行測試腳本,模擬1000個客戶端同時請求,以round robin的負載均衡策略[4]均衡地請求3臺HTTP服務(wù)器。
經(jīng)測試,所有請求都能正確地返回,并且當Redis訪問worker數(shù)量為250時,平均峰值達到了4842(單/秒)。
本文針對高并發(fā)環(huán)境中的限時搶購服務(wù)器后臺設(shè)計面臨的問題,分析其中的關(guān)鍵點和難點,提出了一個解決方案。為了驗證這套方案的可行性和性能,本文實現(xiàn)整套系統(tǒng),并部署在服務(wù)器中進行測試,得到了良好的結(jié)果。本文所提供的方案可以為現(xiàn)有電商平臺優(yōu)化服務(wù)器性能時提供參考。
[1]Terry D.Replicated Data Consistency Explained Through Baseball[J].Communications of the ACM,2013,56(12):82-89.
[2]Zawodny J.Redis:Lightweight Key/Value Store That Goes the Extra Mile[J].Linux Magazine,2009,79.
[3]Schmager F,Cameron N,Noble J.GoHotDraw:Evaluating the go Programming Language with Design Patterns[C].Evaluation and Usability of Programming Languages and Tools.ACM,2010:10.
[4]Shreedhar M,Varghese G.Efficient Fair Queuing Using Deficit Round-Robin[J].Networking,IEEE/ACM Transactions on,1996,4(3): 375-385.
Performance Optimization for Highly Concurrent Flash Sale Server
XIE Zhao-yang
(College of Computer Science,Sichuan University,Chengdu 610065)
Flash sale in e-commerce platform needs to deal with a large number of transient high concurrent requests,which brings some new chal-lenges and problems to back-end server architectural design.The difficulty of the problem lies in improving the response speed of the server while keeping data consistency.Presents a solution based on message queue,and implements the whole system.Tested on real hard-ware,the proposed solution shows a good performance.
High Concurrency;Performance Optimization;Flash Sale;E-Commerce
1007-1423(2016)08-0051-03
10.3969/j.issn.1007-1423.2016.08.010
謝昭陽(1992-),男,福建泉州人,在讀碩士研究生,研究方向為程序設(shè)計語言理論
2016-02-23
2016-03-03