偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

攜程定制化路由代理網(wǎng)關(guān)實(shí)現(xiàn)

開(kāi)發(fā)
本文主要介紹攜程軟負(fù)載產(chǎn)品,在業(yè)務(wù)增長(zhǎng)及路由需求日漸復(fù)雜的背景下,如何從傳統(tǒng)Nginx反向代理逐漸發(fā)展成支持多元化路由的網(wǎng)關(guān)產(chǎn)品。以及其中利用的開(kāi)源框架OpenResty的主要功能,和我們?cè)诼酚赊D(zhuǎn)發(fā)場(chǎng)景的落地實(shí)踐及探索。

一、背景

攜程軟負(fù)載產(chǎn)品(SLB)基于Nginx實(shí)現(xiàn),為攜程幾乎所有HTTP請(qǐng)求流量提供負(fù)載均衡服務(wù),目前每天處理千億次請(qǐng)求。最開(kāi)始時(shí),SLB的主要職責(zé)是管理業(yè)務(wù)的HTTP路由和實(shí)現(xiàn)反向代理,取代更傳統(tǒng)的硬件負(fù)載為業(yè)務(wù)集群提供應(yīng)用層負(fù)載均衡。

近幾年,隨著業(yè)務(wù)增長(zhǎng),以及多機(jī)房容災(zāi)、混合云部署等背景,逐漸衍生出了多機(jī)房容災(zāi),跨區(qū)域流量調(diào)度等定制化需求,一個(gè)請(qǐng)求需要基于不同條件在機(jī)房間轉(zhuǎn)發(fā)。傳統(tǒng)的反向代理功能已經(jīng)無(wú)法滿足業(yè)務(wù)需求,如何在現(xiàn)有Nginx技術(shù)棧上支持越來(lái)越多的定制化路由需求,管理路由配置,并快速迭代功能成為了我們面臨的問(wèn)題。

二、流量鏈路

SLB需要處理攜程內(nèi)網(wǎng)和外網(wǎng)所有的HTTP流量,SLB為業(yè)務(wù)應(yīng)用提供HTTP層負(fù)載均衡能力,管理維護(hù)所有域名訪問(wèn)入口和業(yè)務(wù)應(yīng)用集群的關(guān)聯(lián)關(guān)系。在早期,公司整體的流量模式比較單一,SLB的職責(zé)也較為單一,主要作為HTTP等協(xié)議的反向代理。舉一個(gè)最簡(jiǎn)單的Nginx樣例配置,我們將foo.bar.com/hello的請(qǐng)求轉(zhuǎn)發(fā)到后端一個(gè)三臺(tái)機(jī)器組成的固定集群上,這也是早期SLB大量配置的模式,將HTTP請(qǐng)求轉(zhuǎn)發(fā)到固定的某組機(jī)器。

圖片

server {
  listen 80;
  server_name foo.bar.com


  location ~* ^/hello {
    proxy_pass http://backend_499;
  }
}

upsstream backend_499 {
  server 10.10.10.1:80 weight=5 max_fails=0 fail_timeout=30;
  server 10.10.10.2:80 weight=5 max_fails=0 fail_timeout=30;
  server 10.10.10.3:80 weight=5 max_fails=0 fail_timeout=30;
}

后來(lái)隨著公司業(yè)務(wù)的增長(zhǎng)以及對(duì)可用性更高的要求,有了混合云部署、異地容災(zāi)等場(chǎng)景后,公司業(yè)務(wù)的流量鏈路也更加復(fù)雜,業(yè)務(wù)也提出了很多定制化場(chǎng)景。

2.1 多機(jī)房容災(zāi)

