Search in sources :

Example 1 with ClientDetectionRequest

use of com.alibaba.nacos.api.remote.request.ClientDetectionRequest in project nacos by alibaba.

the class RpcClient method start.

/**
 * Start this client.
 */
public final void start() throws NacosException {
    boolean success = rpcClientStatus.compareAndSet(RpcClientStatus.INITIALIZED, RpcClientStatus.STARTING);
    if (!success) {
        return;
    }
    clientEventExecutor = new ScheduledThreadPoolExecutor(2, r -> {
        Thread t = new Thread(r);
        t.setName("com.alibaba.nacos.client.remote.worker");
        t.setDaemon(true);
        return t;
    });
    // connection event consumer.
    clientEventExecutor.submit(() -> {
        while (!clientEventExecutor.isTerminated() && !clientEventExecutor.isShutdown()) {
            ConnectionEvent take;
            try {
                take = eventLinkedBlockingQueue.take();
                if (take.isConnected()) {
                    notifyConnected();
                } else if (take.isDisConnected()) {
                    notifyDisConnected();
                }
            } catch (Throwable e) {
            // Do nothing
            }
        }
    });
    clientEventExecutor.submit(() -> {
        while (true) {
            try {
                if (isShutdown()) {
                    break;
                }
                ReconnectContext reconnectContext = reconnectionSignal.poll(keepAliveTime, TimeUnit.MILLISECONDS);
                if (reconnectContext == null) {
                    // check alive time.
                    if (System.currentTimeMillis() - lastActiveTimeStamp >= keepAliveTime) {
                        boolean isHealthy = healthCheck();
                        if (!isHealthy) {
                            if (currentConnection == null) {
                                continue;
                            }
                            LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Server healthy check fail, currentConnection = {}", name, currentConnection.getConnectionId());
                            RpcClientStatus rpcClientStatus = RpcClient.this.rpcClientStatus.get();
                            if (RpcClientStatus.SHUTDOWN.equals(rpcClientStatus)) {
                                break;
                            }
                            boolean statusFLowSuccess = RpcClient.this.rpcClientStatus.compareAndSet(rpcClientStatus, RpcClientStatus.UNHEALTHY);
                            if (statusFLowSuccess) {
                                reconnectContext = new ReconnectContext(null, false);
                            } else {
                                continue;
                            }
                        } else {
                            lastActiveTimeStamp = System.currentTimeMillis();
                            continue;
                        }
                    } else {
                        continue;
                    }
                }
                if (reconnectContext.serverInfo != null) {
                    // clear recommend server if server is not in server list.
                    boolean serverExist = false;
                    for (String server : getServerListFactory().getServerList()) {
                        ServerInfo serverInfo = resolveServerInfo(server);
                        if (serverInfo.getServerIp().equals(reconnectContext.serverInfo.getServerIp())) {
                            serverExist = true;
                            reconnectContext.serverInfo.serverPort = serverInfo.serverPort;
                            break;
                        }
                    }
                    if (!serverExist) {
                        LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Recommend server is not in server list, ignore recommend server {}", name, reconnectContext.serverInfo.getAddress());
                        reconnectContext.serverInfo = null;
                    }
                }
                reconnect(reconnectContext.serverInfo, reconnectContext.onRequestFail);
            } catch (Throwable throwable) {
            // Do nothing
            }
        }
    });
    // connect to server, try to connect to server sync RETRY_TIMES times, async starting if failed.
    Connection connectToServer = null;
    rpcClientStatus.set(RpcClientStatus.STARTING);
    int startUpRetryTimes = RETRY_TIMES;
    while (startUpRetryTimes > 0 && connectToServer == null) {
        try {
            startUpRetryTimes--;
            ServerInfo serverInfo = nextRpcServer();
            LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to connect to server on start up, server: {}", name, serverInfo);
            connectToServer = connectToServer(serverInfo);
        } catch (Throwable e) {
            LoggerUtils.printIfWarnEnabled(LOGGER, "[{}] Fail to connect to server on start up, error message = {}, start up retry times left: {}", name, e.getMessage(), startUpRetryTimes);
        }
    }
    if (connectToServer != null) {
        LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect to server [{}] on start up, connectionId = {}", name, connectToServer.serverInfo.getAddress(), connectToServer.getConnectionId());
        this.currentConnection = connectToServer;
        rpcClientStatus.set(RpcClientStatus.RUNNING);
        eventLinkedBlockingQueue.offer(new ConnectionEvent(ConnectionEvent.CONNECTED));
    } else {
        switchServerAsync();
    }
    registerServerRequestHandler(new ConnectResetRequestHandler());
    // register client detection request.
    registerServerRequestHandler(request -> {
        if (request instanceof ClientDetectionRequest) {
            return new ClientDetectionResponse();
        }
        return null;
    });
}
Also used : ConnectionType(com.alibaba.nacos.common.remote.ConnectionType) Closeable(com.alibaba.nacos.common.lifecycle.Closeable) LoggerUtils(com.alibaba.nacos.common.utils.LoggerUtils) ClientAbilities(com.alibaba.nacos.api.ability.ClientAbilities) LoggerFactory(org.slf4j.LoggerFactory) SERVER_ERROR(com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR) HashMap(java.util.HashMap) RequestCallBack(com.alibaba.nacos.api.remote.RequestCallBack) Request(com.alibaba.nacos.api.remote.request.Request) AtomicReference(java.util.concurrent.atomic.AtomicReference) RequestFuture(com.alibaba.nacos.api.remote.RequestFuture) ArrayList(java.util.ArrayList) NumberUtils(com.alibaba.nacos.common.utils.NumberUtils) ConnectResetResponse(com.alibaba.nacos.api.remote.response.ConnectResetResponse) Matcher(java.util.regex.Matcher) Map(java.util.Map) NacosException(com.alibaba.nacos.api.exception.NacosException) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) CollectionUtils(com.alibaba.nacos.common.utils.CollectionUtils) ClientDetectionRequest(com.alibaba.nacos.api.remote.request.ClientDetectionRequest) Response(com.alibaba.nacos.api.remote.response.Response) Logger(org.slf4j.Logger) ClientDetectionResponse(com.alibaba.nacos.api.remote.response.ClientDetectionResponse) HealthCheckRequest(com.alibaba.nacos.api.remote.request.HealthCheckRequest) BlockingQueue(java.util.concurrent.BlockingQueue) ScheduledThreadPoolExecutor(java.util.concurrent.ScheduledThreadPoolExecutor) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) ConnectResetRequest(com.alibaba.nacos.api.remote.request.ConnectResetRequest) TimeUnit(java.util.concurrent.TimeUnit) PayloadRegistry(com.alibaba.nacos.common.remote.PayloadRegistry) ArrayBlockingQueue(java.util.concurrent.ArrayBlockingQueue) List(java.util.List) Constants(com.alibaba.nacos.api.common.Constants) ErrorResponse(com.alibaba.nacos.api.remote.response.ErrorResponse) StringUtils(com.alibaba.nacos.common.utils.StringUtils) Pattern(java.util.regex.Pattern) ClientDetectionRequest(com.alibaba.nacos.api.remote.request.ClientDetectionRequest) ScheduledThreadPoolExecutor(java.util.concurrent.ScheduledThreadPoolExecutor) ClientDetectionResponse(com.alibaba.nacos.api.remote.response.ClientDetectionResponse)

