專注于互聯網服務

專業設計,網站建設,應用軟件開(kāi)發(fā),電子商務平台及商務應用系統開(kāi)發(fā).

億級Web系統搭建——單機到分布式集群

2014-12-6 返回

  當一個Web系統從日訪問量10萬逐步增長(cháng)到1000萬,甚至超過(guò)1億的過(guò)程中,Web系統承受的壓力會(huì)越來越大,在這(zhè)個過(guò)程中,我 們會(huì)遇到很多的問題。爲了解決這(zhè)些性能(néng)壓力帶來問題,我們需要在Web系統架構層面(miàn)搭建多個層次的緩存機制。在不同的壓力階段,我們會(huì)遇到不同的問題,通 過(guò)搭建不同的服務和架構來解決。

  Web負載均衡

  Web負載均衡(Load Balancing),簡單地說(shuō)就(jiù)是給我們的服務器集群分配“工作任務”,而采用恰當的分配方式,對(duì)于保護處于後(hòu)端的Web服務器來說(shuō),非常重要。

  負載均衡的策略有很多,我們從簡單的講起(qǐ)哈。

  1. HTTP重定向(xiàng)

  當用戶發(fā)來請求的時(shí)候,Web服務器通過(guò)修改HTTP響應頭中的Location标記來返回一個新的url,然後(hòu)浏覽器再繼續請求這(zhè)個新 url,實際上就(jiù)是頁面(miàn)重定向(xiàng)。通過(guò)重定向(xiàng),來達到“負載均衡”的目标。例如,我們在下載PHP源碼包的時(shí)候,點擊下載鏈接時(shí),爲了解決不同國(guó)家和地域下 載速度的問題,它會(huì)返回一個離我們近的下載地址。重定向(xiàng)的HTTP返回碼是302,如下圖:

  如果使用PHP代碼來實現這(zhè)個功能(néng),方式如下:

  這(zhè)個重定向(xiàng)非常容易實現,并且可以自定義各種(zhǒng)策略。但是,它在大規模訪問量下,性能(néng)不佳。而且,給用戶的體驗也不好(hǎo),實際請求發(fā)生重定向(xiàng),增加了網絡延時(shí)。

  2. 反向(xiàng)代理負載均衡

  反向(xiàng)代理服務的核心工作主要是轉發(fā)HTTP請求,扮演了浏覽器端和後(hòu)台Web服務器中轉的角色。因爲它工作在HTTP層(應用層),也就(jiù)是網絡七層結構中的第七層,因此也被(bèi)稱爲“七層負載均衡”。可以做反向(xiàng)代理的軟件很多,比較常見的一種(zhǒng)是Nginx。

  Nginx是一種(zhǒng)非常靈活的反向(xiàng)代理軟件,可以自由定制化轉發(fā)策略,分配服務器流量的權重等。反向(xiàng)代理中,常見的一個問題,就(jiù)是Web服務器存 儲的session數據,因爲一般負載均衡的策略都(dōu)是随機分配請求的。同一個登錄用戶的請求,無法保證一定分配到相同的Web機器上,會(huì)導緻無法找到 session的問題。

  解決方案主要有兩(liǎng)種(zhǒng):

  1. 配置反向(xiàng)代理的轉發(fā)規則,讓同一個用戶的請求一定落到同一台機器上(通過(guò)分析cookie),複雜的轉發(fā)規則將(jiāng)會(huì)消耗更多的CPU,也增加了代理服務器的負擔。

  2. 將(jiāng)session這(zhè)類的信息,專門用某個獨立服務來存儲,例如redis/memchache,這(zhè)個方案是比較推薦的。

  反向(xiàng)代理服務,也是可以開(kāi)啓緩存的,如果開(kāi)啓了,會(huì)增加反向(xiàng)代理的負擔,需要謹慎使用。這(zhè)種(zhǒng)負載均衡策略實現和部署非常簡單,而且性能(néng)表現也比 較好(hǎo)。但是,它有“單點故障”的問題,如果挂了,會(huì)帶來很多的麻煩。而且,到了後(hòu)期Web服務器繼續增加,它本身可能(néng)成(chéng)爲系統的瓶頸。

  3. IP負載均衡

  IP負載均衡服務是工作在網絡層(修改IP)和傳輸層(修改端口,第四層),比起(qǐ)工作在應用層(第七層)性能(néng)要高出非常多。原理是,他是對(duì)IP 層的數據包的IP地址和端口信息進(jìn)行修改,達到負載均衡的目的。這(zhè)種(zhǒng)方式,也被(bèi)稱爲“四層負載均衡”。常見的負載均衡方式,是LVS(Linux Virtual Server,Linux虛拟服務),通過(guò)IPVS(IP Virtual Server,IP虛拟服務)來實現。

  在負載均衡服務器收到客戶端的IP包的時(shí)候,會(huì)修改IP包的目标IP地址或端口,然後(hòu)原封不動地投遞到内部網絡中,數據包會(huì)流入到實際Web服務器。實際服務器處理完成(chéng)後(hòu),又會(huì)將(jiāng)數據包投遞回給負載均衡服務器,它再修改目标IP地址爲用戶IP地址,最終回到客戶端。

  上述的方式叫(jiào)LVS-NAT,除此之外,還(hái)有LVS-RD(直接路由),LVS-TUN(IP隧道(dào)),三者之間都(dōu)屬于LVS的方式,但是有一定的區别,篇幅問題,不贅叙。

  IP負載均衡的性能(néng)要高出Nginx的反向(xiàng)代理很多,它隻處理到傳輸層爲止的數據包,并不做進(jìn)一步的組包,然後(hòu)直接轉發(fā)給實際服務器。不過(guò),它的配置和搭建比較複雜。

  4. DNS負載均衡

  DNS(Domain Name System)負責域名解析的服務,域名url實際上是服務器的别名,實際映射是一個IP地址,解析過(guò)程,就(jiù)是DNS完成(chéng)域名到IP的映射。而一個域名是可以配置成(chéng)對(duì)應多個IP的。因此,DNS也就(jiù)可以作爲負載均衡服務。

  這(zhè)種(zhǒng)負載均衡策略,配置簡單,性能(néng)極佳。但是,不能(néng)自由定義規則,而且,變更被(bèi)映射的IP或者機器故障時(shí)很麻煩,還(hái)存在DNS生效延遲的問題。

  5. DNS/GSLB負載均衡

  我們常用的CDN(Content Delivery Network,内容分發(fā)網絡)實現方式,其實就(jiù)是在同一個域名映射爲多IP的基礎上更進(jìn)一步,通過(guò)GSLB(Global Server Load Balance,全局負載均衡)按照指定規則映射域名的IP。一般情況下都(dōu)是按照地理位置,將(jiāng)離用戶近的IP返回給用戶,減少網絡傳輸中的路由節點之間的 跳躍消耗。

  圖中的“向(xiàng)上尋找”,實際過(guò)程是LDNS(Local DNS)先向(xiàng)根域名服務(Root Name Server)獲取到頂級根的Name Server(例如.com的),然後(hòu)得到指定域名的授權DNS,然後(hòu)再獲得實際服務器IP。

  CDN在Web系統中,一般情況下是用來解決大小較大的靜态資源(html/Js/Css/圖片等)的加載問題,讓這(zhè)些比較依賴網絡下載的内容,盡可能(néng)離用戶更近,提升用戶體驗。

  例如,我訪問了一張imgcache.gtimg.cn上的圖片(騰訊的自建CDN,不使用qq.com域名的原因是防止http請求的時(shí)候,帶上了多餘的cookie信息),我獲得的IP是183.60.217.90。

  這(zhè)種(zhǒng)方式,和前面(miàn)的DNS負載均衡一樣(yàng),不僅性能(néng)極佳,而且支持配置多種(zhǒng)策略。但是,搭建和維護成(chéng)本非常高。互聯網一線公司,會(huì)自建CDN服務,中小型公司一般使用第三方提供的CDN。

  Web系統的緩存機制的建立和優化

  剛剛我們講完了Web系統的外部網絡環境,現在我們開(kāi)始關注我們Web系統自身的性能(néng)問題。我們的Web站點随著(zhe)訪問量的上升,會(huì)遇到很多的挑戰,解決這(zhè)些問題不僅僅是擴容機器這(zhè)麼(me)簡單,建立和使用合适的緩存機制才是根本。

  最開(kāi)始,我們的Web系統架構可能(néng)是這(zhè)樣(yàng)的,每個環節,都(dōu)可能(néng)隻有1台機器。

  我們從最根本的數據存儲開(kāi)始看哈。

  一、 MySQL數據庫内部緩存使用

  MySQL的緩存機制,就(jiù)從先從MySQL内部開(kāi)始,下面(miàn)的内容將(jiāng)以最常見的InnoDB存儲引擎爲主。

  1. 建立恰當的索引

  最簡單的是建立索引,索引在表數據比較大的時(shí)候,起(qǐ)到快速檢索數據的作用,但是成(chéng)本也是有的。首先,占用了一定的磁盤空間,其中組合索引最突 出,使用需要謹慎,它産生的索引甚至會(huì)比源數據更大。其次,建立索引之後(hòu)的數據insert/update/delete等操作,因爲需要更新原來的索 引,耗時(shí)會(huì)增加。當然,實際上我們的系統從總體來說(shuō),是以select查詢操作居多,因此,索引的使用仍然對(duì)系統性能(néng)有大幅提升的作用。

  2. 數據庫連接線程池緩存

  如果,每一個數據庫操作請求都(dōu)需要創建和銷毀連接的話,對(duì)數據庫來說(shuō),無疑也是一種(zhǒng)巨大的開(kāi)銷。爲了減少這(zhè)類型的開(kāi)銷,可以在MySQL中配置thread_cache_size來表示保留多少線程用于複用。線程不夠的時(shí)候,再創建,空閑過(guò)多的時(shí)候,則銷毀。

  其實,還(hái)有更爲激進(jìn)一點的做法,使用pconnect(數據庫長(cháng)連接),線程一旦創建在很長(cháng)時(shí)間内都(dōu)保持著(zhe)。但是,在訪問量比較大,機器比較多 的情況下,這(zhè)種(zhǒng)用法很可能(néng)會(huì)導緻“數據庫連接數耗盡”,因爲建立連接并不回收,最終達到數據庫的max_connections(最大連接數)。因此,長(cháng) 連接的用法通常需要在CGI和MySQL之間實現一個“連接池”服務,控制CGI機器“盲目”創建連接數。

  建立數據庫連接池服務,有很多實現的方式,PHP的話,我推薦使用swoole(PHP的一個網絡通訊拓展)來實現。

  3. Innodb緩存設置(innodb_buffer_pool_size)

  innodb_buffer_pool_size這(zhè)是個用來保存索引和數據的内存緩存區,如果機器是MySQL獨占的機器,一般推薦爲機器物理内存的80%。在取表數據的場景中,它可以減少磁盤IO。一般來說(shuō),這(zhè)個值設置越大,cache命中率會(huì)越高。

  4. 分庫/分表/分區。

  MySQL數據庫表一般承受數據量在百萬級别,再往上增長(cháng),各項性能(néng)將(jiāng)會(huì)出現大幅度下降,因此,當我們預見數據量會(huì)超過(guò)這(zhè)個量級的時(shí)候,建議進(jìn) 行分庫/分表/分區等操作。最好(hǎo)的做法,是服務在搭建之初就(jiù)設計爲分庫分表的存儲模式,從根本上杜絕中後(hòu)期的風險。不過(guò),會(huì)犧牲一些便利性,例如列表式的 查詢,同時(shí),也增加了維護的複雜度。不過(guò),到了數據量千萬級别或者以上的時(shí)候,我們會(huì)發(fā)現,它們都(dōu)是值得的。

  二、 MySQL數據庫多台服務搭建

  1台MySQL機器,實際上是高風險的單點,因爲如果它挂了,我們Web服務就(jiù)不可用了。而且,随著(zhe)Web系統訪問量繼續增加,終于有一天,我 們發(fā)現1台MySQL服務器無法支撐下去,我們開(kāi)始需要使用更多的MySQL機器。當引入多台MySQL機器的時(shí)候,很多新的問題又將(jiāng)産生。

  1. 建立MySQL主從,從庫作爲備份

  這(zhè)種(zhǒng)做法純粹爲了解決“單點故障”的問題,在主庫出故障的時(shí)候,切換到從庫。不過(guò),這(zhè)種(zhǒng)做法實際上有點浪費資源,因爲從庫實際上被(bèi)閑著(zhe)了。

  2. MySQL讀寫分離,主庫寫,從庫讀。

  兩(liǎng)台數據庫做讀寫分離,主庫負責寫入類的操作,從庫負責讀的操作。并且,如果主庫發(fā)生故障,仍然不影響讀的操作,同時(shí)也可以將(jiāng)全部讀寫都(dōu)臨時(shí)切換到從庫中(需要注意流量,可能(néng)會(huì)因爲流量過(guò)大,把從庫也拖垮)。

  3. 主主互備。

  兩(liǎng)台MySQL之間互爲彼此的從庫,同時(shí)又是主庫。這(zhè)種(zhǒng)方案,既做到了訪問量的壓力分流,同時(shí)也解決了“單點故障”問題。任何一台故障,都(dōu)還(hái)有另外一套可供使用的服務。

  不過(guò),這(zhè)種(zhǒng)方案,隻能(néng)用在兩(liǎng)台機器的場景。如果業務拓展還(hái)是很快的話,可以選擇將(jiāng)業務分離,建立多個主主互備。

  三、 MySQL數據庫機器之間的數據同步

  每當我們解決一個問題,新的問題必然誕生在舊的解決方案上。當我們有多台MySQL,在業務高峰期,很可能(néng)出現兩(liǎng)個庫之間的數據有延遲的場景。 并且,網絡和機器負載等,也會(huì)影響數據同步的延遲。我們曾經(jīng)遇到過(guò),在日訪問量接近1億的特殊場景下,出現,從庫數據需要很多天才能(néng)同步追上主庫的數據。 這(zhè)種(zhǒng)場景下,從庫基本失去效用了。

  于是,解決同步問題,就(jiù)是我們下一步需要關注的點。

  1. MySQL自帶多線程同步

  MySQL5.6開(kāi)始支持主庫和從庫數據同步,走多線程。但是,限制也是比較明顯的,隻能(néng)以庫爲單位。MySQL數據同步是通過(guò)binlog日 志,主庫寫入到binlog日志的操作,是具有順序的,尤其當SQL操作中含有對(duì)于表結構的修改等操作,對(duì)于後(hòu)續的SQL語句操作是有影響的。因此,從庫 同步數據,必須走單進(jìn)程。

  2. 自己實現解析binlog,多線程寫入。

  以數據庫的表爲單位,解析binlog多張表同時(shí)做數據同步。這(zhè)樣(yàng)做的話,的确能(néng)夠加快數據同步的效率,但是,如果表和表之間存在結構關系或者數據依賴的話,則同樣(yàng)存在寫入順序的問題。這(zhè)種(zhǒng)方式,可用于一些比較穩定并且相對(duì)獨立的數據表。

  國(guó)内一線互聯網公司,大部分都(dōu)是通過(guò)這(zhè)種(zhǒng)方式,來加快數據同步效率。還(hái)有更爲激進(jìn)的做法,是直接解析binlog,忽略以表爲單位,直接寫入。 但是這(zhè)種(zhǒng)做法,實現複雜,使用範圍就(jiù)更受到限制,隻能(néng)用于一些場景特殊的數據庫中(沒(méi)有表結構變更,表和表之間沒(méi)有數據依賴等特殊表)。

  四、 在Web服務器和數據庫之間建立緩存

  實際上,解決大訪問量的問題,不能(néng)僅僅著(zhe)眼于數據庫層面(miàn)。根據“二八定律”,80%的請求隻關注在20%的熱點數據上。因此,我們應該建立 Web服務器和數據庫之間的緩存機制。這(zhè)種(zhǒng)機制,可以用磁盤作爲緩存,也可以用内存緩存的方式。通過(guò)它們,將(jiāng)大部分的熱點數據查詢,阻擋在數據庫之前。

  1. 頁面(miàn)靜态化

  用戶訪問網站的某個頁面(miàn),頁面(miàn)上的大部分内容在很長(cháng)一段時(shí)間内,可能(néng)都(dōu)是沒(méi)有變化的。例如一篇新聞報道(dào),一旦發(fā)布幾乎是不會(huì)修改内容的。這(zhè)樣(yàng)的 話,通過(guò)CGI生成(chéng)的靜态html頁面(miàn)緩存到Web服務器的磁盤本地。除了第一次,是通過(guò)動态CGI查詢數據庫獲取之外,之後(hòu)都(dōu)直接將(jiāng)本地磁盤文件返回給 用戶。

  在Web系統規模比較小的時(shí)候,這(zhè)種(zhǒng)做法看似完美。但是,一旦Web系統規模變大,例如當我有100台的Web服務器的時(shí)候。那樣(yàng)這(zhè)些磁盤文 件,將(jiāng)會(huì)有100份,這(zhè)個是資源浪費,也不好(hǎo)維護。這(zhè)個時(shí)候有人會(huì)想,可以集中一台服務器存起(qǐ)來,呵呵,不如看看下面(miàn)一種(zhǒng)緩存方式吧,它就(jiù)是這(zhè)樣(yàng)做的。

  2. 單台内存緩存

  通過(guò)頁面(miàn)靜态化的例子中,我們可以知道(dào)將(jiāng)“緩存”搭建在Web機器本機是不好(hǎo)維護的,會(huì)帶來更多問題(實際上,通過(guò)PHP的apc拓展,可通過(guò)Key/value操作Web服務器的本機内存)。因此,我們選擇搭建的内存緩存服務,也必須是一個獨立的服務。

  内存緩存的選擇,主要有redis/memcache。從性能(néng)上說(shuō),兩(liǎng)者差别不大,從功能(néng)豐富程度上說(shuō),Redis更勝一籌。

  3. 内存緩存集群

  當我們搭建單台内存緩存完畢,我們又會(huì)面(miàn)臨單點故障的問題,因此,我們必須將(jiāng)它變成(chéng)一個集群。簡單的做法,是給他增加一個slave作爲備份機 器。但是,如果請求量真的很多,我們發(fā)現cache命中率不高,需要更多的機器内存呢?因此,我們更建議將(jiāng)它配置成(chéng)一個集群。例如,類似redis cluster。

  Redis cluster集群内的Redis互爲多組主從,同時(shí)每個節點都(dōu)可以接受請求,在拓展集群的時(shí)候比較方便。客戶端可以向(xiàng)任意一個節點發(fā)送請求,如果是它的 “負責”的内容,則直接返回内容。否則,查找實際負責Redis節點,然後(hòu)將(jiāng)地址告知客戶端,客戶端重新請求。

  對(duì)于使用緩存服務的客戶端來說(shuō),這(zhè)一切是透明的。

  内存緩存服務在切換的時(shí)候,是有一定風險的。從A集群切換到B集群的過(guò)程中,必須保證B集群提前做好(hǎo)“預熱”(B集群的内存中的熱點數據,應該 盡量與A集群相同,否則,切換的一瞬間大量請求内容,在B集群的内存緩存中查找不到,流量直接沖擊後(hòu)端的數據庫服務,很可能(néng)導緻數據庫宕機)。

  4. 減少數據庫“寫”

  上面(miàn)的機制,都(dōu)實現減少數據庫的“讀”的操作,但是,寫的操作也是一個大的壓力。寫的操作,雖然無法減少,但是可以通過(guò)合并請求,來起(qǐ)到減輕壓力的效果。這(zhè)個時(shí)候,我們就(jiù)需要在内存緩存集群和數據庫集群之間,建立一個修改同步機制。

  先將(jiāng)修改請求生效在cache中,讓外界查詢顯示正常,然後(hòu)將(jiāng)這(zhè)些sql修改放入到一個隊列中存儲起(qǐ)來,隊列滿或者每隔一段時(shí)間,合并爲一個請求到數據庫中更新數據庫。

  除了上述通過(guò)改變系統架構的方式提升寫的性能(néng)外,MySQL本身也可以通過(guò)配置參數 innodb_flush_log_at_trx_commit來調整寫入磁盤的策略。如果機器成(chéng)本允許,從硬件層面(miàn)解決問題,可以選擇老一點的 RAID(Redundant Arrays of independent Disks,磁盤列陣)或者比較新的SSD(Solid State Drives,固态硬盤)。

  5. NoSQL存儲

  不管數據庫的讀還(hái)是寫,當流量再進(jìn)一步上漲,終會(huì)達到“人力有窮時(shí)”的場景。繼續加機器的成(chéng)本比較高,并且不一定可以真正解決問題的時(shí)候。這(zhè)個 時(shí)候,部分核心數據,就(jiù)可以考慮使用NoSQL的數據庫。NoSQL存儲,大部分都(dōu)是采用key-value的方式,這(zhè)裡(lǐ)比較推薦使用上面(miàn)介紹過(guò) Redis,Redis本身是一個内存cache,同時(shí)也可以當做一個存儲來使用,讓它直接將(jiāng)數據落地到磁盤。

  這(zhè)樣(yàng)的話,我們就(jiù)將(jiāng)數據庫中某些被(bèi)頻繁讀寫的數據,分離出來,放在我們新搭建的Redis存儲集群中,又進(jìn)一步減輕原來MySQL數據庫的壓力,同時(shí)因爲Redis本身是個内存級别的Cache,讀寫的性能(néng)都(dōu)會(huì)大幅度提升。

  國(guó)内一線互聯網公司,架構上采用的解決方案很多是類似于上述方案,不過(guò),使用的cache服務卻不一定是Redis,他們會(huì)有更豐富的其他選擇,甚至根據自身業務特點開(kāi)發(fā)出自己的NoSQL服務。

  6. 空節點查詢問題

  當我們搭建完前面(miàn)所說(shuō)的全部服務,認爲Web系統已經(jīng)很強的時(shí)候。我們還(hái)是那句話,新的問題還(hái)是會(huì)來的。空節點查詢,是指那些數據庫中根本不存 在的數據請求。例如,我請求查詢一個不存在人員信息,系統會(huì)從各級緩存逐級查找,最後(hòu)查到到數據庫本身,然後(hòu)才得出查找不到的結論,返回給前端。因爲各級 cache對(duì)它無效,這(zhè)個請求是非常消耗系統資源的,而如果大量的空節點查詢,是可以沖擊到系統服務的。

  在我曾經(jīng)的工作經(jīng)曆中,曾深受其害。因此,爲了維護Web系統的穩定性,設計适當的空節點過(guò)濾機制,非常有必要。

  我們當時(shí)采用的方式,就(jiù)是設計一張簡單的記錄映射表。將(jiāng)存在的記錄存儲起(qǐ)來,放入到一台内存cache中,這(zhè)樣(yàng)的話,如果還(hái)有空節點查詢,則在緩存這(zhè)一層就(jiù)被(bèi)阻擋了。

  異地部署(地理分布式)

  完成(chéng)了上述架構建設之後(hòu),我們的系統是否就(jiù)已經(jīng)足夠強大了呢?答案當然是否定的哈,優化是無極限的。Web系統雖然表面(miàn)上看,似乎比較強大了, 但是給予用戶的體驗卻不一定是最好(hǎo)的。因爲東北的同學(xué),訪問深圳的一個網站服務,他還(hái)是會(huì)感到一些網絡距離上的慢。這(zhè)個時(shí)候,我們就(jiù)需要做異地部署,讓 Web系統離用戶更近。

  一、 核心集中與節點分散

  有玩過(guò)大型網遊的同學(xué)都(dōu)會(huì)知道(dào),網遊是有很多個區的,一般都(dōu)是按照地域來分,例如廣東專區,北京專區。如果一個在廣東的玩家,去北京專區玩,那 麼(me)他會(huì)感覺明顯比在廣東專區卡。實際上,這(zhè)些大區的名稱就(jiù)已經(jīng)說(shuō)明了,它的服務器所在地,所以,廣東的玩家去連接地處北京的服務器,網絡當然會(huì)比較慢。

  當一個系統和服務足夠大的時(shí)候,就(jiù)必須開(kāi)始考慮異地部署的問題了。讓你的服務,盡可能(néng)離用戶更近。我們前面(miàn)已經(jīng)提到了Web的靜态資源,可以存 放在CDN上,然後(hòu)通過(guò)DNS/GSLB的方式,讓靜态資源的分散“全國(guó)各地”。但是,CDN隻解決的靜态資源的問題,沒(méi)有解決後(hòu)端龐大的系統服務還(hái)隻集 中在某個固定城市的問題。

  這(zhè)個時(shí)候,異地部署就(jiù)開(kāi)始了。異地部署一般遵循:核心集中,節點分散。

  1. 核心集中:實際部署過(guò)程中,總有一部分的數據和服務存在不可部署多套,或者部署多套成(chéng)本巨大。而對(duì)于這(zhè)些服務和數據,就(jiù)仍然維持一套,而部署地點選擇一個地域比較中心的地方,通過(guò)網絡内部專線來和各個節點通訊。

  2. 節點分散:將(jiāng)一些服務部署爲多套,分布在各個城市節點,讓用戶請求盡可能(néng)選擇近的節點訪問服務。

  例如,我們選擇在上海部署爲核心節點,北京,深圳,武漢,上海爲分散節點(上海自己本身也是一個分散節點)。我們的服務架構如圖:

  需要補充一下的是,上圖中上海節點和核心節點是同處于一個機房的,其他分散節點各自獨立機房。

  國(guó)内有很多大型網遊,都(dōu)是大緻遵循上述架構。它們會(huì)把數據量不大的用戶核心賬号等放在核心節點,而大部分的網遊數據,例如裝備、任務等數據和服務放在地區節點裡(lǐ)。當然,核心節點和地域節點之間,也有緩存機制。

  二、 節點容災和過(guò)載保護

  節點容災是指,某個節點如果發(fā)生故障時(shí),我們需要建立一個機制去保證服務仍然可用。毫無疑問,這(zhè)裡(lǐ)比較常見的容災方式,是切換到附近城市節點。 假如系統的天津節點發(fā)生故障,那麼(me)我們就(jiù)將(jiāng)網絡流量切換到附近的北京節點上。考慮到負載均衡,可能(néng)需要同時(shí)將(jiāng)流量切換到附近的幾個地域節點。另一方面(miàn),核 心節點自身也是需要自己做好(hǎo)容災和備份的,核心節點一旦故障,就(jiù)會(huì)影響全國(guó)服務。

  過(guò)載保護,指的是一個節點已經(jīng)達到最大容量,無法繼續接接受更多請求了,系統必須有一個保護的機制。一個服務已經(jīng)滿負載,還(hái)繼續接受新的請求,結果很可能(néng)就(jiù)是宕機,影響整個節點的服務,爲了至少保障大部分用戶的正常使用,過(guò)載保護是必要的。

  解決過(guò)載保護,一般2個方向(xiàng):

  1. 拒絕服務,檢測到滿負載之後(hòu),就(jiù)不再接受新的連接請求。例如網遊登入中的排隊。

  2. 分流到其他節點。這(zhè)種(zhǒng)的話,系統實現更爲複雜,又涉及到負載均衡的問題。

  小結

  Web系統會(huì)随著(zhe)訪問規模的增長(cháng),漸漸地從1台服務器可以滿足需求,一直成(chéng)長(cháng)爲“龐然大物”的大集群。而這(zhè)個Web系統變大的過(guò)程,實際上就(jiù)是我們解決問題的過(guò)程。在不同的階段,解決不同的問題,而新的問題又誕生在舊的解決方案之上。

  系統的優化是沒(méi)有極限的,軟件和系統架構也一直在快速發(fā)展,新的方案解決了老的問題,同時(shí)也帶來新的挑戰。

公益廣告

登錄 參與評論

評論

暫無任何評論