攜程各業(yè)務(wù)線需要在私有云,公有云的多個(gè)機(jī)房部署,日常情況由各個(gè)機(jī)房部署的機(jī)器共同分擔(dān)處理業(yè)務(wù)流量。如果有機(jī)房大面積故障,需要從路由摘除整個(gè)故障機(jī)房,使外部流量導(dǎo)向正常機(jī)房。另外當(dāng)流量高峰時(shí),支持將高峰流量向容量相對(duì)更多的公有云機(jī)房泄洪。容災(zāi)是業(yè)務(wù)高可用的重要保障,需要SLB在全局、應(yīng)用和服務(wù)層面,有機(jī)房間流量動(dòng)態(tài)分配切換的能力。

圖片

2.2 多元化需求

不同業(yè)務(wù)和場(chǎng)景往往關(guān)心請(qǐng)求中不同的維度和數(shù)據(jù),比如有些場(chǎng)景往往希望同一個(gè)用戶的請(qǐng)求鏈路能夠保持一致,實(shí)現(xiàn)set化的場(chǎng)景,而另一些場(chǎng)景可能更關(guān)心如何分流給不同的后端應(yīng)用和不同的機(jī)房。功能上除了流量調(diào)度,也有請(qǐng)求標(biāo)記,請(qǐng)求響應(yīng)數(shù)據(jù)采集等需求。我們希望能有一個(gè)通用的方案來(lái)實(shí)現(xiàn)這些定制化的需求。

上述復(fù)雜場(chǎng)景和需求,顯然是無(wú)法通過(guò)樸素的反向代理模式和Nginx靜態(tài)配置實(shí)現(xiàn)的,這些需求推動(dòng)SLB向集成API網(wǎng)關(guān)功能的產(chǎn)品前進(jìn)。

三、面臨的問(wèn)題

在SLB著手實(shí)現(xiàn)和落地這些需求的過(guò)程中,我們碰到了一些困難和痛點(diǎn),總結(jié)下來(lái)有這幾方面。

3.1 路由能力

Nginx原生API提供的路由和請(qǐng)求處理能力都比較有限,像一些比較復(fù)雜的條件路由,即需要根據(jù)運(yùn)行時(shí)的情況動(dòng)態(tài)選擇路由目標(biāo)或?qū)φ?qǐng)求做一些處理,Nginx很難以優(yōu)雅的方式支持。

3.2 動(dòng)態(tài)更新

Nginx的配置更新需要一次reload操作,reload操作過(guò)程中master進(jìn)程會(huì)用新配置fork出新的worker進(jìn)程,這是一個(gè)非常耗資源的操作。Nginx和客戶端服務(wù)端的連接都需要重建,進(jìn)程創(chuàng)建和加載配置本身也需要消耗資源,并且對(duì)于一些高頻請(qǐng)求的業(yè)務(wù),reload會(huì)導(dǎo)致有請(qǐng)求失敗的情況。而在實(shí)際場(chǎng)景里,配置變更又是一個(gè)高頻操作,業(yè)務(wù)的一次灰度切流就需要好幾次有損變更,我們需要尋求一種沒(méi)有reload的變更生效方式。

dyups也是一種常見(jiàn)的動(dòng)態(tài)更新方式,我們也通過(guò)這種方式來(lái)動(dòng)態(tài)更新upstream。但實(shí)踐過(guò)程中我們發(fā)現(xiàn),大量dyups實(shí)際也會(huì)阻塞Nginx進(jìn)程,我們需要更優(yōu)雅的方式。

3.3 集群管理

SLB在部署上,需要涵蓋并對(duì)齊公司所有網(wǎng)絡(luò)環(huán)境和機(jī)房,線上目前有上百套集群,我們的一些版本迭代需要消耗非常大的人力去做發(fā)布、版本對(duì)齊和兼容等工作。實(shí)際部署上,不同集群的職責(zé)也有差異,我們希望這些功能切面的升級(jí)更新可以獨(dú)立升級(jí)、動(dòng)態(tài)生效。另外,每次路由邏輯的更新,路由的切換,需要能以灰度的方式進(jìn)行,避免帶來(lái)災(zāi)難性后果。

3.4 Nginx Lua

