長連接網(wǎng)關(guān)技術(shù)專題(十三):基于Netty的攜程高性能網(wǎng)關(guān)異步改造實(shí)踐
本文由攜程技術(shù)Butters分享,原題“干貨 | 日均流量200億,攜程高性能全異步網(wǎng)關(guān)實(shí)踐”,下文有修訂和重新排版。
1、引言
本文分享的是攜程API網(wǎng)關(guān)全異步改造的實(shí)踐分享,包括從Zuul 1.0同步架構(gòu)升級為基于Netty的全異步架構(gòu),通過RxJava實(shí)現(xiàn)業(yè)務(wù)流程異步化,結(jié)合流式轉(zhuǎn)發(fā)、ZGC等技術(shù)顯著提升性能,并構(gòu)建控制面實(shí)現(xiàn)多協(xié)議統(tǒng)一治理與模塊化編排。

技術(shù)交流:
- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)
2、作者介紹
Butters:攜程軟件技術(shù)專家,專注于網(wǎng)絡(luò)架構(gòu)、API網(wǎng)關(guān)、負(fù)載均衡、Service Mesh等領(lǐng)域。
3、專題目錄
本文是專題系列文章的第 13 篇,總目錄如下:
《長連接網(wǎng)關(guān)技術(shù)專題(一):京東京麥的生產(chǎn)級TCP網(wǎng)關(guān)技術(shù)實(shí)踐總結(jié)》
《長連接網(wǎng)關(guān)技術(shù)專題(二):知乎千萬級并發(fā)的高性能長連接網(wǎng)關(guān)技術(shù)實(shí)踐》
《長連接網(wǎng)關(guān)技術(shù)專題(三):手淘億級移動(dòng)端接入層網(wǎng)關(guān)的技術(shù)演進(jìn)之路》
《長連接網(wǎng)關(guān)技術(shù)專題(四):愛奇藝WebSocket實(shí)時(shí)推送網(wǎng)關(guān)技術(shù)實(shí)踐》
《長連接網(wǎng)關(guān)技術(shù)專題(五):喜馬拉雅自研億級API網(wǎng)關(guān)技術(shù)實(shí)踐》
《長連接網(wǎng)關(guān)技術(shù)專題(六):石墨文檔單機(jī)50萬WebSocket長連接架構(gòu)實(shí)踐》
《長連接網(wǎng)關(guān)技術(shù)專題(七):小米小愛單機(jī)120萬長連接接入層的架構(gòu)演進(jìn)》
《長連接網(wǎng)關(guān)技術(shù)專題(八):B站基于微服務(wù)的API網(wǎng)關(guān)從0到1的演進(jìn)之路》
《長連接網(wǎng)關(guān)技術(shù)專題(九):去哪兒網(wǎng)酒店高性能業(yè)務(wù)網(wǎng)關(guān)技術(shù)實(shí)踐》
《長連接網(wǎng)關(guān)技術(shù)專題(十):百度基于Go的千萬級統(tǒng)一長連接服務(wù)架構(gòu)實(shí)踐》
《長連接網(wǎng)關(guān)技術(shù)專題(十一):揭秘騰訊公網(wǎng)TGW網(wǎng)關(guān)系統(tǒng)的技術(shù)架構(gòu)演進(jìn)》
《長連接網(wǎng)關(guān)技術(shù)專題(十二):大模型時(shí)代多模型AI網(wǎng)關(guān)的架構(gòu)設(shè)計(jì)與實(shí)現(xiàn)》
《長連接網(wǎng)關(guān)技術(shù)專題(十三):基于Netty的攜程高性能網(wǎng)關(guān)異步改造實(shí)踐》(* 本文)
4、技術(shù)背景
與許多公司一樣,攜程API網(wǎng)關(guān)也是同微服務(wù)架構(gòu)一起引入的基礎(chǔ)設(shè)施,最早版本發(fā)布于2014年。隨著服務(wù)化在公司的快速推進(jìn),網(wǎng)關(guān)逐漸成為應(yīng)用暴露到外網(wǎng)的標(biāo)準(zhǔn)方案。后來的“ALL IN無線”、國際化、異地多活等,網(wǎng)關(guān)跟隨著公司公共業(yè)務(wù)與基礎(chǔ)架構(gòu)共同演進(jìn)。
技術(shù)方案上,公司微服務(wù)早期發(fā)展受NetflixOSS影響較深,網(wǎng)關(guān)方面最早也是參考了Zuul 1.0進(jìn)行的二次開發(fā)。
核心可概括為四點(diǎn):
- 1)server端:Tomcat NIO + AsyncServlet;
- 2)業(yè)務(wù)流程:獨(dú)立線程池,分階段的責(zé)任鏈模式;
- 3)client端:Apache HttpClient,同步調(diào)用;
- 4)核心組件:Archaius(動(dòng)態(tài)配置客戶端),Hystrix(熔斷限流),Groovy(熱更新支持)。
眾所周知,同步調(diào)用阻塞線程,系統(tǒng)吞吐受IO影響大。作為行業(yè)先驅(qū),Zuul在設(shè)計(jì)上也考慮到了這點(diǎn)——通過引入Hystrix,資源隔離配合限流,將故障(慢IO)框在一定范圍內(nèi);配合熔斷策略,可提前釋放部分線程資源;最終達(dá)到局部異常不影響全局的目的。
但隨著公司業(yè)務(wù)的發(fā)展,上述策略效果逐漸減弱。
主要原因在于兩方面的變動(dòng):
- 1)業(yè)務(wù)出海:網(wǎng)關(guān)作為海外接入層,部分流量需轉(zhuǎn)回國內(nèi),慢IO成為常態(tài);
- 2)服務(wù)規(guī)模增長:局部異常常態(tài)化,加上微服務(wù)異常擴(kuò)散的特性,線程池可能長期處于亞健康狀態(tài)。

