前言
自2020年1月,新型冠狀病毒肺炎被證實人傳人後,無論是普通民衆還是政府部門,都想着怎麼去控制病情。而口罩成爲防疫病情的第一需求,口罩很多時候一罩難求,是全國人民的剛需產品。
我算是半個湖北人,年前因爲各種因素沒去湖北,但身爲一個災區的親屬,一直在想:作爲一個架構師,如何用自己的所學爲疫情中的人們出一份力?碰巧2月底,我收到了一個地方政府口罩預約系統的優化援助信息,當時心裏很是高興,我終於也能除了關注、捐款外,用自己的所長貢獻出更大的力量!
一、需求階段
01 需求收集
口罩在疫情期間是一個全民性的需求,該地方政府每日會採購一批口罩供應市場,市民們採用線上預約的方式進行搶購,由於預約人數過多,現有的口罩預約系統無法支持高併發的搶購,急需進行優化。需求如下:
1. 該地有百萬人口,每日供應口罩量將達到幾十萬個以上,系統要求最高支持十萬級以上人同時預約。
2. 政府爲了滿足公平性,採用在線多端預約的方式:每日不定時開放預約,並更新銷售網點。
3. 每個預約成功者可到定點網點一次性採購5個口罩。
4. 凡預約成功者,自預約成功之日起5日後纔可重新預約。通過預約人的身份證和手機號雙限制。
5. 口罩預約是一個民生急需需求。要求預約系統能夠穩定,快速上線。
6. 現有硬件資源有限,暫時不考慮變更。
02 系統現狀
當時的口罩預約系統是一個使用PHP語言實現的完整後臺管理系統。
視圖層:因爲PHP是快速建站的首選,所以是沒有前後分離的。
存儲層:原先使用Access數據庫,後面因爲預約人數太火爆,改用MySQL。
03 需求分析
針對第一點需求。我們可以分析到:百萬人口級別的市場需求,最高10萬級別的預約記錄。是一個高併發的寫請求,如果直接入庫的話,對於MySQL有比較大的性能壓力,而且也非常浪費資源。更何況一開始還使用Access 數據庫。所以我們只可以選擇異步批量插入數據庫來保障需求。
針對第二點需求。我們可以分析到:這其實是一個秒殺行爲。對於秒殺,因爲有各種限制和庫存的處理,爲提高市民體驗性,所以我們需要採用內存秒殺處理。
針對第三、四點需求。我們可以分析到:需要有黑名單機制、商品扣除校驗等業務需求。
針對第五點需求。我們可以分析到:原有系統的峯值波動不穩定性,已經引起公衆的不滿,有一定的投訴量。所以必須保證峯值的高可用和流暢度。
針對第六點需求。我們可以分析到:身爲架構人員,要做的就是降本增效的設計。怎樣將有限的資源更大利用化其實是咱們最大的工作。
二、架構方案設計
因爲是一個性能優化的援助,所以可以確定爲遺留系統改造的需求。從架構師的思維出發,先進行總體架構的設計模式選擇。針對遺留系統的改造,我們通常選擇絞殺者模式、修繕者模式。
01 絞殺者模式
絞殺者模式是指在遺留系統外圍,將新功能用新的方式構建爲新的服務。隨着時間的推移,新的服務逐漸“絞殺”老的遺留系統。流程如下:
02 修繕者模式
就如修房或修路一樣,將老舊待修繕的部分進行隔離,用新的方式對其進行單獨修復。修復的同時,需保證與其他部分仍能協同功能。
大神Martin Fowler 在 《branch by abstraction》有詳細的介紹,流程如下:
03 結論
絞殺者模式適合對於那些老舊龐大難以更改的遺留系統進行全局改造。然而我們接收的是一個優化援助,是一個緊急的事情。那麼我們只能選擇修繕者模式。
三、詳細設計
01 相關表
現有系統有三張表關係到秒殺的基本業務(不含安全風控)。
1. 配置表,口罩的數量配置表
2. 網點表,記錄網點信息
3. 登記表,記錄購買用戶信息
表設計如下:
配置表主要有id、日期、總數、餘數、狀態(0-過期,1-開放,2-關閉)
網點表主要有id,名字,地點,排序
預約表主要有id,姓名,身份證,手機號,日期,網點id
02 秒殺流程
系統有完整的前後臺及一些運維風控設置,時間又比較緊張的前提下,咱們使用修繕者模式將秒殺場景隔離出來,使用獨立的項目進行執行,協同原有的後臺進行支撐。
登記流程:
03 瓶頸分析
從流程中我們發現預約的瓶頸有以下幾點:
1、 預約頁面的初始化,需要餘量展示以及銷售網點的展示。高併發下有一定的性能的損耗,影響客戶的體驗度。
2、 黑名單校驗,原本通過數據庫查詢來限制。一樣有性能損耗,影響預約流暢度。
3、 搶購預約,大量數據庫插入,數據庫連接不足。引起系統崩潰,系統可用性及其低下。
04 方案設計
根據瓶頸,我們分析以下,如果全內存加載:
1、每條網點信息在UTF8MB4下會佔用1KB。最多千條,全內存加載1M。因爲存在後臺更新網點,日更級別。使用修繕者模式+快速上線,先不做系統對接。所以可以定時異步全刷新網點緩存,更新頻率根據實際分析,每30分鐘刷新一次。
2、 黑名單校驗,通過身份證和手機號來限制,計算下存儲空間:
每個限制:11 + 18 = 29B
平均記錄數:10萬
天數:5天
合計29 *10萬*5 大約15M。
結論:完全可以內存加載。
即使上升一個量級,100萬登記也才150M。
3、 數據插入在秒殺流程是一個超高頻的操作,也是性能的最大屏蔽。所以我們可以採用異步批量插入數據的形式進行優化。
四、僞代碼實現
01 預約邏輯
02 批量更新邏輯
03 黑名單加載機制
04 網點加載機制
05 配置異步刷新機制
06 緩存靜態變量類
07 異常處理機制
因爲是單Tomcat,爲了防止系統故障,使用了優雅停機及Tomcat 崩潰恢復mock
五、成果展示
前後經過7小時的優化,完成了預約單功能的修繕協同。優化後的頁面如下:
測試結果如下:
生產運營環境:
上線當天平穩支撐了80000次併發的預約。全程改造不加任何中間件,在原有的服務器和軟件上,獨立部署一個Tomcat,使用重定向協同完成對客戶的無感知預約。