Zuul 介紹

Zuul是Netflix提供一個(gè)網(wǎng)管服務(wù)。

Zuul是如何工作

Zuul是一些連續(xù)filter的集合。Zuul filter中核心概念:

  • Type: 定義過濾器被應(yīng)用的階段
  • Execution Order:在同一個(gè)Type中,過濾器執(zhí)行的順序
  • Criteria: 過濾器被執(zhí)行必須滿足的條件
  • Action:條件滿足咳燕,過濾器中將要執(zhí)行的動(dòng)作

Zuul會(huì)動(dòng)態(tài)讀取冷离、編譯上遥、執(zhí)行這些filters。
Filter之間不會(huì)直接交流溃肪,他們直接會(huì)通過RequestContext共享狀態(tài)(線程安全)免胃。

Filters是使用groovy寫的,這些filter都是放在指定的目錄下乍惊。

Zuule 結(jié)構(gòu)主要包含三個(gè)部分:1.Filter管理(上傳杜秸、激活、存儲(chǔ));2.Filter加載(將變更的filter加載進(jìn)來)润绎;3.filter運(yùn)行時(shí)撬碟。

Filter類型 解釋 執(zhí)行順序
PRE 在請求被路由到源服務(wù)器前要執(zhí)行的過濾器,例如認(rèn)證莉撇、選路由呢蛤、請求日志 1
ROUTING 處理將請求發(fā)送到源服務(wù)器的過濾器 2
POST 在響應(yīng)從源服務(wù)器返回時(shí)被執(zhí)行的過濾器,例如對(duì)響應(yīng)增加http頭、收集統(tǒng)計(jì)和度量棍郎、將響應(yīng)以流的方式發(fā)送給客戶端 3
ERROR 上述階段出現(xiàn)錯(cuò)誤要執(zhí)行的過濾器 4

正常流程是按照上面順序執(zhí)行的其障,如果發(fā)生錯(cuò)信息,直接跳轉(zhuǎn)到ERROR階段涂佃。
Filter執(zhí)行順序:

1.pre->route->post->over(正常執(zhí)行流程)
2.pre->error->post(錯(cuò)誤流程)
3.pre->route->error->post(錯(cuò)誤流程)
4.pre->route->post->error

路由器過濾器:

1.RibbonRoutingFilter:將url路由到服務(wù)
2.SimpleHostRoutingFilter:將url路由到url地址
3.SendForwardFilter:轉(zhuǎn)發(fā)(轉(zhuǎn)向zuul自己)

網(wǎng)關(guān)獲取地址的的來源:

1.eureka服務(wù),zuul從eureka獲取的服務(wù);
2.從配置文件中獲取

Zuul 2

Zuul2.0就類似一個(gè)Netty Server励翼,執(zhí)行前置filter(入站filter),使用Netty Client代理請求,

執(zhí)行完后置filter(出站filter)返回response辜荠。

Filter

  • 入站filter:在路由到源之前執(zhí)行汽抚,例如:身份驗(yàn)證、路由和修飾請求伯病。
  • 終點(diǎn)filter:可用于返回靜態(tài)響應(yīng)发侵,否則內(nèi)置的ProxyEndpoint過濾器會(huì)將請求路由到源训桶。
  • 出站filter:從源獲取響應(yīng)后執(zhí)行驮履,例如:修飾用戶的響應(yīng)或添加自定義標(biāo)頭苦锨。

Filter分為兩種:同步和異步。在循環(huán)事件中千萬不要使用阻塞药磺。如果想要在異步filter中使用阻塞告组,要在單獨(dú)的線程池上使用,否則使用同步filter与涡。

Zuul2.0在Zuul1.x的基礎(chǔ)上添加了一個(gè)是否使用異步執(zhí)行(是否阻塞)惹谐。

Server Modes

Zuul2.0支持的服務(wù)模式有:HTTP持偏、HTTP2.0(需要tls)、HTTP(手動(dòng)TLS)氨肌。

HTTP

在ELB HTTP監(jiān)聽器之后執(zhí)行鸿秆,該監(jiān)聽器終止TLS并傳遞XFF頭部。

在沒有ELB的情況下怎囚,以純文本的形式運(yùn)行卿叽,出于安全原因,需要做如下處理:

channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);

HTTP 2.0

ELB 不支持HTTP 2.0,如果使用HTTP 2.0恳守,需要使用ELB TCP監(jiān)聽器考婴。