全異步改造是攜程API網(wǎng)關(guān)近年的一項(xiàng)核心工作點(diǎn),本文也將由此展開,聊一聊我們在網(wǎng)關(guān)方面的工作與實(shí)踐。重點(diǎn)包括:性能優(yōu)化、業(yè)務(wù)形態(tài)、技術(shù)架構(gòu)、治理經(jīng)驗(yàn)等。
5、高性能網(wǎng)關(guān)核心設(shè)計(jì)1:異步流程設(shè)計(jì)
全異步 = server端異步 + 業(yè)務(wù)流程異步 + client端異步
對于server與client端,我們選擇了Netty框架,NIO/Epoll + Eventloop本身就是事件驅(qū)動(dòng)的設(shè)計(jì)。
改造核心在于業(yè)務(wù)流程的異步化,常見異步場景包括:
- 1)業(yè)務(wù)IO事件:如請求校驗(yàn)、身份認(rèn)證,涉及遠(yuǎn)程調(diào)用;
- 2)自身IO事件:如讀取到了報(bào)文的前xx字節(jié);
- 3)請求轉(zhuǎn)發(fā):包括TCP連接,HTTP請求。
經(jīng)驗(yàn)上,異步編程相比同步在設(shè)計(jì)、讀寫上都會(huì)困難一些。
所謂的困難,一般包括:
- 1)流程設(shè)計(jì)&狀態(tài)轉(zhuǎn)換;
- 2)異常處理,包括常規(guī)異常與超時(shí);
- 3)上下文傳遞,包括業(yè)務(wù)上下文與trace log;
- 4)線程調(diào)度;
- 5)流量控制。
尤其在Netty上下文內(nèi),對ByteBuf生命周期設(shè)計(jì)的不完善,很容易造成內(nèi)存泄漏。圍繞這些問題,我們設(shè)計(jì)了對應(yīng)外圍框架,最大努力對業(yè)務(wù)代碼抹平同步/異步差異,方便開發(fā);同時(shí)默認(rèn)兜底與容錯(cuò),保證程序整體安全。工具上借助了RxJava,主要流程如下圖所示。
Maybe:
- 1)RxJava內(nèi)置容器類,標(biāo)識正常結(jié)束、有且僅有一個(gè)對象返回、異常三種狀態(tài);
- 2)響應(yīng)式,方便整體狀態(tài)機(jī)設(shè)計(jì),自帶異常處理、超時(shí)、線程調(diào)度等封裝;
- 3)Maybe.empty()/Maybe.just(T),適用同步場景;
- 4)工具類RxJavaPlugins,方便切面邏輯封裝。
Filter:
- 1)代表一塊獨(dú)立的業(yè)務(wù)邏輯,同步&異步業(yè)務(wù)統(tǒng)一接口,返回Maybe;
- 2)異步場景(如遠(yuǎn)程調(diào)用)統(tǒng)一封裝,如涉及線程切換,通過maybe.obesrveOn(eventloop)切回;
- 3)異步filter默認(rèn)增加超時(shí),并按弱依賴處理,忽略錯(cuò)誤。
public interface Processor<T> {
ProcessorType getType();
int getOrder();
boolean shouldProcess(RequestContext context);
//對外統(tǒng)一封裝為Maybe
Maybe process(RequestContext context) throws Exception;
}
public abstract class AbstractProcessor implements Processor {
//同步&無響應(yīng),繼承此方法
//場景:常規(guī)業(yè)務(wù)處理
protected void processSync(RequestContext context) throws Exception {}
//同步&有響應(yīng),繼承此方法,健康檢測
//場景:健康檢測、未通過校驗(yàn)時(shí)的靜態(tài)響應(yīng)
protected T processSyncAndGetReponse(RequestContext context) throws Exception {
process(context);
return null;
};
//異步,繼承此方法
//場景:認(rèn)證、鑒權(quán)等涉及遠(yuǎn)程調(diào)用的模塊
protected Maybe processAsync(RequestContext context) throws Exception
{
T response = processSyncAndGetReponse(context);
if (response == null) {
return Maybe.empty();
} else {
return Maybe.just(response);
}
};
@Override
public Maybe process(RequestContext context) throws Exception {
Maybe<T> maybe = processAsync(context);
if (maybe instanceof ScalarCallable) {
//標(biāo)識同步方法,無需額外封裝
return maybe;
} else {
//統(tǒng)一加超時(shí),默認(rèn)忽略錯(cuò)誤
return maybe.timeout(getAsyncTimeout(context), TimeUnit.MILLISECONDS,
Schedulers.from(context.getEventloop()), timeoutFallback(context));
}
}
protected long getAsyncTimeout(RequestContext context) {
return 2000;
}
protected Maybe<T> timeoutFallback(RequestContext context) {
return Maybe.empty();
}
整體流程:
- 1)沿用責(zé)任鏈的設(shè)計(jì),分為inbound、outbound、error、log四階段;
- 2)各階段由一或多個(gè)filter組成;
- 3)filter順序執(zhí)行,遇到異常則中斷,inbound期間任意filter返回response也觸發(fā)中斷。
public class RxUtil{
//組合某階段(如Inbound)內(nèi)的多個(gè)filter(即Callable<Maybe<T>>)
public static Maybe concat(Iterable
Iterator
while (sources.hasNext()) {
Maybe<T> maybe;
try {
maybe = sources.next().call();
} catch (Exception e) {
return Maybe.error(e);
}
if (maybe != null) {
if (maybe instanceof ScalarCallable) {
//同步方法
T response = ((ScalarCallable<T>)maybe).call();
if (response != null) {
//有response,中斷
return maybe;
}
} else {
//異步方法
if (sources.hasNext()) {
//將sources傳入回調(diào),后續(xù)filter重復(fù)此邏輯
return new ConcattedMaybe(maybe, sources);
} else {
return maybe;
}
}
}
}
return Maybe.empty();
}
}
public class ProcessEngine{
//各個(gè)階段,增加默認(rèn)超時(shí)與錯(cuò)誤處理
private void process(RequestContext context) {
List<Callable<Maybe<Response>>> inboundTask = get(ProcessorType.INBOUND, context);
List<Callable<Maybe<Void>>> outboundTask = get(ProcessorType.OUTBOUND, context);
List<Callable<Maybe<Response>>> errorTask = get(ProcessorType.ERROR, context);
List<Callable<Maybe<Void>>> logTask = get(ProcessorType.LOG, context);
RxUtil.concat(inboundTask) //inbound階段
.toSingle() //獲取response
.flatMapMaybe(response -> {
context.setOriginResponse(response);
return RxUtil.concat(outboundTask);
}) //進(jìn)入outbound
.onErrorResumeNext(e -> {
context.setThrowable(e);
return RxUtil.concat(errorTask).flatMap(response -> {
context.resetResponse(response);
return RxUtil.concat(outboundTask);
});
}) //異常則進(jìn)入error,并重新進(jìn)入outbound
.flatMap(response -> RxUtil.concat(logTask)) //日志階段
.timeout(asyncTimeout.get(), TimeUnit.MILLISECONDS, Schedulers.from(context.getEventloop()),
Maybe.error(new ServerException(500, "Async-Timeout-Processing"))
) //全局兜底超時(shí)
.subscribe( //釋放資源
unused -> {
logger.error("this should not happen, " + context);
context.release();
},
e -> {
logger.error("this should not happen, " + context, e);
context.release();
},
() -> context.release()
);
}
}
6、高性能網(wǎng)關(guān)核心設(shè)計(jì)2:流式轉(zhuǎn)發(fā)&單線程
以HTTP為例,報(bào)文可劃分為initial line/header/body三個(gè)組成部分:
在攜程,網(wǎng)關(guān)層業(yè)務(wù)不涉及body。因?yàn)闊o需全量存,所以解析完header后可直接進(jìn)入業(yè)務(wù)流程。
于此同時(shí),如果接收到body部分:
- 1)若已向upstream轉(zhuǎn)發(fā)請求,則直接轉(zhuǎn)發(fā);
- 2)否則需要將其暫存,待業(yè)務(wù)流程處理完畢,同initial line/header一并發(fā)送;
- 3)對upstream端響應(yīng)的處理方式亦然。
對比完整解析HTTP報(bào)文的方式,這樣處理:
- 1)更早進(jìn)入業(yè)務(wù)流程,意味著upstream更早接收到請求,能有效降低網(wǎng)關(guān)這層引入的延遲;
- 2)body生命周期被壓縮,可降低網(wǎng)關(guān)自身的內(nèi)存開銷。
雖說提升了性能,但流式的方式也極大提升了整個(gè)流程的復(fù)雜度
非流式場景下,Netty Server端編解碼、入向業(yè)務(wù)邏輯、Netty Cerver端編解碼、出向業(yè)務(wù)邏輯,各子流程相互獨(dú)立,各自處理完整的HTTP對象。
采取流式后,請求則可能同時(shí)處于多流程內(nèi),引入的困難可歸納為以下三點(diǎn):
- 1)線程安全問題:不同流程若采用不同線程,會(huì)涉及上下文的并發(fā)修改;
- 2)多階段聯(lián)動(dòng):比如Netty Server請求接收一半遇到了連接中斷,此時(shí)已經(jīng)連上了upstream,那么upstream側(cè)的協(xié)議棧是走不完的,也必須隨之關(guān)閉連接;
- 3)邊緣場景處理:比如upstream在請求未完整發(fā)送情況下返回了404/413,是選擇繼續(xù)發(fā)送、走完協(xié)議棧、讓連接能夠復(fù)用,還是選擇提前終止流程,節(jié)約資源,但同時(shí)放棄連接?再比如,upstream已收到請求但未響應(yīng),此時(shí)Netty Server突然斷開,Netty Client是否也要隨之?dāng)嚅_?等等。
針對這些場景,我們采用了單線程的方式,核心設(shè)計(jì):
- 1)上線文綁定Eventloop,Netty Server/業(yè)務(wù)流程/Netty Client在同個(gè)eventloop執(zhí)行;
- 2)異步filter如因IO庫的關(guān)系,必須使用獨(dú)立線程池,那在后置處理上必須切回;
- 3)流程內(nèi)資源做必要的線程隔離(如連接池)。
采用單線程的好處:
- 1)杜絕了并發(fā)問題,在多階段聯(lián)動(dòng)、邊緣場景問題處理時(shí),整個(gè)系統(tǒng)也處于確定的狀態(tài)下,有效降低了開發(fā)難度與風(fēng)險(xiǎn);
- 2)減少線程切換,一定程度上也能夠提升性能。
與之相對的,因?yàn)閣orker線程數(shù)較少(一般等于CPU核數(shù)),eventloop內(nèi)必須完全杜絕IO操作,否則將對系統(tǒng)吞吐造成毀滅性打擊。
7、高性能網(wǎng)關(guān)核心設(shè)計(jì)3:其他優(yōu)化
內(nèi)部變量懶加載:針對請求的cookie/query等字段,如無必要,不提前進(jìn)行字符串解析
堆外內(nèi)存&零拷貝:結(jié)合前文流式轉(zhuǎn)發(fā)的設(shè)計(jì),進(jìn)一步降低系統(tǒng)內(nèi)存開銷
ZGC:項(xiàng)目因TLSv1.3而引入了JDK11(JDK8支持相對較晚,8u261版本,2020.7.14),自然也對新一代的GC算法進(jìn)行了嘗試,實(shí)際表現(xiàn)也確實(shí)不負(fù)盛名。除CPU占用有少量提升,整體GC耗時(shí)下降非常明顯。

