use of com.alibaba.nacos.api.remote.RequestCallBack in project nacos by alibaba.
the class NamingGrpcClientProxyTest method testServerListChanged.
@Test
public void testServerListChanged() throws Exception {
RpcClient rpc = new RpcClient("testServerListHasChanged", factory) {
@Override
public ConnectionType getConnectionType() {
return ConnectionType.GRPC;
}
@Override
public int rpcPortOffset() {
return 0;
}
@Override
public Connection connectToServer(ServerInfo serverInfo) throws Exception {
return new Connection(serverInfo) {
@Override
public Response request(Request request, long timeoutMills) throws NacosException {
Response response = new Response() {
};
response.setRequestId(request.getRequestId());
return response;
}
@Override
public RequestFuture requestFuture(Request request) throws NacosException {
return new DefaultRequestFuture("test", request.getRequestId());
}
@Override
public void asyncRequest(Request request, RequestCallBack requestCallBack) throws NacosException {
}
@Override
public void close() {
}
};
}
};
Field rpcClient = NamingGrpcClientProxy.class.getDeclaredField("rpcClient");
rpcClient.setAccessible(true);
rpcClient.set(client, rpc);
rpc.serverListFactory(factory);
rpc.registerServerRequestHandler(new NamingPushRequestHandler(holder));
Field listenerField = NamingGrpcClientProxy.class.getDeclaredField("redoService");
listenerField.setAccessible(true);
NamingGrpcRedoService listener = (NamingGrpcRedoService) listenerField.get(client);
rpc.registerConnectionListener(listener);
rpc.start();
int retry = 10;
while (!rpc.isRunning()) {
TimeUnit.SECONDS.sleep(1);
if (--retry < 0) {
Assert.fail("rpc is not running");
}
}
Assert.assertEquals(ORIGIN_SERVER, rpc.getCurrentServer().getServerIp());
String newServer = "www.aliyun.com";
when(factory.genNextServer()).thenReturn(newServer);
when(factory.getServerList()).thenReturn(Stream.of(newServer, "anotherServer").collect(Collectors.toList()));
NotifyCenter.publishEvent(new ServerListChangedEvent());
retry = 10;
while (ORIGIN_SERVER.equals(rpc.getCurrentServer().getServerIp())) {
TimeUnit.SECONDS.sleep(1);
if (--retry < 0) {
Assert.fail("failed to auth switch server");
}
}
Assert.assertEquals(newServer, rpc.getCurrentServer().getServerIp());
}
use of com.alibaba.nacos.api.remote.RequestCallBack in project nacos by alibaba.
the class ClusterRpcClientProxyTest method testAsyncRequest.
@Test
public void testAsyncRequest() {
RequestCallBack requestCallBack = new RequestCallBack() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public long getTimeout() {
return 0;
}
@Override
public void onResponse(Response response) {
}
@Override
public void onException(Throwable e) {
Assert.assertTrue(e instanceof NacosException);
}
};
Member member = new Member();
member.setIp("1.1.1.1");
try {
clusterRpcClientProxy.asyncRequest(member, new HealthCheckRequest(), requestCallBack);
} catch (NacosException e) {
Assert.assertEquals(500, e.getErrCode());
}
}
use of com.alibaba.nacos.api.remote.RequestCallBack in project nacos by alibaba.
the class ServerLoaderController method smartReload.
/**
* Get server state of current server.
*
* @return state json.
*/
@Secured(resource = Commons.NACOS_CORE_CONTEXT_V2 + "/loader", action = ActionTypes.WRITE)
@GetMapping("/smartReloadCluster")
public ResponseEntity<String> smartReload(HttpServletRequest request, @RequestParam(value = "loaderFactor", required = false) String loaderFactorStr, @RequestParam(value = "force", required = false) String force) {
LOGGER.info("Smart reload request receive,requestIp={}", getRemoteIp(request));
Map<String, Object> serverLoadMetrics = getServerLoadMetrics();
Object avgString = serverLoadMetrics.get("avg");
List<ServerLoaderMetrics> details = (List<ServerLoaderMetrics>) serverLoadMetrics.get("detail");
int avg = Integer.parseInt(avgString.toString());
float loaderFactor = StringUtils.isBlank(loaderFactorStr) ? RemoteUtils.LOADER_FACTOR : Float.parseFloat(loaderFactorStr);
int overLimitCount = (int) (avg * (1 + loaderFactor));
int lowLimitCount = (int) (avg * (1 - loaderFactor));
List<ServerLoaderMetrics> overLimitServer = new ArrayList<>();
List<ServerLoaderMetrics> lowLimitServer = new ArrayList<>();
for (ServerLoaderMetrics metrics : details) {
int sdkCount = Integer.parseInt(metrics.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
if (sdkCount > overLimitCount) {
overLimitServer.add(metrics);
}
if (sdkCount < lowLimitCount) {
lowLimitServer.add(metrics);
}
}
// desc by sdkConCount
overLimitServer.sort((o1, o2) -> {
Integer sdkCount1 = Integer.valueOf(o1.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
Integer sdkCount2 = Integer.valueOf(o2.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
return sdkCount1.compareTo(sdkCount2) * -1;
});
LOGGER.info("Over load limit server list ={}", overLimitServer);
// asc by sdkConCount
lowLimitServer.sort((o1, o2) -> {
Integer sdkCount1 = Integer.valueOf(o1.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
Integer sdkCount2 = Integer.valueOf(o2.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
return sdkCount1.compareTo(sdkCount2);
});
LOGGER.info("Low load limit server list ={}", lowLimitServer);
AtomicBoolean result = new AtomicBoolean(true);
for (int i = 0; i < overLimitServer.size() & i < lowLimitServer.size(); i++) {
ServerReloadRequest serverLoaderInfoRequest = new ServerReloadRequest();
serverLoaderInfoRequest.setReloadCount(overLimitCount);
serverLoaderInfoRequest.setReloadServer(lowLimitServer.get(i).address);
Member member = serverMemberManager.find(overLimitServer.get(i).address);
LOGGER.info("Reload task submit ,fromServer ={},toServer={}, ", overLimitServer.get(i).address, lowLimitServer.get(i).address);
if (serverMemberManager.getSelf().equals(member)) {
try {
serverReloaderRequestHandler.handle(serverLoaderInfoRequest, new RequestMeta());
} catch (NacosException e) {
LOGGER.error("Fail to loader self server", e);
result.set(false);
}
} else {
try {
clusterRpcClientProxy.asyncRequest(member, serverLoaderInfoRequest, new RequestCallBack() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public long getTimeout() {
return 100L;
}
@Override
public void onResponse(Response response) {
if (response == null || !response.isSuccess()) {
LOGGER.error("Fail to loader member={},response={}", member.getAddress(), response);
result.set(false);
}
}
@Override
public void onException(Throwable e) {
LOGGER.error("Fail to loader member={}", member.getAddress(), e);
result.set(false);
}
});
} catch (NacosException e) {
LOGGER.error("Fail to loader member={}", member.getAddress(), e);
result.set(false);
}
}
}
return ResponseEntity.ok().body(result.get() ? SUCCESS_RESULT : FAIL_RESULT);
}
use of com.alibaba.nacos.api.remote.RequestCallBack in project nacos by alibaba.
the class ServerLoaderController method getServerLoadMetrics.
private Map<String, Object> getServerLoadMetrics() {
List<ServerLoaderMetrics> responseList = new LinkedList<>();
// default include self.
int memberSize = serverMemberManager.allMembersWithoutSelf().size();
CountDownLatch countDownLatch = new CountDownLatch(memberSize);
for (Member member : serverMemberManager.allMembersWithoutSelf()) {
if (MemberUtil.isSupportedLongCon(member)) {
ServerLoaderInfoRequest serverLoaderInfoRequest = new ServerLoaderInfoRequest();
try {
clusterRpcClientProxy.asyncRequest(member, serverLoaderInfoRequest, new RequestCallBack() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public long getTimeout() {
return 200L;
}
@Override
public void onResponse(Response response) {
if (response instanceof ServerLoaderInfoResponse) {
ServerLoaderMetrics metrics = new ServerLoaderMetrics();
metrics.setAddress(member.getAddress());
metrics.setMetric(((ServerLoaderInfoResponse) response).getLoaderMetrics());
responseList.add(metrics);
}
countDownLatch.countDown();
}
@Override
public void onException(Throwable e) {
LOGGER.error("Get metrics fail,member={}", member.getAddress(), e);
countDownLatch.countDown();
}
});
} catch (NacosException e) {
LOGGER.error("Get metrics fail,member={}", member.getAddress(), e);
countDownLatch.countDown();
}
} else {
countDownLatch.countDown();
}
}
try {
ServerLoaderInfoResponse handle = serverLoaderInfoRequestHandler.handle(new ServerLoaderInfoRequest(), new RequestMeta());
ServerLoaderMetrics metrics = new ServerLoaderMetrics();
metrics.setAddress(serverMemberManager.getSelf().getAddress());
metrics.setMetric(handle.getLoaderMetrics());
responseList.add(metrics);
} catch (NacosException e) {
LOGGER.error("Get self metrics fail", e);
}
try {
countDownLatch.await(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
LOGGER.warn("Get metrics timeout,metrics info may not complete.");
}
int max = 0;
int min = -1;
int total = 0;
for (ServerLoaderMetrics serverLoaderMetrics : responseList) {
String sdkConCountStr = serverLoaderMetrics.getMetric().get("sdkConCount");
if (StringUtils.isNotBlank(sdkConCountStr)) {
int sdkConCount = Integer.parseInt(sdkConCountStr);
if (max == 0 || max < sdkConCount) {
max = sdkConCount;
}
if (min == -1 || sdkConCount < min) {
min = sdkConCount;
}
total += sdkConCount;
}
}
Map<String, Object> responseMap = new HashMap<>(9);
responseList.sort(Comparator.comparing(ServerLoaderMetrics::getAddress));
responseMap.put("detail", responseList);
responseMap.put("memberCount", serverMemberManager.allMembers().size());
responseMap.put("metricsCount", responseList.size());
responseMap.put("completed", responseList.size() == serverMemberManager.allMembers().size());
responseMap.put("max", max);
responseMap.put("min", min);
responseMap.put("avg", total / responseList.size());
responseMap.put("threshold", total / responseList.size() * 1.1);
responseMap.put("total", total);
return responseMap;
}
use of com.alibaba.nacos.api.remote.RequestCallBack 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);
}
Aggregations