架構師訓練營第 1 期 - 第 05 周總結
分布式緩存架構
緩存 Cache 與 緩衝 Buffer
緩存 Cache
存儲在計算機上的一個原始數據複製集,以便於訪問
訪問緩存比訪問原始數據便利
介於數據訪問者和數據源之間的一個高速存儲
多次存儲數據時,加快讀取的速度
通常存於內存中
緩衝 Buffer
高速與低速裝置中的一個裝置
不是用於相同數據多次訪問
調節高低速設備存取速度
低速設備先準備好數據寫入Buffer,再由高速設備讀取
高速設備先把數據寫入Buffer, 再由低速設備處理
異步處理數據,才不會相互牽制等待
也是優化性能的一個手段
緩存無處不在
CPU 緩存
操作系統緩存
數據庫緩存
JVM 編譯緩存
CDN 緩存
代理與反向代理緩存
前端緩存
應用程序緩存
分部式對象緩存
緩存關鍵指標
緩存命中率
緩存是否有效
緩存是否有效依賴於能多少次重用同一個緩存,響應業務請求
有多大的概率在每次查找時能找到所要的數據
如果查询一个缓存,十次查询九次能够得到正确结果,那么它的命中率是 90%。
影響因素
緩存鍵集合大小
集合越大,重用的機率越小
如記錄天氣數據
用 IP 當鍵值 (40億個)
用所在國家數量 (一兩百個)
鍵數量越少,緩存效率越高
因為可用內存的大小固定
想辦法減少可能的還存鍵值數量
緩存可使用的內存空間
內存空間越大,緩存命中率越高
緩存對象生存時間 (TTL,Time To Live)
對象生存時間(數據有效時間)越長,緩存命中率越高
長時間有效的數據更適合緩存
緩存形式
通讀緩存 (read/write through)
給客戶端返回緩存資源
請求未命中時由通讀緩存服務器獲取實際數據
客戶端連接的是通讀緩存,而不是原始的服務器
客戶端甚至不知道原始服務器在哪裡
是客戶端唯一的數據源
example
代理緩存
反向代理緩存
多層反向代理緩存
CDN
旁路緩存 (cache-aside)
獨立的鍵值鍵(key-value)存儲
由客戶端應用代碼處理緩存
詢問需要的對象是否存於緩存
若存在則返回
若不存在或過期,則連接主數據源取得
將新得到的資料存入緩存
客戶端須知道緩存及最終數據源兩者
example
瀏覽器對象緩存
本地對向緩存
遠程分布式對象緩存
一致性hash 特性
一致性
當已有的 key 進行重新映射時
key 保留在原Node中
key 移到新加入的 Node中
若key 移動到原有的其他 Node中就不滿足一致性
均勻性
key 會等概率地映射到每一個Node中
一致性 Hash
基本演算法
建立一致性hash環
值域為hash code的所有空間
如 0 ~ 2^32 -1
順時針排列
計算每一個 Node 的 hash code
可用 Node name, IP
其值一定在 hash 環內
路由計算
求對象 Key 的 hash code
如 Key2
將 key 的 hash code 對應到環上
順時針查找最近 Node hash code
若為 Key0,則為 Node 1
若為 Key6,則為 Node 0
此 Node 即為路由選擇結果
增加 Node 3
計算 Node 3 has code 並置於環上
依路由計算出新的路由
僅 Node 2 至 Node 3之間的 key 會被影響,其他不變
如 key0 及 key3 被影響
由 原本 Node 1,變成新的 Node 3
優點
餘數 hash 增減一個 Node會造成大部分的 Key 緩存不命中
一致性 hash 僅造成小部分 key 緩存不命中
不會對真實數據庫產生極大的負載壓力
缺點
負載壓力不均衡
Node hash code 可能過分集中,造成各 Node 間的
訪問負載不均衡
數據存儲不均衡
訪問頻率不均衡
訪問併發量不均衡
增加 Node 後,對負載的分攤也不均衡
僅部分 Node 負載壓力減輕,其他則不變
如 Node 1減輕負載,但 Node 0及 Node 2則不變
加了一個Node 僅影響一個 Node
非我們增加 Node 的目標
增加 Node 希望減輕所有 Node 的負擔
基於虛擬節點的一致性 Hash
將每個節點都擴充多個虛擬節點放置於環上
150 ~ 200 個
之後依照基本的演算法進行路由計算
若對應到虛擬節點,即看虛擬節點對應到哪一個真實節點
以真實節點為路由選擇結果
造成近似均勻的訪問結果
緩存提升性能的原因
使用內存,訪問速度快
通常存儲數據最終的結果,不需要中間計算
減省 CPU 資源
降低數據庫、磁盤及網路的負載壓力
使 I/O設備有更好的響應特性
使整個系統有更好的響應特性
緩存是系統性能優化的大殺器
技術簡單
性能提升顯著
應用場景多
適合於
多次讀取的性能優化手段
對寫沒有優化效果
需合理使用緩存
不合理
過分依賴緩存
不合適的數據訪問特性
合理使用緩存
頻繁修改的數據不適合緩存
來不及讀就已經失效
同一數據的讀寫比在 2:1 以上,緩存才有意義
讀寫比例越高,緩存越有意義,緩存價值也越大
沒有熱點的訪問不適合緩存
內存有限,僅能存儲一部分數據
內存管理使用 LRU (Least Recently Used) 演算法
寫入後,很長時間不讀或隨機讀取
還沒被再次訪問就被擠出緩存
徒消耗內存資源
不遵循二八定律的數據
大部分數據訪問不是集中在小部分的數據上,不適合緩存
二八定律
80%的訪問須集中在20%的數據上
緩存此20%的數據,可以減少80%的訪問時間
數據允許一定時間內的不一致與髒讀
數據庫更新數據,緩存服務器不一定知道
緩存設有失效時間
應用需要容忍一定時間的數據不一致
通常這種延遲是可以接受的,但仍須審慎評估具體的應用
即時更新緩存
即時通知緩存,數據已經失效,刪除該緩存資料
增加系統開銷
不要造成緩存雪崩
緩存數據丟失或緩存不可用,不能影響到應用程序
雪崩原因
數據庫已經習慣緩存
當緩存服務崩潰,數據庫突然接收超過負載的訪問壓力
數據庫崩潰
應用程序崩潰
使用緩存預熱
系統開啟時將熱點數據加載好
避免系統開啟時段性能不好,數據庫負載高
避免緩存穿透
不恰當的業務或惡意攻擊,持續高併發請求不存在的數據
所有請求沒有緩存而都落到數據庫上
解法
將不存在的數據也緩存起來(其value值為null)
消息隊列
系統寫數據性能優化
透過消息隊列異步架構實現
同步調用
Client code 在遠端調用功能完成前不返回
阻塞等待後才繼續執行
多個同步調用所用的時間會疊加累計
異步調用
Client code將遠端調用放入消息對列(queue)中,就返回
不必等待
增加一個消息隊列消費者,負責真實遠端調用
Client code 與遠程系統異步的併行執行
客戶端利用 "回調" 來得知遠端調用的結果並處理之
多次異步調用,不會阻塞應用線程
多次異步調用是同時並行,時間不是疊加累計
消息隊列構建異步調用架構
角色
消息生產者
消息隊列
消息消費者
消息生產者與消息消費者
異步執行
通過消息隊列解耦合
相互之間不用同步等待
不相互阻塞
模型
點對點模型
多個生產者
多個消費者
生產者生產的每個消息只被消費一次
容易進行擴容和伸縮
發布訂閱模型
消息透過一個Topic (主題)被訂閱
此主題可以被多個消費者訂閱
每個消費者都會得到訂閱主題的消息,分別進行處理
消息一次生產,多次消費
消費者間不會影響對方對同一個訂閱消息的處理
好處
實現異步處理,提升(寫)的處理性能
同步響應時間長
異步響應時間短
更好的伸縮性
若上傳文件須後處理,且須擴容
無消息隊列狀況 (同步處理)
擴容前端集群
連其他無相關的操作也一起擴容
資源利用不均衡
使用消息隊列狀況(異步處理)
可直接擴容文件處理的後端工作者
可以針對某一特定場景單獨進行伸縮
使伸縮更具有針對性
不用對架構上做改變
實現削峰填谷
應用程序的負載不均衡
高低峰時間不定
若以高峰來配置系統,可能有很多時間用不到,造成浪費
使用消息隊列可以解決高峰時的併發
數據庫可以依據自己的能力處理消息
事件可在消息隊列中堆積
可以分在一些消息至低谷時處理
高峰時沒有太高的峰值壓力
低谷的時候也沒有浪費資源
失敗隔離和自我修復
生產者不直接依賴消費者
消息隊列將和消費者系統的錯誤與生產者系統組件隔離
雙方互不受對方失敗影響
可以在任意時刻對消費者系統進行維護和發布操作而不影響生產者系統
簡化部屬和服務器管理的難度
解除生產者與消費者間的耦合
雙方沒有直接調用依賴的耦合
雙方沒有代碼的耦合
雙方可獨立開發發展
事件驅動架構 EDA (Event-Driven Architecture)
生產者發布一個事件
消費者訂閱事件
消費者通過消息隊列獲取事件
因事件驅動後續的消費者程序的執行
通過事件構建一個程序運行的流程
更容易擴展功能
新增一個消費者並訂閱主題
好處
系統性能提升
整體架構更加的低耦合
維護擴展更加的容易
耦合表面積更少
請求/響應為強依賴
多方的耦合
事件驅動僅耦合於事件的格式與含義
負載均衡架構
HTTP 負載均衡架構
利用負載均衡服務器將用戶請求分發給集群中的某一台服務器
集群中的服務器
部署相同的應用程序
提供相同Web (HTTP)處理能力
當高併發請求到達負載均衡服務器,負載均衡服務器會
分發請求給不同的應用服務器
使集群中的服務器均勻分攤高併發的請求
負載均衡服務器為公網 IP 地址
通常應用服務器為內網 IP 地址
防止攻擊、增加安全性
負載均衡服務器兩個關鍵點
請求如何分發
如何選擇服務器來分發
請求如何分發
HTTP 重定向負載均衡
方法
用戶訪問 HTTP重定向負載均衡服務器的 IP 地址
重定向服務器利用路由算法得到一台真正應用服務器的IP地址
寫入HTTP 重定向header內
重定向服務器不對請求作任何其他處理
用戶端瀏覽器得到重定向header,重新把請求發給真正應用服務器
優點
實作方法簡單
部署簡單
缺點
用戶的每一次請求變成兩次請求
第一次請求得到重定向IP地址
第二次才是真正的應用請求
一次 HTTP 通信,變成兩次 HTTP 通信
請求效率低
安全性問題
應用程序服務器必須為對外暴露
IP 必須為公網 IP
很少人使用
性能比較低
安全性比較差
DNS 負載均衡
方法
DNS解析域名時,將相同域名解析出不同的 IP 地址
對不同用戶解析出不同的 IP 地址,實現負載均衡
由域名服務商提供,不用自己部署負載均衡服務器
缺點
無HTTP重定向兩次請求的缺點
第一次或本地緩存超時時才需要做域名解析
因為原本就需要執行域名解析
安全性問題與HTTP重定向相同
很多大型互聯網應用都使用 DNS 負載均衡
DNS解析出來的 IP 地址不是真正的應用服務器IP地址
DNS解析出來的 IP 地址是互聯網內部的負載均衡服務器的IP地址
兩級負載均衡
第一級 - DNS 負載均衡
第二級 - 內部應用負載均衡
以此解決DNS負載均衡安全性問題
反向代理負載均衡
方法
若反向代理無用戶請求內容,則轉發至應用服務器取得
利用轉發時選擇服務器,實現負載均衡
適用於小型互聯網應用
效率比較低
性能比較差
因為
反向代理為一個完整的HTTP 請求
反向代理服務器必須
得到用戶端請求的所有 TCP 封包後才能轉發
得到服務器回應的所有TCP封包後才能將響應返回給用戶
需要一個應用層 (HTTP層)協議的轉換
通信中需要處理應用層協議和規範
IP 負載均衡
方法
對每一個來自用戶的封包的 IP 地址進行處理
將來源 IP 地址 (用戶 IP) 改成負載均衡服務器 內網 IP 地址
將目標 IP 地址(負載均衡服務器公網 IP)改成應用服務器內網 IP 地址
對來自應用服務器的封包的 IP 地址進行處理
將來源 IP 地址 (應用服務器內網 IP 地址) 改成負載均衡服務器公網 IP 地址
將目標 IP 地址改成用戶的 IP 地址
需維護 IP 映射表
不用應用層協議轉換
處理簡單
性能壓力比反向代理小的多
缺點
一般請求
請求封包少
響應封包多
如圖片、影像等
所有應用服務器的響應封包都需經過負載均衡服務器
服務器的網卡出口頻寬有限
會成為瓶頸
數據鏈路層負載均衡
方法
通過修改封包MAC 地址實現負載均衡
負載均衡服務器與後端應用服務器為相同的 虛擬 IP 地址
對來自用戶的封包
將目標 MAC 地址 (負載均衡服務器)修改成應用服務器的 MAC 地址
應用服務器的響應封包可以直接丟至網路中
因為沒有修改請求的來源及目標 IP 地址
又負載均衡服務器 IP 與應用服務器相同
封包不用再經過負載均衡服務器
又稱三角模式
用戶 --> 負載均衡 --> 應用服務器 --> 用戶
為大型互聯網應用中最主要的負載均衡方式
如何選擇服務器來分發 (負載均衡算法)
輪詢
請求依次分法給每一個服務器
加權輪詢
根據硬件的性能,在輪詢的基礎上,按照配置的權重發給服務器
服務器性能好的權重高,性能低的權重低
隨機
請求隨機發給服務器
如果硬件性能不同,也可以使用加權隨機
最少連接
紀錄服務器正在處理的連接數
選取最少連接者
較少使用
連接數容易算錯
輪詢與隨機已經達到均衡的目的
源地址散列
根據請求來源地址進行 hash 計算
可以保證同一個來源的請求總是在同一個服務器上處理
實現會話(session)黏滯
應用服務器集群的 session 管理
Session
Web應用中的狀態訊息
紀錄請求上下文
如交易請求中的購物車
在負載均衡的架構下如何做session管理
請求因算法不同,會落在不同的服務器
上下文無法記錄在一起
管理方法
Session 複製
方法
將修改的 session 複製到其他應用服務器上
所有應用服務器記錄相同的 session
缺點
當應用服務器數量大時
每個session 需複製到所有的服務器,通信數據量大
每個session 存儲在所有服務器上 ,存儲數據量大
不符集群減輕服務器壓力的目的
複製造成服務器的負載壓力提升
很難進行大規模伸縮
消耗資源
幾乎不使用這種方式
Session 綁定
方法
利用源地址散列算法達成
同一用戶請求總是在同一台服務器上
缺點
違反高可用
當服務器失效,原用戶請求會發至新服務器
但新服務器沒有原本的 session
用戶將丟失先前操作的資料
當服務器迭代新功能時也會出現丟失 session
用戶體驗差
幾乎不使用這種方式
利用 Cookie 紀錄 session
方法
利用 cookie紀錄請求上下文
每一次請求都包含 cookie
缺點
cookie 大小有限
某些瀏覽器或特殊的場景下 cookie 會被禁用
雖然有問題,實際應用常用這種方式
使用 session 服務器
方法
建立一個 session 共享服務器或集群
應用服務器不紀錄 session
應用服務器為無狀態服務器
應用服務器由 session 服務器獲得 session 內容
優點
不管應用服務器當機、進行擴容都不影響 session 處理
應用服務器及群
不共享任何訊息
share nothing
不紀錄任何狀態
這種集群最容易進行伸縮
最常見的方式
版权声明: 本文为 InfoQ 作者【Panda】的原创文章。
原文链接:【http://xie.infoq.cn/article/da65e4b6c3023e5a48130cffe】。未经作者许可,禁止转载。
评论