定制的HTTP編解碼:HTTP的悠久歷史,加之協(xié)議自身的開放性,催生了許多“壞實(shí)踐”,輕則影響成功率,重則威脅網(wǎng)站安全,舉兩個(gè)例子:
流量治理:諸如請求體過大(413)、uri過長(414)、非ASCII字符(400)等問題,一般WebServer會(huì)選擇直接拒絕并返回對應(yīng)狀態(tài)碼。由于直接跳過了業(yè)務(wù)流程,這類問題在統(tǒng)計(jì)、服務(wù)定為、排障上都會(huì)比較麻煩。擴(kuò)展編解碼,讓問題請求也能夠走完路由流程,可以幫助解決非標(biāo)流量的治理問題。
請求過濾:如request smuggling(Netty 4.1.61.Final修復(fù),2021.3.30發(fā)布)。擴(kuò)展編解碼,增加自定義的校驗(yàn)邏輯,讓安全補(bǔ)丁能夠更快落地。
8、網(wǎng)關(guān)業(yè)務(wù)形態(tài)
作為獨(dú)立、統(tǒng)一的入向流量收口點(diǎn),網(wǎng)關(guān)對公司的價(jià)值主要體現(xiàn)在三方面:
- 1)解耦不同網(wǎng)絡(luò)環(huán)境:典型場景包括內(nèi)網(wǎng)&外網(wǎng)、生產(chǎn)環(huán)境&辦公區(qū)、IDC內(nèi)部不同安全域、專線等;
- 2)天然的公共業(yè)務(wù)切面:包括安全&認(rèn)證&反爬、路由&灰度、限流&熔斷&降級、監(jiān)控&告警&排障等;
- 3)高效、靈活的流量控制。

