1. 程式人生 > >《億級流量網站架構核心技術》讀書筆記 —— 交易型系統設計的一些原則

《億級流量網站架構核心技術》讀書筆記 —— 交易型系統設計的一些原則

設計一個系統,不僅需要考慮實現業務功能,還要保證系統高併發、高可用、高可靠等,在系統容量規劃(流量、容量)、SLA指定(吞吐量、響應時間、可用性、降級方案等)、壓測方案(線上、線下等)、監控報警(機器負載、響應時間、可用率等)、應急預案(容災、降級、限流、隔離、切流量、可回滾)等方面

1. 高併發原則

1.1 無狀態

應用無狀態易於擴充套件.實際中應用無狀態,配置檔案有狀態。

1.2 拆分

是否拆分取決於系統規模與可利用資源. 如果確實需要拆分,一般來說有以下幾種情況:

  • 系統維度:按照系統功能和系統業務拆分,如商品系統、購物車系統、結算系統、訂單系統等
  • 功能維度:對一個系統進行功能再拆分,比如優惠券系統可以拆分為後臺券建立系統、領券系統、用券系統等;
  • 讀寫維度:根據讀寫比例特徵進行拆分,比如商品系統的讀遠大於寫,可拆分為商品寫服務和商品讀服務;讀的時候可用快取優化;寫的時候可分庫分表;
  • AOP維度:根據訪問特徵,按照AOP進行拆分,比如商品詳情頁可以分為CDN、頁面渲染系統;
  • 模組維度:按照基礎或者程式碼維護特徵拆分,比如基礎模組分庫分表,資料庫池連線等;

1.3 服務化

服務註冊與發現,服務分組、隔離、路由,服務治理:限流、黑白名單等.

題外話: 之前有被問到一個問題:能不能用nginx代替微幅服務API閘道器? 這個問題還是需要根據系統規模來看;如果說你只有兩三個微服務,每個微服務的部署節點也只有兩三個,那不嫌麻煩的話可以手工配置nginx;但如果你微服務數量較多、部署節點較多時,那手動配置nginx就會成為一個災難;這個時候服務註冊於發現以及統一API閘道器就會起到非常巨大的作用,讓你不在進行繁瑣的nginx路由配置,不用擔心服務擴容與縮容修改路由配置.

1.4 訊息佇列

訊息佇列一般用來解耦一些不需要同步呼叫的服務或者訂閱一個自己系統關心的變化。使用訊息佇列可以實現服務解耦、非同步處理、流量削峰/緩衝等.

1.4.1 大流量緩衝

針對較大流量湧入,系統需要進行一些特殊的設計平穩過度,一般來說可以系統強一致性,保證最終一致性.

1.4.2 資料校對

使用了訊息非同步機制的場景下,可能會出現訊息丟失,因此需要考慮進行資料校對和修正來保證資料的一致性和完整性(訊息補償)

1.5 資料異構

異構的目的是實現資料的自我控制,當其他系統出問題或者自己的系統出問題不會互相影響,一般通過訊息佇列實現資料分發.

1.5.1 資料異構

若訂單表按照訂單ID進行分庫分表,那麼查詢使用者所有訂單就會導致全表掃描;異構一套使用者訂單表,按使用者ID進行分庫.

1.5.2 資料閉環

如果請求的資料來源較多,則會增加請求的響應時間和影響服務的穩定,此時可以將用到的資料進行異構儲存,形成資料閉環:

  • 資料異構:通過訊息機制接收資料變更,然後原子化儲存到合適的儲存引擎
  • 資料聚合:將異構的資料進行聚合,一次請求就可以獲取到完整的資料
  • 前端展示:前端通過一次或少量次數就可以拿到所有資料

1.6 快取

快取對於讀服務可以說是一枚抗流量的銀彈.

1.6.1 瀏覽器快取

設定請求的過期時間,如針對響應頭ExpiresCache-control進行控制,適用於對實時性不太敏感的資料;

1.6.2 APP客戶端快取

預先下發訪問素材,APP離線快取

1.6.3 CDN快取

可以考慮將一些公共的或者不頻繁改的資源推送到離使用者最近的CDN節點,如公共JS、圖片等

