zuul 2.1.2 原始碼 (TBC)
zuul 2.1.2 比zuul 1效能提高了4倍。
Handler
在 ZuulServerChannelInitializer 中初始化:
IdleStateHandler
CloseOnIdleStateHandler
... passport
PassportStateServerHandler
... tcp
SourceAddressChannelHandler
ServerChannelMetrics
PerEventLoopMetricsChannelHandler.Connections
ElbProxyProtocolChannelHandler(如果建構函式入參為false不執行此handler)
MaxInboundConnectionsHandler(屬於throttle,如果建構函式入參為0 ,不執行此handler)
... http1
HttpServerCodec屬於codec, netty自帶
Http1ConnectionCloseHandler (ChannelDuplexHandler)
Http1ConnectionExpiryHandler (outbound)
... http
PassportStateHttpServerHandler
HttpRequestReadTimeoutHandler(如果設定了httpRequestReadTimeout不為-1)
HttpServerLifecycleChannelHandler
HttpBodySizeRecordingChannelHandler
HttpMetricsChannelHandler
PerEventLoopMetricsChannelHandler.HttpRequests
AccessLogChannelHandler
ServerStatusHeaderHandler
StripUntrustedProxyHeadersHandler
... zuul handlers
有個rateLimitingChannelHandlerProvider的properties配置,不知道是哪個ChannelHandler?
LoggingHandler
ClientRequestReceiver
PassportLoggingHandler
ZuulFilterChainHandler 初始化一個Endpoint(endpoint指的是後面的服務),EndpointFilter初始化clientManager,是netty到後端服務的netty連線。
ClientResponseWriter
後端服務的連線 (endpoint)
每個Endpoint是一個Filter。
ProxyEndpoint 每個請求對應一個例項,但是重傳請求是相同的例項,因為有成員變數的狀態需要變更,比如重傳次數等。
客戶端
客戶端的管理在BasicNettyOrigin類中,它的建構函式初始化DefaultClientChannelManager,DefaultClientChannelManager建構函式初始化ConnectionPoolConfigImpl,它包含了Bootstrap的option的值,DefaultClientChannelManager還初始化ConcurrentHashMap<Server, PerServerConnectionPool> perServerPools
物件,它的值PerServerConnectionPool含有到該Server的所有連線。此外DefaultClientChannelManager還有各種計數器和計時器。
BasicNettyOrigin 建構函式呼叫DefaultClientChannelManager的init方法,初始化netty的DefaultOriginChannelInitializer類。
handler:
PassportStateOriginHandler(duplex)
SslHandler (如果要ssl的話)
HttpClientCodec (duplex)
PassportStateHttpClientHandler (duplex)
LoggingHandler (duplex, netty)
HttpMetricsChannelHandler (inbound)
HttpClientLifecycleChannelHandler (duplex)
ConnectionPoolHandler (duplex)
當傳送請求時:
ZuulEndPointRunner(BaseZuulFilterRunner)執行filter方法:
final HttpResponseMessage zuulResp = filter(endpoint, zuulReq);
syncFilter.apply(inMesg); // syncFilter即ProxyEndpoint
ProxyEndpoint執行proxyRequestToOrigin方法
private void proxyRequestToOrigin() {
Promise<PooledConnection> promise = null;
try {
attemptNum += 1;
requestStat = createRequestStat();
origin.preRequestChecks(zuulRequest);
concurrentReqCount++;
promise = origin.connectToOrigin(zuulRequest, channelCtx.channel().eventLoop(), attemptNum, passport, chosenServer);
logOriginServerIpAddr();
currentRequestAttempt = origin.newRequestAttempt(chosenServer.get(), context, attemptNum);
requestAttempts.add(currentRequestAttempt);
passport.add(PassportState.ORIGIN_CONN_ACQUIRE_START);
if (promise.isDone()) {
operationComplete(promise);
} else {
promise.addListener(this);
}
}
catch (Exception ex) {
LOG.error("Error while connecting to origin, UUID {} " + context.getUUID(), ex);
logOriginServerIpAddr();
if (promise != null && ! promise.isDone()) {
promise.setFailure(ex);
} else {
errorFromOrigin(ex);
}
}
}
上面的程式碼可總結成三步:
1)BasicNettyOrigin 的connectToOrigin方法獲取連線
2)ProxyEndpoint的operationComplete方法,呼叫自身的onOriginConnectSucceeded方法
3)onOriginConnectSucceeded呼叫自身的writeClientRequestToOrigin方法傳送資料:
private void writeClientRequestToOrigin(final PooledConnection conn) {
final Channel ch = conn.getChannel(); // ch 客戶端channel
passport.setOnChannel(ch);
context.set("_origin_channel", ch);
context.set(POOLED_ORIGIN_CONNECTION_KEY, conn);
// empty body
preWriteToOrigin(chosenServer.get(), context); // 空的
final ChannelPipeline pipeline = ch.pipeline();
originResponseReceiver = getOriginResponseReceiver(); // 獲取client inbound handler,用new 的方式,並且OriginResponseReceiver建構函式傳入ProxyEndpoint,即netty server的ctx。用這個ctx將後端服務發來的報傳送到server。
pipeline.addBefore("connectionPoolHandler", OriginResponseReceiver.CHANNEL_HANDLER_NAME, originResponseReceiver);
// check if body needs to be repopulated for retry
repopulateRetryBody();
ch.write(zuulRequest);
writeBufferedBodyContent(zuulRequest, ch);
ch.flush();
//Get ready to read origin's response
ch.read();
originConn = conn;
channelCtx.read(); // 從伺服器的channel讀取當前請求餘下的資料
}
至此完成將zuul的netty server的資料傳送到netty client。
接收後端服務的響應併發給前端
上面的函式中:
originResponseReceiver = getOriginResponseReceiver();
pipeline.addBefore("connectionPoolHandler", OriginResponseReceiver.CHANNEL_HANDLER_NAME, originResponseReceiver);
將OriginResponseReceiver,一個DuplexHandler動態載入到client的pipeline中。它的建構函式需要ProxyEndpoint,用來寫入到server。
TO BO CONTINUE