這里展開講幾個(gè)細(xì)分場景。
私有協(xié)議:
- 1)在收口的客戶端(APP),由框架層攔截用戶發(fā)起的HTTP請求,通過私有協(xié)議(SOTP)的方式發(fā)往服務(wù)端;
- 2)選址方面:①通過服務(wù)端下發(fā)IP,杜絕DNS劫持;②連接預(yù)熱;③自定義的選址策略,可依據(jù)網(wǎng)絡(luò)質(zhì)量、環(huán)境等自行切換;
- 3)交互方式上:①更加輕量的協(xié)議體;②統(tǒng)一加密&壓縮&多路復(fù)用;③協(xié)議在入口處由網(wǎng)關(guān)統(tǒng)一轉(zhuǎn)換,對業(yè)務(wù)透明。
鏈路優(yōu)化:核心是引入接入層,讓遠(yuǎn)距離用戶就近訪問,緩解握手開銷過大的問題。同時(shí),因?yàn)榻尤雽优cIDC是可控的兩端,網(wǎng)絡(luò)鏈路選擇、協(xié)議交互模式上都有更大的優(yōu)化空間。
異地多活:區(qū)別于按比例分配、就近訪問策略等,異地多活模式下,網(wǎng)關(guān)(接入層)需按照業(yè)務(wù)維度的shardingKey進(jìn)行分流(如userId),防止底層數(shù)據(jù)沖突。