Example 2 with ClientDetectionRequest

use of com.alibaba.nacos.api.remote.request.ClientDetectionRequest in project nacos by alibaba.

the class ConnectionManager method start.

/**
 * Start Task:Expel the connection which active Time expire.
 */
@PostConstruct
public void start() {
    // Start UnHealthy Connection Expel Task.
    RpcScheduledExecutor.COMMON_SERVER_EXECUTOR.scheduleWithFixedDelay(new Runnable() {

        @Override
        public void run() {
            try {
                int totalCount = connections.size();
                Loggers.REMOTE_DIGEST.info("Connection check task start");
                MetricsMonitor.getLongConnectionMonitor().set(totalCount);
                Set<Map.Entry<String, Connection>> entries = connections.entrySet();
                int currentSdkClientCount = currentSdkClientCount();
                boolean isLoaderClient = loadClient >= 0;
                int currentMaxClient = isLoaderClient ? loadClient : connectionLimitRule.countLimit;
                int expelCount = currentMaxClient < 0 ? 0 : Math.max(currentSdkClientCount - currentMaxClient, 0);
                Loggers.REMOTE_DIGEST.info("Total count ={}, sdkCount={},clusterCount={}, currentLimit={}, toExpelCount={}", totalCount, currentSdkClientCount, (totalCount - currentSdkClientCount), currentMaxClient + (isLoaderClient ? "(loaderCount)" : ""), expelCount);
                List<String> expelClient = new LinkedList<>();
                Map<String, AtomicInteger> expelForIp = new HashMap<>(16);
                // 1. calculate expel count  of ip.
                for (Map.Entry<String, Connection> entry : entries) {
                    Connection client = entry.getValue();
                    String appName = client.getMetaInfo().getAppName();
                    String clientIp = client.getMetaInfo().getClientIp();
                    if (client.getMetaInfo().isSdkSource() && !expelForIp.containsKey(clientIp)) {
                        // get limit for current ip.
                        int countLimitOfIp = connectionLimitRule.getCountLimitOfIp(clientIp);
                        if (countLimitOfIp < 0) {
                            int countLimitOfApp = connectionLimitRule.getCountLimitOfApp(appName);
                            countLimitOfIp = countLimitOfApp < 0 ? countLimitOfIp : countLimitOfApp;
                        }
                        if (countLimitOfIp < 0) {
                            countLimitOfIp = connectionLimitRule.getCountLimitPerClientIpDefault();
                        }
                        if (countLimitOfIp >= 0 && connectionForClientIp.containsKey(clientIp)) {
                            AtomicInteger currentCountIp = connectionForClientIp.get(clientIp);
                            if (currentCountIp != null && currentCountIp.get() > countLimitOfIp) {
                                expelForIp.put(clientIp, new AtomicInteger(currentCountIp.get() - countLimitOfIp));
                            }
                        }
                    }
                }
                Loggers.REMOTE_DIGEST.info("Check over limit for ip limit rule, over limit ip count={}", expelForIp.size());
                if (expelForIp.size() > 0) {
                    Loggers.REMOTE_DIGEST.info("Over limit ip expel info, {}", expelForIp);
                }
                Set<String> outDatedConnections = new HashSet<>();
                long now = System.currentTimeMillis();
                // 2.get expel connection for ip limit.
                for (Map.Entry<String, Connection> entry : entries) {
                    Connection client = entry.getValue();
                    String clientIp = client.getMetaInfo().getClientIp();
                    AtomicInteger integer = expelForIp.get(clientIp);
                    if (integer != null && integer.intValue() > 0) {
                        integer.decrementAndGet();
                        expelClient.add(client.getMetaInfo().getConnectionId());
                        expelCount--;
                    } else if (now - client.getMetaInfo().getLastActiveTime() >= KEEP_ALIVE_TIME) {
                        outDatedConnections.add(client.getMetaInfo().getConnectionId());
                    }
                }
                // 3. if total count is still over limit.
                if (expelCount > 0) {
                    for (Map.Entry<String, Connection> entry : entries) {
                        Connection client = entry.getValue();
                        if (!expelForIp.containsKey(client.getMetaInfo().clientIp) && client.getMetaInfo().isSdkSource() && expelCount > 0) {
                            expelClient.add(client.getMetaInfo().getConnectionId());
                            expelCount--;
                            outDatedConnections.remove(client.getMetaInfo().getConnectionId());
                        }
                    }
                }
                String serverIp = null;
                String serverPort = null;
                if (StringUtils.isNotBlank(redirectAddress) && redirectAddress.contains(Constants.COLON)) {
                    String[] split = redirectAddress.split(Constants.COLON);
                    serverIp = split[0];
                    serverPort = split[1];
                }
                for (String expelledClientId : expelClient) {
                    try {
                        Connection connection = getConnection(expelledClientId);
                        if (connection != null) {
                            ConnectResetRequest connectResetRequest = new ConnectResetRequest();
                            connectResetRequest.setServerIp(serverIp);
                            connectResetRequest.setServerPort(serverPort);
                            connection.asyncRequest(connectResetRequest, null);
                            Loggers.REMOTE_DIGEST.info("Send connection reset request , connection id = {},recommendServerIp={}, recommendServerPort={}", expelledClientId, connectResetRequest.getServerIp(), connectResetRequest.getServerPort());
                        }
                    } catch (ConnectionAlreadyClosedException e) {
                        unregister(expelledClientId);
                    } catch (Exception e) {
                        Loggers.REMOTE_DIGEST.error("Error occurs when expel connection, expelledClientId:{}", expelledClientId, e);
                    }
                }
                // 4.client active detection.
                Loggers.REMOTE_DIGEST.info("Out dated connection ,size={}", outDatedConnections.size());
                if (CollectionUtils.isNotEmpty(outDatedConnections)) {
                    Set<String> successConnections = new HashSet<>();
                    final CountDownLatch latch = new CountDownLatch(outDatedConnections.size());
                    for (String outDateConnectionId : outDatedConnections) {
                        try {
                            Connection connection = getConnection(outDateConnectionId);
                            if (connection != null) {
                                ClientDetectionRequest clientDetectionRequest = new ClientDetectionRequest();
                                connection.asyncRequest(clientDetectionRequest, new RequestCallBack() {

                                    @Override
                                    public Executor getExecutor() {
                                        return null;
                                    }

                                    @Override
                                    public long getTimeout() {
                                        return 1000L;
                                    }

                                    @Override
                                    public void onResponse(Response response) {
                                        latch.countDown();
                                        if (response != null && response.isSuccess()) {
                                            connection.freshActiveTime();
                                            successConnections.add(outDateConnectionId);
                                        }
                                    }

                                    @Override
                                    public void onException(Throwable e) {
                                        latch.countDown();
                                    }
                                });
                                Loggers.REMOTE_DIGEST.info("[{}]send connection active request ", outDateConnectionId);
                            } else {
                                latch.countDown();
                            }
                        } catch (ConnectionAlreadyClosedException e) {
                            latch.countDown();
                        } catch (Exception e) {
                            Loggers.REMOTE_DIGEST.error("[{}]Error occurs when check client active detection ,error={}", outDateConnectionId, e);
                            latch.countDown();
                        }
                    }
                    latch.await(3000L, TimeUnit.MILLISECONDS);
                    Loggers.REMOTE_DIGEST.info("Out dated connection check successCount={}", successConnections.size());
                    for (String outDateConnectionId : outDatedConnections) {
                        if (!successConnections.contains(outDateConnectionId)) {
                            Loggers.REMOTE_DIGEST.info("[{}]Unregister Out dated connection....", outDateConnectionId);
                            unregister(outDateConnectionId);
                        }
                    }
                }
                if (isLoaderClient) {
                    loadClient = -1;
                    redirectAddress = null;
                }
                Loggers.REMOTE_DIGEST.info("Connection check task end");
            } catch (Throwable e) {
                Loggers.REMOTE.error("Error occurs during connection check... ", e);
            }
        }
    }, 1000L, 3000L, TimeUnit.MILLISECONDS);
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) ConnectionAlreadyClosedException(com.alibaba.nacos.common.remote.exception.ConnectionAlreadyClosedException) ClientDetectionRequest(com.alibaba.nacos.api.remote.request.ClientDetectionRequest) RequestCallBack(com.alibaba.nacos.api.remote.RequestCallBack) CountDownLatch(java.util.concurrent.CountDownLatch) ConnectResetRequest(com.alibaba.nacos.api.remote.request.ConnectResetRequest) ConnectionAlreadyClosedException(com.alibaba.nacos.common.remote.exception.ConnectionAlreadyClosedException) NacosException(com.alibaba.nacos.api.exception.NacosException) IOException(java.io.IOException) Response(com.alibaba.nacos.api.remote.response.Response) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) PostConstruct(javax.annotation.PostConstruct)

