對(duì).Net系統(tǒng)架構(gòu)改造的一點(diǎn)經(jīng)驗(yàn)和教訓(xùn)
在互聯(lián)網(wǎng)行業(yè),基于Unix/Linux的網(wǎng)站系統(tǒng)架構(gòu)毫無疑問是當(dāng)今主流的架構(gòu)解決方案,這不僅僅是因?yàn)長inux本身足夠的開放性,更因?yàn)閲@傳統(tǒng)Unix/Linux社區(qū)有大量的成熟開源解決方案,覆蓋了網(wǎng)站應(yīng)用擴(kuò)展的方方面面。
我記得十幾年前第一波互聯(lián)網(wǎng)浪潮的時(shí)代,采用Windows平臺(tái)ASP架構(gòu)的大型網(wǎng)站是非常普及的,而如今采用Windows平臺(tái).net架構(gòu)的大流量知名網(wǎng)站已經(jīng)鳳毛麟角了。很多采用Windows平臺(tái).net架構(gòu)的大型網(wǎng)站都面臨了架構(gòu)上的擴(kuò)展問題:
例如國外的SNS網(wǎng)站MySpace網(wǎng)站面臨過很嚴(yán)重的性能擴(kuò)展問題,國內(nèi)電商網(wǎng)站京東也不止一次受困于架構(gòu)擴(kuò)展帶來了性能瓶頸。因此,一些Windows平臺(tái).net架構(gòu)為主的網(wǎng)站,不得不考慮“去.net化”,拋棄.net,全面遷移到以Java為主的架構(gòu)上。
但是大型網(wǎng)站的架構(gòu)遷移,本身也是傷筋動(dòng)骨的事情,風(fēng)險(xiǎn)極高,成功案例尚不多見,失敗案例俯拾皆是,這是因?yàn)椋?/p>
-
架構(gòu)遷移是在現(xiàn)有業(yè)務(wù)系統(tǒng)上進(jìn)行的,并不是從容的開發(fā)新產(chǎn)品,有足夠的時(shí)間測試和完善,相當(dāng)于給正在高空飛行的客機(jī)換引擎,必須一次切換成功,沒有第二次機(jī)會(huì),稍有差池,就會(huì)機(jī)毀人亡。而我們都知道,新開發(fā)一個(gè)大型系統(tǒng),沒有上線磨合和完善過,無法做到一次100%完美。
-
架構(gòu)遷移意味著老的研發(fā)團(tuán)隊(duì)將被淘汰,而往往老團(tuán)隊(duì)體系隨著公司壯大已經(jīng)掌握了足夠話語權(quán),新架構(gòu)的團(tuán)隊(duì)在公司又根基未穩(wěn),出于維護(hù)自身利益的本能,新舊團(tuán)隊(duì)之間很容易爆發(fā)政治斗爭,相互排擠,導(dǎo)致遷移失敗。
5173“去.net化”的教訓(xùn)
5173網(wǎng)站以游戲裝備交易起家,曾經(jīng)在客戶端網(wǎng)絡(luò)游戲發(fā)展黃金時(shí)期,迎來了業(yè)務(wù)爆發(fā)性的增長期。此時(shí),用.net架構(gòu)開發(fā)的網(wǎng)站已經(jīng)不堪重負(fù),由于現(xiàn)有的.net研發(fā)團(tuán)隊(duì)長期無法解決網(wǎng)站的性能問題,5173決定將網(wǎng)站從.net架構(gòu)全面遷移到Java為主的架構(gòu)上。為此,5173花了很大的代價(jià),從淘寶和SUN公司挖了很多工程師,組成了一個(gè)六七十人的Java架構(gòu)研發(fā)部門。
新的Java研發(fā)部門開發(fā)新的5173網(wǎng)站,而老的.net研發(fā)部門維護(hù)現(xiàn)有的5173網(wǎng)站,兩個(gè)部門并行工作,兩個(gè)版本的網(wǎng)站并行運(yùn)行,這帶來了公司內(nèi)部激烈的政治斗爭,新開發(fā)完成的Java版本的5173網(wǎng)站從未正式上線過,老的.net研發(fā)團(tuán)隊(duì)在面臨嚴(yán)重生存威脅的情況下,努力解決了一些核心的可用性和穩(wěn)定性問題。同時(shí)隨著端游黃金時(shí)代的結(jié)束,網(wǎng)站性能問題也逐漸顯得不再重要。
在圍繞新版本網(wǎng)站是否要正式替換老版本網(wǎng)站的問題上,各個(gè)利益方爭執(zhí)不下,反反復(fù)復(fù)拉鋸戰(zhàn),而空降而來的女CTO不屬于任何派系,態(tài)度模棱兩可。最終斗爭的結(jié)果.net利益方戰(zhàn)勝了Java利益方,Java研發(fā)部門被清洗。
我的.net系統(tǒng)架構(gòu)改造的經(jīng)驗(yàn)和教訓(xùn)
3年前,我剛接手CSDN的產(chǎn)品和研發(fā)團(tuán)隊(duì)的時(shí)候,CSDN的核心系統(tǒng)大約2/3是Windows平臺(tái).net架構(gòu),1/3是LAMP架構(gòu)。研發(fā)人員當(dāng)時(shí)也很少:只有2個(gè).net程序員,3個(gè)PHP程序員,后來還有1個(gè)我?guī)н^來的Ruby程序員。當(dāng)時(shí)的計(jì)劃是:網(wǎng)站整體架構(gòu)改造的方向是Linux架構(gòu),逐漸替換掉現(xiàn)有的.net系統(tǒng)。因此不打算繼續(xù)招聘和補(bǔ)充.net程序員了,現(xiàn)有的.net程序員負(fù)責(zé)老的核心系統(tǒng)維護(hù)工作。
但碩果僅存的2個(gè).net程序員在隨后不到半年時(shí)間都走了:一個(gè).net程序員跟著微軟出來的高管去創(chuàng)業(yè),另一個(gè).net程序員跳槽去百度做了前端工程師。這中間的道理也很簡單:既然公司要去.net化,那.net工程師就會(huì)擔(dān)心等到將來.net系統(tǒng)都換掉之后,自己在公司還有價(jià)值嗎,不就徹底邊緣化了嗎?
當(dāng)然我在制訂架構(gòu)遷移計(jì)劃的時(shí)候,也考慮到了這一點(diǎn):我給那個(gè)更資深的.net工程師制訂的是整個(gè)公司總架構(gòu)師的培養(yǎng)計(jì)劃,那個(gè)精通JS的.net 工程師制訂的是未來前端團(tuán)隊(duì)Leader的培養(yǎng)計(jì)劃。不過有不確性的承諾總是不如現(xiàn)實(shí)的威脅更迫切,所以我也特別能夠理解.net工程師的流失。
這個(gè)時(shí)候,我陷入了一個(gè)兩難的處境:
-
如果未來還是沿著“去.net化”的計(jì)劃往下走,就算重新招聘和搭建了.net研發(fā)團(tuán)隊(duì),由于.net在公司是注定要被替換掉的,那么新的.net團(tuán)隊(duì)是不可能穩(wěn)定的,很可能來一兩個(gè)月,一看形勢不對(duì),立馬走人了。而當(dāng)時(shí).net的核心系統(tǒng)占整個(gè)網(wǎng)站的比重很高,且極端復(fù)雜,一旦出問題,根本就束手無策,必須要有好手坐鎮(zhèn)維護(hù)。當(dāng)時(shí)我已經(jīng)開始review核心系統(tǒng)的.net代碼,準(zhǔn)備親自上陣了。
-
如果未來放棄“去.net化”的計(jì)劃,也許短期可以解決一些頭疼的系統(tǒng)維護(hù)的問題,但是對(duì)整個(gè)網(wǎng)站長期的發(fā)展會(huì)帶來很多不利的方面:例如網(wǎng)站的安全性問題,網(wǎng)站的架構(gòu)擴(kuò)展問題,網(wǎng)站服務(wù)端軟件全面正版化的成本問題等等。如果當(dāng)時(shí)不下定決心去.net化,那么將來再想做這個(gè)事情,代價(jià)只會(huì)越來越高。
當(dāng)時(shí),我最初的想法是:招聘2名水平尚可,沒有太大上進(jìn)心,可以安于現(xiàn)狀,踏踏實(shí)實(shí)工作的.net程序員來維護(hù)老的.net核心系統(tǒng);同時(shí)招聘和搭建ruby研發(fā)團(tuán)隊(duì),以我過去用ruby開發(fā)網(wǎng)站的驚人開發(fā)效率,爭取時(shí)間,逐一重寫老的.net核心系統(tǒng)。但是這樣做,風(fēng)險(xiǎn)也很大:
- 我來CSDN的時(shí)間不是很長,當(dāng)時(shí)CSDN線上產(chǎn)品又多又雜,足有上百個(gè)之多,很多系統(tǒng)我都不清楚干什么的;
- 公司領(lǐng)導(dǎo)也不太支持我這么快動(dòng)手,甚至很擔(dān)心我大刀闊斧的改造網(wǎng)站,會(huì)把當(dāng)時(shí)已經(jīng)很脆弱的網(wǎng)站徹底搞休克;
- 我來北京以后,只帶過來1個(gè)Ruby程序員,而搭建Ruby團(tuán)隊(duì),磨合團(tuán)隊(duì),開發(fā)核心系統(tǒng),都不是一朝一夕的事情,想快也很難快起來;
幸運(yùn)的是,我招聘過程中,面試到了兩個(gè)相當(dāng)不錯(cuò)的.net工程師,有很強(qiáng)的上進(jìn)心,編程功底和悟性都很好。雖然不符合我當(dāng)時(shí)想找安于現(xiàn)狀的工程師的標(biāo)準(zhǔn),但我又不太想錯(cuò)過好的人才,所以我臨時(shí)改變了自己的想法,將他們招過來,組建了新的.net團(tuán)隊(duì)。
為了避免出現(xiàn)之前.net團(tuán)隊(duì)流失的問題,給新的.net團(tuán)隊(duì)創(chuàng)造在公司發(fā)展的機(jī)會(huì)和空間,我想來想去,決定采取一個(gè)折衷的方案:即保留和沿用.net編程語言和框架,但是網(wǎng)站整體架構(gòu)仍然去Windows化,概要說來:
- 數(shù)據(jù)層放棄SQL Server數(shù)據(jù)庫和存儲(chǔ)過程,全部遷移到Linux平臺(tái)上的MySQL數(shù)據(jù)庫上;
- 緩存不再依賴.net自身提供的緩存機(jī)制,遷移到部署在Linux平臺(tái)上的分布式的Redis上;
- 服務(wù)之間的調(diào)用,避免使用.net自身專有協(xié)議,改成Restful的HTTP Web API調(diào)用;
- 靜態(tài)資源請(qǐng)求,不再讓IIS自己處理,分離到Linux平臺(tái)上的nginx去處理;
- 需要讀取的文件系統(tǒng),也改成訪問Linux平臺(tái)上的分布式文件系統(tǒng);
- 部署.net代碼的Windows服務(wù)器放在LVS后面,用LVS做負(fù)載均衡和故障切換;
簡單說來,就是單純讓.net做應(yīng)用層的編程語言和框架,其他都交給Linux平臺(tái)的開源解決方案。而.net框架單純做應(yīng)用層,無論 ASP.net MVC的開發(fā)效率,還是.net CLR虛擬機(jī)的運(yùn)行效率都非常好,目前我們單臺(tái)Windows服務(wù)器上跑幾百萬的動(dòng)態(tài)請(qǐng)求毫無壓力,而且應(yīng)用層架構(gòu)是可以橫向擴(kuò)展的:如果請(qǐng)求負(fù)載非常高,只需要添加更多Windows服務(wù)器即可??傊?,做到了揚(yáng)長避短。
此外,我也比較注重不同編程語言研發(fā)團(tuán)隊(duì)之間的交流,鼓勵(lì).net工程師熟悉Linux操作系統(tǒng),培養(yǎng).net工程師整體架構(gòu)意識(shí)。我們現(xiàn)在的主力.net骨干和我說,感覺來到這里以后技術(shù)上最大的提升就是視野一下被打開了。
在后來兩年的整個(gè)網(wǎng)站改造過程中,也證明了這樣的做法是相當(dāng)成功的:
- .net團(tuán)隊(duì)穩(wěn)定的延續(xù)了下來,而且成為整個(gè)研發(fā)部門表現(xiàn)一直非常突出的團(tuán)隊(duì);
- 整個(gè)系統(tǒng)改造的過程非常穩(wěn)健和平滑,沒有碰到過什么風(fēng)險(xiǎn);
- 對(duì)網(wǎng)站用戶的沖擊很小,基本上都是在潛移默化當(dāng)中,不知不覺的完成了整個(gè)網(wǎng)站產(chǎn)品的翻新;
- 對(duì)公司線上業(yè)務(wù)也沒有造成任何影響,而且隨著系統(tǒng)不斷改造,對(duì)業(yè)務(wù)的支持越來越好;
當(dāng)網(wǎng)站架構(gòu)全面Linux化,并且架構(gòu)解決方案全部統(tǒng)一以后,其實(shí)在應(yīng)用層用什么編程語言來寫,就不是一件重要的事情了,我們目前應(yīng)用層現(xiàn)有產(chǎn)品線,既有.net,也有PHP和Ruby寫的,但是架構(gòu)都是統(tǒng)一的,用什么編程語言,主要取決于研發(fā)團(tuán)隊(duì)資源的調(diào)配情況而定。
總之,以我的經(jīng)驗(yàn)來說,一個(gè)傳統(tǒng)上嚴(yán)重依賴微軟解決方案架構(gòu)的網(wǎng)站,如果要進(jìn)行架構(gòu)改造,遷移到Linux平臺(tái),甚至用其他編程語言重寫,從來都不是一個(gè)單純的技術(shù)問題,它至少涉及如下幾個(gè)層面的問題:
- 如何保障舊系統(tǒng)的研發(fā)團(tuán)隊(duì)的利益問題,如何做到激勵(lì)老團(tuán)隊(duì)參與架構(gòu)改造,分享成功。這是最重要的,往往也是架構(gòu)遷移最容易出現(xiàn)的致命問題,如果架構(gòu)改造注定要犧牲老團(tuán)隊(duì),完全不考慮和保障他們的利益,我認(rèn)為一定會(huì)產(chǎn)生殘酷的政治斗爭,最終必然失敗;
- 現(xiàn)有業(yè)務(wù)系統(tǒng)如何保持正常運(yùn)轉(zhuǎn)和平滑過渡的問題,如果架構(gòu)改造影響到了業(yè)務(wù),那一定會(huì)夭折;
- 如何保證網(wǎng)站用戶體驗(yàn)的平滑過渡和改善的問題,如果架構(gòu)改造影響了用戶基本使用體驗(yàn),那也一定會(huì)被叫停;
- 領(lǐng)導(dǎo)對(duì)架構(gòu)改造當(dāng)中出現(xiàn)風(fēng)險(xiǎn)的容忍度問題,以及領(lǐng)導(dǎo)對(duì)架構(gòu)改造周期拉長以后的耐心問題;
一點(diǎn)題外話
我感覺我們互聯(lián)網(wǎng)行業(yè)有一個(gè)不太好的現(xiàn)象:有些網(wǎng)站在促銷期間癱瘓了,有些網(wǎng)站經(jīng)常出現(xiàn)訪問不穩(wěn)定的現(xiàn)象,公司老板就喜歡跑到微博上來放狠話,請(qǐng)下屬喝茶,或者急就章的嚷嚷百萬年薪招CTO,這些都是很幼稚的做法。這就好比一個(gè)人,平常生活習(xí)慣差,花天酒地,從不注意養(yǎng)生,結(jié)果長年累月下來,終于病倒了。在這個(gè)時(shí)候狠狠的揮舞支票嚷嚷,哪個(gè)名醫(yī)能給我藥到病除,我給誰百萬報(bào)酬。
所以,當(dāng)一個(gè)網(wǎng)站出現(xiàn)嚴(yán)重的技術(shù)問題,其根源往往都不是單純的技術(shù)問題,也不是單純換個(gè)CTO就可以藥到病除的,要反思公司企業(yè)文化是不是從來沒有重視過研發(fā),對(duì)技術(shù)團(tuán)隊(duì)的激勵(lì)到位了嗎?對(duì)架構(gòu)師的意見重視過嗎?對(duì)未來可能面臨的技術(shù)門檻是否有過長期的研發(fā)投入?
關(guān)于這個(gè)現(xiàn)象,我記得Fenng說過一句很精辟的話:“技術(shù)問題,總是在短期被高估,在長期被低估”,我也想補(bǔ)充一句:“技術(shù)出現(xiàn)了問題,從來都不單純是技術(shù)導(dǎo)致的問題”。