All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.zuul.netty.server.BaseServerStartup Maven / Gradle / Ivy

There is a newer version: 2.5.13
Show newest version
/*
 * Copyright 2018 Netflix, Inc.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

package com.netflix.zuul.netty.server;

import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.config.DynamicIntProperty;
import com.netflix.discovery.EurekaClient;
import com.netflix.netty.common.accesslog.AccessLogPublisher;
import com.netflix.netty.common.channel.config.ChannelConfig;
import com.netflix.netty.common.channel.config.ChannelConfigValue;
import com.netflix.netty.common.channel.config.CommonChannelConfigKeys;
import com.netflix.netty.common.metrics.EventLoopGroupMetrics;
import com.netflix.netty.common.proxyprotocol.StripUntrustedProxyHeadersHandler;
import com.netflix.netty.common.ssl.ServerSslConfig;
import com.netflix.netty.common.status.ServerStatusManager;
import com.netflix.servo.DefaultMonitorRegistry;
import com.netflix.servo.monitor.BasicCounter;
import com.netflix.servo.monitor.MonitorConfig;
import com.netflix.spectator.api.Registry;
import com.netflix.zuul.FilterLoader;
import com.netflix.zuul.FilterUsageNotifier;
import com.netflix.zuul.RequestCompleteHandler;
import com.netflix.zuul.context.SessionContextDecorator;
import com.netflix.zuul.netty.ratelimiting.NullChannelHandlerProvider;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.Map;

public abstract class BaseServerStartup
{
    protected static final Logger LOG = LoggerFactory.getLogger(BaseServerStartup.class);

    protected final ServerStatusManager serverStatusManager;
    protected final Registry registry;
    protected final DirectMemoryMonitor directMemoryMonitor;
    protected final EventLoopGroupMetrics eventLoopGroupMetrics;
    protected final EurekaClient discoveryClient;
    protected final ApplicationInfoManager applicationInfoManager;
    protected final AccessLogPublisher accessLogPublisher;
    protected final SessionContextDecorator sessionCtxDecorator;
    protected final RequestCompleteHandler reqCompleteHandler;
    protected final FilterLoader filterLoader;
    protected final FilterUsageNotifier usageNotifier;

    private Map portsToChannelInitializers;
    private ClientConnectionsShutdown clientConnectionsShutdown;
    private Server server;


    @Inject
    public BaseServerStartup(ServerStatusManager serverStatusManager, FilterLoader filterLoader,
                             SessionContextDecorator sessionCtxDecorator, FilterUsageNotifier usageNotifier,
                             RequestCompleteHandler reqCompleteHandler, Registry registry,
                             DirectMemoryMonitor directMemoryMonitor, EventLoopGroupMetrics eventLoopGroupMetrics,
                             EurekaClient discoveryClient, ApplicationInfoManager applicationInfoManager,
                             AccessLogPublisher accessLogPublisher)
    {
        this.serverStatusManager = serverStatusManager;
        this.registry = registry;
        this.directMemoryMonitor = directMemoryMonitor;
        this.eventLoopGroupMetrics = eventLoopGroupMetrics;
        this.discoveryClient = discoveryClient;
        this.applicationInfoManager = applicationInfoManager;
        this.accessLogPublisher = accessLogPublisher;
        this.sessionCtxDecorator = sessionCtxDecorator;
        this.reqCompleteHandler = reqCompleteHandler;
        this.filterLoader = filterLoader;
        this.usageNotifier = usageNotifier;
    }

    public Server server()
    {
        return server;
    }

    @PostConstruct
    public void init() throws Exception
    {
        ChannelConfig channelDeps = new ChannelConfig();
        addChannelDependencies(channelDeps);

        ChannelGroup clientChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        clientConnectionsShutdown = new ClientConnectionsShutdown(clientChannels,
                GlobalEventExecutor.INSTANCE, discoveryClient);

        portsToChannelInitializers = choosePortsAndChannels(clientChannels, channelDeps);

        server = new Server(portsToChannelInitializers, serverStatusManager, clientConnectionsShutdown, eventLoopGroupMetrics);
    }

    protected abstract Map choosePortsAndChannels(
            ChannelGroup clientChannels,
            ChannelConfig channelDependencies);

    protected void addChannelDependencies(ChannelConfig channelDeps) throws Exception
    {
        channelDeps.set(ZuulDependencyKeys.registry, registry);

        channelDeps.set(ZuulDependencyKeys.applicationInfoManager, applicationInfoManager);
        channelDeps.set(ZuulDependencyKeys.serverStatusManager, serverStatusManager);

        channelDeps.set(ZuulDependencyKeys.accessLogPublisher, accessLogPublisher);

        channelDeps.set(ZuulDependencyKeys.sessionCtxDecorator, sessionCtxDecorator);
        channelDeps.set(ZuulDependencyKeys.requestCompleteHandler, reqCompleteHandler);
        final BasicCounter httpRequestReadTimeoutCounter =  new BasicCounter(MonitorConfig.builder("server.http.request.read.timeout").build());
        DefaultMonitorRegistry.getInstance().register(httpRequestReadTimeoutCounter);
        channelDeps.set(ZuulDependencyKeys.httpRequestReadTimeoutCounter, httpRequestReadTimeoutCounter);
        channelDeps.set(ZuulDependencyKeys.filterLoader, filterLoader);
        channelDeps.set(ZuulDependencyKeys.filterUsageNotifier, usageNotifier);

        channelDeps.set(ZuulDependencyKeys.eventLoopGroupMetrics, eventLoopGroupMetrics);

        channelDeps.set(ZuulDependencyKeys.sslClientCertCheckChannelHandlerProvider, new NullChannelHandlerProvider());
        channelDeps.set(ZuulDependencyKeys.rateLimitingChannelHandlerProvider, new NullChannelHandlerProvider());

        directMemoryMonitor.init();
    }


    public static ChannelConfig defaultChannelConfig()
    {
        ChannelConfig config = new ChannelConfig();

        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxConnections,
                new DynamicIntProperty("server.connection.max", 20000).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxRequestsPerConnection,
                new DynamicIntProperty("server.connection.max.requests", 20000).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxRequestsPerConnectionInBrownout,
                new DynamicIntProperty("server.connection.max.requests.brownout", CommonChannelConfigKeys.maxRequestsPerConnectionInBrownout.defaultValue()).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.connectionExpiry,
                new DynamicIntProperty("server.connection.expiry", CommonChannelConfigKeys.connectionExpiry.defaultValue()).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.idleTimeout,
                new DynamicIntProperty("server.connection.idle.timeout", 65 * 1000).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.httpRequestReadTimeout,
                new DynamicIntProperty("server.http.request.read.timeout", 5000).get()));

        // For security, default to NEVER allowing XFF/Proxy headers from client.
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER));

        config.set(CommonChannelConfigKeys.withProxyProtocol, true);
        config.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);

        config.add(new ChannelConfigValue(CommonChannelConfigKeys.connCloseDelay,
                new DynamicIntProperty("zuul.server.connection.close.delay", 10).get()));

        return config;
    }

    public static void addHttp2DefaultConfig(ChannelConfig config) {
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxConcurrentStreams,
                new DynamicIntProperty("server.http2.max.concurrent.streams", CommonChannelConfigKeys.maxConcurrentStreams.defaultValue()).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.initialWindowSize,
                new DynamicIntProperty("server.http2.initialwindowsize", CommonChannelConfigKeys.initialWindowSize.defaultValue()).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxHttp2HeaderTableSize,
                new DynamicIntProperty("server.http2.maxheadertablesize", 65536).get()));
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxHttp2HeaderListSize,
                new DynamicIntProperty("server.http2.maxheaderlistsize", 32768).get()));

        // Override this to a lower value, as we'll be using ELB TCP listeners for h2, and therefore the connection
        // is direct from each device rather than shared in an ELB pool.
        config.add(new ChannelConfigValue(CommonChannelConfigKeys.maxRequestsPerConnection,
                new DynamicIntProperty("server.connection.max.requests", 4000).get()));
    }

    protected void logPortConfigured(int port, ServerSslConfig serverSslConfig)
    {
        String msg = "Configured port: " + port;
        if (serverSslConfig != null) {
            msg = msg + " with SSL config: " + serverSslConfig.toString();
        }
        LOG.warn(msg);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy