Search in sources :

Example 1 with ConnectResetRequest

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

the class ConnectionManager method loadSingle.

/**
 * send load request to spefic connetionId.
 *
 * @param connectionId    connection id of client.
 * @param redirectAddress server address to redirect.
 */
public void loadSingle(String connectionId, String redirectAddress) {
    Connection connection = getConnection(connectionId);
    if (connection != null) {
        if (connection.getMetaInfo().isSdkSource()) {
            ConnectResetRequest connectResetRequest = new ConnectResetRequest();
            if (StringUtils.isNotBlank(redirectAddress) && redirectAddress.contains(Constants.COLON)) {
                String[] split = redirectAddress.split(Constants.COLON);
                connectResetRequest.setServerIp(split[0]);
                connectResetRequest.setServerPort(split[1]);
            }
            try {
                connection.request(connectResetRequest, 3000L);
            } catch (ConnectionAlreadyClosedException e) {
                unregister(connectionId);
            } catch (Exception e) {
                Loggers.REMOTE.error("error occurs when expel connection, connectionId: {} ", connectionId, e);
            }
        }
    }
}
Also used : ConnectionAlreadyClosedException(com.alibaba.nacos.common.remote.exception.ConnectionAlreadyClosedException) 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)

Example 2 with ConnectResetRequest

use of com.alibaba.nacos.api.remote.request.ConnectResetRequest 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)

Example 3 with ConnectResetRequest

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

the class GrpcBiStreamRequestAcceptor method requestBiStream.

@Override
public StreamObserver<Payload> requestBiStream(StreamObserver<Payload> responseObserver) {
    StreamObserver<Payload> streamObserver = new StreamObserver<Payload>() {

        final String connectionId = CONTEXT_KEY_CONN_ID.get();

        final Integer localPort = CONTEXT_KEY_CONN_LOCAL_PORT.get();

        final int remotePort = CONTEXT_KEY_CONN_REMOTE_PORT.get();

        String remoteIp = CONTEXT_KEY_CONN_REMOTE_IP.get();

        String clientIp = "";

        @Override
        public void onNext(Payload payload) {
            clientIp = payload.getMetadata().getClientIp();
            traceDetailIfNecessary(payload);
            Object parseObj;
            try {
                parseObj = GrpcUtils.parse(payload);
            } catch (Throwable throwable) {
                Loggers.REMOTE_DIGEST.warn("[{}]Grpc request bi stream,payload parse error={}", connectionId, throwable);
                return;
            }
            if (parseObj == null) {
                Loggers.REMOTE_DIGEST.warn("[{}]Grpc request bi stream,payload parse null ,body={},meta={}", connectionId, payload.getBody().getValue().toStringUtf8(), payload.getMetadata());
                return;
            }
            if (parseObj instanceof ConnectionSetupRequest) {
                ConnectionSetupRequest setUpRequest = (ConnectionSetupRequest) parseObj;
                Map<String, String> labels = setUpRequest.getLabels();
                String appName = "-";
                if (labels != null && labels.containsKey(Constants.APPNAME)) {
                    appName = labels.get(Constants.APPNAME);
                }
                ConnectionMeta metaInfo = new ConnectionMeta(connectionId, payload.getMetadata().getClientIp(), remoteIp, remotePort, localPort, ConnectionType.GRPC.getType(), setUpRequest.getClientVersion(), appName, setUpRequest.getLabels());
                metaInfo.setTenant(setUpRequest.getTenant());
                Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get());
                connection.setAbilities(setUpRequest.getAbilities());
                boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted();
                if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) {
                    // Not register to the connection manager if current server is over limit or server is starting.
                    try {
                        Loggers.REMOTE_DIGEST.warn("[{}]Connection register fail,reason:{}", connectionId, rejectSdkOnStarting ? " server is not started" : " server is over limited.");
                        connection.request(new ConnectResetRequest(), 3000L);
                        connection.close();
                    } catch (Exception e) {
                        // Do nothing.
                        if (connectionManager.traced(clientIp)) {
                            Loggers.REMOTE_DIGEST.warn("[{}]Send connect reset request error,error={}", connectionId, e);
                        }
                    }
                }
            } else if (parseObj instanceof Response) {
                Response response = (Response) parseObj;
                if (connectionManager.traced(clientIp)) {
                    Loggers.REMOTE_DIGEST.warn("[{}]Receive response of server request  ,response={}", connectionId, response);
                }
                RpcAckCallbackSynchronizer.ackNotify(connectionId, response);
                connectionManager.refreshActiveTime(connectionId);
            } else {
                Loggers.REMOTE_DIGEST.warn("[{}]Grpc request bi stream,unknown payload receive ,parseObj={}", connectionId, parseObj);
            }
        }

        @Override
        public void onError(Throwable t) {
            if (connectionManager.traced(clientIp)) {
                Loggers.REMOTE_DIGEST.warn("[{}]Bi stream on error,error={}", connectionId, t);
            }
            if (responseObserver instanceof ServerCallStreamObserver) {
                ServerCallStreamObserver serverCallStreamObserver = ((ServerCallStreamObserver) responseObserver);
                if (serverCallStreamObserver.isCancelled()) {
                // client close the stream.
                } else {
                    try {
                        serverCallStreamObserver.onCompleted();
                    } catch (Throwable throwable) {
                    // ignore
                    }
                }
            }
        }

        @Override
        public void onCompleted() {
            if (connectionManager.traced(clientIp)) {
                Loggers.REMOTE_DIGEST.warn("[{}]Bi stream on completed", connectionId);
            }
            if (responseObserver instanceof ServerCallStreamObserver) {
                ServerCallStreamObserver serverCallStreamObserver = ((ServerCallStreamObserver) responseObserver);
                if (serverCallStreamObserver.isCancelled()) {
                // client close the stream.
                } else {
                    try {
                        serverCallStreamObserver.onCompleted();
                    } catch (Throwable throwable) {
                    // ignore
                    }
                }
            }
        }
    };
    return streamObserver;
}
Also used : StreamObserver(io.grpc.stub.StreamObserver) ServerCallStreamObserver(io.grpc.stub.ServerCallStreamObserver) ServerCallStreamObserver(io.grpc.stub.ServerCallStreamObserver) Connection(com.alibaba.nacos.core.remote.Connection) ConnectResetRequest(com.alibaba.nacos.api.remote.request.ConnectResetRequest) Response(com.alibaba.nacos.api.remote.response.Response) Payload(com.alibaba.nacos.api.grpc.auto.Payload) ConnectionMeta(com.alibaba.nacos.core.remote.ConnectionMeta) ConnectionSetupRequest(com.alibaba.nacos.api.remote.request.ConnectionSetupRequest)

Example 4 with ConnectResetRequest

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

the class GrpcBiStreamRequestAcceptorTest method testConnectionSetupRequest.

@Test
public void testConnectionSetupRequest() {
    StreamObserver<Payload> streamObserver = new StreamObserver<Payload>() {

        @Override
        public void onNext(Payload payload) {
            System.out.println("Receive data from server, data: " + payload);
            Assert.assertNotNull(payload);
            ConnectResetRequest connectResetRequest = (ConnectResetRequest) GrpcUtils.parse(payload);
            Response response = new ConnectResetResponse();
            response.setRequestId(connectResetRequest.getRequestId());
            Payload res = GrpcUtils.convert(response);
            payloadStreamObserver.onNext(res);
            payloadStreamObserver.onCompleted();
        }

        @Override
        public void onError(Throwable throwable) {
            Assert.fail(throwable.getMessage());
        }

        @Override
        public void onCompleted() {
            System.out.println("complete");
        }
    };
    payloadStreamObserver = streamStub.requestBiStream(streamObserver);
    RequestMeta metadata = new RequestMeta();
    metadata.setClientIp("127.0.0.1");
    metadata.setConnectionId(connectId);
    ConnectionSetupRequest connectionSetupRequest = new ConnectionSetupRequest();
    connectionSetupRequest.setRequestId(requestId);
    connectionSetupRequest.setClientVersion("2.0.3");
    Payload payload = GrpcUtils.convert(connectionSetupRequest, metadata);
    payloadStreamObserver.onNext(payload);
}
Also used : StreamObserver(io.grpc.stub.StreamObserver) ConnectResetResponse(com.alibaba.nacos.api.remote.response.ConnectResetResponse) Response(com.alibaba.nacos.api.remote.response.Response) ConnectResetResponse(com.alibaba.nacos.api.remote.response.ConnectResetResponse) RequestMeta(com.alibaba.nacos.api.remote.request.RequestMeta) Payload(com.alibaba.nacos.api.grpc.auto.Payload) ConnectionSetupRequest(com.alibaba.nacos.api.remote.request.ConnectionSetupRequest) ConnectResetRequest(com.alibaba.nacos.api.remote.request.ConnectResetRequest) Test(org.junit.Test)

Aggregations

ConnectResetRequest (com.alibaba.nacos.api.remote.request.ConnectResetRequest)4 Response (com.alibaba.nacos.api.remote.response.Response)3 NacosException (com.alibaba.nacos.api.exception.NacosException)2 Payload (com.alibaba.nacos.api.grpc.auto.Payload)2 ConnectionSetupRequest (com.alibaba.nacos.api.remote.request.ConnectionSetupRequest)2 ConnectionAlreadyClosedException (com.alibaba.nacos.common.remote.exception.ConnectionAlreadyClosedException)2 StreamObserver (io.grpc.stub.StreamObserver)2 IOException (java.io.IOException)2 RequestCallBack (com.alibaba.nacos.api.remote.RequestCallBack)1 ClientDetectionRequest (com.alibaba.nacos.api.remote.request.ClientDetectionRequest)1 RequestMeta (com.alibaba.nacos.api.remote.request.RequestMeta)1 ConnectResetResponse (com.alibaba.nacos.api.remote.response.ConnectResetResponse)1 Connection (com.alibaba.nacos.core.remote.Connection)1 ConnectionMeta (com.alibaba.nacos.core.remote.ConnectionMeta)1 ServerCallStreamObserver (io.grpc.stub.ServerCallStreamObserver)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1