大型Java項目架構演進過程
1. All-In-One (所有服務在一臺服務器上):
也就是所有的服務都在同一個服務器上,包括應用服務器、文件服務器和數據庫
2. 各服務分別部署在不同的服務器上
隨着用戶越來越多,訪問量越來越大,硬盤、CPU、內存等硬件開始吃緊,一臺服務器已經無法滿足需求,這個時候就需要將不同的服務部署在多個服務器上,給應用服務(Application server)配置更好的內存和cpu,給數據庫服務器配置更好,更大,更快的硬盤。
3. 添加緩存服務器:
隨着訪問的併發越來越高,爲了縮短接口的訪問時間,提高訪問性能。
同時發現,我們的很多業務數據不需要每次都從數據庫中獲取,於是我們使用緩存來進行數據緩存,提高訪問速度。
(80%的業務集中在20%的數據上,即2--8原則)
在這裏緩存又可以分爲 本地緩存 和 遠程緩存。 同時,遠程緩存又有兩種情形:單機緩存 和 分佈式集羣緩存
使用該架構需要思考和解決的問題:
1. 哪種業務特點的數據需要進行緩存
2. 哪些數據適合進行本地緩存,哪些數據適合進行遠程緩存
3. 分佈式緩存在擴容時會遇到什麼問題,如果解決
4. 分佈式緩存的算法都有哪幾種,各有什麼優缺點
4. 增加負載均衡器,服務器均衡:
隨着訪問的QPS(每秒查詢率)不斷的提高,服務器的處理能力(例如Tomcat)可能就會出現瓶頸,雖然也可以購買更加強大的硬件,但總會有上限,而且這個成本到了後期會出現指數級的增長,這個時候就需要做一個服務器的集羣,通過負責均衡服務器來實現服務集羣訪問。
這個時候需要考慮的問題:
1. 負責均衡的調度策略都有哪些,各有什麼優缺點,各適合什麼場景。
調度策略: 輪訓、權重、地址散列(包含:源ip散列 和 目的ip散列)、最少連接、加權最少連接
2. session的管理問題
同一用戶可能第一次登陸的是A服務器,那麼session信息是保存在A服務器上的,第二次可能訪問的是B服務器,這個時候B服務器上並沒有該用戶的session信息,這時就涉及到了session管理的問題問題。
方式1. 可以使用 Session Sticky(粘滯會話)
實現原理:對於同一連接中的數據包,負載均衡會將其進行一個轉化,然後轉發至後端固定的服務器上進行處理。也就像上圖所示,Browser1每次都會訪問Application1這個服務器。這個方案解決了session的共享問題。但是同時又有缺點:1. 如果Application1進行了重啓,那麼保存在其上的信息將會全部消失,2. 負載均衡器成爲了一個有狀態的服務器,要實現容災會有麻煩。
方式2. Session Copy
實現原理:Application之間會copy自身保存的session到其他服務器上,使得用戶通過負載均衡不論將請求發送至哪個Application,該Application都有該用戶的session信息。缺點:1. 由於Application之間要不斷的同步session信息,可能造成帶寬不夠的問題。2. 當大量用戶在線的時候,Application會佔用大量的內存,不適合做大規模集羣。
方式3. 基於cookie
實現原理:用戶攜帶含有session信息的cookie去訪問Application。缺點:1. cookie的長度是有限制的 2. cookie保存在瀏覽器上,安全性是一個問題。
方式4. 使用session服務器
實現原理:所有用戶的session信息都統一保存在session server中。缺點:1. session server是個單點的,如何解決該server的單點,保證其高可用性
5. 數據庫的讀寫分離:
當用戶量達到一定量的時候,數據庫的讀寫操作的都是同一個數據庫,這個時候數據庫就成爲了一個瓶頸,這個時候就可以進行數據庫的讀寫分離
包含主庫和從庫,同時應用要接入多數據源,並且通過統一的數據訪問模型進行數據訪問,數據庫讀寫分離將所有的讀操作全部引入到Slave這個數據庫中,將所有的寫操作全部引入到Master這個數據庫中,同時由於進行了讀寫數據分離,我們在應用中實現了數據訪問模塊,使得上層寫代碼的人不知道數據讀寫分離的情況,這樣我們多數據源的讀寫對業務代碼就沒有了侵入。
這個時候引申的問題就有:1. 如何支持多數據源,2. 如何封裝對業務沒有侵入,3. 如何使用目前項目使用的ORM框架完成底層的讀寫分離,4. 是否需要更換ORM,又各有什麼優缺點,如何取捨。
當數據量非常大的時候,數據庫的讀寫分離又會遇到一下問題:1. 主庫和從庫在同步的時候,有沒有延時;如果我們將主庫和從庫進行了誇機房部署,那麼在跨機房數據傳輸的時候,延時更是一個問題。2. 應用對數據源的路由問題
6. 曾加了CDN和反向代理服務器:
爲了提高服務器,又增加了CDN 和反向代理服務器。使用CDN可以很好的解決不同地區訪問速度的問題;反向代理則可以緩存用戶的資源
7. 文件服務器改爲了分佈式文件服務器:
需要考慮的問題:1. 如何不影響已部署在線上的業務訪問(不能出現某個圖片不能訪問了),2. 是否需要業務部門幫忙清洗數據 3. 是否需要備份服務器 4. 是否需要重新做域名解析等等。
8. 數據庫分表:
數據量大的時候,數據的增刪改查又出現了瓶頸,這個時候我們選擇使用專庫專用的方式,進行數據的垂直拆分,相關的業務都使用自己專有的庫。
需要考慮的問題:1. 跨業務的事物,誇庫的事物 (可以考慮分佈式事物,或者去掉事物,或者不追求強事物),2. 誇庫的join怎麼實現
9. 數據庫分表
隨着訪問量過大,業務量過大,可能出現某個業務的數據庫的數據達到了單個數據庫的瓶頸,這個時候就要考慮進行數據庫的水平拆分(將同一個表的數據拆分到兩個數據庫中)
需要考慮的問題:1. sql路由的問題(假設查詢某個用戶,如何確定用戶在哪個數據庫中)2. 主見的策略會有所不同 3 分頁的問題
10. 添加了搜索引擎和NoSql服務器
假如發現我們應用服務器上的搜索量飆升,或者因爲我們對外做了一個推廣,這個時候我們將Application中的搜索功能單獨拆分出來,做了一個搜索引擎,同時部分場景可以使用NoSql提高性能,同時我們開發一個統一的數據訪問模塊,這個某塊下面連着數據庫集羣、搜索引擎、還有NoSql,解決上層應用開發的數據源問題。