某種程度上,為了進(jìn)一步拓展SLB的路由功能,我們引入了OpenResty的Nginx Lua模塊來(lái)嘗試解決這個(gè)問(wèn)題。OpenResty開(kāi)源的Nginx Lua模塊為Nginx嵌入了LuaJIT,提供了豐富的指令和API,包括但不限于:

1)讀寫(xiě)請(qǐng)求(header, url, body),實(shí)現(xiàn)一些請(qǐng)求標(biāo)記,rewrite等功能

2)請(qǐng)求轉(zhuǎn)發(fā),實(shí)現(xiàn)自定義的路由邏輯,不再局限于固定的upstream和server

3)共享內(nèi)存,Nginx進(jìn)程間共享數(shù)據(jù)

4)網(wǎng)絡(luò)編程,實(shí)現(xiàn)一些旁路請(qǐng)求

我們通過(guò)Lua腳本在Nginx處理請(qǐng)求的各種階段,執(zhí)行自定義的腳本,實(shí)現(xiàn)不同的功能。涵蓋了nginx初始化、請(qǐng)求處理、請(qǐng)求轉(zhuǎn)發(fā)、響應(yīng)和日志等非常完整的請(qǐng)求和響應(yīng)流程,并且在很多公司都有實(shí)際應(yīng)用。

圖片

在SLB早期方案中我們使用Nginx Lua實(shí)現(xiàn)一些相對(duì)固定的邏輯如集群間流量灰度。業(yè)務(wù)可以配置某個(gè)路徑的請(qǐng)求在新老集群間的流量比例,或指定某個(gè)集群路由,舉個(gè)例子:

server {
     location /foo/bar {
         content_by_lua_block {
             # 取隨機(jī)數(shù)
             local r = math.random()
     if (ngx.var.flag == "group_1" or ngx.var.flag == "group_2" ) then
         ngx.exec("@" .. ngx.var.flag)     # 指定訪問(wèn)某個(gè)集群
     elseif (r >= 0.00 and r < 0.20) then  # 一定比例到一個(gè)集群
         ngx.exec("@group_1")
     elseif (r >= 0.20 and r <= 1.00) then # 一定比例到另一個(gè)集群
         ngx.exec("@group_2")
     end
         }
     }


     location @group_1 {
         content_by_lua_block {
             ngx.say("I am group_1")
         }
     }


     location @group_2 {
         content_by_lua_block {
             ngx.say("I am group_2")
         }
     }
 }

Nginx Lua一定程度上解決了傳統(tǒng)反向代理路由能力的問(wèn)題,但在動(dòng)態(tài)更新上仍然存在問(wèn)題:變更仍然需要reload生效,一次業(yè)務(wù)灰度從0到100需要經(jīng)歷多次reload。

四、解決方案

4.1 核心:邏輯和數(shù)據(jù)

一個(gè)較為理想的方案來(lái)解決傳統(tǒng)路由動(dòng)態(tài)更新所需的reload和它帶來(lái)的開(kāi)銷問(wèn)題:在Nginx中將數(shù)據(jù)和邏輯進(jìn)行隔離。比如我們可以直接在Nginx配置中引用一個(gè)Lua文件,由Lua文件提供一個(gè)固定的方法入口,讀取內(nèi)存中的數(shù)據(jù)進(jìn)行計(jì)算和轉(zhuǎn)發(fā)。通過(guò)這種方式,流量調(diào)度邏輯是相對(duì)固定的,動(dòng)態(tài)和高頻變更的部分在數(shù)據(jù)模型,這樣我們就能避免reload,業(yè)務(wù)就可以進(jìn)行高頻操作和修改。

server {
     location /foo/bar {
         content_by_lua_block {
             local foo = require("foo.lua")     # lua 庫(kù)
             local destination = foo.bar(data)  # 根據(jù)數(shù)據(jù)模型執(zhí)行
             ngx.exec(destination)              # 轉(zhuǎn)發(fā)
         }
     }


     location @somewhere {
         server xxxx;
     }
 }




 -- foo.lua
 function bar(data)
   return some_func(data)
 end