9、網(wǎng)關(guān)治理概述
下圖總結(jié)了線上網(wǎng)關(guān)的工作狀態(tài):

橫向?qū)?yīng)我們的業(yè)務(wù)流程:不同渠道(APP、H5、小程序、供應(yīng)商)、不同協(xié)議(HTTP、SOTP)的流量經(jīng)由負(fù)載均衡打到網(wǎng)關(guān),經(jīng)過系列業(yè)務(wù)邏輯的處理,最終轉(zhuǎn)發(fā)至后端服務(wù)。經(jīng)歷了第二章的改造后,橫向業(yè)務(wù)在性能、穩(wěn)定性上都得到了較好的提升。
另一方面:由于多渠道/協(xié)議的存在,線上網(wǎng)關(guān)按業(yè)務(wù)劃分,進(jìn)行了獨(dú)立集群的部署。業(yè)務(wù)差異(路由數(shù)據(jù)、功能模塊)早期通過獨(dú)立代碼分支管理,隨著分支數(shù)的增加,整體的運(yùn)維復(fù)雜度越來越高。系統(tǒng)設(shè)計(jì)中,復(fù)雜度往往也意味著風(fēng)險(xiǎn)。如何對多協(xié)議、多角色的網(wǎng)關(guān)實(shí)施統(tǒng)一治理,如何以較低的成本,快速為新業(yè)務(wù)搭建定制化網(wǎng)關(guān),成為了我們后一階段的工作重心。
解決方案也比較直觀地在圖中畫了出來:
- 1)是協(xié)議上兼容處理,讓線上代碼跑在一套框架下;
- 2)是引入控制面,對線上網(wǎng)關(guān)的差異特性進(jìn)行統(tǒng)一管理。

