好的架構(gòu)不是設(shè)計出來的,而是演進出來的
對很多創(chuàng)業(yè)公司而言努隙,很難在初期就預(yù)估到流量十倍球恤、百倍以及千倍以后網(wǎng)站架構(gòu)會是什么樣的一個狀況。同時荸镊,如果系統(tǒng)初期就設(shè)計一個千萬級并發(fā)的流量架構(gòu)咽斧,很難有公司可以支撐這個成本。
因此躬存,這里主要會關(guān)注架構(gòu)的眼花张惹。在每個階段,找到對應(yīng)該階段網(wǎng)站架構(gòu)所面臨的問題岭洲,然后在不斷解決這些問題宛逗,在這個過程中整個架構(gòu)會一直演進。
在58同城建立之初盾剩,站點的流量非常小雷激,可能也就是十萬級別,這也就意味著告私,平均每秒鐘也就是幾次的訪問屎暇,此時網(wǎng)站架構(gòu)的特點是:請求量比較低,數(shù)據(jù)量比較小驻粟,代碼量也比較小根悼。這個時候的站點可以被幾個工程師輕易搞定,因此根本沒什么“架構(gòu)”可言蜀撑。
其實這也是很多創(chuàng)業(yè)公司初期面臨的問題挤巡,最開始58同城的站點架構(gòu)用一個詞概括就是“ALL IN ONE”,如下圖所示:
就像一個單機系統(tǒng)屯掖,所有的東西都部署在一臺機器上,包括站點襟衰、數(shù)據(jù)庫贴铜、文件等等。而工程師每天的核心工作就是CURD瀑晒,前端傳過來一些數(shù)據(jù)绍坝,然后業(yè)務(wù)邏輯層拼裝成一些CURD訪問數(shù)據(jù)庫,數(shù)據(jù)庫返回數(shù)據(jù)苔悦,數(shù)據(jù)拼裝成頁面轩褐,最終返回到瀏覽器。相信很多創(chuàng)業(yè)團隊初期都面臨一個與之類似的情況玖详,每天寫代碼把介,寫SQL勤讽、接口參數(shù)、訪問數(shù)據(jù)等等拗踢。
這里需要說明一個問題脚牍,大家都知道最初58同城使用的是Windows、iis巢墅、SQL-Sever诸狭、C#這條路。現(xiàn)在很多創(chuàng)業(yè)公司可能就不會這么做君纫。
如果可以重來驯遇?那么會選擇LAMP
很多創(chuàng)業(yè)的同學(xué)可能會想,初期什么樣的一個架構(gòu)合適蓄髓? 如果重來叉庐,站在現(xiàn)在這個角度上58會選擇LAMP,為什么双吆?首先是無須編譯眨唬,而且快速發(fā)布功能強大,從前端到后端好乐、數(shù)據(jù)庫訪問匾竿、業(yè)務(wù)邏輯處理等等全部可以搞定,最重要都是成熟的開源產(chǎn)品蔚万,完全免費的岭妖。如果使用LAMP搭建一個論壇,兩天的時間就足夠了反璃。所以昵慌,如果在創(chuàng)業(yè)初期,就盡量不要再使用Windows淮蜈。
在這個階段58同城面臨的主要問題是什么斋攀?其實就是招人,最初工程師寫CURD都容易出錯梧田。當(dāng)時引進了DAO和ORM淳蔼,從而避免直接面對CURD語句,而是面對工程師比較擅長的是面向?qū)ο蟛妹校軌驑O大的提高工作效率鹉梨,降低出錯率。
中等規(guī)模:流量跨過十萬的階段穿稳,數(shù)據(jù)庫成為瓶頸
隨著58同城的高速增長存皂,系統(tǒng)很快跨越了十萬流量階段。主要需求是什么逢艘?網(wǎng)站能夠正常訪問旦袋,當(dāng)然速度更快點就好了骤菠。而此時系統(tǒng)面臨的問題有:在流量峰值期容易宕機,因為大量的請求會壓到數(shù)據(jù)庫上猜憎,所以數(shù)據(jù)庫成為新的瓶頸娩怎,從而,人越多訪問越慢胰柑。而在這個時候截亦,機器數(shù)量也從一臺變成了多臺,所以很自然的行程了分布式架構(gòu)柬讨,如下圖所示:
首先崩瓤,使用了一些非常常見的技術(shù),一方面是動靜分離踩官,動態(tài)的頁面通過Web-Servre訪問却桶,靜態(tài)的像圖片等就單獨放到了一些服務(wù)器上。另外一點就是讀寫分離蔗牡。其實颖系,對58同城或者說絕大部分的站點而言,一般來說都是讀多寫少辩越。對58同城來說嘁扼,絕大部分用戶是訪問信息,只有很少的用戶過來發(fā)貼黔攒。那么如何擴展整個站點架構(gòu)的讀請求呢趁啸?常用的是主從同步,讀寫分離督惰。同時原來只有一個數(shù)據(jù)庫不傅,現(xiàn)在使用多個不同的數(shù)據(jù)庫提供服務(wù),這樣的話赏胚,就擴展了讀寫访娶,很快就解決了中等規(guī)模下數(shù)據(jù)訪問的問題。
在這個階段觉阅,系統(tǒng)的主要矛盾就是“站點耦合+讀寫延時”崖疤,58同城是如何進行解耦,如何緩解延時呢留拾?
對58同城而言戳晌,典型業(yè)務(wù)場景是主頁鲫尊,發(fā)布信息有發(fā)布頁痴柔,信息聚合、標(biāo)題聚合有列表頁疫向,點開一個標(biāo)題有詳細(xì)頁咳蔚,而這些站點都是耦合在一個程序中的豪嚎,或者說耦合在一個站點中的,當(dāng)一個站點出現(xiàn)問題谈火,整個站點就會因為耦合一起出問題侈询。
第二個問題,大家都知道做數(shù)據(jù)庫讀請求和寫請求糯耍,分布在不同的數(shù)據(jù)庫上扔字,這個時候如果再讀取可能讀到的是舊數(shù)據(jù),因為讀寫有一個延時温技。如果有用戶發(fā)帖子革为,馬上去找的話肯定找不到,很可能帶來的后果就是陸續(xù)在發(fā)布兩條信息舵鳞,這就是一個很大的問題震檩。尤其是在請求量越來越大的時候,這個問題就更加突出蜓堕。
在解決這些問題時抛虏,最先想到的是針對原來站點的核心業(yè)務(wù)做切分,然后工程師根據(jù)自己的站點和業(yè)務(wù)場景進行細(xì)分套才。首先迂猴,業(yè)務(wù)拆分是58同城最先嘗試的優(yōu)化——將業(yè)務(wù)垂直拆分成了首頁和發(fā)布頁。另外霜旧,在數(shù)據(jù)庫層面错忱,隨之也進行了拆分,將大數(shù)據(jù)量拆分成一個個小的數(shù)據(jù)量挂据。這樣以清,讀寫延時就馬上得到了緩解。尤其是在代碼拆分成了不同的層面之后崎逃,站點耦合也得到了緩解掷倔,數(shù)據(jù)加載速度也提升了很多。
當(dāng)時个绍,還使用了一些技術(shù)勒葱,前面也提到了對動態(tài)資源和靜態(tài)資源進行拆分。其中巴柿,我們對靜態(tài)資源使用了CDN服務(wù)凛虽,便于數(shù)據(jù)緩存和就近訪問,訪問速度得到很明顯的提升广恢。除此之外凯旋,還使用了MVC模式,擅長前端的去做展示層,擅長協(xié)作邏輯的工程師就做Contorller至非,擅長數(shù)據(jù)的人就負(fù)責(zé)數(shù)據(jù)钠署,效率就會逐步的提高,最后就是負(fù)載均衡技術(shù)荒椭。
大流量:將整個Windows技術(shù)體系轉(zhuǎn)向了Java體系
流量越來越大谐鼎,當(dāng)流量超過一千多萬時,58同城面臨的最大問題就是性能和成本趣惠。此前曾提到58同城最初的技術(shù)選型是Windows狸棍,整個網(wǎng)站的性能變得非常之低。即使進行了業(yè)務(wù)拆分和一些優(yōu)化味悄,依然解決不了這個問題隔缀,所以當(dāng)時做了一個非常艱難的決定,就是轉(zhuǎn)型:將整個Windows技術(shù)體系轉(zhuǎn)向了Java體系傍菇,這涵蓋了操作系統(tǒng)猾瘸、數(shù)據(jù)庫等多個維度。
其實丢习,現(xiàn)在很多大的互聯(lián)網(wǎng)公司在流量從小到大的過程中都經(jīng)歷過轉(zhuǎn)型牵触,包括京東、淘寶等等咐低。對技術(shù)的要求越來越高揽思,任何一個站點都不能掛,對站點的可用性要求也是越來越高见擦。
就在這個時候钉汗,58同城業(yè)務(wù)量也出現(xiàn)一個爆發(fā)期。于是招聘了很多工程師鲤屡,大家一起寫越來越多的站點损痰,但是發(fā)現(xiàn)效率很低,經(jīng)常做一些重復(fù)性的工作酒来,比如參數(shù)解析等等卢未。同時,業(yè)務(wù)之間相互依賴堰汉,無論是分類的子系統(tǒng)還是信息的子系統(tǒng)辽社,二手車業(yè)務(wù)、房產(chǎn)業(yè)務(wù)都要訪問用戶和信息等一些底層數(shù)據(jù)翘鸭,代碼之間頻繁的溝通滴铅,效率也不可能很高。
問題隨之而來就乓,站點數(shù)越來越多汉匙,數(shù)據(jù)量越來越大譬淳,機器數(shù)從最開始的幾臺上升到幾百臺的級別。那么如何提供整個架構(gòu)的可用性呢盹兢?首先,在上層進行了一些改進和優(yōu)化守伸,再做進一步的垂直拆分绎秒,同時引入了Cache,如下圖所示:
在架構(gòu)的改進上尼摹,這里構(gòu)建了一個相對獨立的服務(wù)層见芹,這個服務(wù)層做的每個業(yè)務(wù)線都會寫對應(yīng)的代碼。如果用戶發(fā)出請求蠢涝,就由這個服務(wù)層統(tǒng)一來管理玄呛,所有的上游業(yè)務(wù)線就像調(diào)用本地函數(shù)一樣,通過IDC的框架來調(diào)用這個服務(wù)和二。整個用戶登錄先訪問Cache徘铝,如果Cache變動了就直接返回,如果Cache不變動惯吕,就會訪問數(shù)據(jù)庫惕它,這樣把數(shù)據(jù)庫的數(shù)據(jù)拿到本地再放回Cache,再打回上一輪废登。如此一來淹魄,業(yè)務(wù)邏輯全部封裝在這個服務(wù)的上游管理,該業(yè)務(wù)邏輯只有服務(wù)層能夠編寫代碼堡距,然后由這個服務(wù)層集中管理甲锡、集中優(yōu)化,這樣就提高了效率羽戒。
除此之外缤沦,為了保證站點的高可用,主要使用了反向代理技術(shù)易稠。因為對用戶而言疚俱,他主要為了使用58同城的服務(wù),不會關(guān)注訪問是58同城或者有十臺首頁的服務(wù)器缩多。58同城通過反向代理技術(shù)呆奕,通過DNS群,通過LVS技術(shù)衬吆,來保證接入層的高可用性梁钾,同時還保證了服務(wù)層、站點層逊抡、數(shù)據(jù)層的高可用姆泻。另外零酪,為了保證高可用還使用了冗余的方法,無論是站點服務(wù)和數(shù)據(jù)服務(wù)都可以使用這種方式進行解決拇勃,一個站點不可用四苇,就換一個站點,一個數(shù)據(jù)庫不夠用方咆,就多加幾個月腋。當(dāng)然,數(shù)據(jù)冗余也會帶來一些副作用瓣赂,如果數(shù)據(jù)量更新的話榆骚,那就需要將所有的“冗余”都要進行更新。
58同城也做了一個圖片存儲系統(tǒng)煌集,開始都是存儲在操作系統(tǒng)之上妓肢,隨著新增站點、新增服務(wù)苫纤,壓力就變得越來越大碉钠。于是,58同城就自建了站點框架和服務(wù)框架卷拘,現(xiàn)在這兩個框架也已經(jīng)開源(如何降低站點開發(fā)成本放钦?https://github.com/58code/Argo?如何降低服務(wù)開發(fā)成本?https://github.com/58code/Gaea)只需要修改一些基本的配置就可以使用了恭金。
當(dāng)架構(gòu)變成“蜘蛛網(wǎng)”操禀,人肉已很難搞定!
隨著用戶量横腿、數(shù)據(jù)量并發(fā)量進一步的增長颓屑,58同城也拓展了很多的新業(yè)務(wù),那么對產(chǎn)品迭代速度要求就非常高耿焊,整體的架構(gòu)對自動化的要求越來越高揪惦。
為了支撐業(yè)務(wù)的發(fā)展,技術(shù)團隊對架構(gòu)做了進一步的解耦罗侯,另外就是引入了配置中心器腋,如果要訪問任何一個服務(wù),不會直接在本地的配置中留下一個服務(wù)钩杰,配置中心告訴這個服務(wù)的特點纫塌,如果擴展的話,配置中心自動下達消息讲弄,如果有機器要下線的話措左,配置中心會反向通過發(fā)郵件的方式進行通知。
而柔性服務(wù)是指當(dāng)流量增加的時候避除,自動的新增服務(wù)怎披⌒剜遥可以看到進一步解耦之后,有垂直業(yè)務(wù)凉逛、無線業(yè)務(wù)性宏、集成業(yè)務(wù)等等,這些子系統(tǒng)之間都是通過配置中心相應(yīng)之間發(fā)生關(guān)系的状飞。
另一點就是關(guān)于數(shù)據(jù)庫毫胜,當(dāng)某一點成為一個業(yè)務(wù)線重點的時候,就會集中解決這個點的問題昔瞧。最初期的時候每個業(yè)務(wù)線都要訪問數(shù)據(jù)庫,訪問緩存菩佑,訪問用戶數(shù)據(jù)自晰,于是把代碼集中的放到了服務(wù)層。現(xiàn)在數(shù)據(jù)量越來越大稍坯,大家都要做數(shù)據(jù)切分酬荞,每個業(yè)務(wù)線都做切分,這個時候58同城的每個頁面都面對這樣的痛點瞧哟,于是把這個痛點拿到集中的層面來解決混巧。
最后一點就是效率矛盾,此時有很多問題勤揩,靠“人肉”已經(jīng)很難進行搞定了咧党。這就需要自動化,包括回歸陨亡、測試傍衡、運維、監(jiān)控等等都要回歸到自動化负蠕。
這里需要補充一點蛙埂,就是在產(chǎn)品層面引入了智能化,比如說智能推薦遮糖,主動推薦一些相關(guān)的話題绣的;智能廣告,通過一些智能的策略欲账,讓用戶對廣告的點擊更多屡江,增加對58同城的收錄;智能搜索赛不,在搜索的過程中加入一些搜索的策略盼理,可以提高搜索的權(quán)重,也可以增加58同城的PV俄删。當(dāng)然宏怔,所有的自動化的產(chǎn)品背后都是由技術(shù)在驅(qū)動奏路。
未來的挑戰(zhàn)
現(xiàn)在,58同城的流量已經(jīng)突破了10億量級臊诊,那么架構(gòu)上未來面臨哪些挑戰(zhàn)呢鸽粉?一方面是無線化、移動化抓艳。另一方面就是需求的變化触机,必須加快迭代一些東西。如果擁有10億的流量玷或,卻跑在一億的架構(gòu)上肯定是不行的儡首。未來,還會使用更多的并行計算偏友、實時計算蔬胯,如果能做到實時推薦,效果肯定非常好位他,這也是挑戰(zhàn)之一氛濒。最后一點,58同城現(xiàn)在的服務(wù)器大概在3000臺左右鹅髓,未來將拓展到10000臺舞竿,這就是運維的挑戰(zhàn)了。
總結(jié)
最后做一個小的總結(jié)窿冯,網(wǎng)站在不同的階段遇到的問題不一樣骗奖,而解決這些問題使用的技術(shù)也不一樣,流量小的時候醒串,主要目的是提高開發(fā)效率重归,在早期要引入ORM,DAO這些技術(shù)厦凤。隨著流量變大鼻吮,使用動靜分離、讀寫分離较鼓、主從同步椎木、垂直拆分、CDN博烂、MVC等方式不斷地提升網(wǎng)站穩(wěn)定性香椎。面對更大的流量時,通過垂直拆分禽篱、服務(wù)化姨蟋、反向代理爵川、開發(fā)框架(站點/服務(wù))等等曹抬,不斷提升高可用。在面對上億級的更大流量時万矾,通過中心化、柔性服務(wù)慎框、消息總線良狈、自動化(回歸,測試笨枯,運維薪丁,監(jiān)控)來迎接新的挑戰(zhàn)。未來的就是繼續(xù)實現(xiàn).
作者:58沈劍