前言以淘寶網(wǎng)為例,簡單了解一下大型電商的服務(wù)端架構(gòu)是怎樣的。如圖所示 除圖中所示之外還包含一些我們看不到的,比如高可用的體現(xiàn)。淘寶目前已經(jīng)實現(xiàn)多機房容災(zāi)和異地機房單元化部署,為淘寶的業(yè)務(wù)也提供了穩(wěn)定、高效和易于維護的基礎(chǔ)架構(gòu)支撐。 這是一個含金量非常高的架構(gòu),也是一個非常復(fù)雜而龐大的架構(gòu),當(dāng)然這個架構(gòu)不是一天兩天演進成這樣的,也不是一開始就設(shè)計并開發(fā)成這樣的,對于初創(chuàng)公司而言,很難在初期就預(yù)估到未來流量千倍、萬倍的網(wǎng)站架構(gòu)會是怎樣的狀況,同時如果初期就設(shè)計成千萬級并發(fā)的流量架構(gòu),也很難去支撐這個成本。 因此一個大型服務(wù)系統(tǒng),都是從小一步一步走過來的,在每個階段找到對應(yīng)該階段網(wǎng)站架構(gòu)所面臨的問題,然后不斷解決這些問題,在這個過程中,整個架構(gòu)會一直演進,同時內(nèi)含的代碼也就會演進,大到架構(gòu)、小到代碼都是在不斷演進和優(yōu)化的。所以說高大上的項目技術(shù)架構(gòu)和開發(fā)設(shè)計實現(xiàn)不是一蹴而就的,這是所謂的萬丈高樓平地起。 單機架構(gòu)從一個小網(wǎng)站說起,一般來說初始一臺服務(wù)器就夠了,文件服務(wù)器、數(shù)據(jù)庫以及應(yīng)用都部署在一臺機器上。也就是俗稱的 多機部署隨著網(wǎng)站用戶逐漸增多,訪問量越來越大,硬盤、cpu、內(nèi)存等開始吃緊,一臺服務(wù)器難以支撐??匆幌卵葸M過程,我們將數(shù)據(jù)服務(wù)和應(yīng)用服務(wù)進行分離,給應(yīng)用服務(wù)器配置更好的 cpu、內(nèi)存等等,而給數(shù)據(jù)服務(wù)器配置更好、更快的大的硬盤,如圖所示用了三臺服務(wù)器進行部署,能提高一定的性能和可用性。 分布式緩存隨著訪問的并發(fā)越來越高,為了降低接口的訪問時間提高服務(wù)性能,繼續(xù)對架構(gòu)進行演進。 我們發(fā)現(xiàn)有很多業(yè)務(wù)數(shù)據(jù)不需要每次都從數(shù)據(jù)庫中獲取,于是我們使用了緩存,因為 80% 的業(yè)務(wù)訪問都集中在 20% 的數(shù)據(jù)上 (二八原則),如果能將這部分?jǐn)?shù)據(jù)緩存下來,性能就能提高很多,緩存又分兩種,一種是 Application 中的本地緩存,還有遠(yuǎn)程緩存,遠(yuǎn)程緩存又分為遠(yuǎn)程的單機式緩存和分布式緩存 (圖所示的是分布式緩存集群)。 我們需要思考幾點,具有哪種業(yè)務(wù)特點的數(shù)據(jù)使用緩存,具有哪種業(yè)務(wù)特點的數(shù)據(jù)使用本地緩存,具有哪種業(yè)務(wù)特點的數(shù)據(jù)使用遠(yuǎn)程緩存。分布式緩存在擴容時會遇上什么問題,如何解決,分布式緩存的算法都有哪幾種,都有什么優(yōu)缺點。這些問題都是我們在使用這個架構(gòu)時需要思考并解決的問題。 服務(wù)器集群這個時候隨著訪問的 qps 不斷提高,假設(shè)我們使用的 Application Server 是 tomcat,那么 tomcat 服務(wù)器的處理能力就會成為一個瓶頸,雖然我們也可以通過購買更強大的硬件但總會有上限,并且這個成本到后期是呈指數(shù)級的增長。 這時候就可以對服務(wù)器做一個集群 此時我們又需要思考幾個問題, 負(fù)載均衡的調(diào)度策略都有哪些,各有什么優(yōu)缺點,各適合什么場景,比如輪詢、權(quán)重、地址散列,地址散列又分為原 IP 地址散列、目標(biāo) IP 地址散列、最小連接、加權(quán)最小連接等等。 服務(wù)器集群后,假設(shè)我們登陸了 A 服務(wù)器,session 信息存放在 A 服務(wù)器上了,如果我們的負(fù)載均衡策略是輪詢或者最小連接等,下次是有可能訪問到 B 服務(wù)器,這時候存儲在 A 服務(wù)器上的 session 信息我們在 B 服務(wù)器是讀取不到的,所以我們需要解決 session 管理的問題。 Session 共享解決方案session sticky我們使用 如圖所示客戶端 1 通過負(fù)載均衡會固定轉(zhuǎn)發(fā)到服務(wù)器 1 中。缺點是第一假設(shè)有一臺服務(wù)器重啟了,那么該服務(wù)器的 session 將全部消失,第二是我們的負(fù)載均衡服務(wù)器成了一種有狀態(tài)的服務(wù)器,要實現(xiàn)容災(zāi)會有麻煩。 session 復(fù)制session 復(fù)制,即當(dāng) browser1 經(jīng)過負(fù)載均衡服務(wù)器把 session 存到 application1 中,會同時把 session 復(fù)制到 application2 中,所以多臺服務(wù)器都保存著相同的 session 信息。 缺點是應(yīng)用服務(wù)器的帶寬問題,服務(wù)器之間要不斷同步 session 信息,當(dāng)大量用戶在線時,服務(wù)器占用內(nèi)存會過多,不適合大規(guī)則集群,適合機器不多情況。 基于 cookie基于 cookie,也就是說我們每次都用攜帶 session 信息的 cookie 去訪問應(yīng)用服務(wù)器。缺點是 cookie 的長度是有限制的,cookie 保存在瀏覽器上安全性也是一個問題。 session 服務(wù)器把 session 做成了一個 session 服務(wù)器,比如可以使用 redis 實現(xiàn)。這樣每個用戶訪問到應(yīng)用服務(wù)器,其 session 信息最終都存到 session server 中,應(yīng)用服務(wù)器也是從 session server 中去獲取 session。 要考慮以下幾個問題,在當(dāng)前架構(gòu)中 session server 是一個單點的,如何解決單點,保證它的可用性,當(dāng)然也可以將 session server 做成一個集群,這種方式適用于 session 數(shù)量及 web 服務(wù)器數(shù)量大的情況,同時改成這種架構(gòu)后,在寫應(yīng)用時,也要調(diào)整存儲 session 的業(yè)務(wù)邏輯。 數(shù)據(jù)庫讀寫分離在解決了服務(wù)器橫向擴展之后,繼續(xù)看數(shù)據(jù)庫,數(shù)據(jù)庫的讀與寫操作都需要經(jīng)過數(shù)據(jù)庫,當(dāng)用戶量達到一定量時,數(shù)據(jù)庫性能又成為了一個瓶頸,我們繼續(xù)演進。 我們可以使用數(shù)據(jù)庫的讀寫分離,同時應(yīng)用要接入多數(shù)據(jù)源。通過統(tǒng)一的數(shù)據(jù)訪問模型進行訪問。數(shù)據(jù)庫的讀寫分離是將所有的寫操作引入到主庫中 如何支持多數(shù)據(jù)源,如何封裝對業(yè)務(wù)沒有侵入,如何使用目前業(yè)務(wù)使用的 ORM 框架完成主從的讀寫分離,是否需要更換 ORM,各有什么優(yōu)缺點,如何取舍都是當(dāng)前這個架構(gòu)需要考慮的問題。 例如主庫和從庫復(fù)制有沒有延遲,如果我們將主庫和從庫分機房部署的話,跨機房傳輸同步數(shù)據(jù)更是一個問題。另外應(yīng)用對數(shù)據(jù)源的路由問題,這些也是需要思考和解決的點。 CDN 加速與反向代理我們繼續(xù)增加了 分布式文件服務(wù)器這個時候我們的文件服務(wù)器又出現(xiàn)了瓶頸,我們將文件服務(wù)器改成了分布式文件服務(wù)器集群,在使用分布式文件系統(tǒng)時,需要考慮幾個問題,如何不影響部署在線上的應(yīng)用訪問,是否需要業(yè)務(wù)部門幫忙清洗數(shù)據(jù),是否需要備份服務(wù)器,是否需要重新做域名解析等等。 數(shù)據(jù)庫分庫分表這個時候我們的數(shù)據(jù)庫又出現(xiàn)了瓶頸,我們選擇專庫專用的形式,進行數(shù)據(jù)的垂直拆分,相關(guān)的業(yè)務(wù)獨用自己的一個庫,我們解決了寫數(shù)據(jù)并發(fā)量大的問題。 當(dāng)我們把這些表分成不同的庫,又會帶來一些新的問題。例如跨業(yè)務(wù)和跨庫的事務(wù),可以使用分布式事務(wù),或者去掉事務(wù),或者不追求強事務(wù)。 隨著訪問量過大,數(shù)據(jù)量過大,某個業(yè)務(wù)的數(shù)據(jù)庫數(shù)據(jù)量和更新量已經(jīng)達到了單個數(shù)據(jù)庫的瓶頸了,這個時候就需要進行數(shù)據(jù)庫的水平拆分,例如把 user 拆分成了 user1 和 user2,就是將同一個表的數(shù)據(jù)拆分到兩個數(shù)據(jù)庫當(dāng)中,這個時候我們解決了單數(shù)據(jù)庫的瓶頸。 水平拆分時候又要注意哪些點,都有哪幾種水平拆分的方式。進行了水平拆分后,又會遇到幾個問題,第一 sql 路由的問題,假設(shè)有一個用戶,我們?nèi)绾沃肋@個用戶信息是存在了 user1 還是 user2 數(shù)據(jù)庫中,由于分庫了,我們的主鍵策略也會有所不同,同時會面臨分頁的問題,假設(shè)我們要查詢某月份已經(jīng)下單的用戶明細(xì),而這些用戶又分布在 user1 和 user2 庫中,我們后臺運營管理系統(tǒng)對它進行展示的時候還要進行分頁。這些都是我們在使用這個架構(gòu)時需要解決的問題。 搜索引擎與 NoSQL在網(wǎng)站發(fā)布并進行了大規(guī)模的推廣后,導(dǎo)致我們應(yīng)用服務(wù)器的搜索量又飆升,我們把應(yīng)用服務(wù)器的搜索功能單獨抽取出來做了一個搜索引擎,同時部分場景可以使用 后序這里只是簡單舉例,并沒有依據(jù)什么實際的業(yè)務(wù)場景。事實上各個服務(wù)的架構(gòu)是要根據(jù)實際的業(yè)務(wù)特點進行優(yōu)化和演進的,所以這個過程也不是完全相同的。當(dāng)然這個架構(gòu)也不是最終形態(tài),還存在很多要提升的地方。 例如負(fù)載均衡服務(wù)器目前是一個單點的,如果負(fù)載均衡服務(wù)器訪問不了,那么后續(xù)的包括服務(wù)器集群等也就無法訪問了。所以可以將負(fù)載均衡服務(wù)器做成集群,然后做一些主從的雙機熱備,同時做一個自動切換的解決方案。 在整個架構(gòu)的演進過程中,其實還包含更多需要關(guān)注的內(nèi)容,比如安全性、數(shù)據(jù)分析、監(jiān)控、反作弊...... 最后,我想說高大上的項目技術(shù)架構(gòu)和開發(fā)設(shè)計實現(xiàn)絕不是一僦而就的。 (完) |
|