當前位置:
首頁 > 知識 > 當Golang遇到高並發秒殺,世界開始變得簡單

當Golang遇到高並發秒殺,世界開始變得簡單

遇到GO語言也是偶爾的一次機會,工作上做架構相關的事情,對新發展比較火爆的語言肯定要關注下。就這樣步入了GO語言的世界,GO給我帶來了全新的體驗;

一直做一件事情的人往往會被一件事情所困,開始實踐GO語言的時候總感覺哪哪都彆扭,特別是把結構體當成類,還有結構體的繼承,寫面向對想多了開始還真扭不過來。不過寫的多了漸漸地也習慣了,甚至感覺越來越順眼。

在熟悉了GO一段時間後,也停止了一會,腦子裡一直在想著GO的簡潔(代碼風格一致,用起來簡練不拖泥帶水,部署極其簡單,編譯速度用快來形容),能給項目系統和架構帶來哪些改變。但是當時一時半會兒還真沒想到有多大幫助,後來系統逐步開始用GO實現,用的多了慢慢地發現:

咦~,部署再也不要搭建依賴環境了(不部署環境發布,剛開始還真有點不習慣,總感覺少來點什麼;

別人寫的代碼看著也沒有抵觸心理,雖然說有的代碼不是自己寫的,仔細閱讀的時候就感覺像是自己寫的,寫JAVA 和PHP的時候 閱讀代碼哪是從內心拒絕的;

開發某個微服務介面一切變得簡單了,寫個main,寫個介面,提交,秒秒種就上線了~;

上面主要說了自己和GO的相遇還有GO給我帶來的初步影響,就在某天晚上我腦袋裡突然蹦出一個想法,GO語言用簡潔帶來諸多提升,從事的架構系統是否也能利用GO來簡化,降低系統複雜度?這個想法從蹦出來,就一直在我腦袋裡徘徊。回想剛開始從事架構相關事情的時候,一看到講中間件有什麼原理,有什麼優化能提高性能就非常興奮,埋頭苦研直到自己感覺掌握(當然現在也要),然後就信誓旦旦的用到系統中,感覺系統架構用中間件組件越多越好,越多越顯得自己做的架構有多厲害。但是隨著越做越久你就會發現,系統能用就行,不能為了架構而架構。從傳統技術棧上做減法同樣需要深厚的功底,因為只有充分知道技術原理才能替換,也才敢想敢幹,不出問題。常言道:「條條大陸通羅馬」,從個人較角度講架構要適合當時的業務,達到用儘可能少的代價完成儘可能多的事情就算達到架構設計的目標了,就比如消耗伺服器資源相同情況下能支撐好幾倍甚至好幾十倍的請求,達到相同請求量的情況下,實現和部署非常簡單可操作等。GO的思想這段時間就一直這麼潛移默化地影響這我。

直到我們公司決定做微服務,剛開始我們用java做微服務。後來想了下其它語言是否也能做微服務,自然而然的就想到了GO,經過一番折騰後感覺還可以,就用GO開始寫點微服務,寫著寫著就發現Golang 寫微服務還挺順手,效率那個高啊,也不用封裝tomcat(這東西放jar包里,感覺特別不合適),二進位不用系統依賴都能在docker裡面跑(不信你試試),就這樣打心底來說越來越喜歡GO,後續的系統啥的也想用GO重構(寫多了java多了遇到這麼方便的真是感覺發現了春天)GO已經深入的影響了對系統的架構的看法。

但究竟什麼是架構,架構師又是這麼煉成的 ?在這裡分享下架構師煉成的八段艱辛:

第一段:搬磚分為能辦好磚和只會搬磚(有一批人留在了搬磚上,剩下的繼續發展);

第二段:能搬磚的可以分為要了解原理的和編程就是搬磚的;

第三段:了解原理的又分為不斷研究的和一知半解的;

第四段:不斷研究也能分成兩種研究深入有廣度和蜻蜓點水沒廣度的;

第五段:有深度有廣度的又分為純技術型和業務型(開始分化);

第六段:業務型要求有良好溝通,對系統和需求有一定設計把控能力的;

第七段:這層很容易出現單純使用堆中間件搭出「架構」系統的(初級架構師);

第八段:這層很重要的一點,考慮問題足夠細緻、全面、善於溝通。做底層實現,理解底層原理,從業務,研發,測試,部署,維護升級多角度出發,因地制宜搭出的「架構」是為了開發效率,為了運行效率,為了開發質量,為了業務靈活和運行穩定,為了維護方便等等這樣的人,可稱為架構師(有這方面經驗的回想下,有多少架構是表面上看著漂亮,實際用著難受的)。

在做秒殺系統的時候,剛開始想到也最容易想到的傳統技術棧就是,分散式session,Redis集群,分散式緩存,nginx反向代理nginx深層優化,機器優化,消息隊列。沒錯Cap老師當年也是想到這些,也認為這些「成熟」的技術能應用到我們秒殺系統中沒問題,況且公司內部討論都感覺這些沒問題。而且做了深入的研究比如:

1.分散式Session 我們化了很大的力氣,用Nginx web redis集群的方式來保存Session達到Session驗證的目的,單點Session這塊的架構就如下圖所示:

乍一看沒問題,都是這麼做的,真的大流量來了,就加Nginx,web伺服器,也滿足橫向擴展,但是流量達到上億級別以後我門的成本有點大,來回的網路請求session的時間我們也想壓榨(那時候總感覺哪裡不對),nginx在高流量下也時不時出現504。

2.分散式緩存,這東西看著很簡單,但是在大流量高並發系統裡面是個非常複雜的事情,主要能遇到以下一些問題;

1)緩存一致性(如果用這個的話,處理不好會出現超賣);

