我伴隨公司走了4年了科平,我覺得有必要把我這四年來經(jīng)歷的技術(shù)架構(gòu)的演進(jìn)沉淀下來分享給大伙勃教,里面有些內(nèi)容不一定100%準(zhǔn)確,因為有些已經(jīng)記不太清楚了匠抗,如有偏差故源,請反饋給我哈,謝謝汞贸。
這個是我們早期的樣子绳军,17年2月份,我進(jìn)入公司矢腻,那時候只有一個大的工程门驾,里面大概有12個子工程;當(dāng)時的工程是有服務(wù)化思維的多柑,因此奶是,采用了dubbo做服務(wù)化的隔離(用戶、商戶竣灌、報名單聂沙、崗位、青團(tuán)寶)初嘹。dubbo的上層是web層及汉,采用springMVC的框架進(jìn)行入?yún)⑻幚怼?/p>
這套有一個比較頭痛的問題就是打包問題,當(dāng)時的團(tuán)隊還沒有將dubbo拆分到不同的工程中屯烦,這就出現(xiàn)了兩個問題:
- 代碼庫沒有隔離坷随,導(dǎo)致大伙還是要在一個工程里開發(fā),分支無數(shù)驻龟。
- 打包的容錯率極低温眉,只要任何一個項目有問題,打包都會失斘毯类溢;這是因為這12個工程都依賴一個大的parent配置。
于是谴蔑,我們做的第一件事兒豌骏,就是將服務(wù)化拆分;通過把工程分開隐锭,把組織架構(gòu)明確窃躲,每個人只維護(hù)自己的工程,迭代的效率當(dāng)然也提高了不少钦睡。雖然應(yīng)用架構(gòu)被很好的剝離了蒂窒,但我們又面臨另一個問題,數(shù)據(jù)庫是都放在一起的荞怒;這會直接導(dǎo)致
- 早期的RDS的監(jiān)控功能不多洒琢,我們也沒有開啟日志,不能查看全量的sql(因為窮褐桌,得省著點花)衰抑。
- 早期的sql寫的很差,甚至索引建的都是錯誤的荧嵌;因此呛踊,全屏飄著慢sql,你都不知道CPU彪起來是哪個業(yè)務(wù)干的啦撮。
為了解決這個問題谭网,我們繼續(xù)拆分了DB,將DB隔離開赃春,解決了業(yè)務(wù)之間因為慢sql影響的問題愉择,但沒有解決慢sql本身(后面有詳解)。但分開之后织中,我們面臨一個問題锥涕,就是級聯(lián)查詢沒法用了面對運(yùn)營跑sql的需求,我們得要寫很多腳本狭吼,這極大程度增加了我們的工作難度站楚。我們想了集中解決方案:
- 用ES來承接數(shù)據(jù),做信息聚合操作搏嗡,但問題一個是ES的成本在阿里云上太高了窿春,我們用不起;另一個是ES的DSL學(xué)習(xí)成本也很高采盒,有一些查詢寫不出來旧乞。
- 將所有實例的數(shù)據(jù),通過binlog導(dǎo)入到一個實例中磅氨,這個帶來的問題是尺栖,需要搭建一套canal,并要開發(fā)一套消費邏輯烦租。
- 用數(shù)據(jù)工具將數(shù)據(jù)直接導(dǎo)入延赌,例如:datax這種開源中間件除盏。
我們基于阿里云,選擇了方案3挫以,通過云上的dts(數(shù)據(jù)傳輸工具)者蠕,來將多實例匯總到一個實例中,我們基于這個實例開發(fā)整個的后臺和數(shù)據(jù)中心功能掐松。我們這套數(shù)據(jù)庫體系跑了一年踱侣,還是比較穩(wěn)定的,大概是在第二年才慢慢出現(xiàn)了一些瓶頸(后續(xù)闡述)大磺。
隨著我們迭代越來越快抡句,我們爆發(fā)了另一個問題,就是當(dāng)一個dubbo的接口做了更新的時候杠愧,沒有意識去通知對方待榔,直接導(dǎo)致系統(tǒng)報錯。理論上流济,dubbo的接口一般是開閉原則究抓,并不支持你在上面更新。但實際上業(yè)務(wù)在早期的時候的變化是非诚疲快的刺下,表的DDL變更相當(dāng)頻繁,如果每次都新追加接口稽荧,系統(tǒng)維護(hù)的成本會非常大橘茉,而spring cloud的http的接口,在接口的字段的增加和刪除方面姨丈,有天然的支持畅卓。
另一方面,團(tuán)隊要快速擴(kuò)招蟋恬,那時候的我們沒有錢翁潘,我們無法給出很有競爭力的薪資來招募那些能力很強(qiáng)的人。而dubbo這時候就顯得很笨重歼争,不僅要學(xué)會springMVC這一套拜马,還要學(xué)習(xí)dubbo的服務(wù)化生態(tài),學(xué)習(xí)成本十分高沐绒;因此俩莽,我們做了一個決定:把dubbo全面過度到springcloud體系上去。當(dāng)然這件事兒乔遮,我們是一步步做的:
- 建立springcloud注冊中心eurika扮超,新的應(yīng)用統(tǒng)一用cloud來寫。
- 老的項目,如果調(diào)用新的出刷,通過cloud客戶端去調(diào)用璧疗。
- 將老系統(tǒng)由下往上梳理,下層提供全套cloud接口馁龟,上層一個個切換崩侠,這個階段過程中是很痛苦的,因為整個系統(tǒng)體系中屁柏,cloud和dubbo是并存的啦膜,這里面我們踩了很多坑有送,比如dubbo重啟的時候淌喻,eurika還沒有摘掉,導(dǎo)致訪問報錯等雀摘。
這里順便提一句裸删,因為在cloud體系內(nèi),對內(nèi)部和外部提供的接口阵赠,我們用的都是一套涯塔;那如何區(qū)分內(nèi)部和外部的接口呢,我們是通過/cloudService/***加這么一個前綴清蚀,然后通過nginx來判斷前綴匕荸,阻斷外網(wǎng)IP訪問的。這里有一些細(xì)節(jié)枷邪,為什么要阻斷呢榛搔?因為內(nèi)部接口和外部的接口的差異很大,外部接口要承載DDOS→WAF→網(wǎng)關(guān)的三層保護(hù)东揣,還要有用戶的token校驗等践惑;而內(nèi)部接口天然保持信任,并沒有很多校驗嘶卧。如果你把內(nèi)部接口暴露到外網(wǎng)上尔觉,那等于你把家門給拆了,誰都能進(jìn)來芥吟。