Mutual TLS

ELB也不支持交互TLS,所以催烘,你不得不使用 ELB TCP監(jiān)聽器沥阱,在Zuul里終止使用TLS。在該模式下伊群,你將需要一個(gè) TLS cert和一個(gè)客戶證書的信任的存儲(chǔ)考杉。也需要啟用代理協(xié)議代替XFF頭。

Core Features

Service Discovery

Zuul可以和Eureka無縫結(jié)合舰始,也可以與靜態(tài)服務(wù)器結(jié)合或者使用其他服務(wù)發(fā)現(xiàn)方式崇棠。

與Eureka結(jié)合的配置:

### Load balancing backends with Eureka
eureka.shouldUseDns=true
eureka.eurekaServer.context=discovery/v2
eureka.eurekaServer.domainName=discovery${environment}.netflix.net
eureka.eurekaServer.gzipContent=true
eureka.serviceUrl.default=http://${region}.${eureka.eurekaServer.domainName}:7001/${eureka.eurekaServer.context}
api.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
api.ribbon.DeploymentContextBasedVipAddresses=api-test.netflix.net:7001

需要指定Eureka的地址,Zuul自動(dòng)從Eureka獲取服務(wù)列表丸卷,如果配置靜態(tài)資源枕稀,按照下面的配置:

### Load balancing backends without Eureka
eureka.shouldFetchRegistry=false
api.ribbon.listOfServers=100.66.23.88:7001,100.65.155.22:7001
api.ribbon.client.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList
api.ribbon.DeploymentContextBasedVipAddresses=api-test.netflix.net:7001

服務(wù)列表的類名用ConfigurationBasedServerList替換DiscoveryEnabledNIWSServerList。

Load Balancing

Zuul默認(rèn)使用的基于區(qū)域的負(fù)載均衡谜嫉。該算法是對(duì)可用實(shí)例進(jìn)行輪詢萎坷,并跟蹤可用性區(qū)域以便彈性恢復(fù)。如果某個(gè)區(qū)域失敗節(jié)點(diǎn)達(dá)到一定程度沐兰,就會(huì)丟棄這個(gè)區(qū)域食铐。

用戶使用自定義的負(fù)載均衡器,需要指定NFLoadBalancerClassName屬性僧鲁,重寫DefaultClientChannelManager的getLoadBalancerClass方法。自定義的負(fù)載均衡器繼承DynamicServerListLoadBalancer象泵。

Ribbon允許用戶配置負(fù)載均衡策略:RoundRobinRule寞秃、WeightedResponseTimeRule、AvailabilityFilteringRule偶惠。

連接池

Zuul2.0使用NettyClient來使用自己的連接池春寿。Zuul2.0為每一個(gè)主機(jī)、每個(gè)循環(huán)時(shí)間創(chuàng)建連接池忽孽。這樣可以減少線程之間上下文切換绑改,確保入站事件和出站事件循環(huán)的完整性谢床。

這樣就可以使得整個(gè)請求在同樣的線程內(nèi)運(yùn)行。該策略的一個(gè)副作用:如果運(yùn)行多個(gè)Zuul實(shí)例厘线,每個(gè)實(shí)例有很多事件循環(huán)识腿,到每個(gè)后端服務(wù)的連接會(huì)很多。

### Ribbon Client Config Properties
<originName>.ribbon.ConnectTimeout                   // default: 500 (ms)
<originName>.ribbon.ReadTimeout                      // default: 90000 (ms)
<originName>.ribbon.MaxConnectionsPerHost            // default: 50
<originName>.ribbon.ConnIdleEvictTimeMilliSeconds    // default: 60000 (ms)
<originName>.ribbon.ReceiveBufferSize                // default: 32 * 1024
<originName>.ribbon.SendBufferSize                   // default: 32 * 1024
<originName>.ribbon.UseIPAddrForServer               // default: true
###Zuul Properties
# Max amount of requests any given connection will have before forcing a close
<originName>.netty.client.maxRequestsPerConnection    // default: 1000
# Max amount of connection per server, per event loop
<originName>.netty.client.perServerWaterline          // default: 4

