遇到GO語言也是偶爾的一次機會,工做上作架構相關的事情,對新發展比較火爆的語言確定要關注下。就這樣步入了GO語言的世界,GO給我帶來了全新的體驗;php
一直作一件事情的人每每會被一件事情所困,開始實踐GO語言的時候總感受哪哪都彆扭,特別是把結構體當成類,還有結構體的繼承,寫面向對想多了開始還真扭不過來。不過寫的多了漸漸地也習慣了,甚至感受愈來愈順眼。java
在熟悉了GO一段時間後,也中止了一會,腦子裏一直在想着GO的簡潔(代碼風格一致,用起來簡練不拖泥帶水,部署極其簡單,編譯速度用快來形容),能給項目系統和架構帶來哪些改變。可是當時一時半會兒還真沒想到有多大幫助,後來系統逐步開始用GO實現,用的多了慢慢地發現:nginx
咦~,部署不再要搭建依賴環境了(不部署環境發佈,剛開始還真有點不習慣,總感受少來點什麼;web
別人寫的代碼看着也沒有抵觸心理,雖說有的代碼不是本身寫的,仔細閱讀的時候就感受像是本身寫的,寫JAVA 和PHP的時候 閱讀代碼哪是從心裏拒絕的;redis
開發某個微服務接口一切變得簡單了,寫個main,寫個接口,提交,秒秒種就上線了~;sql
上面主要說了本身和GO的相遇還有GO給我帶來的初步影響,就在某天晚上我腦殼裏忽然蹦出一個想法,GO語言用簡潔帶來諸多提高,從事的架構系統是否也能利用GO來簡化,下降系統複雜度?這個想法從蹦出來,就一直在我腦殼裏徘徊。回想剛開始從事架構相關事情的時候,一看到講中間件有什麼原理,有什麼優化能提升性能就很是興奮,埋頭苦研直到本身感受掌握(固然如今也要),而後就信誓旦旦的用到系統中,感受系統架構用中間件組件越多越好,越多越顯得本身作的架構有多厲害。可是隨着越作越久你就會發現,系統能用就行,不能爲了架構而架構。從傳統技術棧上作減法一樣須要深厚的功底,由於只有充分知道技術原理才能替換,也纔敢想敢幹,不出問題。常言道:「條條大陸通羅馬」,從我的較角度講架構要適合當時的業務,達到用盡量少的代價完成儘量多的事情就算達到架構設計的目標了,就好比消耗服務器資源相同狀況下能支撐好幾倍甚至好幾十倍的請求,達到相同請求量的狀況下,實現和部署很是簡單可操做等。GO的思想這段時間就一直這麼潛移默化地影響這我。docker
直到咱們公司決定作微服務,剛開始咱們用java作微服務。後來想了下其它語言是否也能作微服務,天然而然的就想到了GO,通過一番折騰後感受還能夠,就用GO開始寫點微服務,寫着寫着就發現Golang 寫微服務還挺順手,效率那個高啊,也不用封裝tomcat(這東西放jar包裏,感受特別不合適),二進制不用系統依賴都能在docker裏面跑(不信你試試),就這樣打心底來講愈來愈喜歡GO,後續的系統啥的也想用GO重構(寫多了java多了遇到這麼方便的真是感受發現了春天)GO已經深刻的影響了對系統的架構的見解。編程
但究竟什麼是架構,架構師又是這麼煉成的 ?在這裏分享下架構師煉成的八段艱辛:centos
第一段:搬磚分爲能辦好磚和只會搬磚(有一批人留在了搬磚上,剩下的繼續發展);緩存
第二段:能搬磚的能夠分爲要了解原理的和編程就是搬磚的;
第三段:瞭解原理的又分爲不斷研究的和只知其一;不知其二的;
第四段:不斷研究也能分紅兩種研究深刻有廣度和走馬觀花沒廣度的;
第五段:有深度有廣度的又分爲純技術型和業務型(開始分化);
第六段:業務型要求有良好溝通,對系統和需求有必定設計把控能力的;
第七段:這層很容易出現單純使用堆中間件搭出「架構」系統的(初級架構師);
第八段:這層很重要的一點,考慮問題足夠細緻、全面、善於溝通。作底層實現,理解底層原理,從業務,研發,測試,部署,維護升級多角度出發,因地制宜搭出的「架構」是爲了開發效率,爲了運行效率,爲了開發質量,爲了業務靈活和運行穩定,爲了維護方便等等這樣的人,可稱爲架構師(有這方面經驗的回想下,有多少架構是表面上看着漂亮,實際用着難受的)。
在作秒殺系統的時候,剛開始想到也最容易想到的傳統技術棧就是,分佈式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帶動了思惟模式的改變,自己簡單帶動了實現簡單,自己高效穩定帶動了架構優化。好的系統架構就應該簡單,高效,易實現;