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

org.apache.eventmesh.runtime.boot.EventMeshTCPServer Maven / Gradle / Ivy

There is a newer version: 1.10.0-release
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.eventmesh.runtime.boot;

import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo;
import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo;
import org.apache.eventmesh.common.ThreadPoolFactory;
import org.apache.eventmesh.common.exception.EventMeshException;
import org.apache.eventmesh.common.protocol.tcp.codec.Codec;
import org.apache.eventmesh.common.utils.ConfigurationContextUtil;
import org.apache.eventmesh.common.utils.IPUtils;
import org.apache.eventmesh.metrics.api.MetricsPluginFactory;
import org.apache.eventmesh.metrics.api.MetricsRegistry;
import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration;
import org.apache.eventmesh.runtime.constants.EventMeshConstants;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpConnectionHandler;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpExceptionHandler;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpMessageDispatcher;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance.EventMeshRebalanceService;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance.EventmeshRebalanceImpl;
import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.EventMeshTcpRetryer;
import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMonitor;
import org.apache.eventmesh.runtime.registry.Registry;
import org.apache.eventmesh.runtime.util.EventMeshThreadFactoryImpl;
import org.apache.eventmesh.webhook.admin.AdminWebHookConfigOperationManage;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;

import org.assertj.core.util.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.traffic.ChannelTrafficShapingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;

import com.google.common.util.concurrent.RateLimiter;


public class EventMeshTCPServer extends AbstractRemotingServer {
    private static final Logger LOGGER = LoggerFactory.getLogger(EventMeshTCPServer.class);

    private ClientSessionGroupMapping clientSessionGroupMapping;

    private transient EventMeshTcpRetryer eventMeshTcpRetryer;

    private transient EventMeshTcpMonitor eventMeshTcpMonitor;

    private final transient EventMeshServer eventMeshServer;

    private final transient EventMeshTCPConfiguration eventMeshTCPConfiguration;

    private transient GlobalTrafficShapingHandler globalTrafficShapingHandler;

    private transient ScheduledExecutorService scheduler;

    private transient ExecutorService taskHandleExecutorService;

    private transient ExecutorService broadcastMsgDownstreamExecutorService;

    private final transient Registry registry;

    private transient EventMeshRebalanceService eventMeshRebalanceService;

    private transient AdminWebHookConfigOperationManage adminWebHookConfigOperationManage;

    private transient RateLimiter rateLimiter;

    public void setClientSessionGroupMapping(final ClientSessionGroupMapping clientSessionGroupMapping) {
        this.clientSessionGroupMapping = clientSessionGroupMapping;
    }

    public ScheduledExecutorService getScheduler() {
        return scheduler;
    }

    public void setScheduler(final ScheduledExecutorService scheduler) {
        this.scheduler = scheduler;
    }

    public ExecutorService getTaskHandleExecutorService() {
        return taskHandleExecutorService;
    }

    public ExecutorService getBroadcastMsgDownstreamExecutorService() {
        return broadcastMsgDownstreamExecutorService;
    }

    public void setTaskHandleExecutorService(final ExecutorService taskHandleExecutorService) {
        this.taskHandleExecutorService = taskHandleExecutorService;
    }

    public RateLimiter getRateLimiter() {
        return rateLimiter;
    }

    public void setRateLimiter(final RateLimiter rateLimiter) {
        this.rateLimiter = rateLimiter;
    }


    public EventMeshTCPServer(final EventMeshServer eventMeshServer,
                              final EventMeshTCPConfiguration eventMeshTCPConfiguration, final Registry registry) {
        super();
        this.eventMeshServer = eventMeshServer;
        this.eventMeshTCPConfiguration = eventMeshTCPConfiguration;
        this.registry = registry;
    }

