分佈式架構心得

1. 爲何要分佈式

隨着信息化的推動, 不管是 PC 仍是 mobile 的用戶量都在激增, 單機的性能和可靠性是不可能知足用戶的增加需求的. 爲何分佈式? 簡單來講, 不用分佈式, 沒有更好的方法來解決不斷增加的用戶訪問需求.nginx

分佈式是趨勢, 對分佈式架構中的機制有所瞭解, 是實施分佈式架構的前提. 本文先簡要介紹分佈式架構中一些的重要的概念和機制, 後續會對其中的機制進行更細緻的講解, 並給出實現示例.redis

2. 分佈式架構帶來的挑戰

實施分佈式以後, 首先面對的就是服務數量的增長, 由此給 監控調度 帶來了新的挑戰. 分佈式的複雜性確定比單機要高, 由此又帶來 可靠性性能 上的挑戰.算法

3. 提升可靠性的設計

提升可靠性, 先得知道可靠性是怎麼計算的, 通常有 2 個指標 MTTFMTTR數據庫

  1. MTTF: mean time to failure 平均故障前時間, 注意, 這裏是 故障前 時間, 不是 故障 時間
  2. MTTR: mean time to recovery 平均修復時間

系統可用性計算方法 MTTF/(MTTF+MTTR)緩存

提升系統的可靠性, 有 2 種方式, 一種是作到沒有故障, 一種作到故障發生時, 系統依然可以工做. 顯然第一種方式就像寫出沒有 BUG 的程序同樣不可能作到, 因此, 應該把故障也當成正常的業務邏輯來處理, 只要故障有了應對之策, 那麼對系統的損害就微乎其微, 至少損害是可控的.網絡

3.1 監控設計

監控是可靠性的前提, 沒有監控, 沒法在第一時間發現問題, 更別說預防問題的發生了. 監控也是分層的:架構

  • 基礎層: CPU, 內存, 網絡吞吐, 磁盤 等
  • 中間層: nginx, redis, 消息隊列, 數據庫 等
  • 應用層: HTTP 響應時間, 返回碼, API 調用鏈路, 客戶端訪問信息 等

3.2 一致性設計

一致性是單機應用改形成分佈式以後, 首先面對的問題. 一致性有強一致性(ACID)和最終一致性(BASE) 2 種. 現實中, 要求強一致性的場景其實遠沒有咱們想象的那麼多, 在分佈式系統中, 不少時候只須要最終一致性(BASE)便可.併發

  1. ACID: 原子性(Atomcity), 一致性(Consistency), 隔離性(Isolation,又稱獨立性), 持久性(Durability)
  2. BASE: 基本可用(Basic Availability), 軟狀態(Soft-state), 最終一致性(Eventual Consistency)

ACID 是真正的強調一致性, BASE 實際上是強調可用性異步

3.3 重試設計

分佈式系統中, 存在不少服務之間的調用, 頻繁的互相調用中, 常常會發生些意料以前的間歇性錯誤. 有些錯誤在響應端是會自動恢復的, 因此請求端不用對每一個錯誤都直接返回給客戶端, 有時須要再重試幾回, 等待響應端的恢復.數據庫設計

固然, 重試要看狀況, 調用返回超時, 或者返回能夠重試的錯誤(好比, 繁忙中, 維護中, 資源不足等), 那麼就能夠重試幾回. 若是返回 http 503 等, 這些可能觸發了響應端的 BUG, 或者響應端服務已經不正常了, 就沒有必要重試了.

重試也有策略, 不是一味不停的反覆調用, 這樣可能會給響應端帶來更大的壓力, 讓其更難自動恢復. 重試的策略有多種, 根據實際狀況, 可讓重試的時間間隔愈來愈大, 或者對重試次數作限制.

3.4 熔斷設計

重試是請求端的機制, 熔斷是響應端的機制, 目的是爲了防止響應端的進一步惡化. 熔斷是響應端保護本身的一種機制, 也就是在不堪重負的時候, 斷開本身和外部的聯繫, 防止進一步惡化(就像家裏保護電器的保險絲)

熔斷相似保險絲, 但也有不一樣, 它不只僅只有 斷開連通 2 種狀態, 還能夠有 半開 的狀態, 也就是限制請求的流量, 只處理有限的請求, 直至服務恢復. 當響應端的熔斷斷開的時候, 應該通知請求端, 中止重試

3.5 限流設計

限流的目的是經過對併發訪問進行限速, 讓服務端可以響應更多的請求, 不至於在峯值被壓死 限流的算法有: 計數器方式, 隊列算法(請求速度波動, 處理速度勻速), 漏斗算法, 令牌桶算法

3.6 降級設計

降級是在系統應對突發狀況時, 下降損失的一個方案 主要的降級方式有:

  1. 下降一致性: 從強一致性變爲最終一致性
  2. 中止次要功能: 中止訪問不重要的功能, 從而釋放出更多的資源
  3. 簡化功能: 把一些功能簡化掉. 好比, 簡化業務流程, 或是再也不返回全量數據, 只返回部分數據

4. 提升性能的設計

