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