內(nèi)存數(shù)據(jù)可以是基于不同路由場(chǎng)景自定義的數(shù)據(jù)結(jié)構(gòu),來(lái)描述期望的配置、關(guān)聯(lián)關(guān)系、路由目標(biāo)等。比如上述的集群間流量灰度,如果要實(shí)現(xiàn)流量根據(jù)不同比例轉(zhuǎn)發(fā)到兩個(gè)集群,這個(gè)結(jié)構(gòu)可以類似于:

{
  "groups": [
    "group_1": {"weight": 20},
    "group_2": {"weight": 80}
  ]
}

類似的,如果要實(shí)現(xiàn)根據(jù)請(qǐng)求不同條件轉(zhuǎn)發(fā):

{
  "groups": [
    "group_1": {"header": "foo"},
    "group_2": {"header": "bar"}
  ]
}

對(duì)于每個(gè)流量調(diào)度場(chǎng)景,我們只要定義流量調(diào)度邏輯和相應(yīng)的數(shù)據(jù)模型,就能比較方便的實(shí)現(xiàn)我們需要的功能。

4.2 整體架構(gòu)

圖片

方案整體上分為三個(gè)職責(zé)不同的模塊:

1)API模塊:作為控制面集群的核心組件,API模塊基于Java開(kāi)發(fā),它負(fù)責(zé)管理Lua文件和數(shù)據(jù)模型的生命周期。這包括對(duì)Lua文件和數(shù)據(jù)模型的創(chuàng)建、更新、刪除和持久化等操作,支持灰度下發(fā)。此外,API模塊還負(fù)責(zé)集群配置的管理,包括節(jié)點(diǎn)的注冊(cè)和發(fā)現(xiàn)、路由配置等。

2)Agent模塊:Agent模塊是連接控制面和數(shù)據(jù)面的橋梁,承擔(dān)著數(shù)據(jù)的加工和傳遞的任務(wù)。它負(fù)責(zé)將控制面下發(fā)的Lua文件和數(shù)據(jù)模型持久化到本地存儲(chǔ),以便在數(shù)據(jù)面進(jìn)行實(shí)時(shí)的路由計(jì)算和流量處理。Agent模塊還負(fù)責(zé)與管理層的API模塊進(jìn)行通信,下發(fā)最新的Lua腳本文件和數(shù)據(jù)模型的更新,并將其應(yīng)用到本地存儲(chǔ)中,以確保數(shù)據(jù)面能夠及時(shí)獲取最新的路由規(guī)則。

3)Nginx & Lua模塊:作為數(shù)據(jù)面集群的核心組件,Nginx & Lua模塊承擔(dān)著實(shí)際的請(qǐng)求處理和路由邏輯的執(zhí)行。Nginx Lua提供了靈活的編程能力,使得我們可以根據(jù)業(yè)務(wù)需求定制化地處理請(qǐng)求和路由流量。Lua腳本可以訪問(wèn)實(shí)時(shí)更新的數(shù)據(jù)模型,根據(jù)其中的信息進(jìn)行動(dòng)態(tài)的路由計(jì)算,并將請(qǐng)求轉(zhuǎn)發(fā)到預(yù)期的目標(biāo)。這種動(dòng)態(tài)路由的能力使得系統(tǒng)能夠根據(jù)實(shí)時(shí)的業(yè)務(wù)需求和環(huán)境變化來(lái)靈活地調(diào)整流量分配。

4.3 數(shù)據(jù)模型生命周期