# Netty configuration connection
<originName>.netty.client.TcpKeepAlive                // default: false
<originName>.netty.client.TcpNoDelay                  // default: false
<originName>.netty.client.WriteBufferHighWaterMark    // default: 32 * 1024
<originName>.netty.client.WriteBufferLowWaterMark     // default: 8 * 1024
<originName>.netty.client.AutoRead                    // default: false

Status Categories

狀態(tài)分類 定義
SUCCESS 成功請求
SUCCESS_NOT_FOUND 成功代理但是狀態(tài)為404
SUCCESS_LOCAL_NOTSET 成功請求但是沒有分類
SUCCESS_LOCAL_NO_ROUTE 沒有找到請求的終端點(diǎn)
FAILURE_LOCAL 本地Zuul失敗
FAILURE_LOCAL_THROTTLED_ORIGIN_SERVER_MAXCONN 請求超最大連接限制
FAILURE_LOCAL_THROTTLED_ORIGIN_CONCURRENCY 請求超源的并發(fā)限制
FAILURE_LOCAL_IDLE_TIMEOUT 請求因?yàn)閕dle超時(shí)失敗
FAILURE_CLIENT_CANCELLED 客戶端取消造壮,請求失敗
FAILURE_CLIENT_PIPELINE_REJECT 客戶端試圖發(fā)送管道HTTP請求渡讼,請求失敗
FAILURE_CLIENT_TIMEOUT 來自客戶端的讀超時(shí)
FAILURE_ORIGIN 源返回失敗
FAILURE_ORIGIN_READ_TIMEOUT 請求源超時(shí)
FAILURE_ORIGIN_CONNECTIVITY 連不到源
FAILURE_ORIGIN_THROTTLED 源扼殺了請求
FAILURE_ORIGIN_NO_SERVERS 沒有有效的源的服務(wù)
FAILURE_ORIGIN_RESET_CONNECTION 請求完成前,源復(fù)位了連接

設(shè)置Zuul狀態(tài):

StatusCategoryUtils.setStatusCategory(request.getContext(), ZuulStatusCategory.SUCCESS)

獲取Zuul狀態(tài)

StatusCategoryUtils.getStatusCategory(response)

Retries

重試機(jī)制是Netflix增強(qiáng)彈性的主要功能之一耳璧。下面的邏輯來確定如何重試:

Retry on errors

如果發(fā)生讀超時(shí)成箫,充值連接或者連接錯(cuò)誤

Retry on status codes
  • 如果狀態(tài)碼為503
  • 如果狀態(tài)碼是配置的冪等狀態(tài),方法是:GET、HEAD或者OPTIONS
  • 下列情況不重試:已經(jīng)向客戶端發(fā)送響應(yīng);body不完整旨枯。
# Sets a retry limit for both error and status code retries
<originName>.ribbon.MaxAutoRetriesNextServer            // default: 0
# This is a comma-delimited list of status codes
zuul.retry.allowed.statuses.idempotent                  // default: 500

Request Password

調(diào)試工具蹬昌,它是請求過程中,按時(shí)間排序的狀態(tài)集攀隔,帶nanoseconds時(shí)間戳皂贩。

可以記錄 passport,可以加到頭里竞慢,或者持久化保存先紫。可以使用 channel或者 session context筹煮。

Request Attempt

通常遮精,我們將其添加為每個(gè)響應(yīng)的僅供內(nèi)部使用的標(biāo)頭,這對(duì)于我們和我們的內(nèi)部合作伙伴而言使跟蹤和調(diào)試請求變得更加簡單败潦。

Origin Concurrency Protection

為了保護(hù)源和Zuul本冲,使用并發(fā)限制,防止服務(wù)中斷劫扒。

兩種方法管理源并發(fā):

##Overall Origin Concurrency
zuul.origin.<originName>.concurrency.max.requests        // default: 200
zuul.origin.<originName>.concurrency.protect.enabled     // default: true
##Per Server Concurrency
<originName>.ribbon.MaxConnectionsPerHost     // default: 50

HTTP/2

server.http2.max.concurrent.streams            // default: 100
server.http2.initialwindowsize                 // default: 5242880
server.http2.maxheadertablesize                // default: 65536
server.http2.maxheaderlistsize                 // default: 32768

Proxy Protocol

//strip XFF headers since we can no longer trust them
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);
// prefer proxy protocol when available
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);
// enable proxy protocol
channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, true);
//客戶端IP被正確設(shè)置到過濾器的 HttpRequestMessage檬洞,也可以這樣檢索
String clientIp = channel.attr(SourceAddressChannelHandler.ATTR_SOURCE_ADDRESS).get();