1.6.4 接入層快取

對於沒有CDN快取的應用來說,可以使用Nginx搭建一層接入層,使用如下機制:

  • URL重寫:將URL按照指定的順序或者格式重寫
  • 一致性hash:按照查詢引數做一致性hash
  • proxy_cache:使用記憶體級或者SSD級代理快取來快取內容
  • proxy_cache_lock: 使用lock機制,將多個回源合併為一個,以減少回源量
  • shared_dict:考慮使用lua shared_dict, 最大的好處是reload快取不會丟失

1.6.5 應用層快取

如使用tomcat時,可採用堆內快取和堆外快取;堆內快取重啟時丟失,堆外快取如local redis cache,就是使用本機redis快取,降低網路消耗. 適用於資料量不大的結構.

1.6.6 分散式快取

資料量較大單機不能處理,可採用分散式快取

1.7 併發化

針對一次請求多份資料,根據其先後順序以及依存關係,進行併發處理請求,以減少耗時.

2. 高可用原則

2.1 降級

對於高可用服務,很重要的設計是降級開關,主要有以下思路:

  • 開關集中化管理:通過推送機制把降級開關推送到各個應用
  • 可降級的多級讀服務:比如服務呼叫降級為只讀本地快取、只讀分散式快取、只讀預設降級資料(如訂單始終有貨)
  • 開關前置化:將降級開關前置,如前置到nginx,不讓請求回源到後端tomcat
  • 業務降級:當高併發流量來襲時,為保證核心業務正常進行,並滿足最終一致性,可把一些同步呼叫改為非同步呼叫,優先處理優先順序資料或者特殊特徵的資料

2.2 限流

限流的目的是防止惡意請求流量,惡意攻擊,或者防止流量超出系統峰值;原則是限制流量穿透的後端薄弱的應用層. 主要有以下思路:

  • 惡意請求流量只訪問到cache
  • 對於穿透到後端應用的流量可以考慮使用nginx的limit模組處理
  • 對於惡意IP可使用nginx-deny進行遮蔽

2.3 切流量

如果某個機架或者機房出現故障,可使用以下方式切流量:

  • DNS:切換入口
  • HttpDNS: 主要用於APP場景下,在客戶端分配好流量入口,繞過運營商的localDNS
  • LVS/HaProxy: 切換故障的nginx層
  • Nginx: 切換故障的應用層

2.4 可回滾

版本化的目的是實現可審計可追溯,可回滾;如果有版本化機制,當出現故障或錯誤時,可進行回滾,如事務回滾程式碼庫回滾部署版本回滾資料版本回滾靜態資源版本回滾.

3. 業務設計原則

3.1 防重設計

如重複支付、重複扣減等

3.2 冪等設計

業務系統在進行訊息消費時需要進行冪等處理,包括使用第三方支付非同步回撥時的冪等處理

3.3 流程可定義

不同的流程進行分離,必要時進行關聯;

3.4 狀態與狀態機

  • 在設計交易系統時,會存在正向狀態(待付款、待發貨、已發貨、完成)和逆向狀態(取消、退款)等,根據系統特徵來決定需不需要分離儲存正向狀態和逆向狀態.
  • 狀態設計時應有狀態軌跡,方便使用者跟蹤當前訂單的軌跡並記錄相關的日誌;
  • 對於狀態的變遷,考慮要不要使用狀態機來驅動狀態的變更和後續流程的操作;
  • 併發狀態修改問題,狀態變更的有序性,比如需要考慮支付成功訊息和使用者取消訊息的時間差。

3.5 後臺系統操作可反饋

在後臺系統的設計中,需要考慮操作結果的可預覽、可反饋.

3.6 後臺系統審批化

對於重要的功能,要設計審批流,比如調整價格,對操作日誌記錄,從而保證操作可追溯可審計

3.7 文件和註釋

建立文件庫,包括設計架構、設計思想、資料字典、業務流程、現有問題,此外業務程式碼特殊需求需要由註釋

3.8 備份

包括程式碼和人員的備份,程式碼入版本庫; 人員的話一個系統至少兩個全面瞭解的人(小公司壓力大)