分層,分割,分佈式
大型網站要很好支撐高併發,這是須要長期的規劃設計
在初期就須要把系統進行分層,在發展過程當中把核心業務進行拆分紅模塊單元,根據需求進行分佈式部署,能夠進行獨立團隊維護開發。node
- 分層
- 將系統在橫向維度上切分紅幾個部分,每一個部門負責一部分相對簡單並比較單一的職責,而後經過上層對下層的依賴和調度組成一個完整的系統
- 好比把電商系統分紅:應用層,服務層,數據層。(具體分多少個層次根據本身的業務場景)
- 應用層:網站首頁,用戶中心,商品中心,購物車,紅包業務,活動中心等,負責具體業務和視圖展現
- 服務層:訂單服務,用戶管理服務,紅包服務,商品服務等,爲應用層提供服務支持
- 數據層:關係數據庫,nosql數據庫 等,提供數據存儲查詢服務
- 分層架構是邏輯上的,在物理部署上能夠部署在同一臺物理機器上,可是隨着網站業務的發展,必然須要對已經分層的模塊分離部署,分別部署在不一樣的服務器上,使網站能夠支撐更多用戶訪問
- 分割
- 在縱向方面對業務進行切分,將一塊相對複雜的業務分割成不一樣的模塊單元
- 包裝成高內聚低耦合的模塊不只有助於軟件的開發維護,也便於不一樣模塊的分佈式部署,提升網站的併發處理能力和功能擴展
- 好比用戶中心能夠分割成:帳戶信息模塊,訂單模塊,充值模塊,提現模塊,優惠券模塊等
- 分佈式
- 分佈式應用和服務,將分層或者分割後的業務分佈式部署,獨立的應用服務器,數據庫,緩存服務器
- 當業務達到必定用戶量的時候,再進行服務器均衡負載,數據庫,緩存主從集羣
- 分佈式靜態資源,好比:靜態資源上傳cdn
- 分佈式計算,好比:使用hadoop進行大數據的分佈式計算
- 分佈式數據和存儲,好比:各分佈節點根據哈希算法或其餘算法分散存儲數據
![image](http://static.javashuo.com/static/loading.gif)
網站分層-圖1來自網絡mysql
集羣
對於用戶訪問集中的業務獨立部署服務器,應用服務器,數據庫,nosql數據庫。 核心業務基本上須要搭建集羣,即多臺服務器部署相同的應用構成一個集羣,經過負載均衡設備共同對外提供服務, 服務器集羣可以爲相同的服務提供更多的併發支持,所以當有更多的用戶訪問時,只須要向集羣中加入新的機器便可, 另外能夠實現當其中的某臺服務器發生故障時,能夠經過負載均衡的失效轉移機制將請求轉移至集羣中其餘的服務器上,所以能夠提升系統的可用性nginx
![image](http://static.javashuo.com/static/loading.gif)
經過反向代理均衡負載-圖2來自網絡git
異步
在高併發業務中若是涉及到數據庫操做,主要壓力都是在數據庫服務器上面,雖然使用主從分離,可是數據庫操做都是在主庫上操做,單臺數據庫服務器鏈接池容許的最大鏈接數量是有限的
當鏈接數量達到最大值的時候,其餘須要鏈接數據操做的請求就須要等待有空閒的鏈接,這樣高併發的時候不少請求就會出現connection time out
的狀況
那麼像這種高併發業務咱們要如何設計開發方案能夠下降數據庫服務器的壓力呢?redis
-
如:算法
- 自動彈窗簽到,雙11跨0點的時候併發請求籤到接口
- 雙11搶紅包活動
- 雙11訂單入庫
- 等
-
設計考慮:sql
- 逆向思惟,壓力在數據庫,那業務接口就不進行數據庫操做不就沒壓力了
- 數據持久化是否容許延遲?
- 如何讓業務接口不直接操做DB,又可讓數據持久化?
-
方案設計:數據庫
- 像這種涉及數據庫操做的高併發的業務,就要考慮使用異步了
- 客戶端發起接口請求,服務端快速響應,客戶端展現結果給用戶,數據庫操做經過異步同步
- 如何實現異步同步?
- 使用消息隊列,將入庫的內容enqueue到消息隊列中,業務接口快速響應給用戶結果(能夠舒適提示高峯期延遲到帳)
- 而後再寫個獨立程序從消息隊列dequeue數據出來進行入庫操做,入庫成功後刷新用戶相關緩存,若是入庫失敗記錄日誌,方便反饋查詢和從新持久化
- 這樣一來數據庫操做就只有一個程序(多線程)來完成,不會給數據帶來壓力
-
補充:express
- 消息隊列除了能夠用在高併發業務,其餘只要有相同需求的業務也是可使用,如:短信發送中間件等
- 高併發下異步持久化數據可能會影響用戶的體驗,能夠經過可配置的方式,或者自動化監控資源消耗來切換時時或者使用異步,這樣在正常流量的狀況下可使用時時操做數據庫來提升用戶體驗
- 異步同時也能夠指編程上的異步函數,異步線程,在有的時候可使用異步操做,把不須要等待結果的操做放到異步中,而後繼續後面的操做,節省了等待的這部分操做的時間
![image](http://static.javashuo.com/static/loading.gif)
緩存
高併發業務接口多數都是進行業務數據的查詢,如:商品列表,商品信息,用戶信息,紅包信息等,這些數據都是不會常常變化,而且持久化在數據庫中
高併發的狀況下直接鏈接從庫作查詢操做,多臺從庫服務器也抗不住這麼大量的鏈接請求數(前面說過,單臺數據庫服務器容許的最大鏈接數量是有限的)
那麼咱們在這種高併發的業務接口要如何設計呢?編程
-
設計考慮:
- 仍是逆向思惟,壓力在數據庫,那麼咱們就不進行數據庫查詢
- 數據不常常變化,咱們爲啥要一直查詢DB?
- 數據不變化客戶端爲啥要向服務器請求返回同樣的數據?
-
方案設計:
- 數據不常常變化,咱們能夠把數據進行緩存,緩存的方式有不少種,通常的:應用服務器直接Cache內存,主流的:存儲在memcache、redis內存數據庫
- Cache是直接存儲在應用服務器中,讀取速度快,內存數據庫服務器容許鏈接數能夠支撐到很大,並且數據存儲在內存,讀取速度快,再加上主從集羣,能夠支撐很大的併發查詢
- 根據業務情景,使用配合客戶端本地存,若是咱們數據內容不常常變化,爲啥要一直請求服務器獲取相同數據,能夠經過匹配數據版本號,若是版本號不同接口從新查詢緩存返回數據和版本號,若是同樣則不查詢數據直接響應
- 這樣不只能夠提升接口響應速度,也能夠節約服務器帶寬,雖然有些服務器帶寬是按流量計費,可是也不是絕對無限的,在高併發的時候服務器帶寬也可能致使請求響應慢的問題
-
補充:
- 緩存同時也指靜態資源客戶端緩存
- cdn緩存,靜態資源經過上傳cdn,cdn節點緩存咱們的靜態資源,減小服務器壓力
- redis的使用技巧參考個人博文[大話Redis基礎],[大話Redis進階]
![image](http://static.javashuo.com/static/loading.gif)
面向服務
SOA
面向服務架構設計
微服務
更細粒度服務化,一系列的獨立的服務共同組成系統
使用服務化思惟,將核心業務或者通用的業務功能抽離成服務獨立部署,對外提供接口的方式提供功能。
最理想化的設計是能夠把一個複雜的系統抽離成多個服務,共同組成系統的業務,優勢:鬆耦合,高可用性,高伸縮性,易維護。
經過面向服務化設計,獨立服務器部署,均衡負載,數據庫集羣,可讓服務支撐更高的併發
- 服務例子:
- 說明:
- 經過上報應用模塊,操做事件,事件對象,等數據,記錄用戶的操做行爲
- 好比:記錄用戶在某個商品模塊,點擊了某一件商品,或者瀏覽了某一件商品
- 背景:
- 因爲服務須要記錄用戶的各類操做行爲,而且能夠重複上報,準備接入服務的業務又是核心業務的用戶行爲跟蹤,因此請求量很大,高峯期會產生大量併發請求。
- 架構:
- nodejs WEB應用服務器均衡負載
- redis主從集羣
- mysql主
- nodejs+express+ejs+redis+mysql
- 服務端採用nodejs,nodejs是單進程(PM2根據cpu核數開啓多個工做進程),採用事件驅動機制,適合I/O密集型業務,處理高併發能力強
- 業務設計:
- 併發量大,因此不能直接入庫,採用:異步同步數據,消息隊列
- 請求接口上報數據,接口將上報數據push到redis的list隊列中
- nodejs寫入庫腳本,循環pop redis list數據,將數據存儲入庫,並進行相關統計Update,無數據時sleep幾秒
- 由於數據量會比較大,上報的數據表按天命名存儲
- 接口:
- 上線跟進:
冗餘,自動化
當高併發業務所在的服務器出現宕機的時候,須要有備用服務器進行快速的替代,在應用服務器壓力大的時候能夠快速添加機器到集羣中,因此咱們就須要有備用機器能夠隨時待命。 最理想的方式是能夠經過自動化監控服務器資源消耗來進行報警,自動切換降級方案,自動的進行服務器替換和添加操做等,經過自動化能夠減小人工的操做的成本,並且能夠快速操做,避免人爲操做上面的失誤。
經過GitLab事件,咱們應該反思,作了備份數據並不表明就萬無一失了,咱們須要保證高可用性,首先備份是否正常進行,備份數據是否可用,須要咱們進行按期的檢查,或者自動化監控, 還有包括如何避免人爲上的操做失誤問題。(不過事件中gitlab的開放性姿態,積極的處理方式仍是值得學習的)
總結
高併發架構是一個不斷衍變的過程,冰洞三尺非一日之寒,長城築成非一日之功
打好基礎架構方便之後的拓展,這點很重要
![image](http://static.javashuo.com/static/loading.gif)
這裏從新整理了下高併發下的架構思路,舉例了幾個實踐的例子,若是對錶述內容有啥意見或者建議歡迎在博客中留言[原文地址]