    private void startServer() {
        Runnable r = () -> {
            ServerBootstrap bootstrap = new ServerBootstrap();
            ChannelInitializer channelInitializer = new ChannelInitializer() {
                @Override
                public void initChannel(final Channel ch) throws Exception {
                    ch.pipeline()
                            .addLast(new Codec.Encoder())
                            .addLast(new Codec.Decoder())
                            .addLast("global-traffic-shaping", globalTrafficShapingHandler)
                            .addLast("channel-traffic-shaping", newCTSHandler(eventMeshTCPConfiguration.getCtc().getReadLimit()))
                            .addLast(new EventMeshTcpConnectionHandler(EventMeshTCPServer.this))
                            .addLast(
                                    getWorkerGroup(),
                                    new IdleStateHandler(
                                            eventMeshTCPConfiguration.eventMeshTcpIdleReadSeconds,
                                            eventMeshTCPConfiguration.eventMeshTcpIdleWriteSeconds,
                                            eventMeshTCPConfiguration.eventMeshTcpIdleAllSeconds),
                                    new EventMeshTcpMessageDispatcher(EventMeshTCPServer.this),
                                    new EventMeshTcpExceptionHandler(EventMeshTCPServer.this)
                            );
                }
            };

            bootstrap.group(this.getBossGroup(), this.getIoGroup())
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000)
                    .childOption(ChannelOption.SO_KEEPALIVE, false)
                    .childOption(ChannelOption.SO_LINGER, 0)
                    .childOption(ChannelOption.SO_TIMEOUT, 600_000)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_SNDBUF, 65_535 * 4)
                    .childOption(ChannelOption.SO_RCVBUF, 65_535 * 4)
                    .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(2_048, 4_096, 65_536))
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childHandler(channelInitializer);

            try {
                int port = eventMeshTCPConfiguration.eventMeshTcpServerPort;
                ChannelFuture f = bootstrap.bind(port).sync();
                LOGGER.info("EventMeshTCPServer[port={}] started.....", port);
                f.channel().closeFuture().sync();
            } catch (Exception e) {
                LOGGER.error("EventMeshTCPServer RemotingServer Start Err!", e);
                try {
                    shutdown();
                } catch (Exception ex) {
                    LOGGER.error("EventMeshTCPServer RemotingServer shutdown Err!", ex);
                }
            }
        };

        Thread t = new Thread(r, "eventMesh-tcp-server");
        t.start();
    }

    public void init() throws Exception {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("==================EventMeshTCPServer Initialing==================");
        }
        initThreadPool();

        rateLimiter = RateLimiter.create(eventMeshTCPConfiguration.eventMeshTcpMsgReqnumPerSecond);

        globalTrafficShapingHandler = newGTSHandler(scheduler, eventMeshTCPConfiguration.getGtc().getReadLimit());


        adminWebHookConfigOperationManage = new AdminWebHookConfigOperationManage();
        adminWebHookConfigOperationManage.setConfigurationWrapper(eventMeshTCPConfiguration.getConfigurationWrapper());
        adminWebHookConfigOperationManage.init();


        clientSessionGroupMapping = new ClientSessionGroupMapping(this);
        clientSessionGroupMapping.init();

        eventMeshTcpRetryer = new EventMeshTcpRetryer(this);
        eventMeshTcpRetryer.init();

        // The MetricsRegistry is singleton, so we can use factory method to get.
        final List metricsRegistries = Lists.newArrayList();
        Optional.ofNullable(eventMeshTCPConfiguration.getEventMeshMetricsPluginType())
                .ifPresent(
                        metricsPlugins -> metricsPlugins.forEach(
                                pluginType -> metricsRegistries.add(MetricsPluginFactory.getMetricsRegistry(pluginType))));
        eventMeshTcpMonitor = new EventMeshTcpMonitor(this, metricsRegistries);
        eventMeshTcpMonitor.init();

        if (eventMeshTCPConfiguration.isEventMeshServerRegistryEnable()) {
            eventMeshRebalanceService = new EventMeshRebalanceService(this,
                    new EventmeshRebalanceImpl(this));
            eventMeshRebalanceService.init();
        }

        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("--------------------------EventMeshTCPServer Inited");
        }
    }

    @Override
    public void start() throws Exception {
        startServer();

        clientSessionGroupMapping.start();

        eventMeshTcpRetryer.start();

        eventMeshTcpMonitor.start();

        if (eventMeshTCPConfiguration.isEventMeshServerRegistryEnable()) {
            this.register();
            eventMeshRebalanceService.start();
        }

        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("--------------------------EventMeshTCPServer Started");
        }
    }

    @Override
    public void shutdown() throws Exception {
        if (this.getBossGroup() != null) {
            this.getBossGroup().shutdownGracefully();
            LOGGER.info("shutdown bossGroup, no client is allowed to connect access server");
        }

        if (eventMeshTCPConfiguration.isEventMeshServerRegistryEnable()) {
            eventMeshRebalanceService.shutdown();

            this.unRegister();
        }

        clientSessionGroupMapping.shutdown();
        try {
            Thread.sleep(40 * 1000);
        } catch (InterruptedException e) {
            LOGGER.error("interruptedException occurred while sleeping", e);
        }

        globalTrafficShapingHandler.release();

        if (this.getIoGroup() != null) {
            this.getIoGroup().shutdownGracefully();
            LOGGER.info("shutdown ioGroup");
        }
        if (this.getWorkerGroup() != null) {
            this.getWorkerGroup().shutdownGracefully();
            LOGGER.info("shutdown workerGroup");
        }

        eventMeshTcpRetryer.shutdown();

        eventMeshTcpMonitor.shutdown();

        shutdownThreadPool();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("--------------------------EventMeshTCPServer Shutdown");
        }
    }

    public boolean register() {
        boolean registerResult = false;
        try {
            String endPoints = IPUtils.getLocalAddress()
                    + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshTCPConfiguration.eventMeshTcpServerPort;
            EventMeshRegisterInfo eventMeshRegisterInfo = new EventMeshRegisterInfo();
            eventMeshRegisterInfo.setEventMeshClusterName(eventMeshTCPConfiguration.getEventMeshCluster());
            eventMeshRegisterInfo.setEventMeshName(eventMeshTCPConfiguration.getEventMeshName() + "-"
                    + ConfigurationContextUtil.TCP);
            eventMeshRegisterInfo.setEndPoint(endPoints);
            eventMeshRegisterInfo.setEventMeshInstanceNumMap(clientSessionGroupMapping.prepareProxyClientDistributionData());
            eventMeshRegisterInfo.setProtocolType(ConfigurationContextUtil.TCP);
            registerResult = registry.register(eventMeshRegisterInfo);
        } catch (Exception e) {
            LOGGER.error("eventMesh register to registry failed", e);
        }

        return registerResult;
    }

    private void unRegister() throws Exception {
        String endPoints = IPUtils.getLocalAddress()
                + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshTCPConfiguration.eventMeshTcpServerPort;
        EventMeshUnRegisterInfo eventMeshUnRegisterInfo = new EventMeshUnRegisterInfo();
        eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshTCPConfiguration.getEventMeshCluster());
        eventMeshUnRegisterInfo.setEventMeshName(eventMeshTCPConfiguration.getEventMeshName());
        eventMeshUnRegisterInfo.setEndPoint(endPoints);
        eventMeshUnRegisterInfo.setProtocolType(ConfigurationContextUtil.TCP);
        boolean registerResult = registry.unRegister(eventMeshUnRegisterInfo);
        if (!registerResult) {
            throw new EventMeshException("eventMesh fail to unRegister");
        }
    }

    private void initThreadPool() throws Exception {
        super.init("eventMesh-tcp");

        scheduler = ThreadPoolFactory.createScheduledExecutor(eventMeshTCPConfiguration.eventMeshTcpGlobalScheduler,
                new EventMeshThreadFactoryImpl("eventMesh-tcp-scheduler", true));

        taskHandleExecutorService = ThreadPoolFactory.createThreadPoolExecutor(
                eventMeshTCPConfiguration.eventMeshTcpTaskHandleExecutorPoolSize,
                eventMeshTCPConfiguration.eventMeshTcpTaskHandleExecutorPoolSize,
                new LinkedBlockingQueue<>(10_000),
                new EventMeshThreadFactoryImpl("eventMesh-tcp-task-handle", true));

        broadcastMsgDownstreamExecutorService = ThreadPoolFactory.createThreadPoolExecutor(
                eventMeshTCPConfiguration.eventMeshTcpMsgDownStreamExecutorPoolSize,
                eventMeshTCPConfiguration.eventMeshTcpMsgDownStreamExecutorPoolSize,
                new LinkedBlockingQueue<>(10_000),
                new EventMeshThreadFactoryImpl("eventMesh-tcp-msg-downstream", true));
    }

    private void shutdownThreadPool() {
        scheduler.shutdown();
        taskHandleExecutorService.shutdown();
    }

    private GlobalTrafficShapingHandler newGTSHandler(final ScheduledExecutorService executor, final long readLimit) {
        GlobalTrafficShapingHandler handler = new GlobalTrafficShapingHandler(executor, 0,
                readLimit) {
            @Override
            protected long calculateSize(final Object msg) {
                return 1;
            }
        };
        handler.setMaxTimeWait(1_000);
        return handler;
    }

    private ChannelTrafficShapingHandler newCTSHandler(final long readLimit) {
        ChannelTrafficShapingHandler handler = new ChannelTrafficShapingHandler(0, readLimit) {
            @Override
            protected long calculateSize(final Object msg) {
                return 1;
            }
        };
        handler.setMaxTimeWait(3_000);
        return handler;
    }

    public ClientSessionGroupMapping getClientSessionGroupMapping() {
        return clientSessionGroupMapping;
    }

    public EventMeshTcpRetryer getEventMeshTcpRetryer() {
        return eventMeshTcpRetryer;
    }

    public EventMeshTcpMonitor getEventMeshTcpMonitor() {
        return eventMeshTcpMonitor;
    }

    public EventMeshServer getEventMeshServer() {
        return eventMeshServer;
    }

    public EventMeshTCPConfiguration getEventMeshTCPConfiguration() {
        return eventMeshTCPConfiguration;
    }

    public Registry getRegistry() {
        return registry;
    }

    public EventMeshRebalanceService getEventMeshRebalanceService() {
        return eventMeshRebalanceService;
    }

    public AdminWebHookConfigOperationManage getAdminWebHookConfigOperationManage() {
        return adminWebHookConfigOperationManage;
    }

    public void setAdminWebHookConfigOperationManage(AdminWebHookConfigOperationManage adminWebHookConfigOperationManage) {
        this.adminWebHookConfigOperationManage = adminWebHookConfigOperationManage;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy