1. 程式人生 > >說說如何實現可擴充套件性的大型網站架構

說說如何實現可擴充套件性的大型網站架構

網站的可擴充套件性架構設計,能夠在對現有系統影響最小的情況下,系統功能可以可持續擴充套件及提升的能力。

在此,對容易混為一談的 “擴充套件性” 和 “伸縮性” 的概念進行詳細說明:

擴充套件性

表現為:基礎設施不需要經常變更,應用之間較少依賴或耦合,可以對需求變更快速響應。它對擴充套件開放,對修改關閉。架構設計會考慮到未來功能的可擴充套件性,所以當系統增加新功能時,不需要對現有系統的結構和程式碼進行修改。

伸縮性

是指系統通過增加(或減少)自身資源規模的方式增強(或減少)處理業務的能力。如果這種增減是成比例的,就可以稱之為線性伸縮性。通常是利用叢集的方式增加伺服器的數量,以提高系統整體業務吞吐能力。

1 構建可擴充套件的網站架構

度量一個開發框架、設計模式或程式語言優劣的一個重要尺度就是它是否能夠讓軟體開發過程和軟體產品更加低耦合。

因為低耦合的系統更容易擴充套件,也更容易被複用,而且也會讓開發過程和維護變得更加容易。但如何分解系統的各個模組、如何定義各個模組的介面、如何複用、組合不同模組構造一個完整的系統,這是軟體設計中最具挑戰性的部分。

軟體架構師的最大價值,就在於把一個大系統分解為 N 個低耦合的子模組的能力,這些子模組包含橫向的業務模組與縱向的基礎技術模組。這種能力來源於專業技術能力與經驗、業務場景的理解、對人性的把握以及對世界的認知。

構建可擴充套件的網站架構的核心思想是模組化,並在此基礎上,降低模組之間的耦合性,提高模組的複用性。

可以利用分層與分割的方式,把軟體分割為若干個低耦合、獨立的元件模組,然後在這些元件模組之間以訊息傳遞或依賴呼叫的方式聚合成一個完整的系統。

這些模組可以通過分散式部署的方式,部署在獨立的伺服器上。這種從物理上分離模組之間的耦合關係,可以進一步降低耦合性。

模組的分散式部署後的聚合方式有:  * 分散式訊息佇列。  * 分散式服務。

1 使用分散式訊息佇列降低耦合性

如果模組之間不存在直接呼叫關係,那麼新增或修改模組對其他部分的影響最小,這樣的擴充套件性自然更好。

1.1 事件驅動架構

事件驅動架構指的是:在低耦合的模組之間傳輸事件訊息,保持模組之間的鬆散耦合,通過事件訊息來完成模組之間的通訊。 事件驅動架構最常見的實現方式就是使用分散式訊息佇列。

基於訊息佇列的事件驅動架構

訊息佇列基於釋出——訂閱模式工作,訊息傳送者釋出訊息,一個或多個訊息接收者訂閱訊息。訊息傳送者把訊息傳送至分散式訊息佇列後就處理完畢,然後由訊息訂閱者從訊息佇列中獲取訊息進行處理。對於新增的業務,只要對某個訊息感興趣,就可以訂閱該訊息,而這對原有的系統和業務沒有任何影響,從而實現系統的可擴充套件性設計。

訊息接收者還可以對收到的訊息再構造,定義出一個新的訊息型別,然後再把訊息傳送給訂閱了這一新訊息型別的接收者。所以基於訊息物件的事件驅動架構可以是一系列的流程。

因為訊息傳送者無須等待就可以返回,所以系統具有更好的響應時間;而且在訪問高峰,訊息可以暫存於訊息佇列中,從而減輕了資料庫的儲存負載壓力。

1.2 分散式訊息佇列

佇列是一種先進先出的資料結構,我們可以把訊息佇列部署到獨立的伺服器中。應用通過遠端訪問介面使用訊息佇列,進行訊息的存取操作,從而實現分散式的非同步呼叫:

分散式訊息佇列原理

目前較為流行的分散式訊息佇列是 Apache ActiveMQ。

因為訊息佇列伺服器上的資料可以看做是即時處理的,所以在伸縮性上,我們把新伺服器加入分散式訊息佇列集群后,只需要通知生產者伺服器更改訊息佇列的伺服器列表就好啦O(∩_∩)O~

可用性上,如果記憶體佇列滿了,要將訊息寫入磁碟,這樣當訊息推送模組把記憶體佇列中的訊息處理完畢後,就會把磁碟中的訊息載入到佇列中繼續處理。

為了避免訊息佇列伺服器宕機造成訊息丟失,會把訊息儲存在訊息的生產者伺服器上,這樣等訊息確實被訊息消費者伺服器處理後才會刪除。如果訊息佇列伺服器宕機,生產者伺服器會選擇分散式訊息佇列伺服器叢集內的其他伺服器釋出訊息。

分散式訊息佇列可以很複雜,比如支援 ESB(企業服務匯流排)和 SOA(面向服務的架構)等。也可以很簡單,比如使用 MySQL 作為分散式訊息佇列:訊息的生產者把訊息作為記錄寫入資料庫,消費者查詢資料庫(按記錄寫入庫表的時間戳排序),這就是一個分散式訊息佇列啦。再配上成熟的 MySQL 運維手段,也可以達到一個較高的可用性和效能指標哦O(∩_∩)O~

2 使用分散式服務構建可複用的業務平臺

分散式服務可以通過介面降低系統的耦合性,不同的子系統之間通過相同的介面描述呼叫服務。

隨著網站功能的日益複雜,系統會逐漸發展成為一個巨無霸,裡面聚合了大量的應用和服務元件,這樣的一個系統會給開發、維護、部署帶來巨大的麻煩:  * 編譯、部署困難。  * 程式碼分支管理困難:複用的程式碼模組由多個團隊共同維護修改,所以在程式碼合併時總會發生衝突。  * 耗盡資料庫連線:假設一個應用設定了 10 個數據庫連線,那麼一個擁有數百臺伺服器叢集的應用就會在資料庫上建立數千個連線。  * 新增業務困難。在這樣一個剪不斷、理還亂的系統中新增業務?開玩笑吧O(∩_∩)O~

所以我們要做拆分,把模組獨立部署,降低系統的耦合性:  * 縱向拆分 - 把一個大應用拆分為多個小應用。如果新增的業務較為獨立,就直接將其設計並部署為一個獨立的 Web 應用。  * 橫向拆分 - 把複用的業務拆分出來,獨立部署為分散式服務,新增的業務只需要呼叫這些分散式的服務,就可以快速搭建出一個應用系統。即使模組內的業務邏輯發生變化,只要保持介面一致,就不會影響其他模組。

分散式服務架構

縱向拆分較簡單,通過梳理業務,把關聯較少的業務剝離,使其成為獨立的 Web 應用。而橫向拆分不僅需要識別出可複用的業務、設計服務介面以及規範服務之間的依賴關係,而且還需要一個完善的分散式服務管理框架。

2.1 Web Service 分散式服務

Web Service 曾經是企業應用系統在開發領域中最時髦的詞彙之一,它用於整合異構系統以及構建分散式系統:

Web Service 原理

服務提供者通過 WSDL(Web Services Description Language,Web 服務描述語言)向註冊中心(Service Broker)描述自身所能提供的服務介面內容,然後註冊中心使用 UDDI(Universal Description, Discovery, and Integration,統一描述、發現和整合)釋出服務提供者提供的服務。服務請求者從註冊中心檢索到服務後,通過 SOAP(Simple Object Access Protocol ,簡單物件訪問協議)與服務提供者通訊,使用該服務。

Web Service 雖然有成熟的技術規範和實現,但有如下缺點:  1. 臃腫的註冊、發現機制。  2. 低效的 XML 序列化手段。  3. 開銷較高的 HTTP 遠端通訊。  4. 複雜的部署與維護手段。

這些問題導致 Web Service 難以滿足大型網站對高效能、高可用、易部署與易維護的要求。

2.2 大型網站分散式服務的要求

分散式服務框架需要能夠支援以下特性:  * 負載均衡 - 對於服務請求者能夠使用可配置的負載均衡演算法來訪問熱門服務(比如登入或商品服務,這些服務被部署在一個叢集上)。  *失效轉移 - 可複用的服務被多個應用呼叫,一旦服務不可用,就會影響到很多應用的可用性。所以即使是很少訪問的服務,也需要叢集部署。分散式服務框架檢測到某個服務不可用時,就會切換到其他服務例項上,保證整體高可用。  * 高效的遠端通訊  * 整合異構系統  * 對應用最小侵入 - 分散式服務框架支援服務(服務模組需要即支援集中式部署,也支援分散式部署)的漸進式演化和反覆。  * 版本管理 - 網站服務不可中斷,所以分散式服務框架需要支援服務的多版本釋出,服務提供者升級釋出介面新版本的同時,還會繼續支援舊版本的服務,直到請求者呼叫的介面升級後,才會關閉舊版本的服務。  * 實時監控 - 監控服務提供者和呼叫者的各項指標,提供運維與運營的支援。

