[應用]北市疫喵接種預約系統一點看法

作者: kentyeh (kent)   2021-07-01 11:37:25
https://booking.health.gov.tw/Home/TakeNum
網路上看到台北市疫喵接種預約系統順利運行,也去看了一下,
試用了一下整個過程是:
1.首頁(同意後選莫德納)
->2.選院所(3個同意再Load時段Json)
->3.填資料送出(未真的送出)
發覺這系統沒上雲端,後台居然還是IIS 10,也沒有提升到HTTP/2,
dig一下發現也沒有用DNS做RoundRobin,
查了一下北市75歲以上統計人口約19萬多,
表示單一IP可能要同時承受上萬人的毆打(×)點擊(○),
北市府的資訊處真的厲害的打擊手。
想說如果是一般規模不大的公司要如何解決,盤點一下設計思路,
1.不能時間一到就讓所有人一擁而上。
2.毋須登錄。
3.寫入永遠比讀取慢很多,寫入資料庫則是更慢,檔案則好些。
4.太多人選擇同一時段造成的超額處理。
我想大多數解決人多的想法,就是多架幾台(load balancer)來應付就好,
頻寬不是問題,電信商調整一下就好。
首先第一要務是解決"單一IP可能要同時承受上萬人的點擊"這件事,
當然有錢的買一台高級的負載平衡器,用硬體來解決,
規模不大的公司出不起這個錢,所以我的做法是最前線就是
一台稍微好一點的機器架上一個 Linux Virtual Server(LVS)來分散入口流量,
LVS後面就接上2~3台Nginx做反向代理(裝在VM上做Load balancer用),
再來就是架上多台Web Server(也是在VM上)。
大概架構如下(我會把實體機接在同一個Hub上,減少網路傳輸時間,
同樣VM也是分散在不同的實體機):
(1)×LVS(實機)→(N)×Nginx(VM)→(X×N)×Tomcat(VM)
因為上述所有的機台都是用Linux,所以自然必須重新調整內核參數,
以應付大量Request,(可以用Nginx併發優化找到一堆內核調整的文章)。
1.防止時間一到所有人一擁而上,最好的策略,就是閱讀測驗:
例如閱讀需知,點選同意與先回答一些問題,最後再跳出視窗再確認一下,
造成每人的時間差異,分散一下開局的壓力。
2.毋須登錄,讓Web程式變成Stateless,也就是request資料,
無論送到哪一台Tomcat都一樣,萬一需要用戶登錄,最簡單的方法就是導入
redisson-tomcat,把Session資料在Tomcat間共享,或都非Tomcat系直接導入
Spring-Session,但是就是要額外多架一台redis server
或是使用Hazelcast Library。(我的建議是redis)
3.最終資料總是要寫入資料庫的,不管怎麼Tune,concurrent connections
最多也只是調整到1、2干個,查詢(快且佔大多數)+寫入(慢很多),
我覺得較好的策略就是快取(讀取結果)+JMS(資料庫緩寫入),
當用戶取得資格,最好的方式就是登記資料寫入redis當快取並
拋給JMS慢慢寫入資料庫,完成再發簡訊。
4.最後要說的就是Race condition的問題,舉例多個人同時看到剩一個
名額時,最簡單的方式,就是開sequence,但缺點是每個院所都要開一個,
也有人用trigger避免超過,但人一多都容易引發DB overwhelming。
更好的方式是使用redis的atomic做取號,超過就叫人重選一次院所。
雖然推薦redis,只是因為網路上都說好,我實際上只用Hazelcast實戰過,
這裡不得說一下,Redis雖然本身雖然有Transction,但她沒有ROLLBACK,
如果要達成XA,必須引入redisson做為redis的Client。
另外還有一些改善點,Nginx支援HTTP/2與Etag,
常用的css,js,與圖片,連到首頁時就用同一個連線送出,並且就加ETag,
下次就客戶端就無須重新載入這些Resources。
北市預約系統的jquery-3.3.1.min.js首頁出來時未加ETag,
選醫療院所第2次才有ETag
然後重選醫療院所時ETag沒有發揮效用,又再一次載入。
不知道是不是IIS的問題,

Links booklink

Contact Us: admin [ a t ] ucptt.com