Aggregations

NacosException (com.alibaba.nacos.api.exception.NacosException)2 RequestCallBack (com.alibaba.nacos.api.remote.RequestCallBack)2 ClientDetectionRequest (com.alibaba.nacos.api.remote.request.ClientDetectionRequest)2 ConnectResetRequest (com.alibaba.nacos.api.remote.request.ConnectResetRequest)2 Response (com.alibaba.nacos.api.remote.response.Response)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 ClientAbilities (com.alibaba.nacos.api.ability.ClientAbilities)1 Constants (com.alibaba.nacos.api.common.Constants)1 SERVER_ERROR (com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR)1 RequestFuture (com.alibaba.nacos.api.remote.RequestFuture)1 HealthCheckRequest (com.alibaba.nacos.api.remote.request.HealthCheckRequest)1 Request (com.alibaba.nacos.api.remote.request.Request)1 ClientDetectionResponse (com.alibaba.nacos.api.remote.response.ClientDetectionResponse)1 ConnectResetResponse (com.alibaba.nacos.api.remote.response.ConnectResetResponse)1 ErrorResponse (com.alibaba.nacos.api.remote.response.ErrorResponse)1 Closeable (com.alibaba.nacos.common.lifecycle.Closeable)1 ConnectionType (com.alibaba.nacos.common.remote.ConnectionType)1