在方案實(shí)踐中比較重要且復(fù)雜的地方是路由邏輯依賴的數(shù)據(jù)模型如何更新和生效。我們采用類似于Nginx配置文件的工作和生效方式,把數(shù)據(jù)模型存儲(chǔ)在磁盤,而不同之處在于我們旁路將數(shù)據(jù)模型從磁盤讀取到內(nèi)存,運(yùn)行時(shí)從內(nèi)存讀取模型,這樣就不再依賴reload生效。

具體來(lái)說(shuō),Nginx是一個(gè)多進(jìn)程的應(yīng)用,會(huì)存在多個(gè)worker進(jìn)程處理請(qǐng)求,進(jìn)程間天然存在內(nèi)存隔離。在worker的生命周期里,在每個(gè)worker初始化時(shí)先加載數(shù)據(jù)到內(nèi)存,運(yùn)行時(shí)動(dòng)態(tài)同步更新內(nèi)存數(shù)據(jù)。為了把更新推送到每個(gè)worker進(jìn)程,我們基于Nginx Lua提供的共享內(nèi)存功能,在共享內(nèi)存中緩存每個(gè)數(shù)據(jù)模型的最新版本,而worker進(jìn)程通過(guò)一個(gè)timer來(lái)不斷輪詢共享內(nèi)存,發(fā)現(xiàn)版本有更新后從磁盤讀取數(shù)據(jù)模型,加載到內(nèi)存,對(duì)于每個(gè)場(chǎng)景可以在Lua中自定義具體的數(shù)據(jù)加載邏輯。

圖片

相比于worker直接或旁路輪詢數(shù)據(jù)接口,共享內(nèi)存最小化了請(qǐng)求和解析數(shù)據(jù)對(duì)運(yùn)行時(shí)的影響。另外Agent把每個(gè)數(shù)據(jù)模型都持久化到磁盤解決了進(jìn)程重啟時(shí)內(nèi)存數(shù)據(jù)丟失的問(wèn)題,worker進(jìn)程可以在初始化時(shí)主動(dòng)從磁盤重新讀取數(shù)據(jù)。這樣即使我們的Nginx由于一些意外重啟或者退出(發(fā)布,OOM,機(jī)器重啟等),至少還能以磁盤上持久化的數(shù)據(jù)繼續(xù)工作,并且不依賴其他組件(API、Agent)的存活。

4.4 實(shí)踐和落地情況

在實(shí)踐中我們注意到,Lua或者說(shuō)數(shù)據(jù)面應(yīng)用的處理邏輯應(yīng)盡可能簡(jiǎn)單,但對(duì)于運(yùn)維和開(kāi)發(fā)同學(xué)來(lái)說(shuō),一般都是希望有全局視角的數(shù)據(jù)來(lái)掌控全局。

所以在數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)上,我們一般會(huì)進(jìn)行拆分:API和運(yùn)維人員及其他系統(tǒng)的交互通常采用全局?jǐn)?shù)據(jù),會(huì)有多個(gè)層級(jí)。而在和Agent中間層交互時(shí)主動(dòng)加工數(shù)據(jù)模型,去掉運(yùn)行時(shí)不需要的部分,如其他集群的配置,被關(guān)閉的配置等;到了真正處理請(qǐng)求的數(shù)據(jù)面,往往我們只希望從一個(gè)扁平化的數(shù)據(jù)模型以類似key-value的形式讀取。比方說(shuō)一個(gè)應(yīng)用在多數(shù)據(jù)中心的流量分配,在全局視角來(lái)看類似于:

{
  "app_1": {
    "idc_1": {"target": "group1"},
    "idc_2": {"target": "group2"},
    "idc_3": {"target": "group3"}
  }
}

對(duì)于某個(gè)IDC集群的數(shù)據(jù)面來(lái)說(shuō),Lua中讀取的理想形式是盡可能平面化的Table:

{
  "app_1": "group1"
}

避免了運(yùn)行時(shí)Lua做過(guò)多的數(shù)據(jù)解析邏輯,是較為合理的職責(zé)分配方式。

