趙 凱
(中國(guó)人民大學(xué) 信息學(xué)院,北京 100872)
隨著互聯(lián)網(wǎng)應(yīng)用軟件的發(fā)展,具有迭代周期短、靈活性高、擴(kuò)展容易等特點(diǎn)的微服務(wù)架構(gòu)成為當(dāng)下最流行的軟件架構(gòu)方案。微服務(wù)架構(gòu)由面向服務(wù)的架構(gòu)(Service-Oriented Architecture,SOA)演化而來(lái),解決了SOA架構(gòu)笨重、靈活性差的缺點(diǎn),幾乎成為當(dāng)前互聯(lián)網(wǎng)企業(yè)建設(shè)各類Web服務(wù)的事實(shí)標(biāo)準(zhǔn)。
互聯(lián)網(wǎng)應(yīng)用往往面對(duì)海量用戶,后臺(tái)的各個(gè)微服務(wù)模塊需要部署在服務(wù)器或容器集群中,根據(jù)用戶訪問(wèn)壓力進(jìn)行適應(yīng)性的調(diào)整,以上場(chǎng)景對(duì)建立一個(gè)高效、易用的負(fù)載均衡服務(wù)提出迫切的需求,本研究將介紹一種基于Nginx反向代理機(jī)制的負(fù)載均衡方法。
微服務(wù)架構(gòu)從SOA演化而來(lái)[1],借助輕量的Http協(xié)議與數(shù)據(jù)格式,克服了SOA架構(gòu)笨重、改造成本高的缺點(diǎn),減少了落地實(shí)際業(yè)務(wù)所面臨的技術(shù)成本。微服務(wù)架構(gòu)良好地滿足了現(xiàn)代互聯(lián)網(wǎng)應(yīng)用迭代快、成本低、可伸縮等方面的需求,得到了來(lái)自企業(yè)和社區(qū)的大力支持,相關(guān)的概念和技術(shù)框架也得到了進(jìn)一步發(fā)展。
微服務(wù)架構(gòu)的核心在于“微”,是相對(duì)于將所有代碼打包到一起的單體應(yīng)用架構(gòu)而言的。構(gòu)建微服務(wù)的核心是要做到代碼的“單一職責(zé)”,具體而言,就是按照業(yè)務(wù)對(duì)后臺(tái)服務(wù)進(jìn)行組件化的拆分,一個(gè)服務(wù)中除了與該服務(wù)相關(guān)的邏輯不包含其他無(wú)關(guān)代碼。服務(wù)運(yùn)行在不同的進(jìn)程中,通過(guò)統(tǒng)一資源定位系統(tǒng)(Uniform Resource Locator,URL)進(jìn)行調(diào)用,實(shí)現(xiàn)業(yè)務(wù)的解耦。在服務(wù)模塊進(jìn)行升級(jí)維護(hù)時(shí),只需更新、重啟指定服務(wù),而不必重啟整個(gè)應(yīng)用,提升了維護(hù)效率與業(yè)務(wù)健壯性。
由于微服務(wù)強(qiáng)調(diào)“微”,需要拆分眾多服務(wù)模塊,有服務(wù)治理的需求,否則可能出現(xiàn)在不同的服務(wù)中充斥著雜亂的URL調(diào)用的局面,埋下更大的業(yè)務(wù)隱患。
服務(wù)治理的3個(gè)核心概念是服務(wù)網(wǎng)關(guān)、服務(wù)注冊(cè)、負(fù)載均衡。服務(wù)網(wǎng)關(guān)抽象了微服務(wù)的公共功能,統(tǒng)一接入用戶請(qǐng)求,并提供授權(quán)、路由、限流、監(jiān)控、路由、日志、協(xié)議轉(zhuǎn)換等功能[2];服務(wù)注冊(cè)提供一種機(jī)制,使得微服務(wù)能將自身的URL、名稱共享到一個(gè)公享庫(kù)中;負(fù)載均衡負(fù)責(zé)將用戶請(qǐng)求按照一定策略代理到各個(gè)活躍的服務(wù)實(shí)例上,是確保微服務(wù)可伸縮、高可用、高效率的關(guān)鍵機(jī)制。
Nginx是一個(gè)高性能的HTTP和反向代理Web服務(wù)器,由俄羅斯的伊戈?duì)枴べ愃饕蜷_(kāi)發(fā),第一個(gè)公開(kāi)版本0.1.0發(fā)布于2004年10月4日。Nginx采用事件驅(qū)動(dòng)的多進(jìn)程架構(gòu)、異步網(wǎng)絡(luò)輸入輸出(Input-Output,IO)機(jī)制以及極少的進(jìn)程間切換設(shè)計(jì),能夠同時(shí)支持百萬(wàn)級(jí)別的網(wǎng)絡(luò)連接[3]。得益于Nginx采用的多進(jìn)程架構(gòu),Nginx管理進(jìn)程可以在負(fù)責(zé)處理網(wǎng)絡(luò)請(qǐng)求的工作進(jìn)程異常退出后重新啟動(dòng)新的進(jìn)程,從而提高Web服務(wù)器的穩(wěn)定性。除此之外,主從架構(gòu)結(jié)合IO多路復(fù)用的事件機(jī)制消除了以Apache和Tomcat為代表的進(jìn)程模型與線程模型所帶來(lái)的進(jìn)程創(chuàng)建、銷毀以及線程創(chuàng)建、切換和銷毀等較重的操作,極大地提升了網(wǎng)絡(luò)IO處理能力。
Nginx提供了upstream模塊,用于提供反向代理服務(wù)。在接收到客戶端請(qǐng)求時(shí),Nginx可以不直接產(chǎn)生響應(yīng),而是在緩存客戶端請(qǐng)求的基礎(chǔ)上從upstream模塊所配置的后端服務(wù)中挑選一個(gè)發(fā)送客戶端請(qǐng)求,后端服務(wù)的響應(yīng)直接回復(fù)給Nginx,Nginx在接收的同時(shí)也將響應(yīng)數(shù)據(jù)發(fā)送到緩存的客戶端連接上。upstream模塊是借助Nginx實(shí)現(xiàn)負(fù)載均衡的核心,在選擇后端服務(wù)時(shí),upstream模塊支持5類算法,分別是輪詢及加權(quán)輪詢、網(wǎng)際互聯(lián)協(xié)議(Internet Protocol,IP)散列算法、URL散列算法、最少連接數(shù)法、最短響應(yīng)時(shí)間法。
基于Nginx反向代理機(jī)制的微服務(wù)負(fù)載均衡技術(shù)主要內(nèi)容包括:服務(wù)注冊(cè)、消息隊(duì)列、upstream配置動(dòng)態(tài)管理和心跳。
(1)服務(wù)注冊(cè),是實(shí)現(xiàn)微服務(wù)架構(gòu)的一個(gè)重要基礎(chǔ),負(fù)責(zé)記錄、更新微服務(wù)組件的具體訪問(wèn)IP、端口、權(quán)重和其他必須內(nèi)容,配合服務(wù)網(wǎng)關(guān)實(shí)現(xiàn)后端服務(wù)組件的路由、負(fù)載均衡、限流等功能。服務(wù)注冊(cè)中心需要兩個(gè)基本模塊,一個(gè)是用作存儲(chǔ)、共享服務(wù)組件信息的MySQL數(shù)據(jù)庫(kù);另一個(gè)是負(fù)責(zé)接收服務(wù)組件心跳包,并更新數(shù)據(jù)庫(kù)的心跳監(jiān)聽(tīng)模塊。分布在不同設(shè)備進(jìn)程中的服務(wù)實(shí)例通過(guò)心跳機(jī)制將自身的IP、端口、URL、負(fù)載、資源等情況以心跳包的形式發(fā)布到消息隊(duì)列中,心跳監(jiān)聽(tīng)模塊從消息隊(duì)列獲取心跳并根據(jù)心跳包中服務(wù)ID,IP、端口、負(fù)載等信息新增一項(xiàng)紀(jì)錄或更新已有服務(wù)紀(jì)錄的心跳時(shí)間、可用狀態(tài)、服務(wù)負(fù)載等信息。
(2)消息隊(duì)列,是一個(gè)共享的數(shù)據(jù)通道,用于傳遞服務(wù)組件的心跳包、服務(wù)組件變化通知,實(shí)現(xiàn)各個(gè)功能模塊的相互協(xié)作,降低模塊耦合性。消息隊(duì)列使用Kafka提供,Kafka通過(guò)發(fā)布/訂閱模式可以提供可靠、快速、分布式的消息隊(duì)列服務(wù),最新的Kafka提供了流處理模塊,使用Kafka提供的Stream API可以不引入額外的流計(jì)算框架的情況下實(shí)現(xiàn)對(duì)消息的實(shí)時(shí)處理。在這里,需要兩個(gè)消息隊(duì)列(Kafka中使用topic概念):topic_heartbeat作為心跳包傳輸?shù)年?duì)列,topic_upstream_conf作為upstream配置項(xiàng)傳輸?shù)年?duì)列。
(3)upstream配置動(dòng)態(tài)管理,主要是根據(jù)注冊(cè)中心服務(wù)組件的狀態(tài)信息,自動(dòng)剔除失效服務(wù)節(jié)點(diǎn)、增加新注冊(cè)服務(wù)節(jié)點(diǎn)和更新各服務(wù)實(shí)例的權(quán)重,并將更新后的配置重載進(jìn)入Nginx進(jìn)程,自動(dòng)化地依據(jù)服務(wù)注冊(cè)信息及時(shí)調(diào)節(jié)整體服務(wù)組件負(fù)載均衡配置。在這里,需要兩個(gè)基本功能模塊:一個(gè)負(fù)責(zé)定時(shí)輪詢注冊(cè)中心數(shù)據(jù)庫(kù),根據(jù)各服務(wù)組件的最后心跳時(shí)間來(lái)篩選出活躍的服務(wù)組件記錄,對(duì)超時(shí)未進(jìn)行心跳上報(bào)的服務(wù)記錄做標(biāo)注。在確認(rèn)有服務(wù)注冊(cè)記錄發(fā)生更改后,根據(jù)最新注冊(cè)信息生成upstream配置文件,并將配置文件內(nèi)容發(fā)送到topic_upstream_conf消息隊(duì)列中。另一個(gè)是與Nginx服務(wù)器部署在同節(jié)點(diǎn)的topic_upstream_conf隊(duì)列消息處理程序,在收到最新的配置內(nèi)容后,覆蓋本機(jī)提前使用Nginx自帶的include命令包含在主配置文件nginx.conf中的upstream配置文件upstream.conf,并調(diào)用nginx -s reload命名,讓最新的配置生效。
(4)心跳,是一種探測(cè)服務(wù)組件存活狀態(tài)的機(jī)制。要求服務(wù)組件按照心跳包的數(shù)據(jù)格式每10 s發(fā)送一次心跳數(shù)據(jù)到topic_upstream_conf實(shí)現(xiàn),最后一次心跳時(shí)間至今超過(guò)30 s的認(rèn)定為失效服務(wù)。心跳至少需要提供發(fā)送時(shí)間、服務(wù)ID、服務(wù)URL、部署IP、端口,負(fù)載情況與資源情況等內(nèi)容可以根據(jù)需要進(jìn)行增補(bǔ),可以配合upstream的負(fù)載均衡算法實(shí)現(xiàn)更細(xì)致的負(fù)載均衡控制。
上述各項(xiàng)技術(shù)都是非常成熟、性能穩(wěn)定、被廣泛應(yīng)用在互聯(lián)網(wǎng)一線業(yè)務(wù)場(chǎng)景中的技術(shù)或解決方案,具有技術(shù)復(fù)雜性低、改造成本低、與編程語(yǔ)言和平臺(tái)無(wú)關(guān)的優(yōu)點(diǎn),既適合基于Docker的容器化服務(wù)集群,又適合基于內(nèi)核虛擬機(jī)(Kernel Virtual Machine,KVM)技術(shù)的虛擬化服務(wù)集群,適應(yīng)場(chǎng)景范圍較廣。
文章對(duì)微服務(wù)架構(gòu)的起源、特點(diǎn)和核心概念進(jìn)行了說(shuō)明,對(duì)高性能Web服務(wù)器Nginx及其反向代理機(jī)制進(jìn)行了介紹,在此基礎(chǔ)上,利用非常成熟的MySQL技術(shù)、Kafka技術(shù)、心跳機(jī)制設(shè)計(jì)了一個(gè)適用于基于Docker的容器化服務(wù)集群和基于KVM技術(shù)的虛擬化服務(wù)集群的負(fù)載均衡方案,并對(duì)其中關(guān)鍵的技術(shù)角色和信息進(jìn)行了較為詳細(xì)的說(shuō)明。該技術(shù)具有易用性高、技術(shù)改造少、平臺(tái)無(wú)關(guān)的特點(diǎn),可以作為當(dāng)前開(kāi)源社區(qū)發(fā)布的各類微服務(wù)框架的補(bǔ)充,希望能為從事微服務(wù)應(yīng)用研發(fā)的讀者提供更多選擇。