Gzip

Zuul出站GZipResponseFilter,將gzip傳出響應(yīng)沟饥。它根據(jù)內(nèi)容類型添怔,主體大小以及請求的Accept-Encoding標(biāo)頭是否包含gzip做出決定。

Push Messaging

Zuul2.0支持消息推送贤旷,支持Web Socket和SSE广料。

Authentication

Zuul推送服務(wù)器在入站推送連接時(shí),必須要認(rèn)證幼驶。自定義認(rèn)證要繼承PushAuthHandler艾杏,實(shí)現(xiàn)doAuth()抽象類。

Client Registration and Lookup

Zuul推送服務(wù)注冊每個(gè)已鑒權(quán)的連接或者用戶標(biāo)識(shí)盅藻。

每個(gè) Zuul推送服務(wù)使用PushConnectionRegistry 在內(nèi)存里維護(hù)一個(gè)本地的全部已連接的客戶端的注冊信息购桑。

單節(jié)點(diǎn)使用基于內(nèi)存的畅铭,多節(jié)點(diǎn)使用一個(gè)二級(jí)的外部全局?jǐn)?shù)據(jù)源。

查找特定的client步驟:1.在全局的外部存儲(chǔ)里查找客戶端連接的服務(wù)器;2.返回的服務(wù)器里的本地注冊到查找實(shí)際的連接勃蜘。

可以通過集成PushRegistrationHandler類硕噩,重現(xiàn)registerClient()。

Zuul推送使用的數(shù)據(jù)源必須有下面的特征:低讀取延遲元旬、TTL或者自動(dòng)超時(shí)記錄榴徐、分區(qū)、副本匀归。例如:Redis坑资、Cassandra、Amazon DynamoDB穆端。

Load balancers vs WebSockets and SSE

推送連接是持久袱贮、長期存活的。其他的連接体啰,如果一段事件不活躍攒巍,就會(huì)斷開。

集群負(fù)載均衡器:1)HAProxy荒勇、Nginx柒莉、ALB來支持WebSocket代理;2)Load Balance 運(yùn)行在4層沽翔,而不是7層兢孝。

Configuration Properties

Name 描述 默認(rèn)值
zuul.push.registry.ttl.seconds 全局注冊的超時(shí)時(shí)間 1800s
zuul.push.reconnect.dither.seconds 每個(gè)客戶端的最長連接期的隨機(jī)窗口。以后重連的間隔 180s
zuul.push.reconnect.dither.seconds 服務(wù)器等待客戶端關(guān)閉連接的時(shí)間仅偎,超時(shí)在服務(wù)器側(cè)強(qiáng)制關(guān)閉連接 4s

參考文獻(xiàn)

Announcing Zuul: Edge Service in the Cloud
How It Works 2.0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跨蟹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子橘沥,更是在濱河造成了極大的恐慌窗轩,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件座咆,死亡現(xiàn)場離奇詭異痢艺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)介陶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門腹备,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斤蔓,你說我怎么就攤上這事《频海” “怎么了弦牡?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵友驮,是天一觀的道長。 經(jīng)常有香客問我驾锰,道長卸留,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任椭豫,我火速辦了婚禮耻瑟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赏酥。我一直安慰自己喳整,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布裸扶。 她就那樣靜靜地躺著框都,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呵晨。 梳的紋絲不亂的頭發(fā)上魏保,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音摸屠,去河邊找鬼谓罗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛季二,可吹牛的內(nèi)容都是我干的檩咱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼戒傻,長吁一口氣:“原來是場噩夢啊……” “哼税手!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起需纳,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤芦倒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后不翩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兵扬,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年口蝠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了器钟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妙蔗,死狀恐怖傲霸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤昙啄,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布穆役,位于F島的核電站,受9級(jí)特大地震影響梳凛,放射性物質(zhì)發(fā)生泄漏耿币。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一韧拒、第九天 我趴在偏房一處隱蔽的房頂上張望淹接。 院中可真熱鬧,春花似錦叛溢、人聲如沸塑悼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拢肆。三九已至,卻和暖如春靖诗,著一層夾襖步出監(jiān)牢的瞬間郭怪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工刊橘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鄙才,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓促绵,卻偏偏與公主長得像攒庵,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子败晴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容