10、網(wǎng)關(guān)治理能力1:多協(xié)議兼
協(xié)議兼容的做法并不新鮮,整體可以參考Tomcat對HTTP/1.0、HTTP/1.1、HTTP/2.0的抽象。HTTP自身雖然在各個(gè)版本內(nèi)新增了大量feature,但我們在做業(yè)務(wù)開發(fā)時(shí)通常感知不到這些,核心在于HttpServletRequest接口的抽象。
在攜程,網(wǎng)關(guān)面對的都是請求—響應(yīng)模式的無狀態(tài)協(xié)議,報(bào)文組成上也可以劃分為元數(shù)據(jù)、擴(kuò)展頭、業(yè)務(wù)報(bào)文三部分,因此可以比較方便地進(jìn)行類似的嘗試。
對應(yīng)工作可以用以下兩點(diǎn)概括:
- 1)協(xié)議適配層:用于屏蔽不同協(xié)議的編解碼、交互模式、對TCP連接的處理等;
- 2)定義通用中間模型與接口:業(yè)務(wù)面向中間模型與接口編程,更好地聚焦到協(xié)議對應(yīng)的業(yè)務(wù)屬性上去。

11、網(wǎng)關(guān)治理能力2:路由模塊
路由模塊是控制面的兩個(gè)主要組成部分之一。
除了管理網(wǎng)關(guān)—服務(wù)間的映射關(guān)系,服務(wù)本身可以用以下模型概括:
{
//匹配方式
"type": "uri",
//HTTP默認(rèn)采用uri前綴匹配,內(nèi)部通過樹結(jié)構(gòu)尋址;私有協(xié)議(SOTP)通過服務(wù)唯一標(biāo)識定位。
"value": "/hotel/order",
"matcherType": "prefix",
//標(biāo)簽與屬性
//用于portal端權(quán)限管理、切面邏輯運(yùn)行(如按核心/非核心)等
"tags": [
"owner_admin",
"org_framework",
"appId_123456"
],
"properties": {
"core": "true"
},
//endpoint信息
"routes": [{
//condition用于二級路由,如按app版本劃分、按query重分配等
"condition": "true",
"conditionParam": {},
"zone": "PRO",
//具體服務(wù)地址,權(quán)重用于灰度場景
"targets": [{
"url": "http://test.ctrip.com/hotel",
"weight": 100
}
]
}]
}
12、網(wǎng)關(guān)治理能力3:模塊編排
模塊編排是控制面的另一項(xiàng)核心部分。

我們在網(wǎng)關(guān)處理流程內(nèi)預(yù)留了多個(gè)階段(上圖中用粉色標(biāo)記)。除開熔斷、限流、日志等通用功能,運(yùn)行時(shí)不同網(wǎng)關(guān)所需執(zhí)行的業(yè)務(wù)功能由控制面統(tǒng)一下發(fā)。功能本身在網(wǎng)關(guān)內(nèi)部有獨(dú)立的代碼模塊,控制面額外定義了功能對應(yīng)的執(zhí)行條件、參數(shù)、灰度比例、錯(cuò)誤處理方式等。這種編排方式也在側(cè)面保證了模塊間的解耦。
{
//模塊名稱,對應(yīng)網(wǎng)關(guān)內(nèi)部某個(gè)具體模塊
"name": "addResponseHeader",
//執(zhí)行階段
"stage": "PRE_RESPONSE",
//執(zhí)行順序
"ruleOrder": 0,
//灰度比例
"grayRatio": 100,
//執(zhí)行條件
"condition": "true",
"conditionParam": {},
//執(zhí)行參數(shù)
//大量${}形式的內(nèi)置模板,用于獲取運(yùn)行時(shí)數(shù)據(jù)
"actionParam": {
"connection": "keep-alive",
"x-service-call": "${request.func.remoteCost}",
"Access-Control-Expose-Headers": "x-service-call",
"x-gate-root-id": "${func.catRootMessageId}"
},
//異常處理方式,可以拋出或忽略
"exceptionHandle": "return"
}
13、本文小結(jié)
網(wǎng)關(guān)長期以來都是各類技術(shù)交流平臺上的熱點(diǎn),方案也非常豐富:發(fā)展早、易上手的Zuul1.0、高性能的Nginx、集成度高的SpringCloud Gateway、如日中天的Istio等等。最終決定選型的還是各公司自身的業(yè)務(wù)背景與技術(shù)生態(tài)。也正因此,在攜程我們選擇了自研的道路。
技術(shù)不斷發(fā)展,我們也在持續(xù)探索,公共網(wǎng)關(guān)同業(yè)務(wù)網(wǎng)關(guān)的關(guān)系、新協(xié)議的落地(HTTP3)、與ServiceMesh的關(guān)系等等,真誠歡迎有興趣的同學(xué)一起參與討論。
14、參考資料
[1] 京東京麥的生產(chǎn)級TCP網(wǎng)關(guān)技術(shù)實(shí)踐總結(jié)
[2] 手淘億級移動(dòng)端接入層網(wǎng)關(guān)的技術(shù)演進(jìn)之路
[3] 喜馬拉雅自研億級API網(wǎng)關(guān)技術(shù)實(shí)踐
[4] 小米小愛單機(jī)120萬長連接接入層的架構(gòu)演進(jìn)
[5] B站基于微服務(wù)的API網(wǎng)關(guān)從0到1的演進(jìn)之路
[6] 去哪兒網(wǎng)酒店高性能業(yè)務(wù)網(wǎng)關(guān)技術(shù)實(shí)踐
[7] 少啰嗦!一分鐘帶你讀懂Java的NIO和經(jīng)典IO的區(qū)別
[8] 史上最強(qiáng)Java NIO入門:擔(dān)心從入門到放棄的,請讀這篇!
[9] Java的BIO和NIO很難懂?用代碼實(shí)踐給你看,再不懂我轉(zhuǎn)行!
[10] 史上最通俗Netty框架入門長文:基本介紹、環(huán)境搭建、動(dòng)手實(shí)戰(zhàn)
作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
出處:http://www.52im.net/space-uid-1.html
交流:歡迎加入即時(shí)通訊開發(fā)交流群 215477170
討論:http://www.52im.net/
Jack Jiang同時(shí)是【原創(chuàng)Java
Swing外觀工程BeautyEye】和【輕量級開源移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
本博文
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處(也可前往 我的52im.net 找到我)。


浙公網(wǎng)安備 33010602011771號