2)緩存穿透;

3)緩存雪崩;

4)緩存黑洞問題:

5)狗樁效應;

.....還有許多需要注意的事情,總之分散式緩存用途很廣泛也很有價值,但是要建立一個能夠滿足高並發,大流量的分散式緩存系統需要極強的技術團隊支持,實現起來也特別的複雜這裡就不在贅述;

然而,我們看似沒有問題的解決方案存在巨大的問題,實現「太不容易了」,門檻那個是高啊。用起來資源成本也是蠻高的,Session要滿足橫向擴展,web緩存也要滿足橫向擴展,包括redis集群也要滿足,只能是不斷的加集群;

舉個簡單的例子(拋去其它因素,為了說明架構的重要性),假設我們現在單台機器,介面有5000QPS的處理能力(8核8G),要處理秒殺的上億流量,秒殺開始瞬時流量按照300W預估,平均等待按照時間7秒計算(介面容忍到3.5WQPS),得出的結果也就是我們系統,就介面這塊需要將近90台,這還沒有算其它同等要求的的配套伺服器,這些配套伺服器簡單說明如下;

1.首先nginx層面要有同等級處理能力(每台不優化大概2WQPS,預估20台左右);

2.web介面同樣要擴展到相應等級(預估的90台);

3.Reids集群多商品有情況下有左右(單獨商品,大量訪問量的情況下集群也沒用);

上面是分散式Session要滿足的機器需求,還沒算上分散式緩存,同學們大概可以感覺到做個和做好秒殺系統有多麼不容易了,部署的複雜度也還沒考慮。實施起來真是複雜,經驗4-5年一兩個人短時間還真完成不了。能想出其它的辦法來簡化嗎?答案是:有的。首先要理解原理,其次要從架構上做減法。不用就沒有必要優化。

要從哪些地方優化呢?

1)Session在秒殺並發里,根據許可權驗證的原理是可以省略的;

2)我們可以不用分散式緩存(用介面代替);

3)把nginx也省了(降低運維難度);

4)redis集群也可以省略;

這麼一除二去,秒殺怎麼做啊?用java和php不是不能實現,而是實現起來可以比較吃力,但是現在可以結合GO語言特性來給我們提供新的思路;

1.Nginx 可以省略,直接用GO啟動埠暴露服務(這裡可以省去nginx);

2.採用cookie方式或者wt方式來代替分散式Session方案,伺服器端代碼層面驗證;

3.超賣採用介面形式代替redis集群;

4.負載均衡採用廉價的SLB(避免了Nginx);

秒殺優化以後總統架構可以展示為下圖結構,詳細做法請參閱《Go高並發秒殺實踐》:

從改造後的結果來看我們主要列下:

1.web應用都採用Go部署進位文件的方法,centos伺服器不需要按照任何依賴(極大的方便了部署):

2.採用SLB廉價實用方案避免了nginx的反向代理,甚至高級lua腳本也避免了;

3.redis集群在這裡也被避免了,採用介面的方式提供服務;

整個技術棧只需要會:GO,RabbitMQ,Mysql就能完成高並發秒殺系統,首先從易操作上就很誘人;下面大家可以在調整後的架構上推演下(目前單機GO提供web介面,在未經過優化的情況下大概能達到2WQPS):

1.單機GO介面許可權驗證性能提高4倍,部署複雜度可以說已經接近與零(無nginx,無redis集群,運行也無依賴環境);

2.隨著流量等級的不斷提高只需要添加web伺服器和數量控制伺服器,沒有其它服務開銷(擴展性上可以說是盡最大的可能降低了成本,成正比例增長模式,且無性能瓶頸);

3.對比傳統方案,伺服器數量降低不止4倍(大家可以在原有的基礎上計算下);

上面的解決方案是在GO語言的簡單的基礎上實現的,恰巧GO部署方便提高了易實現性,有恰好GO能提供web服務減少了外部依賴(本身web務性能也很高)。有了GO的兩個恰到好處的特性,在配合架構上減法操作,讓秒殺系統整體實現不在是件難事,當然java和PHP都可以做上圖中調整後的秒殺架構,但是從多方面考慮來講,總統還是GO優勢明顯點。

回首看方案感覺是Go帶動了思維模式的改變,本身簡單帶動了實現簡單,本身高效穩定帶動了架構優化。好的系統架構就應該簡單,高效,易實現;

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 千鋒JAVA開發學院 的精彩文章:

MariaDB10.3 系統版本表 有效防止數據丟失
Kotlin技術分享-運算符重載

TAG:千鋒JAVA開發學院 |