2.3 分散式服務框架設計

大型網站需要更簡單、更高效的分散式服務框架構建其 SOA(Service Oriented Architecture ,面向服務的體系結構)。目前國內有較多成功實施案例的開源分散式服務框架是阿里巴巴的 Dubbo。

Dubbo 架構

服務消費者通過介面使用服務,介面通過代理載入具體服務,可以是本地的程式碼,也可以是遠端的服務,因此對應用侵入較小。

客戶端模組通過服務註冊中心載入服務提供者列表(服務提供者啟動後自動向服務註冊中心註冊自己可以提供的服務介面列表),然後根據配置的負載均衡策略把服務呼叫請求傳送到某臺服務提供者的伺服器。如果服務呼叫失敗,客戶端模組會自動從服務提供者列表中選擇一個可以提供同樣服務的伺服器重新請求,即自動失效轉移,保證服務的高可用。

Dubbo 使用 NIO 通訊框架,因此具有較高的網路通訊效能。

4 可擴充套件的資料結構

使用 NoSQL 資料庫(如 Cassandra)的 ColumnFamily (列族)技術可以做到可擴充套件的資料結構設計。它是一種面向列族的稀疏矩陣的儲存格式。

只需要指定 ColumnFamily 的名字,即可建立表。欄位可以在寫入資料時再指定,通過這種方式,一張表可以包含數百萬個欄位。這就使得應用的資料結構可以隨意擴充套件。只需要指定任意欄位名稱和值即可查詢。

5 利用開放平臺建立生態圈

使用者只有得到他們想要價值,才會願意使用網站的服務,這樣的網站才有存在的意義。但一個網站畢竟不能滿足所有使用者的需求。

使用者不會為網站提供的價值買單,所以網站必須提供更多的增值服務才能賺錢。根據長尾效應,增值服務的數量越大,種類越多,盈利也就越多。但一個網站能夠自己開發的增值服務也是有限的。

大型網站為了更好地服務使用者、為他們開發出更多的增值服務,會把網站內部的服務封裝成介面開放出去,供外部第三方開發者使用,這個平臺就叫做開放平臺。第三方開發者利用這些開放的介面就可以開發應用程式(如 APP)或網站,為使用者提供更多的價值。網站、使用者、第三方開發者  相互依賴,形成一個生態圈。

開放平臺是網站內部和外部互動的介面。外部會面對眾多的第三方開發者,內部面對的是網站內眾多的業務服務。下面是開放平臺的架構:

開放平臺的架構

  • API 介面:暴露給開發者的一組 API,可以是 RESTful、WebService、RPC 等形式。
  • 協議轉換:把各種 API 的輸入轉換為內部服務可識別的形式,並把內部服務的返回資訊封裝為 API 格式。
  • 安全:除了身份識別、許可權控制等手段之外,還要對訪問頻寬進行分級限制,保證平臺資源被第三方應用合理公平地使用,也能保證網站自身的內部服務不會被外部應用拖垮。
  • 審計:監控第三方應用的訪問情況並計費。
  • 路由:把開放平臺的各種訪問路由對映到具體的內部服務。
  • 流程:把一組鬆散的服務組織成一個上下文相關的新服務,對外提供介面供開發者使用。

最近整理出了有關大資料,微服務,分散式,Java,Python,Web前端,產品運營,互動等1.7G的學習資料,有視訊教程,原始碼,課件,軟體工具,面試題等等,這裡將珍藏多年的資源免費分享給各位小夥伴們。

歡迎大家關注我的公眾號:

裡面會分享很多JAVA技術、新知識、新技術、面試寶典等。 有讓技術愛好者(程式猿)得到很大提升的文章資料。

還在猶豫什麼,趕緊關注一波,微信搜尋公眾號:程式設計師的成長之路。或者掃描下方二維碼進行關注。

                                                                     

                                                                       歡迎關注公眾號,和我一起成長!