目前我們通過(guò)該方案實(shí)現(xiàn)了應(yīng)用和服務(wù)粒度的流量分配,使得業(yè)務(wù)應(yīng)用能夠在多個(gè)數(shù)據(jù)中心提供服務(wù)。同時(shí),該方案還提供了全局及應(yīng)用粒度的故障降級(jí)功能,以增強(qiáng)業(yè)務(wù)的可用性,經(jīng)過(guò)多次機(jī)房故障演練驗(yàn)證,切換可以在秒級(jí)生效。除了實(shí)現(xiàn)復(fù)雜的請(qǐng)求路由功能之外,我們通過(guò)Lua也落地了請(qǐng)求響應(yīng)數(shù)據(jù)采集,不同渠道流量標(biāo)記等旁路功能。

五、結(jié)語(yǔ)

流量鏈路隨著公司技術(shù)和業(yè)務(wù)的拓展,走向多元、動(dòng)態(tài)和定制化的發(fā)展方向,不斷對(duì)負(fù)載均衡和網(wǎng)關(guān)產(chǎn)品提出新的場(chǎng)景和需求。定制化路由解決方案解決了傳統(tǒng)反向代理在路由能力和動(dòng)態(tài)更新上的問(wèn)題,降低了大規(guī)模集群部署下的研發(fā)和迭代成本,幫助SLB產(chǎn)品從傳統(tǒng)的反向代理中間件向綜合性的API網(wǎng)關(guān)逐漸靠攏。方案對(duì)不同場(chǎng)景有良好的擴(kuò)展性和可靠性,未來(lái)也會(huì)有更多的流量調(diào)度模式通過(guò)統(tǒng)一方案快速落地交付。

在產(chǎn)品技術(shù)棧上,不同的編程語(yǔ)言和技術(shù)各有所長(zhǎng),我們希望能使不同技術(shù)達(dá)成優(yōu)勢(shì)互補(bǔ),像Lua的動(dòng)態(tài),Nginx的性能。需要我們持續(xù)在這些技術(shù)上不斷學(xué)習(xí)和投入,加深我們對(duì)產(chǎn)品技術(shù)棧的理解,揚(yáng)長(zhǎng)避短。

在未來(lái),如何更好的利用現(xiàn)有技術(shù)棧,方便Java開(kāi)發(fā)的同學(xué)能快速上手Lua開(kāi)發(fā),如何優(yōu)化Lua責(zé)任鏈和異常處理,優(yōu)化Lua的內(nèi)存管理,還有進(jìn)一步努力和探索的空間。

責(zé)任編輯:張燕妮 來(lái)源: 攜程技術(shù)
相關(guān)推薦

2014-12-25 17:51:07

2023-08-18 10:49:14

開(kāi)發(fā)攜程

2023-08-25 09:51:21

前端開(kāi)發(fā)

2025-01-03 14:33:41

2013-06-27 14:32:13

華為網(wǎng)絡(luò)虛擬化虛擬化Hyper-V

2022-07-15 12:58:02

鴻蒙攜程華為

2022-05-13 09:27:55

Widget機(jī)票業(yè)務(wù)App

2024-05-23 17:14:49

2021-11-24 08:55:38

代理網(wǎng)關(guān)Netty

2021-08-20 11:00:04

Redis攜程數(shù)據(jù)庫(kù)

2017-04-11 15:11:52

ABtestABT變量法

2022-10-21 10:40:08

攜程酒店MySQL慢查詢

2015-05-29 13:59:53

2024-11-05 09:56:30

2023-02-08 16:34:05

數(shù)據(jù)庫(kù)工具

2022-08-12 08:34:32

攜程數(shù)據(jù)庫(kù)上云

2022-07-08 09:38:27

攜程酒店Flutter技術(shù)跨平臺(tái)整合

2022-07-15 09:20:17

性能優(yōu)化方案

2013-08-12 16:58:12

博科太網(wǎng)矩陣虛擬化

2024-01-12 09:31:08

Java代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)