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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值