今天和大家聊聊作為一個后端開發,在實際工作中,我們如何打造一個高并發的系統?
如下圖所示,大概有六個層面,我們結合具體的場景直播間簽到去一一細說。
一、前端
1、打散請求:即把用戶的接口分散一點去請求后端,盡量不要集中在某一時刻。
場景:比如直播間講師發起了一個簽到,用戶去點擊簽到,調用簽到請求接口。假設這個直播間的在線人數上百萬,那么這個簽到接口的請求可能會有近百萬的QPS。毫無疑問,這會對后端服務造成瞬時、巨大的流量沖擊。
解決措施:這種瞬時洪峰流量,我們就可以在前端對用戶簽到接口做打散處理。比如針對直播間的在線人數,當超過某個閾值時,做3秒內任一毫秒的分散請求。避免這些請求在大流量直播的直播間里,瞬間同時請求過來,沖垮后端服務。
2、防抖防重:即在前端加上防止重復點擊、重復請求后端的邏輯。比如點擊簽到按鈕后,前端做一些類似3秒的防重復請求處理,避免用戶多次點擊請求到后端,這樣可以減少大量無意義無效的請求。
3、服務降級:在高并發、系統壓力較大或部分服務出現故障時,通過暫時減少或關閉某些功能,以保證系統的核心功能仍然能夠正常運行,避免整個系統崩潰。
場景:比如在簽到服務中,用戶簽到是核心接口,當簽到服務受到流量沖擊導致壓力過大時,可以將除該接口外的其它功能在前端暫時屏蔽掉(可配置),這樣用戶就不會去請求對應的接口了,優先保證核心接口正常運行。
二、Nginx/網關
1、負載均衡:這個應該大家都比較熟悉,就是盡可能將請求均勻地打在各個服務器上,常見的有輪詢策略、hash策略等,就不一一贅述了。
2、網關限流:一般我們C端的服務都會有一個統一的網關系統,實現比如用戶信息獲取、路由的分發、接口限流等功能。我們對于C端的接口,在上線前會經過接口壓測,然后根據壓測結果設置接口限流值。在高并發場景下,比如簽到接口設置的是10WQPS,我們就會把在同一秒內超過10W的請求直接在網關層丟棄掉,避免將下游的簽到服務打掛。
三、業務層
1、同步返回:比如前端請求簽到接口,我們后端會返回簽到成功給前端,但實際是否成功還不確定,因為我們肯定不會實時同步去查詢或者寫入MySQL。畢竟我們的MySQL還是比較脆弱的,經不住上萬QPS同時操作。
2、異步處理:跟上面其實意思差不多,同步返回結果,但我們會將實際的數據使用中間件如kafka、RocketMQ、RabbitMQ、Redis等進行削峰,然后推送到下游,最后使用腳本去消費推送的數據進行實際的邏輯處理。
四、數據層
1、本地緩存:感興趣的可以翻翻 我之前寫的文章 。可以說本地緩存是服務器上讀寫性能都最高的介質了,因為本地緩存是直接操作該服務器本身的內存呀。只要內存夠大,幾十萬、幾百萬的QPS都輕輕松松不在話下。
2、Redis緩存:Redis緩存的性能僅此于本地緩存,一般抗10萬以下的QPS用Redis就夠了。Redis緩存實際上也是操作的Redis服務器的內存,只是Redis服務器和本地服務器還有網絡連接。所以Redis性能會比本地緩存稍微差一點,一般同等配置可能都會差一到兩個量級。
3、MySQL:這個大家應該都很熟系了,常用的分庫分表、讀寫分離等等這時都排上用場了。
五、底層架構
1、K8s彈性伸縮:在高峰期提前擴容、高峰期之后縮容。在流量突刺時快速擴容,在流量下落時縮容。k8s提供了多種靈活的彈性伸縮機制,可以根據不同場景和需求自動調整集群的資源使用,確保系統能夠在負載波動時穩定運行。根據實際的應用場景,合理配置這些伸縮機制,能夠有效提升系統的彈性和可用性。最重要的是,比之前使用CVM物理機,能極大地降低服務器成本。
2、微服務架構:微服務架構通過將單一應用拆分成多個獨立的服務,使得每個服務可以獨立擴展和維護,從而提高系統的可擴展性和維護性。例如直播間紅包是一個服務、直播間簽到是一個服務、直播間抽獎又是另一個服務…。這些服務通常是在單獨的服務去維護,盡量做到互相隔離,互不影響。
六、日志監控和告警
假如現網服務出現了問題,我們如何快速地感知呢?那當然是在各個關鍵服務都增加日志記錄,然后增加監控告警,觸發某個閾值時就告警。盡量在用戶感知到問題前,我們去發現到并解決。
以上,就是我們在設計高并發系統時,需要考慮的一些問題和一些解決方案。當然,這里只是講了大的宏觀架構層面,落地到具體的業務場景中,還需要結合實際情況去思考一些細節和方案,去解決實際的性能瓶頸點,這是一件非常有意思的事,希望大家都能從解決問題中收獲快樂。