網(wǎng)關一詞較早出現(xiàn)在網(wǎng)絡設備里面,比如兩個相互獨立的局域網(wǎng)段之間通過路由器或者橋接設備進行通信, 這中間的路由或者橋接設備我們稱之為網(wǎng)關夏伊。
相應的 API 網(wǎng)關將各系統(tǒng)對外暴露的服務聚合起來,所有要調用這些服務的系統(tǒng)都需要通過 API 網(wǎng)關進行訪問,基于這種方式網(wǎng)關可以對 API 進行統(tǒng)一管控铜靶,例如:認證、鑒權他炊、流量控制争剿、協(xié)議轉換、監(jiān)控等等痊末。
API 網(wǎng)關的流行得益于近幾年微服務架構的興起蚕苇,原本一個龐大的業(yè)務系統(tǒng)被拆分成許多粒度更小的系統(tǒng)進行獨立部署和維護,這種模式勢必會帶來更多的跨系統(tǒng)交互凿叠,企業(yè) API 的規(guī)模也會成倍增加涩笤,API 網(wǎng)關(或者微服務網(wǎng)關)就逐漸成為了微服務架構的標配組件。
如下是我們整理的 API 網(wǎng)關的幾種典型應用場景:
1盒件、面向 Web 或者移動 App
這類場景蹬碧,在物理形態(tài)上類似前后端分離,前端應用通過 API 調用后端服務炒刁,需要網(wǎng)關具有認證恩沽、鑒權、緩存切心、服務編排飒筑、監(jiān)控告警等功能。
2绽昏、面向合作伙伴開放 API
這類場景协屡,主要為了滿足業(yè)務形態(tài)對外開放,與企業(yè)外部合作伙伴建立生態(tài)圈全谤,此時的 API 網(wǎng)關注重安全認證肤晓、權限分級、流量管控、緩存等功能的建設补憾。
3漫萄、企業(yè)內部系統(tǒng)互聯(lián)互通
對于中大型的企業(yè)內部往往有幾十、甚至上百個系統(tǒng)盈匾,尤其是微服務架構的興起系統(tǒng)數(shù)量更是急劇增加腾务。系統(tǒng)之間相互依賴,逐漸形成網(wǎng)狀調用關系不便于管理和維護削饵,需要 API 網(wǎng)關進行統(tǒng)一的認證岩瘦、鑒權、流量管控窿撬、超時熔斷启昧、監(jiān)控告警管理,從而提高系統(tǒng)的穩(wěn)定性劈伴、降低重復建設密末、運維管理等成本。
設計目標
- 純 Java 實現(xiàn)跛璧;
- 支持插件化严里,方便開發(fā)人員自定義組件;
- 支持橫向擴展追城,高性能田炭;
- 避免單點故障,穩(wěn)定性要高漓柑,不能因為某個 API 故障導致整個網(wǎng)關停止服務;
- 管理控制臺配置更新可自動生效叨吮,不需要重啟網(wǎng)關辆布;
應用架構設計
整個平臺拆分成 3 個子系統(tǒng),Gateway-Core(核心子系統(tǒng))茶鉴、Gateway-Admin(管理中心)锋玲、Gateway-Monitor(監(jiān)控中心)。
- Gateway-Core 負責接收客戶端請求涵叮,調度惭蹂、加載和執(zhí)行組件,將請求路由到上游服務端割粮,處理上游服務端返回的結果等盾碗;
- Gateway-Admin 提供統(tǒng)一的管理界面,用戶可在此進行 API舀瓢、組件廷雅、系統(tǒng)基礎信息的設置和維護;
- Gateway-Monitor 負責收集監(jiān)控日志、生成各種運維管理報表航缀、自動告警等商架;
系統(tǒng)架構設計
說明:
- 網(wǎng)關核心子系統(tǒng)通過 HAProxy 或者 Nginx 進行負載均衡,為避免正好路由的 LB 節(jié)點服務不可用芥玉,可以考慮在此基礎上增加 Keepalived 來實現(xiàn) LB 的失效備援蛇摸,當 LB Node1 停止服務,Keepalived 會將虛擬 IP 自動飄移到 LB Node2灿巧,從而避免因為負載均衡器導致單點故障赶袄。DNS 可以直接指向 Keepalived 的虛擬 IP。
- 網(wǎng)關除了對性能要求很高外砸烦,對穩(wěn)定性也有很高的要求弃鸦,引入 Zookeeper 及時將 Admin 對 API 的配置更改同步刷新到各網(wǎng)關節(jié)點。
管理中心和監(jiān)控中心可以采用類似網(wǎng)關子系統(tǒng)的高可用策略幢痘,如果嫌麻煩管理中心可以省去 Keepalived唬格,相對來說管理中心沒有這么高的可用性要求。
理論上監(jiān)控中心需要承載很大的數(shù)據(jù)量颜说,比如有 1000 個 API购岗,平均每個 API 一天調用 10 萬次,對于很多互聯(lián)網(wǎng)公司單個 API 的量遠遠大于 10 萬门粪,如果將每次調用的信息都存儲起來太浪費喊积,也沒有太大的必要⌒瑁可以考慮將 API 每分鐘的調用情況匯總后進行存儲乾吻,比如 1 分鐘的平均響應時間、調用次數(shù)拟蜻、流量绎签、正確率等等。 - 數(shù)據(jù)庫選型可以靈活考慮酝锅,原則上網(wǎng)關在運行時要盡可能減少對 DB 的依賴诡必,否則 IO 延時會嚴重影響網(wǎng)關性能∩Ρ猓可以考慮首次訪問后將 API 配置信息緩存爸舒,Admin 對 API 配置更改后通過 Zookeeper 通知網(wǎng)關刷新,這樣一來 DB 的訪問量可以忽略不計稿蹲,團隊可根據(jù)自身偏好靈活選型扭勉。
非阻塞式 HTTP 服務
管理和監(jiān)控中心可以根據(jù)團隊的情況采用自己熟悉的 Servlet 容器部署,網(wǎng)關核心子系統(tǒng)對性能的要求非常高苛聘,考慮采用 NIO 的網(wǎng)絡模型剖效,實現(xiàn)純 HTTP 服務即可嫉入,不需要實現(xiàn) Servlet 容器,推薦 Netty 框架(設計優(yōu)雅璧尸,大名鼎鼎的 Spring Webflux 默認都是使用的 Netty咒林,更多的優(yōu)勢就不在此詳述了),內部測試在相同的機器上分別通過 Tomcat 和 Netty 生成 UUID爷光,Netty 的性能大約有 20% 的提升垫竞,如果后端服務響應耗時較高的話吞吐量還有更大的提升。(補充:Netty4.x 的版本即可蛀序,不要采用 5 以上的版本欢瞪,有嚴重的缺陷沒有解決)
采用 Netty 作為 Http 容器首先需要解決的是 Http 協(xié)議的解析和封裝,好在 Netty 本身提供了這樣的 Handler徐裸,具體參考如下代碼:
- 1遣鼓、構建一個單例的 HttpServer,在 SpringBoot 啟動的時候同時加載并啟動 Netty 服務
int sobacklog = Integer.parseInt(AppConfigUtil.getValue("netty.sobacklog"));
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(this.portHTTP))
.option(ChannelOption.SO_BACKLOG, sobacklog)
.childHandler(new ChannelHandlerInitializer(null));
// 綁定端口
ChannelFuture f = b.bind(this.portHTTP).sync();
logger.info("HttpServer name is " + HttpServer.class.getName() + " started and listen on " + f.channel().localAddress());
- 2重贺、初始化 Handler
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new HttpRequestDecoder());
p.addLast(new HttpResponseEncoder());
int maxContentLength = 2000;
try {
maxContentLength = Integer.parseInt(AppConfigUtil.getValue("netty.maxContentLength"));
} catch (Exception e) {
logger.warn("netty.maxContentLength 配置異常骑祟,系統(tǒng)默認為:2000KB");
}
p.addLast(new HttpObjectAggregator(maxContentLength * 1024));// HTTP 消息的合并處理
p.addLast(new HttpServerInboundHandler());
}
HttpRequestDecoder 和 HttpResponseEncoder 分別實現(xiàn) Http 協(xié)議的解析和封裝,Http Post 內容超過一個數(shù)據(jù)包大小會自動分組气笙,通過 HttpObjectAggregator 可以自動將這些數(shù)據(jù)粘合在一起次企,對于上層收到是一個完整的 Http 請求。
- 3潜圃、通過 HttpServerInboundHandler 將網(wǎng)絡請求轉發(fā)給網(wǎng)關執(zhí)行器
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws Exception {
try {
if (msg instanceof HttpRequest && msg instanceof HttpContent) {
CmptRequest cmptRequest = CmptRequestUtil.convert(ctx, msg);
CmptResult cmptResult = this.gatewayExecutor.execute(cmptRequest);
FullHttpResponse response = encapsulateResponse(cmptResult);
ctx.write(response);
ctx.flush();
}
} catch (Exception e) {
logger.error("網(wǎng)關入口異常缸棵," \+ e.getMessage());
e.printStackTrace();
}
}
設計上建議將 Netty 接入層代碼跟網(wǎng)關核心邏輯代碼分離,不要將 Netty 收到 HttpRequest 和 HttpContent 直接給到網(wǎng)關執(zhí)行器谭期,可以考慮做一層轉換封裝成自己的 Request 給到執(zhí)行器堵第,方便后續(xù)可以很容易的將 Netty 替換成其它 Http 容器。(如上代碼所示隧出,CmptRequest 即為自定義的 Http 請求封裝類型诚,CmptResult 為網(wǎng)關執(zhí)行結果類)
組件化及自定義組件支持
組件是網(wǎng)關的核心,大部分功能特性都可以基于組件的形式提供鸳劳,組件化可以有效提高網(wǎng)關的擴展性。
先來看一個簡單的微信認證組件的例子:
如下實現(xiàn)的功能是對 API 請求傳入的 Token 進行校驗也搓,其結果分別是認證通過赏廓、Token 過期和無效 Token,認證通過后再將微信 OpenID 攜帶給上游服務系統(tǒng)傍妒。
/**
* 微信 token 認證幔摸,token 格式:
* {appID:'',openID:'',timestamp:132525144172,sessionKey: ''}
*/
public class WeixinAuthTokenCmpt extends AbstractCmpt {
private static Logger logger = LoggerFactory.getLogger(WeixinAuthTokenCmpt.class);
private final CmptResult SUCCESS_RESULT;
public WeixinAuthTokenCmpt() {
SUCCESS_RESULT = buildSuccessResult();
}
@Override
public CmptResult execute(CmptRequest request, Map<String, FieldDTO> config) {
if (logger.isDebugEnabled()) {
logger.debug("WeixinTokenCmpt ......");
}
CmptResult cmptResult = null;
//Token 認證超時間 (傳入單位: 分)
long authTokenExpireTime = getAuthTokenExpireTime(config);
WeixinTokenDTO authTokenDTO = this.getAuthTokenDTO(request);
logger.debug("Token=" + authTokenDTO);
AuthTokenState authTokenState = validateToken(authTokenDTO, authTokenExpireTime);
switch (authTokenState) {
case ACCESS: {
cmptResult = SUCCESS_RESULT;
Map<String, String> header = new HashMap<>();
header.put(HeaderKeyConstants.HEADER\_APP\_ID_KEY, authTokenDTO.getAppID());
header.put(CmptHeaderKeyConstants.HEADER\_WEIXIN\_OPENID_KEY, authTokenDTO.getOpenID());
header.put(CmptHeaderKeyConstants.HEADER\_WEIXIN\_SESSION_KEY, authTokenDTO.getSessionKey());
cmptResult.setHeader(header);
break;
}
case EXPIRED: {
cmptResult = buildCmptResult(RespErrCode.AUTH\_TOKEN\_EXPIRED, "token 過期, 請重新獲取 Token!");
break;
}
case INVALID: {
cmptResult = buildCmptResult(RespErrCode.AUTH\_INVALID\_TOKEN, "Token 無效颤练!");
break;
}
}
return cmptResult;
}
...
}
上面例子看不懂沒關系既忆,接下來會詳細闡述組件的設計思路。
- 1、組件接口定義
public interface ICmpt {
/**
* 組件執(zhí)行入口
*
* @param request
* @param config患雇,組件實例的參數(shù)配置
* @return
*/
CmptResult execute(CmptRequest request, Map<String, FieldDTO> config);
/**
* 銷毀組件持有的特殊資源跃脊,比如線程。
*/
void destroy();
}
execute 是組件執(zhí)行的入口方法苛吱,request 前面提到過是 http 請求的封裝酪术,config 是組件的特殊配置,比如上面例子提到的微信認證組件就有一個自定義配置 -Token 的有效期翠储,不同的 API 使用該組件可以設置不同的有效期绘雁。
FieldDTO 定義如下:
public class FieldDTO {
private String title;
private String name;
private FieldType fieldType = FieldType.STRING;
private String defaultValue;
private boolean required;
private String regExp;
private String description;
}
CmptResult為組件執(zhí)行后的返回結果,其定義如下:
``` java
public class CmptResult {
RespErrMsg respErrMsg;// 組件返回錯誤信息
private boolean passed;// 組件過濾是否通過
private byte\[\] data;// 組件返回數(shù)據(jù)
private Map<String, String> header = new HashMap<String, String>();// 透傳后端服務響應頭信息
private MediaType mediaType;// 返回響應數(shù)據(jù)類型
private Integer statusCode = 200;// 默認返回狀態(tài)碼為 200
}
- 2援所、組件類型定義
執(zhí)行器需要根據(jù)組件類型和組件執(zhí)行結果判斷是要直接返回客戶端還是繼續(xù)往下面執(zhí)行庐舟,比如認證類型的組件,如果認證失敗是不能繼續(xù)往下執(zhí)行的住拭,但緩存類型的組件沒有命中才繼續(xù)往下執(zhí)行挪略。當然這樣設計存在一些缺陷,比如新增組件類型需要執(zhí)行器配合調整處理邏輯废酷。(Kong 也提供了大量的功能組件瘟檩,沒有研究過其網(wǎng)關框架是如何跟組件配合的,是否支持用戶自定義組件類型澈蟆,知道的朋友詳細交流下墨辛。)
初步定義如下組件類型:
認證、鑒權趴俘、流量管控睹簇、緩存、路由寥闪、日志等太惠。
其中路由類型的組件涵蓋了協(xié)議轉換的功能,其負責調用上游系統(tǒng)提供的服務疲憋,可以根據(jù)上游系統(tǒng)提供 API 的協(xié)議定制不同的路由組件凿渊,比如:Restful、WebService缚柳、Dubbo埃脏、EJB 等等。
- 3、組件執(zhí)行位置和優(yōu)先級設定
執(zhí)行位置:Pre、Routing搪搏、After,分別代表后端服務調用前堵幽、后端服務調用中和后端服務調用完成后狗超,相同位置的組件根據(jù)優(yōu)先級決定執(zhí)行的先后順序。
- 4朴下、組件發(fā)布形式
組件打包成標準的 Jar 包努咐,通過 Admin 管理界面上傳發(fā)布。
附 - 組件可視化選擇 UI 設計
組件熱插拔設計和實現(xiàn)
JVM 中 Class 是通過類加載器 + 全限定名來唯一標識的桐猬,上面章節(jié)談到組件是以 Jar 包的形式發(fā)布的麦撵,但相同組件的多個版本的入口類名需要保持不變,因此要實現(xiàn)組件的熱插拔和多版本并存就需要自定義類加載器來實現(xiàn)溃肪。
大致思路如下:
網(wǎng)關接收到 API 調用請求后根據(jù)請求參數(shù)從緩存里拿到 API 配置的組件列表免胃,然后再逐一參數(shù)從緩存里獲取組件對應的類實例,如果找不到則嘗試通過自定義類加載器載入 Jar 包惫撰,并初始化組件實例及緩存羔沙。
附 - 參考示例
public static ICmpt newInstance(final CmptDef cmptDef) {
ICmpt cmpt = null;
try {
final String jarPath = getJarPath(cmptDef);
if (logger.isDebugEnabled()) {
logger.debug("嘗試載入 jar 包,jar 包路徑: " + jarPath);
}
// 加載依賴 jar
CmptClassLoader cmptClassLoader = CmptClassLoaderManager.loadJar(jarPath, true);
// 創(chuàng)建實例
if (null != cmptClassLoader) {
cmpt = LoadClassUtil.newObject(cmptDef.getFullQualifiedName(), ICmpt.class, cmptClassLoader);
} else {
logger.error("加載組件 jar 包失敗! jarPath: " + jarPath);
}
} catch(Exception e) {
logger.error("組件類加載失敗,請檢查類名和版本是否正確厨钻。ClassName=" + cmptDef.getFullQualifiedName() + ", Version=" + cmptDef.getVersion());
e.printStackTrace();
}
return cmpt;
}
補充說明:
自定義類加載器可直接需要繼承至 URLClassLoader扼雏,另外必須指定其父類加載器為執(zhí)行器的加載器,否則組件沒法引用網(wǎng)關的其它類夯膀。
API 故障隔離及超時诗充、熔斷處理
在詳細闡述設計前先講個實際的案例,大概 12 年的時候某公司自研了一款 ESB 的中間件(企業(yè)服務總線跟 API 網(wǎng)關很類似诱建,當年 SOA 理念大行其道的時候都推崇的是 ESB蝴蜓,側重服務的編排和異構系統(tǒng)的整合。)俺猿,剛開始用的還行茎匠,但隨著接入系統(tǒng)的增多,突然某天運維發(fā)現(xiàn)大量 API 出現(xiàn)緩慢甚至超時押袍,初步檢查發(fā)現(xiàn) ESB 每個節(jié)點的線程幾乎消耗殆盡诵冒,起初判斷是資源不夠,緊急擴容后還是很快線程占滿谊惭,最終導致上百個系統(tǒng)癱瘓汽馋。
最終找到問題的癥結是某個業(yè)務系統(tǒng)自身的原因導致服務不可用,下游業(yè)務系統(tǒng)請求大量堆積到 ESB 中圈盔,從而導致大量線程堵塞豹芯。
以上案例說明了一個在企業(yè)應用架構設計里面的經(jīng)典原則 - 故障隔離,由于所有的 API 請求都要經(jīng)過網(wǎng)關药磺,必須隔離 API 之間的相互影響,尤其是個別 API 故障導致整個網(wǎng)關集群服務中斷煤伟。
接下來分別介紹故障隔離癌佩、超時管控木缝、熔斷的實現(xiàn)思路。
- 1围辙、故障隔離
有兩種方式可以實現(xiàn)我碟,一是為每個 API 創(chuàng)建一個線程池,每個線程分配 10~20 個線程姚建,這也是常用的隔離策略矫俺,但這種方式有幾個明顯的缺點:
線程數(shù)會隨著 API 接入數(shù)量遞增,1000 個 API 就需要 2 萬個線程掸冤,光線程切換對 CPU 就是不小的開銷厘托,而其線程還需要占用一定的內存資源;
平均分配線程池大小導致個別訪問量較大且響應時間相對較長的 API 吞吐量上不去稿湿;
Netty 本身就有工作線程池了铅匹,再增加 API 的線程池,導致某些需要 ThreadLocal 特性的編程變得困難饺藤。
二是用信號量隔離包斑,直接復用 Netty 的工作線程,上面線程池隔離提到的 3 個缺點都可以基本避免涕俗, 建議設置單個 API 的信號量個數(shù)小于等于 Netty 工作線程池數(shù)量的 1/3罗丰,這樣既兼顧了單個 API 的性能又不至于單個 API 的問題導致整個網(wǎng)關堵塞。
具體實現(xiàn)可以考慮直接引用成熟的開源框架再姑,推薦 Hystrix萌抵,可以同時解決超時控制和熔斷。
參考配置如下:
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey ))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
// 艙壁隔離策略 - 信號量
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
// 設置每組 command 可以申請的信號量最大數(shù)
.withExecutionIsolationSemaphoreMaxConcurrentRequests(CmptInvoker.maxSemaphore)
/* 開啟超時設置 */
.withExecutionIsolationThreadInterruptOnTimeout(true)
/* 超時時間設置 */
.withExecutionIsolationThreadTimeoutInMilliseconds(timeout)
.withCircuitBreakerEnabled(true)// 開啟熔斷
.withCircuitBreakerSleepWindowInMilliseconds(Constants.DEFAULT_CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS)// 5 秒后會嘗試閉合回路
- 2询刹、超時管控
API 的超時控制是必須要做的谜嫉,否則上游服務即便是間歇性響應緩慢也會堵塞大量線程(雖然通過信號量隔離后不會導致整個網(wǎng)關線程堵塞)。
其次凹联,每個 API 最好可以單獨配置超時時間沐兰,但不建議可以讓用戶隨意設置,還是要有個最大閾值蔽挠。(API 網(wǎng)關不適合需要長時間傳輸數(shù)據(jù)的場景住闯,比如大文件上傳或者下載、DB 數(shù)據(jù)同步等)
實現(xiàn)上可以直接復用開源組件的功能澳淑,比如:HttpClient 可以直接設置獲取連接和 Socket 響應的超時時間比原,Hystrix 可以對整個調用進行超時控制等。
- 3杠巡、熔斷
熔斷類似電路中的保險絲量窘,當超過負荷或者電阻被擊穿的時候自動斷開對設備起到保護作用。在 API 網(wǎng)關中設置熔斷的目的是快速響應請求氢拥,避免不必要的等待蚌铜,比如某個 API 后端服務正常情況下 1s 以內響應锨侯,但現(xiàn)在因為各種原因出現(xiàn)堵塞大部分請求 20s 才能響應,雖然設置了 10s 的超時控制冬殃,但讓請求線程等待 10s 超時不僅沒有意義囚痴,反而會增加服務提供方的負擔。
為此我們可以設置單位時間內超過多少比例的請求超時或者異常审葬,則直接熔斷鏈路深滚,等待一段時間后再次嘗試恢復鏈路。
實現(xiàn)層面可以直接復用 Hystrix涣觉。
運行時配置更新機制
前面章節(jié)提到過出于性能考慮網(wǎng)關在運行時要盡可能減小對 DB 的訪問痴荐,設計上可以將 API、組件等關鍵內容進行緩存旨枯,這樣一來性能是提升了蹬昌,但也帶來了新的問題,比如 Admin 對 API 或者組件進行配置調整后如何及時更新到集群的各個網(wǎng)關節(jié)點攀隔。
解決方案很多皂贩,比如引入消息中間件,當 Admin 調整配置后就往消息中心發(fā)布一條消息昆汹,各網(wǎng)關節(jié)點訂閱消息明刷,收到消息后刷新緩存數(shù)據(jù)。
我們在具體實現(xiàn)過程中采用的是 Zookeeper 集群數(shù)據(jù)同步機制满粗,其實現(xiàn)原理跟消息中間件很類似辈末,只不過網(wǎng)關在啟動的時候就會向 ZK 節(jié)點進行注冊,也是被動更新機制映皆。
性能考慮
性能是網(wǎng)關一項非常重要的衡量指標挤聘,尤其是響應時間,客戶端本來可以直連服務端的捅彻,現(xiàn)在增加了一個網(wǎng)關層组去,對于一個本身耗時幾百毫秒的服務接入網(wǎng)關后增加幾毫秒,影響倒是可以忽略不計步淹;但如果服務本身只需要幾毫秒从隆,因為接入網(wǎng)關再增加一倍的延時,用戶感受就會比較明顯缭裆。
建議在設計上需要遵循如下原則:
- 核心網(wǎng)關子系統(tǒng)必須是無狀態(tài)的键闺,便于橫向擴展。
- 運行時不依賴本地存儲澈驼,盡量在內存里面完成服務的處理和中轉辛燥。
- 減小對線程的依賴,采用非阻塞式 IO 和異步事件響應機制。
- 后端服務如果是 HTTP 協(xié)議挎塌,盡量采用連接池或者 Http2畅铭,測試連接復用和不復用性能有幾倍的差距。(TCP 建立連接成本很高)
附 -HttpClient 連接池設置:
PoolingHttpClientConnectionManager cmOfHttp = new PoolingHttpClientConnectionManager();
cmOfHttp.setMaxTotal(maxConn);
cmOfHttp.setDefaultMaxPerRoute(maxPerRoute);
httpClient = HttpClients.custom()
.setConnectionManager(cmOfHttp)
.setConnectionManagerShared(true)
.build();
說明:
httpClient 對象可以作為類的成員變量長期駐留內存勃蜘,這個是連接池復用的前提
結語
API 網(wǎng)關作為企業(yè) API 服務的匯聚中心,其良好的性能假残、穩(wěn)定性和可擴展性是基礎缭贡,只有這個基礎打扎實了,我們才能在上面擴展更多的特性辉懒。
這篇文章主要介紹網(wǎng)關的總體架構設計阳惹, 后面的篇幅在詳細探討下各種組件的具體設計和實現(xiàn)。
原網(wǎng)頁地址:http://www.infoq.com/cn/articles/api-gateway-archi...