歐陽習彪,徐寶林
(廣東白云學院大數據與計算機學院,廣州 510450)
高并發系統是當今互聯網時代的關鍵技術之一。隨著互聯網用戶數量的不斷增加,社交、媒體以及電商、游戲等Web 網站用戶數量越來越大,并發流量也越來越高,這對于傳統Web系統架構設計提出新的挑戰,如何構建高效、穩定、可擴展的系統成為了互聯網企業必須面對的問題[1]。高并發系統架構作為解決這一問題的核心技術,已經成為了各大互聯網企業競爭的重要因素。本文將從架構設計和技術選型及實現等方面,對高并發系統架構進行深入研究。探討如何通過分布式架構、緩存技術、負載均衡等手段來提高系統的性能和可用性,從而為用戶提供更好的服務體驗。
對傳統虛擬機技術下LAMP架構部署的Web應用資源消耗大、部署速度較慢等問題,使用Docker 可更快地打包、測試以及部署應用程序,過去需要用數天乃至數周的任務,在Docker 容器的處理下,只需要數秒就能完成,提供持續集成和持續部署的服務。同時Docker 容器包含了運行環境和可執行程序,可以跨平臺和主機使用,也避免了開發環境、測試環境、生成環境不一致的問題[2]。在本系統中采用dockercompose 編排工具來創建容器和鏡像,dockercompose.yml 配置內容如圖1 所示,通過dockercompose 命令啟動容器,docker images 可查看到系統共創建了php+nginx+mysql+redis 四個鏡像以及docker ps-a命令可看到共創建了php+nginx+mysql+redis四個容器,如圖2所示。

圖2 創建的容器及鏡像
面向高并發的Web 系統架構設計的核心思想是降低服務器端對資源調度和使用的程度,除了在程序設計應用高效的算法之外,在系統架構上可以采取分布式架構、緩存技術、負載均衡等技術來降低服務器端的數據處理性能開銷[3]。系統架構設計如圖3所示。

圖3 系統架構
CDN 加速的原理是通過在現有的網絡中增加一層網絡架構,將目標網站的內容發布到最接近用戶的網絡“邊緣”,使用戶可以就近取得所需的內容,提高用戶訪問網站的響應速度。CDN 主要是用來緩存網站中的靜態數據,如:CSS、JS、圖片和靜態頁面等數據。用戶發送請求到后端服務器,處理完動態內容后,直接從CDN中獲取靜態數據,從而加快響應時間[4]。
在高并發系統中,需要保證系統的高可用性和負載均衡,而Keepalived LVS(linux virtual server)是一種常見的解決方案。Keepalived LVS通過將請求分發到多個服務器上,來實現負載均衡和高可用性。它使用IP 負載均衡技術將網絡流量分發到多個服務器,并使用虛擬IP 地址來屏蔽后端服務器的IP 地址。當一個服務器故障時,Keepalived LVS 會將請求重新路由到其他可用服務器上,從而保證系統的高可用性。
2.3.1 動靜分離
通過中間件將動態請求和靜態請求分離,可以減少不必要的請求消耗,同時能減少請求的延時。動靜分離后,即使動態服務不可用,靜態資源也不會受到影響。
2.3.2 負載均衡
隨著網站用戶量不斷增大,同一時間請求數不斷提高,單臺服務器已經不能滿足需要,此時需要進行服務器擴容,將客戶端發過來的請求分攤到其他服務器上,減少每臺服務器的壓力,進而提高系統的吞吐率;另外如果其中某一臺服務器宕機,其他服務器還可以正常提供服務,以此來提高系統的可伸縮性與可靠性。常見的負載均衡算法有輪詢、加權輪詢和hash。在本游戲系統中由于三臺服務器配置一樣,故選用加權輪詢的策略,nginx 負載均衡主要配置如圖4所示。

