朱革 余浩源 王先全 周錫祥
摘要:隨著互聯(lián)網(wǎng)的迅速發(fā)展普及以及手機App的快速壯大,服務(wù)器需要承受的用戶訪問量變得越來越大,加上現(xiàn)在用戶對上網(wǎng)體驗的重視,這些都對當(dāng)前服務(wù)器設(shè)計提出了新的挑戰(zhàn)。單一服務(wù)器架構(gòu)已經(jīng)不適合用來承受高并發(fā)請求,前幾年流行的SSM框架能通過集群提高性能,但單體應(yīng)用不適合做大型系統(tǒng),且僅通過服務(wù)器集群帶來的性能提升也會遇到瓶頸,故需要新的架構(gòu)來滿足當(dāng)前的需求。從集群、分布式、數(shù)據(jù)庫幾個方面入手對服務(wù)器設(shè)計進(jìn)行分析,提出適合高并發(fā)環(huán)境的服務(wù)器架構(gòu)。
關(guān)鍵詞:高并發(fā);集群;分布式;架構(gòu)
中圖分類號:TP311? ? ? 文獻(xiàn)標(biāo)識碼:A
文章編號:1009-3044(2021)12-0069-04
Abstract: With the rapid development and popularization of the Internet and the rapid growth of mobile phone apps. The server has to bear more and more user visits, and now users attach importance to the Internet experience, which all pose new challenges to the current server architecture. The single server architecture is no longer suitable for handling high concurrent requests, The popular SSM frameworks of the past few years can improve performance through clustering, but monolithic applications are not suitable for large system, and the performance improvement only through server clusters will also encounter bottlenecks, therefore, a new architecture is needed to meet the current needs. Analyze server design from the aspects of cluster, distributed, and database, and proposes a server architecture suitable for high-concurrency environments.
Key words: high concurrency; cluster; distributed; framework
1 背景
互聯(lián)網(wǎng)發(fā)展初期對服務(wù)器的要求不高,通常在一臺服務(wù)器上搭建服務(wù)就能夠滿足需求,隨著上網(wǎng)人數(shù)的增多以及網(wǎng)速的提高,服務(wù)器需要承受的壓力也越來越大。比如淘寶在雙十一凌晨0點的時候所承受的訪問量巨大,12306鐵路購票網(wǎng)站曾經(jīng)就出現(xiàn)過由于服務(wù)器壓力過大系統(tǒng)崩潰的情況,解決服務(wù)器在高并發(fā)情況下的性能低下問題是必要的。增強服務(wù)器的并發(fā)能力除了提升硬件性能,參數(shù)調(diào)優(yōu)等方式外,還能通過優(yōu)化服務(wù)器的架構(gòu)來提高系統(tǒng)的性能,增強系統(tǒng)的容災(zāi)性與穩(wěn)定性。本文從集群、分布式、數(shù)據(jù)庫等方面來對服務(wù)器架構(gòu)設(shè)計進(jìn)行分析,為高性能服務(wù)器的設(shè)計提供一種可行的方案。
2 架構(gòu)優(yōu)化的必要性
對服務(wù)器性能進(jìn)行提升有多種方式,進(jìn)行硬件的升級是最為簡單的方式,但這種方式成本高且不能從根本上解決問題[1]。對單體應(yīng)用進(jìn)行集群部署能有效地提高系統(tǒng)的并發(fā)能力與穩(wěn)定性,但單體應(yīng)用存在著不易迭代及部署效率低等問題,并發(fā)到了一定程度僅靠集群并不能完全解決性能問題,此時就需要從其他部分進(jìn)優(yōu)化,單靠某一個技術(shù)無法滿足需求,所以需要對服務(wù)器架構(gòu)進(jìn)行設(shè)計。
3 設(shè)計方案
在實際的使用中,影響服務(wù)器性能的因素有很多,架構(gòu)的不同會使服務(wù)器的性能有很大的差距。本節(jié)主要從集群、分布式的使用以及數(shù)據(jù)庫方面進(jìn)行分析。
3.1 使用服務(wù)器集群
客戶端發(fā)送多個請求到單個服務(wù)器,服務(wù)器對請求進(jìn)行處理并且連接數(shù)據(jù)庫,處理完畢后再將結(jié)果返回到客戶端。這種架構(gòu)的成本低,代碼編寫也較為簡單,是比較適合早期并發(fā)較少的情況的。但隨著現(xiàn)在請求并發(fā)變得越來越大,如果想要繼續(xù)采取單一服務(wù)器來處理請求,就得提升服務(wù)器的性能,隨著摩爾定律[2]逐漸失效,硬件性能的提升已經(jīng)跟不上需求的提升,就算不考慮成本將硬件的配置提升到最好仍然不能滿足需求,那通過提升硬件配置這條縱向解決問題的道路就走不通。服務(wù)器集群[3]這種通過橫向增加服務(wù)器數(shù)量的方式就正好能夠解決這個問題。
3.1.1 服務(wù)器集群的作用
服務(wù)器集群就是將多個做同種服務(wù)的服務(wù)器集中起來,利用多個計算機來進(jìn)行并行的計算以提高性能,每個服務(wù)器是一個節(jié)點,所有節(jié)點構(gòu)成了集群[4]。當(dāng)單個服務(wù)器處理高并發(fā)請求遇到瓶頸的時候使用集群可以提升系統(tǒng)的處理能力,當(dāng)集群的性能不夠時也可以適當(dāng)增加節(jié)點數(shù)量。對客戶端而言,訪問服務(wù)器的集群就和訪問一個服務(wù)器是一樣的,客戶端不用專門為此做配置。
3.1.2 用負(fù)載均衡服務(wù)器搭建服務(wù)器集群
服務(wù)器集群是由多個服務(wù)器組成,但是用戶的請求到底由哪個服務(wù)器來進(jìn)行處理,需要一個調(diào)度者來進(jìn)行調(diào)度,這個調(diào)度者就是負(fù)載均衡服務(wù)器。用戶的請求先發(fā)送給負(fù)載均衡服務(wù)器,然后服務(wù)器再根據(jù)相應(yīng)的設(shè)置以及當(dāng)時負(fù)載的情況,來選出一個合適的節(jié)點對請求進(jìn)行處理。
本文選用Nginx作為負(fù)載均衡服務(wù)器,它可以通過反向代理來實現(xiàn)軟件負(fù)載均衡,反向代理時客戶端不需要做任何配置[5]。如圖1所示客戶端對代理是無感知的,請求發(fā)送到了反向代理服務(wù)器,由反向代理服務(wù)器去選擇目標(biāo)服務(wù)器,從目標(biāo)服務(wù)器獲取返回的數(shù)據(jù)后再返回給客戶端,客戶端訪問的實際是代理服務(wù)器的地址,而不是直接訪問的被隱藏了的真實服務(wù)器地址。
使用Nginx作為負(fù)載均衡服務(wù)器首先需要對其配置文件nginx.conf進(jìn)行修改,在http塊中添加:
upstream myserver {
server 192.168.0.1:8080;
server 192.168.0.2:8080;
server 192.168.0.3:8080;
}
表示使用默認(rèn)的負(fù)載均衡策略輪詢將請求分配給三個服務(wù)。然后將http塊里的server部分修改為:
server{
listen 80;
server_name localhost;
location /{
proxy_pass http://myserver ;
}
......
其中l(wèi)isten為監(jiān)聽的端口,server_name為監(jiān)聽的地址,proxy_pass則為請求的轉(zhuǎn)向,值為前面upstream定義的服務(wù)器列表。除輪詢外常見的負(fù)載均衡策略還有Weight、ip_hash、fair、least_conn等。
3.2 采用分布式架構(gòu)
前面講了通過服務(wù)器集群來提高性能,當(dāng)訪問量越來越大,單一應(yīng)用增加服務(wù)器數(shù)量所帶來的性能提升變得越來越小,這時候就需要用到分布式架構(gòu)了,從圖2中可以看出一般服務(wù)器集群中的單體架構(gòu)和分布式系統(tǒng)間的區(qū)別。
分布式與集群相比,分布式是一種工作方式而集群則是一種物理形態(tài)。將同一個業(yè)務(wù)放到不同的機器上以提高性能與可用性就能稱為集群,而分布式則是將不同的業(yè)務(wù)或者一個業(yè)務(wù)拆分成多個子業(yè)務(wù)部署到不同的服務(wù)器上通過交換信息的方式來進(jìn)行協(xié)作[6]。分布式是通過縮短單個任務(wù)的執(zhí)行時間來提升工作效率,集群則是通過提高相同時間并行執(zhí)行的任務(wù)數(shù)量來提高效率的,所以當(dāng)增加集群服務(wù)器數(shù)量提升的性能有限時可通過分布式來提升性能。
3.2.1 微服務(wù)的概念
簡單地來說微服務(wù)[7]就是很小的服務(wù),甚至功能可以單一到只做一件事,一個操作。單體應(yīng)用將它的所有功能放在一個進(jìn)程里執(zhí)行,能夠在多個服務(wù)器里復(fù)制這單體應(yīng)用實現(xiàn)擴(kuò)展。而微服務(wù)則將它的每個功能元素放在不同的服務(wù)中,通過跨服務(wù)器的分發(fā)這些服務(wù)進(jìn)行擴(kuò)展,對需要進(jìn)行復(fù)制的功能元素進(jìn)行復(fù)制也可以實現(xiàn)性能提升。
分布式也屬于微服務(wù),兩者的概念比較相似但是也有一些差別。分布式是一種讓分散的機器相互協(xié)助完成業(yè)務(wù)的手段,微服務(wù)相比一般的分布式則對服務(wù)進(jìn)行更細(xì)粒度的切分,使得整個系統(tǒng)更加易于迭代且并行度更高。
3.2.2 分布式服務(wù)中應(yīng)解決的問題
在微服務(wù)架構(gòu)中隨著功能模塊的增多,代碼和配置文件變得越來越冗雜,為解決這個問題可使用Spring Boot來快速構(gòu)建微服務(wù)應(yīng)用,它能幫助開發(fā)者解決開發(fā)中大部分的配置問題,大部分配置都可以用java類加上注解來代替。Spring Boot能簡化Spring的開發(fā),它為Spring整合了許多第三方技術(shù),去繁從簡約定大于配置,十分適合微服務(wù)開發(fā)[8]。它的特點有:
1)能快速創(chuàng)建獨立運行的Spring項目以及集成了主流的框架。
2)擁有內(nèi)嵌的Servlet容器,方便運行。
3)簡化了Maven配置。
4)無代碼生成,不需要配置XML文件。
5)有大量的自動配置,簡化開發(fā),當(dāng)然也能修改默認(rèn)值。
微服務(wù)雖然帶來了許多好處,同時也使得運維變得更加復(fù)雜,監(jiān)控更加困難,分布式的復(fù)雜性也提高了。比較明顯的幾個問題是:
①服務(wù)間的調(diào)用問題。各個服務(wù)間實現(xiàn)調(diào)用需要知道服務(wù)所在的地址,服務(wù)不會放在固定的機器上,故不能將要調(diào)用的目標(biāo)服務(wù)地址寫死在配置文件里。
②配置問題。微服務(wù)要將單體服務(wù)中的業(yè)務(wù)拆分成多個粒度較小的子服務(wù),這樣就會導(dǎo)致系統(tǒng)中出現(xiàn)大量的服務(wù),如果仍然為每個服務(wù)都提供單獨的配置文件則會出現(xiàn)配置信息冗余。
③系統(tǒng)的穩(wěn)定性問題。由于微服務(wù)間的調(diào)用是鏈性的,如果在整個調(diào)用鏈中某個服務(wù)出現(xiàn)了問題則整個系統(tǒng)則會雪崩式癱瘓。
3.2.3 分布式服務(wù)設(shè)計
分布式服務(wù)中存在的問題使其構(gòu)建變得復(fù)雜,可以使用Spring Cloud[9]來解決這些問題,它提供很多工具用來進(jìn)行分布式系統(tǒng)的構(gòu)建,比如:服務(wù)發(fā)現(xiàn),配置管理,熔斷,微代理,智能路由,控制總線,全局鎖,一次性token,決策競選,分布式session,集群狀態(tài)等。
Spring Cloud Alibaba[10]是阿里巴巴推出的解決方案,使用其中的Nacos、Sentinel、Seata組件來解決前面所提到的問題。
服務(wù)間調(diào)用的地址問題可以使用Nacos中的服務(wù)注冊發(fā)現(xiàn)來解決,在服務(wù)的配置中添加如下代碼:
spring:
application:
name: provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
該配置指定了Nacos的地址以及該服務(wù)的服務(wù)名。
將服務(wù)提供者注冊進(jìn)Nacos后,服務(wù)消費者可以用restTemplate或OpenFeign等來請求調(diào)用該服務(wù)中的功能。其原理是在服務(wù)器啟動的時候會將服務(wù)器的服務(wù)地址通信地址等用別名注冊進(jìn)注冊中心,而另一邊服務(wù)的消費者則以該別名在注冊中心中獲取到服務(wù)的真實通信地址。
配置問題同樣也可以使用Nacos來解決,使用其配置管理功能來充當(dāng)配置中心。需要注意的是在使用配置中心管理配置時,springboot的配置文件需要使用bootstrap.yml,這是因為在項目初始化時需要保證配置先從配置中心拉取,拉取配置后項目才能正常啟動,application.yml是用戶級的資源配置項,而bootstrap.yml是系統(tǒng)級的,優(yōu)先級更高。
bootstrap.yml中相關(guān)配置代碼寫法:
spring:
application:
name: config
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
group: DEV_GROUP
namespace: 077e4037-3b40-4d4a-801e-c8d
4012a815f
使用Sentinel從流量切入,在流量控制、熔斷降級等維度來維持服務(wù)的穩(wěn)定性。流量控制是監(jiān)控應(yīng)用流量的QPS或并發(fā)線程數(shù)來避免瞬時高流量沖垮服務(wù)器。熔斷就好比保險絲,當(dāng)請求滿足設(shè)定的異常條件就會熔斷掉服務(wù),而不是一直等待到此服務(wù)超時。降級則是對服務(wù)進(jìn)行有策略的降級,可以理解為保證核心業(yè)務(wù)正常運行的兜底方法。
啟動好Sentinel與服務(wù)并且進(jìn)行過一次請求后登錄Sentinel控制臺就可以看到相關(guān)服務(wù)并且對其進(jìn)行控制。圖3為新增流控規(guī)則的面板,可以看到閾值類型有QPS和線程數(shù)兩種,QPS是指當(dāng)調(diào)用該api的QPS達(dá)到閾值的時候,進(jìn)行限流。線程數(shù)則是當(dāng)調(diào)用該api的線程數(shù)達(dá)到閾值的時候,進(jìn)行限流。
新增降級規(guī)則的面板為圖4,降級策略有RT、異常比例以及異常數(shù)。RT為平均響應(yīng)時間,滿足平均響應(yīng)時間超出閾值且在時間窗口內(nèi)通過的請求數(shù)大于一定值兩個條件時觸發(fā)降級。異常比例和異常數(shù)則分別是發(fā)生異常的比例和異常的個數(shù)超過閾值時觸發(fā)降級。
3.3 數(shù)據(jù)庫優(yōu)化方案
在高并發(fā)的環(huán)境下,對數(shù)據(jù)庫的操作頻繁,如果只對單實例數(shù)據(jù)庫進(jìn)行簡單的操作無法支撐系統(tǒng)的正常運行,所以需要對數(shù)據(jù)庫的使用進(jìn)行設(shè)計。
3.3.1 索引優(yōu)化分析
數(shù)據(jù)庫執(zhí)行查詢語句時會根據(jù)條件進(jìn)行全表掃描,正確的使用索引可以提高查詢的效率[11]。索引的本質(zhì)是數(shù)據(jù)結(jié)構(gòu),它能夠幫助數(shù)據(jù)庫高效的獲取數(shù)據(jù),但其本身也會占用磁盤空間。使用索引時每次對表進(jìn)行更新操作時需要更新索引,故會降低表的更新速度。當(dāng)表的數(shù)據(jù)特別多時,索引能帶來的性能提升會降低,這就需要合理的設(shè)計索引,以免影響性能的提升甚至帶來負(fù)面效果[12]。
索引在使用中也需要注意避免索引失效,在mysql中可以使用explain關(guān)鍵字來看mysql如何處理sql語句,其使用方法是Explain + SQL語句:
EXPLAIN SELECT * FROM t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id
圖5為執(zhí)行Explain的結(jié)果,可以看到內(nèi)容并不是一般查詢語句的格式。其中各個字段都有其含義:
1)id:查詢序列號,表示查詢中執(zhí)行的順序,值相同則從上往下執(zhí)行,值不同則id越大的越先執(zhí)行。
2)select_type:查詢的類型。
3)table:此行數(shù)據(jù)與哪張表相關(guān)。
4)type:表示訪問的類型,較為重要的一個指標(biāo),能顯示出數(shù)據(jù)庫引擎查找表的方式。
5)possible_keys:可能應(yīng)用在這張表上的索引。
6)key:實際使用的索引。
7)key_len:索引中使用的字節(jié)數(shù),檢查是否充分利用上了索引。
8)ref:索引被使用的列。
9)rows:顯示mysql認(rèn)為執(zhí)行查詢時需檢查的行數(shù)。
3.3.2 讀寫分離
一個系統(tǒng)對數(shù)據(jù)庫的讀寫需求通常不同,讓單一數(shù)據(jù)庫處理讀和寫操作可能會使其承受的壓力過大??梢允褂弥鲝膹?fù)制來實現(xiàn)讀寫分離,讓主服務(wù)器只執(zhí)行寫操作,從服務(wù)器執(zhí)行讀操作,以此分散服務(wù)器的壓力[13]。
如圖6所示,主從復(fù)制的原理是從數(shù)據(jù)庫slave通過讀取主數(shù)據(jù)庫master的binlog然后執(zhí)行一遍master執(zhí)行過的操作從而達(dá)到主從同步的效果??梢詫⑵渲械倪^程分為三個部分:1)master將每個會改變數(shù)據(jù)的操作串行的記錄進(jìn)二進(jìn)制日志binlog中,將這些記錄稱為二進(jìn)制日志事件。2)slave從master拷貝二進(jìn)制日志事件到它的中繼日志中。3)slave按照順序執(zhí)行中繼日志中的事件,將master的改變應(yīng)用到自己的數(shù)據(jù)庫中。
3.3.3 分表存儲
在數(shù)據(jù)量特別大的情況下,數(shù)據(jù)庫的讀取性能會有較大的降低,為了解決這個問題可以將一張表的數(shù)據(jù)拆分到多張表上存儲[14]。
切分有垂直切分與水平切分,根據(jù)業(yè)務(wù)對表進(jìn)行分類然后分布到不同的數(shù)據(jù)庫上,這屬于對數(shù)據(jù)的垂直切分。切分時可按照模塊進(jìn)行分類,有時也可以根據(jù)數(shù)據(jù)量的大小來切分。垂直切分并不會縮表,所以依然存在著單庫的瓶頸,這時就需要用到水平切分。水平切分是根據(jù)某個字段的一些規(guī)則將原本放在一個表里的數(shù)據(jù)放在不同的數(shù)據(jù)庫里,就相當(dāng)于對表按照數(shù)據(jù)行來進(jìn)行切分。
隨著數(shù)據(jù)量的增大,先對表進(jìn)行水平切分,此時利用多塊硬盤來提升IO性能與存儲空間,成本比較低。數(shù)據(jù)庫到了需要垂直切分的階段,此時修改數(shù)據(jù)庫結(jié)構(gòu)的主要原因已經(jīng)不是數(shù)據(jù)量而是整個業(yè)務(wù)系統(tǒng)不能承受壓力了。若過早對數(shù)據(jù)庫進(jìn)行垂直切分需要重新構(gòu)建業(yè)務(wù)系統(tǒng),工作量大,而水平切分不需要對業(yè)務(wù)做大量修改,所以在實際應(yīng)用時建議先考慮水平切分,然后再做垂直切分。
4 結(jié)束語
高并發(fā)服務(wù)器的設(shè)計需要從多方面考慮,若某個部分出現(xiàn)短板就會影響整體性能。本文從服務(wù)器集群、分布式、數(shù)據(jù)庫幾個方面入手設(shè)計服務(wù)器架構(gòu),以提升服務(wù)器的可用性與并發(fā)性能。提高服務(wù)器性能的方式并不唯一,且不同的使用情景需要不同的架構(gòu),除了文中的方案外,還可從其他部分優(yōu)化,比如使用緩存、動靜分離、對熱點部分進(jìn)行優(yōu)化、對表的設(shè)計進(jìn)行優(yōu)化、對jvm等參數(shù)進(jìn)行調(diào)優(yōu)、使用CDN等等?;ヂ?lián)網(wǎng)正在高速發(fā)展,這使得高并發(fā)的場景變得越來越多。雖然各自解決高并發(fā)問題使用的技術(shù)各不相同,但是遇到的各種問題有很多都是類似的,故能夠?qū)e人的解決方案進(jìn)行參考,然后找到自己解決問題的思路。希望本文提供的方案能夠有助于大家對高并發(fā)服務(wù)器搭建知識的學(xué)習(xí)。
參考文獻(xiàn):
[1] 王亞楠,吳華瑞,黃鋒.高并發(fā)Web應(yīng)用系統(tǒng)的性能優(yōu)化分析與研究[J].計算機工程與設(shè)計,2014,35(8)5:2976-2981.
[2] 逄健,劉佳.摩爾定律發(fā)展述評[J].科技管理研究,2015,35(15):46-50.
[3] 吳海明.基于Linux高可用性負(fù)載均衡集群技術(shù)的研究與應(yīng)用[J].科技創(chuàng)新與應(yīng)用,2018(36):17-18.
[4] 李海軍.服務(wù)器集群技術(shù)綜述[J].電腦知識與技術(shù),2013,9(22):5018-5020.
[5] 劉金秀,陳怡華,谷長樂.基于Nginx的高可用Web系統(tǒng)的架構(gòu)研究與設(shè)計[J].現(xiàn)代信息科技,2019,3(11):94-97.
[6] 金磐石.分布式架構(gòu)在銀行核心業(yè)務(wù)系統(tǒng)的應(yīng)用[J].計算機系統(tǒng)應(yīng)用,2017,26(6):46-52.
[7] 趙然,朱小勇.微服務(wù)架構(gòu)評述[J].網(wǎng)絡(luò)新媒體技術(shù),2019,8(1):58-61,65.
[8] 熊永平.基于SpringBoot框架應(yīng)用開發(fā)技術(shù)的分析與研究[J].電腦知識與技術(shù),2019,15(36):76-77.
[9] 周永圣,侯峰裕,孫雯,等.基于SpringCloud微服務(wù)架構(gòu)的進(jìn)銷存管理系統(tǒng)的設(shè)計與實現(xiàn)[J].工業(yè)控制計算機,2018,31(11):129-130,133.
[10] 方永敢.微服務(wù)架構(gòu)的研究及小區(qū)生活服務(wù)平臺的實現(xiàn)[D].成都:電子科技大學(xué),2020.
[11] 母鳳雯.數(shù)據(jù)庫索引技術(shù)概述[J].電腦知識與技術(shù),2017,13(25):9-11,13.
[12] 王麗娟,靳繼紅.基于MySQL的查詢優(yōu)化技術(shù)研究[J].電腦知識與技術(shù),2017,13(30):35-36.
[13] 劉建宏.MySQL數(shù)據(jù)庫優(yōu)化與集群[J].數(shù)字通信世界,2017(7):47.
[14] 韋美雁,段華斌,周新林.大數(shù)據(jù)環(huán)境下的MySQL優(yōu)化技術(shù)探討[J].現(xiàn)代計算機(專業(yè)版),2018(30):68-72.
【通聯(lián)編輯:謝媛媛】