採用分佈式設計以後, 不只不會下降性能, 反而在分佈式環境下, 有了更多的手段來提升性能.

4.1 緩存設計

緩存能夠有效的提升 I/O, 是提升性能的有效手段之一. 在分佈式環境下, 除了性能, 緩存的策略還要考慮一致性的問題, 通常有 3 種經常使用策略:

  • Cache Aside 更新模式 失效 先從 Cache 取數據, 沒有則從數據庫獲取, 成功後, 放入 Cache 命中 從 Cache 中取數據, 而後返回 更新 先把數據存入數據庫中, 成功後, 讓緩存失效
  • Read/Write Through 更新模式, 與 Cache Aside 相比, 應用不用再關心數據放在緩存仍是數據庫中了 Read Through 查詢時若是未命中, 則更新緩存, 可是更新緩存的動做由緩存服務來完成, 應用自己不用關心 Write Through 若是未命中, 直接更新數據庫, 而後返回. 若是命中, 則更新緩存, 而後由緩存服務本身去更新數據庫
  • Write Behind Caching 更新模式 在更新數據的時候,只更新緩存,不更新數據庫,而咱們的緩存會異步地批量更新數據庫 由於 I/O 是異步處理的, 全部更新操做會很是快, 可是帶來的問題是, 數據不是強一致性的, 有數據丟失的風險

緩存的設計中, 要考慮爬蟲的影響, 由於爬蟲有可能會改變緩存數據的優先級, 讓真正有用的數據被緩存清除.

4.2 異步設計

同步調用 影響吞吐量, 消耗系統資源, 只能一對一, 有多米諾骨牌效應, 而 異步調用 能有效提升系統的吞吐量. 採用異步設計, 服務解耦以後, 必定要有 監控, 不然出了問題沒法及時對應.

異步調用的方式主要有:

  1. 請求響應方式: 給請求中加入回調, 響應結束後出發回調
  2. 訂閱方式: 接收方訂閱發送方的消息, 收到消息就放入處理隊列中, 逐步處理
  3. Broker 方式: 接收方和發送方互相看不到對方, 發送方發送消息到 broker, 接受方從 broker 中獲取消息來處理, 這種方式的好處是將服務完全解耦

異步處理的事務一致性通常不是強一致性, 而是最終一致性, 異步處理能夠和事件溯源(Event Sourcing)結合, 異步處理 + 事件溯源的方式,能夠很好地讓咱們的整個系統進行任務的統籌安排、批量處理,可讓總體處理過程達到性能和資源的最大化利用

4.3 數據庫設計

分佈式環境中, 不管是 緩存, 仍是 異步, 最終數據仍是要持久化到數據庫中, 若是數據庫慢的話, 前面作的再好也效果有限. 提升數據庫性能的方式主要有:

  1. 讀寫分離(CQRS): 將 Command 和 Query 分開, 若是 Command 操做變爲 Event Sourcing, 就能夠把寫操做也簡化掉, 也變成無狀態的, 大幅下降寫操做的反作用, 以獲得更大的併發和性能
  2. 分庫分表(Sharding): 通常來講, 數據庫最大的性能問題有 2 個, 一個是對數據庫的操做, 一個是數據庫中數據的大小 分庫的策略能夠按地理位置, 按日期或者某個範圍分, 或是按一種哈希散列算法. 數據庫分片必須考慮業務, 從業務的角度入手, 而不是從技術的角度入手 只考慮業務分片, 不要考慮哈希散列的方式分片
  3. 數據分片有水平分片和垂直分片 2 種, 水平分片就是分庫, 垂直分片則是分表, 把一張表中的一些字段放到一張表中,另外一些字段放到另外一張表中

5. 分佈式架構的部署

分佈式環境下, 部署升級的方式也和單機應用不同, 更加靈活, 主要有:

  1. 停機部署: 現有服務停機, 部署新版本以後再啓動
  2. 藍綠部署: 分別有 stage/prod 2 套環境, 升級 stage 以後, 將流量切換到 stage, stage 變爲 prod, prod 做爲下一次升級的 stage 使用物理機的話, 2 套環境會有資源浪費, 虛擬機的話隨時回收會好些. 若是服務中有狀態的話, 好比緩存之類的, 那麼停機部署和藍綠部署都會有問題
  3. 滾動部署: 逐步替換應用的全部實例, 來緩慢發佈一個新版本, 這種方式對於有狀態的服務也是比較友好的 這種方式的問題是新舊版本同時在線, 若是有問題, 回滾麻煩, 並且 2 個版本同時在會帶來兼容性的問題
  4. 灰度部署(金絲雀部署): 將生產環境的流量逐步切換到新環境, 能夠按流量分配, 先切 10%, 沒有問題, 再加, 有問題回滾. 在多租戶環境, 也能夠按租戶切換流量.
  5. A/B 測試: 這種方式同時上線 2 個版本, 而後比較可用性, 受歡迎程度, 可見性等 藍綠部署是爲了避免停機, 灰度部署是對新版本的質量沒信心. 而 A/B 測試是對新版的功能沒信心
相關文章
相關標籤/搜索