圖4 nginx負載均衡機制示意圖
2.4.1 分布式數據庫
高并發系統中,隨著業務的發展,系統用戶數越來越多,單表數量達到一定量的時候,可能會導致表中索引失效,查詢速度變得非常慢,同時現有的單臺數據庫服務器滿足不了業務需求,需要進行擴容,本系統主要采用數據庫分布式部署、負載均衡、分庫分表、讀寫分離的技術來滿足高并發場景下數據庫服務器的高性能、高可用特性[5]。
(1)讀寫分離:由于業務中大多數是處理讀的操作,數據庫的壓力主要是由這些讀的請求造成的,通過數據庫讀寫分離,能有效減少數據庫的壓力,提高查詢響應速度。
(2)主從復制:對系統進行讀寫分離后,主服務器負責寫入操作,從服務器負責讀操作,由于讀和寫操作不是同一個表,會導致數據不一致的問題。因此,需要通過主從復制的方式來同步數據,保證主從服務器數據的一致。
(3)數據庫負載均衡:在主從部署的數據庫集群系統中,從服務器通常有幾臺,為了分攤系統請求壓力,最大化利用每臺從服務器,本系統中采用Haproxy+Keepalived 負載均衡技術,通過Haproxy 實現負載均衡,Keepalived 確保即使主服務器宕機,從服務器仍舊可以作為主服務器使用,保證系統的高可用性。
(4)分庫分表:在高并發數據量大的系統中,頻繁的IO 操作成了數據庫的性能瓶頸,最終都會導致數據庫的活躍連接數增加,進而逼近甚至達到數據庫可承載活躍連接數的閾值,使得可用數據庫連接少甚至無連接可用。通過分庫分表,將數據分散存儲,使得單一數據庫/表的數據量變小來緩解單一數據庫的性能問題。在本游戲系統中,用戶千萬級,游戲記錄表數據每日新增量非常大,單表已不能滿足需要,故采用范圍分表的方式,共分為20 個子表,每個子表存放500000 條記錄,根據用戶ID 對單表最大記錄數500000 取商,再加1,以此確定當前用戶游戲數據對應保存的子表序號,具體實現代碼如下:


2.4.2 數據緩存redis
當表的記錄變得非常龐大時,索引失效,查詢速度將變得非常慢,影響網站的性能,這種情況下可以將數據緩存起來,每次訪問數據的時候先從緩存中讀取,如果緩存中沒有需要的數據,才去數據庫中查找。這樣可以極大降低數據庫的負載壓力,也有效提高了獲取數據的速度。常用的緩存技術有redis 和memcache,由于redis 擁有豐富的數據類型,支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用。系統中用redis作為緩存數據庫,該游戲系統中用戶量大、并發高,同一時刻需要更新玩家數據的量非常大,如果直接操作數據庫將導致數據庫無法承受壓力而崩潰,此時可以選用redis 的hash 數據類型,以用戶id 作為鍵,玩家游戲數據作為值,同時將有數據變換的玩家id存放到redis集合中。然后通過定時任務,從redis 集合中獲取所有玩家有數據變化的玩家id,并依次取出數據內容插入數據庫中,具體實現代碼如下:


由于redis 是純內存操作,內存空間有限,在高并發系統中一臺redis 服務器并不能滿足系統高可用的要求,本游戲系統中采用一主二從的架構,通過主從復制實現了數據的熱備份,當主服務器宕機時,從服務器可以充當主服務器進行使用,同時在主從復制的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務,分擔服務器負載;尤其是在寫多讀少的情況下,通過多個從節點分擔讀負載,可以大大提高redis服務器的并發量。
對于大流量、高并發系統,任何一個環節到達性能瓶頸都可能導致系統宕機崩潰,進行在進行系統架構設計時,每一層都需要考慮系統的可用性、擴展性、安全性,等等。本文從接入層、應用層、數據存儲層三個方面進行了探討,利用DNS 加速、負載均衡、redis 主從、MySQL 主從復制、MySQL 讀寫分離等技術實現了系統高并發、高性能、高可用的特性。