1 高并發原則
1.1 無狀態
如果應用的設計是無狀態的,那么應用比較容易進行水平擴展。實際生產環境是:應用無狀態、配置文件有狀態。
1.2 拆分
訪問量大,資源充足,可考慮拆分。幾種主要的拆分情況:
- 系統維度:按照系統功能/業務拆分。
- 功能維度:對一個系統按照功能拆分。
- 讀寫維度:根據讀寫比例特征進行拆分。讀的量太大,可用緩存;寫的量太大,可分庫分表。聚合讀取場景,可考慮數據異構拆分系統,將分散在多處的數據聚合到一處存儲,以提升系統的性能和可靠性。
- AOP維度:根據訪問特征,按照AOP進行拆分。
- 模塊維度:按照基礎或者代碼維護特征進行拆分。
1.3 服務化
進程內服務--->單機遠程服務--->集群手動注冊服務--->自動注冊和發現服務--->服務的分組/隔離/路由--->服務治理(限流/黑白名單)
1.4 消息隊列
消息隊列用來解耦一些不需要同步調用的服務,或者訂閱一些自己系統關心的變化。使用消息隊列可以實現服務解耦(一對多消費)、異步處理、流量削峰/緩沖等。
1.5 數據異構
1 數據異構
訂單分庫分表一般按照訂單ID進行拆分,如果要查詢某個用戶的訂單列表,則需要聚合多個表的數據后才能返回,這樣會導致訂單表的讀性能很低。此時需要對訂單表進行異構,異構一套用戶訂單表,按照用戶ID進行分庫分表。
另外,還需要考慮對訂單數據進行歸檔處理,以提升服務的性能和穩定性。
2 數據閉環
如商品詳情頁,因為數據來源太多,影響服務穩定性的因素就非常多。因此,最好的辦法就是把使用到的數據進行異構存儲,形成數據閉環,基本步驟如下:
- 數據異構:通過MQ機制接收數據變更,然后原子化存儲到合適的存儲引擎,如Redis或者持久化KV存儲。
- 數據聚合:數據異構的目的是把數據從多個數據源拿過來,數據聚合的目的是把這些數據做個聚合,這樣前端就可以通過一次調用拿到所有數據。此步驟一般存儲在KV中。
- 前端展示:前端通過一次或少量幾次調用就拿到所需要的數據。
這種方式的好處是數據閉環,任何依賴系統出問題了,還是能正常工作,只是更新會有積壓,但是不影響前端展示。
另外,如果一次需要多個數據,那么可以考慮使用HashTag機制把相關的數據聚合到一個實例,如在展示商品詳情頁時需要使用商品基本信息"p:productId:"和商品規格參數信息"d:productId:",此時就可以使用冒號中間的productId作為數據分片的Key,這樣相同productId的商品相關數據就在同一個實例。
1.6 緩存銀彈
- 瀏覽器端緩存
- APP客戶端緩存
- CDN(Content Delivery Network)緩存
- 接入層緩存
- 應用層緩存
- 分布式緩存
對于兜底數據或者異常數據,不應該讓其緩存,否則用戶會在很長一段時間里看到這些數據。
1.7 并發化
改串行為并行。
2 高可用原則
2.1 降級
對于高可用服務,很重要的一個設計就是降級開關,在設計降級開關時,主要依據如下思路:
- 開關集中化管理:通過推送機制把開關推送到各個應用。
- 可降級的多級讀服務:比如服務調用降級為只讀本地緩存、只讀分布式緩存、只讀默認降級數據(如庫存狀態默認有貨)。
- 開關前置化:如架構是Nginx-->tomcat,可以將開關前置到Nginx接入層,在Nginx層做開關,請求流量回源后端應用或者只是一小部分流量回源。
- 業務降級:當高并發流量來襲,在電商系統大促設計時保障用戶能下單、能支付是核心要求,并保障數據最終一致性即可。這樣就可以把一些同步調用改成異步調用,優先處理高優先級數據或特殊特征的數據,合理分配進入系統的流量,以保障系統可用。
2.2 限流
限流的目的是防止惡意請求流量、惡意攻擊,或者放置流量超出系統峰值。可以考慮如下思路:
- 惡意請求流量只訪問到cache。
- 對于穿透到后端應用的流量可以考慮使用Ningx的limit模塊處理。
- 對于惡意IP可以使用nginx deny進行屏蔽。
原則是限制流量穿透到后端薄弱的應用層。
2.3 切流量
對于一個大型應用,切流量是非常重要的,比如多機房環境下某個機房掛了,或者某個機架掛了,或者某臺服務器掛了,都需要切流量,可以使用如下手段進行切換:
- DNS
- HttpDNS
- LVS/HaProxy
- Nginx
2.4 可回滾
版本化的目的是實現可審計、可追溯,并且可回滾。當程序或者數據出錯,如果有版本化機制,那么久可以通過回滾恢復到最近一個正確的版本,比如事務回滾、代碼庫回滾、部署版本回滾、數據版本回滾、靜態資源版本回滾等。通過回滾機制可以保證系統在某些場景下的高可用。
3 業務設計原則
3.1 防重設計
例如防止重復支付、重復扣減內存等。
3.2 冪等設計
一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函數或冪等方法,是指可以使用相同參數重復執行,并能獲得相同結果的函數。
3.3 流程可定義
復用流程系統,提供個性化的流程服務。
3.4 狀態與狀態機
在設計交易訂單系統時,會存在正向狀態(待付款、待發貨、已發貨、完成)和逆向狀態(取消、退款)等,正向狀態和逆向狀態應該根據系統的特征來決定要不要分離存儲。狀態設計時應有狀態軌跡,方便用戶跟蹤當前訂單的軌跡并記錄相關日志,萬一出問題時可回溯問題。
3.5 后臺系統操作可反饋
設計后臺系統時,考慮效果的可預覽、可反饋。
3.6 后臺系統審批化
對于有些重要的后臺功能需要設計審批流,比如調整價格,并對操作進行日志記錄,從而保證操作可追溯、可審計。
3.7 文檔和注釋
系統發展的最初階段就應該有文檔庫(設計架構、設計思想、數據字典/業務流程、現有問題),業務代碼合特殊需求都要有注釋。
3.8 備份
包括代碼和人員的備份。代碼主要提交到代碼倉庫進行管理和備份,代碼倉庫至少應該具備多版本的功能。人員備份指的是一個系統至少應該有兩名開發人員是了解的。
4 總結
系統設計不僅需要考慮實現業務功能,還要保證系統高并發、高可用、高可靠等。同時還應考慮系統容量規劃(流量、容量等)、SLA指定(吞吐量、響應時間、可用性、降級方案等)、監控報警(機器負載、響應時間、可用率等)、應急預案(容災、降級、限流、隔離、切流量、可回滾等)。
4.1 高并發原則
- 緩存
- 異步并發
- 連接池
- 線程池
- 擴容
- 消息隊列
- 分布式任務
4.2 高可用原則
- 通過負載均衡和反向代理實現分流。
- 通過限流保護服務免受雪崩之災。
- 通過降級實現部分可用、有損服務。
- 通過隔離實現故障隔離。
- 通過合理設置的超時與重試機制避免請求堆積造成雪崩。
- 通過回滾機制快速修復錯誤版本。
參考來源:
[1] 億級流量網站架構核心技術.張開濤著