Refactor connection limit module to plugin (#9653)
* 限流插件提交 * 限流插件提交 * 限流插件提交 * 限流插件重构提交 * connection control test case submit * tps control test case submit * tps control test case submit * tps control test case submit * exact model has higher priority * exact model has higher priority * tpsreporter * tpsreporter * tpsreporter * check style * log optimize * interceptor * checkstyle * tps check * configController query http * rename component * 优化参数命名 * 优化参数命名 * 优化参数命名 * 优化参数命名 * optimize connection manager * optimize connection manager * optimize connection manager * optimize connection manager * interceptor to mse * Monitor Model * Monitor Model * revert opensource tps ability * revert opensource tps ability * revert opensource tps ability * revert opensource tps ability * revert opensource tps ability * revert opensource tps ability * opensource submit * opensource submit * check style * check style * pmd ,rat * update db params * test case fix * 简化开源反脆弱实现 * test case * test case fix * 修复单测 * 修复单测 * 修复单测
This commit is contained in:
parent
d30aeadb63
commit
acc8ab46cf
@ -628,7 +628,7 @@ public abstract class RpcClient implements Closeable {
|
||||
public Response request(Request request, long timeoutMills) throws NacosException {
|
||||
int retryTimes = 0;
|
||||
Response response;
|
||||
Exception exceptionThrow = null;
|
||||
Throwable exceptionThrow = null;
|
||||
long start = System.currentTimeMillis();
|
||||
while (retryTimes < rpcClientConfig.retryTimes() && System.currentTimeMillis() < timeoutMills + start) {
|
||||
boolean waitReconnect = false;
|
||||
@ -661,7 +661,7 @@ public abstract class RpcClient implements Closeable {
|
||||
lastActiveTimeStamp = System.currentTimeMillis();
|
||||
return response;
|
||||
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
if (waitReconnect) {
|
||||
try {
|
||||
// wait client to reconnect.
|
||||
@ -701,8 +701,8 @@ public abstract class RpcClient implements Closeable {
|
||||
*/
|
||||
public void asyncRequest(Request request, RequestCallBack callback) throws NacosException {
|
||||
int retryTimes = 0;
|
||||
|
||||
Exception exceptionToThrow = null;
|
||||
|
||||
Throwable exceptionToThrow = null;
|
||||
long start = System.currentTimeMillis();
|
||||
while (retryTimes < rpcClientConfig.retryTimes() && System.currentTimeMillis() < start + callback
|
||||
.getTimeout()) {
|
||||
@ -714,7 +714,7 @@ public abstract class RpcClient implements Closeable {
|
||||
}
|
||||
this.currentConnection.asyncRequest(request, callback);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
if (waitReconnect) {
|
||||
try {
|
||||
// wait client to reconnect.
|
||||
|
@ -117,6 +117,11 @@
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-contrl-plugin</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-datasource-plugin</artifactId>
|
||||
|
@ -55,6 +55,7 @@ import com.alibaba.nacos.config.server.utils.RequestUtil;
|
||||
import com.alibaba.nacos.config.server.utils.TimeUtils;
|
||||
import com.alibaba.nacos.config.server.utils.YamlParserUtil;
|
||||
import com.alibaba.nacos.config.server.utils.ZipUtils;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
|
||||
@ -133,13 +134,14 @@ public class ConfigController {
|
||||
/**
|
||||
* Adds or updates non-aggregated data.
|
||||
* <p>
|
||||
* request and response will be used in aspect, see
|
||||
* {@link com.alibaba.nacos.config.server.aspect.CapacityManagementAspect} and
|
||||
* {@link com.alibaba.nacos.config.server.aspect.RequestLogAspect}.
|
||||
* request and response will be used in aspect, see {@link com.alibaba.nacos.config.server.aspect.CapacityManagementAspect}
|
||||
* and {@link com.alibaba.nacos.config.server.aspect.RequestLogAspect}.
|
||||
* </p>
|
||||
*
|
||||
* @throws NacosException NacosException.
|
||||
*/
|
||||
@PostMapping
|
||||
@TpsControl(pointName = "ConfigPublish")
|
||||
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
|
||||
public Boolean publishConfig(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam(value = "dataId") String dataId,
|
||||
@ -204,6 +206,7 @@ public class ConfigController {
|
||||
* @throws NacosException NacosException.
|
||||
*/
|
||||
@GetMapping
|
||||
@TpsControl(pointName = "ConfigQuery")
|
||||
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
|
||||
public void getConfig(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam("dataId") String dataId, @RequestParam("group") String group,
|
||||
@ -237,7 +240,7 @@ public class ConfigController {
|
||||
// check params
|
||||
ParamUtils.checkParam(dataId, group, "datumId", "content");
|
||||
ConfigAllInfo configAllInfo = configInfoPersistService.findConfigAllInfo(dataId, group, tenant);
|
||||
|
||||
|
||||
// decrypted
|
||||
if (Objects.nonNull(configAllInfo)) {
|
||||
String encryptedDataKey = configAllInfo.getEncryptedDataKey();
|
||||
@ -252,9 +255,8 @@ public class ConfigController {
|
||||
* Synchronously delete all pre-aggregation data under a dataId.
|
||||
*
|
||||
* <p>
|
||||
* request and response will be used in aspect, see
|
||||
* {@link com.alibaba.nacos.config.server.aspect.CapacityManagementAspect} and
|
||||
* {@link com.alibaba.nacos.config.server.aspect.RequestLogAspect}.
|
||||
* request and response will be used in aspect, see {@link com.alibaba.nacos.config.server.aspect.CapacityManagementAspect}
|
||||
* and {@link com.alibaba.nacos.config.server.aspect.RequestLogAspect}.
|
||||
* </p>
|
||||
*
|
||||
* @throws NacosException NacosException.
|
||||
@ -298,10 +300,10 @@ public class ConfigController {
|
||||
ConfigChangePublisher.notifyConfigChange(
|
||||
new ConfigDataChangeEvent(false, configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), time.getTime()));
|
||||
|
||||
ConfigTraceService.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), null, time.getTime(), clientIp, ConfigTraceService.PERSISTENCE_EVENT_REMOVE,
|
||||
null);
|
||||
|
||||
ConfigTraceService
|
||||
.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(), configInfo.getTenant(), null,
|
||||
time.getTime(), clientIp, ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
|
||||
}
|
||||
return RestResultUtils.success(true);
|
||||
}
|
||||
@ -434,8 +436,8 @@ public class ConfigController {
|
||||
LOGGER.error("remove beta data error", e);
|
||||
return RestResultUtils.failed(500, false, "remove beta data error");
|
||||
}
|
||||
ConfigChangePublisher.notifyConfigChange(
|
||||
new ConfigDataChangeEvent(true, dataId, group, tenant, System.currentTimeMillis()));
|
||||
ConfigChangePublisher
|
||||
.notifyConfigChange(new ConfigDataChangeEvent(true, dataId, group, tenant, System.currentTimeMillis()));
|
||||
return RestResultUtils.success("stop beta ok", true);
|
||||
}
|
||||
|
||||
@ -454,7 +456,7 @@ public class ConfigController {
|
||||
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant) {
|
||||
try {
|
||||
ConfigInfo4Beta ci = configInfoBetaPersistService.findConfigInfo4Beta(dataId, group, tenant);
|
||||
|
||||
|
||||
if (Objects.nonNull(ci)) {
|
||||
String encryptedDataKey = ci.getEncryptedDataKey();
|
||||
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, encryptedDataKey, ci.getContent());
|
||||
@ -497,15 +499,15 @@ public class ConfigController {
|
||||
}
|
||||
String metaDataId = ci.getDataId();
|
||||
if (metaDataId.contains(".")) {
|
||||
metaDataId = metaDataId.substring(0, metaDataId.lastIndexOf(".")) + "~" + metaDataId.substring(
|
||||
metaDataId.lastIndexOf(".") + 1);
|
||||
metaDataId = metaDataId.substring(0, metaDataId.lastIndexOf(".")) + "~" + metaDataId
|
||||
.substring(metaDataId.lastIndexOf(".") + 1);
|
||||
}
|
||||
metaData.append(ci.getGroup()).append('.').append(metaDataId).append(".app=")
|
||||
// Fixed use of "\r\n" here
|
||||
.append(ci.getAppName()).append("\r\n");
|
||||
}
|
||||
Pair<String, String> pair = EncryptionHandler.decryptHandler(ci.getDataId(), ci.getEncryptedDataKey(),
|
||||
ci.getContent());
|
||||
Pair<String, String> pair = EncryptionHandler
|
||||
.decryptHandler(ci.getDataId(), ci.getEncryptedDataKey(), ci.getContent());
|
||||
String itemName = ci.getGroup() + Constants.CONFIG_EXPORT_ITEM_FILE_SEPARATOR + ci.getDataId();
|
||||
zipItemList.add(new ZipUtils.ZipItem(itemName, pair.getSecond()));
|
||||
}
|
||||
@ -551,15 +553,15 @@ public class ConfigController {
|
||||
configMetadataItem.setGroup(ci.getGroup());
|
||||
configMetadataItem.setType(ci.getType());
|
||||
configMetadataItems.add(configMetadataItem);
|
||||
Pair<String, String> pair = EncryptionHandler.decryptHandler(ci.getDataId(), ci.getEncryptedDataKey(),
|
||||
ci.getContent());
|
||||
Pair<String, String> pair = EncryptionHandler
|
||||
.decryptHandler(ci.getDataId(), ci.getEncryptedDataKey(), ci.getContent());
|
||||
String itemName = ci.getGroup() + Constants.CONFIG_EXPORT_ITEM_FILE_SEPARATOR + ci.getDataId();
|
||||
zipItemList.add(new ZipUtils.ZipItem(itemName, pair.getSecond()));
|
||||
}
|
||||
ConfigMetadata configMetadata = new ConfigMetadata();
|
||||
configMetadata.setMetadata(configMetadataItems);
|
||||
zipItemList.add(
|
||||
new ZipUtils.ZipItem(Constants.CONFIG_EXPORT_METADATA_NEW, YamlParserUtil.dumpObject(configMetadata)));
|
||||
zipItemList.add(new ZipUtils.ZipItem(Constants.CONFIG_EXPORT_METADATA_NEW,
|
||||
YamlParserUtil.dumpObject(configMetadata)));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
String fileName =
|
||||
EXPORT_CONFIG_FILE_NAME + DateFormatUtils.format(new Date(), EXPORT_CONFIG_FILE_NAME_DATE_FORMAT)
|
||||
@ -625,15 +627,16 @@ public class ConfigController {
|
||||
final String srcIp = RequestUtil.getRemoteIp(request);
|
||||
String requestIpApp = RequestUtil.getAppName(request);
|
||||
final Timestamp time = TimeUtils.getCurrentTime();
|
||||
Map<String, Object> saveResult = configInfoPersistService.batchInsertOrUpdate(configInfoList, srcUser, srcIp, null, time,
|
||||
false, policy);
|
||||
Map<String, Object> saveResult = configInfoPersistService
|
||||
.batchInsertOrUpdate(configInfoList, srcUser, srcIp, null, time, false, policy);
|
||||
for (ConfigInfo configInfo : configInfoList) {
|
||||
ConfigChangePublisher.notifyConfigChange(
|
||||
new ConfigDataChangeEvent(false, configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), time.getTime()));
|
||||
ConfigTraceService.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), requestIpApp, time.getTime(), InetUtils.getSelfIP(),
|
||||
ConfigTraceService.PERSISTENCE_EVENT_PUB, configInfo.getContent());
|
||||
ConfigTraceService
|
||||
.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(), configInfo.getTenant(),
|
||||
requestIpApp, time.getTime(), InetUtils.getSelfIP(),
|
||||
ConfigTraceService.PERSISTENCE_EVENT_PUB, configInfo.getContent());
|
||||
}
|
||||
// unrecognizedCount
|
||||
if (!unrecognizedList.isEmpty()) {
|
||||
@ -686,11 +689,11 @@ public class ConfigController {
|
||||
String dataId = groupAdnDataId[1];
|
||||
String tempDataId = dataId;
|
||||
if (tempDataId.contains(".")) {
|
||||
tempDataId = tempDataId.substring(0, tempDataId.lastIndexOf(".")) + "~" + tempDataId.substring(
|
||||
tempDataId.lastIndexOf(".") + 1);
|
||||
tempDataId = tempDataId.substring(0, tempDataId.lastIndexOf(".")) + "~" + tempDataId
|
||||
.substring(tempDataId.lastIndexOf(".") + 1);
|
||||
}
|
||||
final String metaDataId = group + "." + tempDataId + ".app";
|
||||
|
||||
|
||||
//encrypted
|
||||
String content = item.getItemData();
|
||||
Pair<String, String> pair = EncryptionHandler.encryptHandler(dataId, content);
|
||||
@ -863,22 +866,24 @@ public class ConfigController {
|
||||
ci4save.setAppName(ci.getAppName());
|
||||
}
|
||||
ci4save.setDesc(ci.getDesc());
|
||||
ci4save.setEncryptedDataKey(ci.getEncryptedDataKey() == null ? StringUtils.EMPTY : ci.getEncryptedDataKey());
|
||||
ci4save.setEncryptedDataKey(
|
||||
ci.getEncryptedDataKey() == null ? StringUtils.EMPTY : ci.getEncryptedDataKey());
|
||||
configInfoList4Clone.add(ci4save);
|
||||
}
|
||||
|
||||
|
||||
final String srcIp = RequestUtil.getRemoteIp(request);
|
||||
String requestIpApp = RequestUtil.getAppName(request);
|
||||
final Timestamp time = TimeUtils.getCurrentTime();
|
||||
Map<String, Object> saveResult = configInfoPersistService.batchInsertOrUpdate(configInfoList4Clone, srcUser, srcIp, null,
|
||||
time, false, policy);
|
||||
Map<String, Object> saveResult = configInfoPersistService
|
||||
.batchInsertOrUpdate(configInfoList4Clone, srcUser, srcIp, null, time, false, policy);
|
||||
for (ConfigInfo configInfo : configInfoList4Clone) {
|
||||
ConfigChangePublisher.notifyConfigChange(
|
||||
new ConfigDataChangeEvent(false, configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), time.getTime()));
|
||||
ConfigTraceService.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(),
|
||||
configInfo.getTenant(), requestIpApp, time.getTime(), InetUtils.getSelfIP(),
|
||||
ConfigTraceService.PERSISTENCE_EVENT_PUB, configInfo.getContent());
|
||||
ConfigTraceService
|
||||
.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(), configInfo.getTenant(),
|
||||
requestIpApp, time.getTime(), InetUtils.getSelfIP(),
|
||||
ConfigTraceService.PERSISTENCE_EVENT_PUB, configInfo.getContent());
|
||||
}
|
||||
return RestResultUtils.success("Clone Completed Successfully", saveResult);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.config.server.service.ConfigCacheService;
|
||||
import com.alibaba.nacos.config.server.utils.GroupKey2;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.utils.StringPool;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
|
@ -22,7 +22,7 @@ import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.config.server.service.dump.DumpService;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;
|
||||
import com.alibaba.nacos.config.server.utils.GroupKey;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKeyParser;
|
||||
|
||||
/**
|
||||
* Parser to get group key of config query request.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ConfigPublishGroupKeyParser.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class ConfigPublishGroupKeyParser extends MonitorKeyParser {
|
||||
|
||||
/**
|
||||
* parse group.
|
||||
*
|
||||
* @param args parameters.
|
||||
* @return MonitorKey.
|
||||
*/
|
||||
@Override
|
||||
public MonitorKey parse(Object... args) {
|
||||
if (args != null && args.length != 0 && args[0] instanceof ConfigPublishRequest) {
|
||||
|
||||
return new ConfigGroupKey(GroupKey.getKeyTenant(((ConfigPublishRequest) args[0]).getDataId(),
|
||||
((ConfigPublishRequest) args[0]).getGroup(), ((ConfigPublishRequest) args[0]).getTenant()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ConfigGroupKey extends MonitorKey {
|
||||
|
||||
public ConfigGroupKey(String key) {
|
||||
this.setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "groupKey";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKeyParser;
|
||||
|
||||
/**
|
||||
* parse to get group from config publish parser.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ConfigPublishGroupParser.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class ConfigPublishGroupParser extends MonitorKeyParser {
|
||||
|
||||
/**
|
||||
* parse group.
|
||||
*
|
||||
* @param args parameters.
|
||||
* @return MonitorKey.
|
||||
*/
|
||||
@Override
|
||||
public MonitorKey parse(Object... args) {
|
||||
if (args != null && args.length != 0 && args[0] instanceof ConfigPublishRequest) {
|
||||
return new ConfigGroupKey(((ConfigPublishRequest) args[0]).getGroup());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigGroupKey extends MonitorKey {
|
||||
|
||||
public ConfigGroupKey(String key) {
|
||||
this.setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "group";
|
||||
}
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
|
||||
import com.alibaba.nacos.config.server.utils.ParamUtils;
|
||||
import com.alibaba.nacos.config.server.utils.TimeUtils;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
@ -70,8 +70,7 @@ public class ConfigPublishRequestHandler extends RequestHandler<ConfigPublishReq
|
||||
}
|
||||
|
||||
@Override
|
||||
@TpsControl(pointName = "ConfigPublish", parsers = {ConfigPublishGroupKeyParser.class,
|
||||
ConfigPublishGroupParser.class})
|
||||
@TpsControl(pointName = "ConfigPublish")
|
||||
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
|
||||
public ConfigPublishResponse handle(ConfigPublishRequest request, RequestMeta meta) throws NacosException {
|
||||
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest;
|
||||
import com.alibaba.nacos.config.server.utils.GroupKey;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKeyParser;
|
||||
|
||||
/**
|
||||
* ConfigQueryGroupKeyParser.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ConfigQueryGroupKeyParser.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class ConfigQueryGroupKeyParser extends MonitorKeyParser {
|
||||
|
||||
/**
|
||||
* parse group key.
|
||||
*
|
||||
* @param args parameters.
|
||||
* @return MonitorKey.
|
||||
*/
|
||||
@Override
|
||||
public MonitorKey parse(Object... args) {
|
||||
if (args != null && args.length != 0 && args[0] instanceof ConfigQueryRequest) {
|
||||
|
||||
return new ConfigGroupKey(GroupKey.getKeyTenant(((ConfigQueryRequest) args[0]).getDataId(),
|
||||
((ConfigQueryRequest) args[0]).getGroup(), ((ConfigQueryRequest) args[0]).getTenant()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ConfigGroupKey extends MonitorKey {
|
||||
|
||||
public ConfigGroupKey(String key) {
|
||||
this.setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "groupKey";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package com.alibaba.nacos.config.server.remote;
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKeyParser;
|
||||
|
||||
/**
|
||||
* parse to get group from config query parser.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ConfigQueryGroupParser.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class ConfigQueryGroupParser extends MonitorKeyParser {
|
||||
|
||||
/**
|
||||
* parse group.
|
||||
*
|
||||
* @param args parameters.
|
||||
* @return MonitorKey.
|
||||
*/
|
||||
@Override
|
||||
public MonitorKey parse(Object... args) {
|
||||
if (args != null && args.length != 0 && args[0] instanceof ConfigQueryRequest) {
|
||||
return new ConfigGroupKey(((ConfigQueryRequest) args[0]).getGroup());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigGroupKey extends MonitorKey {
|
||||
|
||||
public ConfigGroupKey(String key) {
|
||||
this.setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "group";
|
||||
}
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ import com.alibaba.nacos.config.server.utils.LogUtil;
|
||||
import com.alibaba.nacos.config.server.utils.PropertyUtil;
|
||||
import com.alibaba.nacos.config.server.utils.TimeUtils;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
@ -79,7 +79,7 @@ public class ConfigQueryRequestHandler extends RequestHandler<ConfigQueryRequest
|
||||
}
|
||||
|
||||
@Override
|
||||
@TpsControl(pointName = "ConfigQuery", parsers = {ConfigQueryGroupKeyParser.class, ConfigQueryGroupParser.class})
|
||||
@TpsControl(pointName = "ConfigQuery")
|
||||
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
|
||||
public ConfigQueryResponse handle(ConfigQueryRequest request, RequestMeta meta) throws NacosException {
|
||||
|
||||
|
@ -30,7 +30,7 @@ import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
|
||||
import com.alibaba.nacos.config.server.utils.ParamUtils;
|
||||
import com.alibaba.nacos.config.server.utils.TimeUtils;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest;
|
||||
import com.alibaba.nacos.api.config.remote.response.ConfigQueryResponse;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.utils.NetUtils;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent;
|
||||
import com.alibaba.nacos.config.server.utils.GroupKey;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControlRuleChangeEvent;
|
||||
import com.alibaba.nacos.core.remote.event.ConnectionLimitRuleChangeEvent;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ConfigChangeNotifier.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ConfigChangeNotifier.java, v 0.1 2020年07月20日 3:00 PM liuzunfei Exp $
|
||||
*/
|
||||
@Component(value = "internalConfigChangeNotifier")
|
||||
public class InternalConfigChangeNotifier extends Subscriber<LocalDataChangeEvent> {
|
||||
|
||||
@Autowired
|
||||
private ConfigQueryRequestHandler configQueryRequestHandler;
|
||||
|
||||
public InternalConfigChangeNotifier() {
|
||||
NotifyCenter.registerToPublisher(ConnectionLimitRuleChangeEvent.class, 16384);
|
||||
NotifyCenter.registerToPublisher(TpsControlRuleChangeEvent.class, 16384);
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
|
||||
}
|
||||
|
||||
private static final String DATA_ID_TPS_CONTROL_RULE = "nacos.internal.tps.control_rule_";
|
||||
|
||||
private static final String DATA_ID_CONNECTION_LIMIT_RULE = "nacos.internal.connection.limit.rule";
|
||||
|
||||
private static final String NACOS_GROUP = "nacos";
|
||||
|
||||
@Override
|
||||
public void onEvent(LocalDataChangeEvent event) {
|
||||
String groupKey = event.groupKey;
|
||||
String dataId = GroupKey.parseKey(groupKey)[0];
|
||||
String group = GroupKey.parseKey(groupKey)[1];
|
||||
if (DATA_ID_CONNECTION_LIMIT_RULE.equals(dataId) && NACOS_GROUP.equals(group)) {
|
||||
|
||||
try {
|
||||
String content = loadLocalConfigLikeClient(dataId, group);
|
||||
NotifyCenter.publishEvent(new ConnectionLimitRuleChangeEvent(content));
|
||||
|
||||
} catch (NacosException e) {
|
||||
Loggers.REMOTE.error("connection limit rule load fail.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (dataId.startsWith(DATA_ID_TPS_CONTROL_RULE) && NACOS_GROUP.equals(group)) {
|
||||
try {
|
||||
String pointName = dataId.replaceFirst(DATA_ID_TPS_CONTROL_RULE, "");
|
||||
|
||||
String content = loadLocalConfigLikeClient(dataId, group);
|
||||
NotifyCenter.publishEvent(new TpsControlRuleChangeEvent(pointName, content));
|
||||
|
||||
} catch (NacosException e) {
|
||||
Loggers.REMOTE.error("connection limit rule load fail.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String loadLocalConfigLikeClient(String dataId, String group) throws NacosException {
|
||||
ConfigQueryRequest queryRequest = new ConfigQueryRequest();
|
||||
queryRequest.setDataId(dataId);
|
||||
queryRequest.setGroup(group);
|
||||
RequestMeta meta = new RequestMeta();
|
||||
meta.setClientIp(NetUtils.localIP());
|
||||
ConfigQueryResponse handle = configQueryRequestHandler.handle(queryRequest, meta);
|
||||
if (handle == null) {
|
||||
throw new NacosException(NacosException.SERVER_ERROR, "load local config fail,response is null");
|
||||
}
|
||||
if (handle.isSuccess()) {
|
||||
return handle.getContent();
|
||||
} else if (handle.getErrorCode() == ConfigQueryResponse.CONFIG_NOT_FOUND) {
|
||||
return null;
|
||||
} else {
|
||||
Loggers.REMOTE.error("connection limit rule load fail,errorCode={}", handle.getErrorCode());
|
||||
throw new NacosException(NacosException.SERVER_ERROR,
|
||||
"load local config fail,error code=" + handle.getErrorCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return LocalDataChangeEvent.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,9 +30,10 @@ import com.alibaba.nacos.core.remote.Connection;
|
||||
import com.alibaba.nacos.core.remote.ConnectionManager;
|
||||
import com.alibaba.nacos.core.remote.ConnectionMeta;
|
||||
import com.alibaba.nacos.core.remote.RpcPushService;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorPoint;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsControlManager;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -56,8 +57,7 @@ public class RpcConfigChangeNotifier extends Subscriber<LocalDataChangeEvent> {
|
||||
|
||||
private static final String POINT_CONFIG_PUSH_FAIL = "CONFIG_PUSH_FAIL";
|
||||
|
||||
@Autowired
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
TpsControlManager tpsControlManager = ControlManagerCenter.getInstance().getTpsControlManager();
|
||||
|
||||
public RpcConfigChangeNotifier() {
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
@ -65,10 +65,9 @@ public class RpcConfigChangeNotifier extends Subscriber<LocalDataChangeEvent> {
|
||||
|
||||
@PostConstruct
|
||||
private void registerTpsPoint() {
|
||||
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(POINT_CONFIG_PUSH));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(POINT_CONFIG_PUSH_SUCCESS));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(POINT_CONFIG_PUSH_FAIL));
|
||||
tpsControlManager.registerTpsPoint(POINT_CONFIG_PUSH);
|
||||
tpsControlManager.registerTpsPoint(POINT_CONFIG_PUSH_SUCCESS);
|
||||
tpsControlManager.registerTpsPoint(POINT_CONFIG_PUSH_FAIL);
|
||||
|
||||
}
|
||||
|
||||
@ -171,18 +170,27 @@ public class RpcConfigChangeNotifier extends Subscriber<LocalDataChangeEvent> {
|
||||
@Override
|
||||
public void run() {
|
||||
tryTimes++;
|
||||
if (!tpsMonitorManager.applyTpsForClientIp(POINT_CONFIG_PUSH, connectionId, clientIp)) {
|
||||
TpsCheckRequest tpsCheckRequest = new TpsCheckRequest();
|
||||
|
||||
tpsCheckRequest.setPointName(POINT_CONFIG_PUSH);
|
||||
if (!tpsControlManager.check(tpsCheckRequest).isSuccess()) {
|
||||
push(this);
|
||||
} else {
|
||||
rpcPushService.pushWithCallback(connectionId, notifyRequest, new AbstractPushCallBack(3000L) {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
tpsMonitorManager.applyTpsForClientIp(POINT_CONFIG_PUSH_SUCCESS, connectionId, clientIp);
|
||||
TpsCheckRequest tpsCheckRequest = new TpsCheckRequest();
|
||||
|
||||
tpsCheckRequest.setPointName(POINT_CONFIG_PUSH_SUCCESS);
|
||||
tpsControlManager.check(tpsCheckRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(Throwable e) {
|
||||
tpsMonitorManager.applyTpsForClientIp(POINT_CONFIG_PUSH_FAIL, connectionId, clientIp);
|
||||
TpsCheckRequest tpsCheckRequest = new TpsCheckRequest();
|
||||
|
||||
tpsCheckRequest.setPointName(POINT_CONFIG_PUSH_FAIL);
|
||||
tpsControlManager.check(tpsCheckRequest);
|
||||
Loggers.REMOTE_PUSH.warn("Push fail", e);
|
||||
push(RpcPushTask.this);
|
||||
}
|
||||
@ -197,10 +205,10 @@ public class RpcConfigChangeNotifier extends Subscriber<LocalDataChangeEvent> {
|
||||
private void push(RpcPushTask retryTask) {
|
||||
ConfigChangeNotifyRequest notifyRequest = retryTask.notifyRequest;
|
||||
if (retryTask.isOverTimes()) {
|
||||
Loggers.REMOTE_PUSH.warn(
|
||||
"push callback retry fail over times .dataId={},group={},tenant={},clientId={},will unregister client.",
|
||||
notifyRequest.getDataId(), notifyRequest.getGroup(), notifyRequest.getTenant(),
|
||||
retryTask.connectionId);
|
||||
Loggers.REMOTE_PUSH
|
||||
.warn("push callback retry fail over times .dataId={},group={},tenant={},clientId={},will unregister client.",
|
||||
notifyRequest.getDataId(), notifyRequest.getGroup(), notifyRequest.getTenant(),
|
||||
retryTask.connectionId);
|
||||
connectionManager.unregister(retryTask.connectionId);
|
||||
} else if (connectionManager.getConnection(retryTask.connectionId) != null) {
|
||||
// first time:delay 0s; second time:delay 2s; third time:delay 4s
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.service;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.connection.ConnectionMetricsCollector;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* long polling connection metrics.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class LongPollingConnectionMetricsCollector implements ConnectionMetricsCollector {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "long_polling";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalCount() {
|
||||
return ApplicationUtils.getBean(LongPollingService.class).allSubs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCountForIp(String ip) {
|
||||
return ApplicationUtils.getBean(LongPollingService.class).allSubs.stream()
|
||||
.filter(a -> a.ip.equalsIgnoreCase(ip)).collect(Collectors.toList()).size();
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.config.server.model.SampleResult;
|
||||
import com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent;
|
||||
import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
|
||||
@ -29,7 +30,9 @@ import com.alibaba.nacos.config.server.utils.GroupKey;
|
||||
import com.alibaba.nacos.config.server.utils.LogUtil;
|
||||
import com.alibaba.nacos.config.server.utils.MD5Util;
|
||||
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.connection.request.ConnectionCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.connection.response.ConnectionCheckResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
@ -240,8 +243,6 @@ public class LongPollingService {
|
||||
|
||||
String str = req.getHeader(LongPollingService.LONG_POLLING_HEADER);
|
||||
String noHangUpFlag = req.getHeader(LongPollingService.LONG_POLLING_NO_HANG_UP_HEADER);
|
||||
final String appName = req.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
|
||||
final String tag = req.getHeader("Vipserver-Tag");
|
||||
int delayTime = SwitchService.getSwitchInteger(SwitchService.FIXED_DELAY_TIME, 500);
|
||||
|
||||
// Add delay time for LoadBalance, and one response is returned 500 ms in advance to avoid client timeout.
|
||||
@ -266,6 +267,11 @@ public class LongPollingService {
|
||||
}
|
||||
}
|
||||
String ip = RequestUtil.getRemoteIp(req);
|
||||
ConnectionCheckResponse connectionCheckResponse = checkLimit(req);
|
||||
if (!connectionCheckResponse.isSuccess()) {
|
||||
generate503Response(req, rsp, connectionCheckResponse.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// Must be called by http thread, or send response.
|
||||
final AsyncContext asyncContext = req.startAsync();
|
||||
@ -273,10 +279,21 @@ public class LongPollingService {
|
||||
// AsyncContext.setTimeout() is incorrect, Control by oneself
|
||||
asyncContext.setTimeout(0L);
|
||||
|
||||
String appName = req.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
|
||||
String tag = req.getHeader("Vipserver-Tag");
|
||||
ConfigExecutor.executeLongPolling(
|
||||
new ClientLongPolling(asyncContext, clientMd5Map, ip, probeRequestSize, timeout, appName, tag));
|
||||
}
|
||||
|
||||
private ConnectionCheckResponse checkLimit(HttpServletRequest httpServletRequest) {
|
||||
String ip = RequestUtil.getRemoteIp(httpServletRequest);
|
||||
String appName = httpServletRequest.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
|
||||
ConnectionCheckRequest connectionCheckRequest = new ConnectionCheckRequest(ip, appName, "LongPolling");
|
||||
ConnectionCheckResponse checkResponse = ControlManagerCenter.getInstance().getConnectionControlManager()
|
||||
.check(connectionCheckRequest);
|
||||
return checkResponse;
|
||||
}
|
||||
|
||||
public static boolean isSupportLongPolling(HttpServletRequest req) {
|
||||
return null != req.getHeader(LONG_POLLING_HEADER);
|
||||
}
|
||||
@ -523,6 +540,21 @@ public class LongPollingService {
|
||||
}
|
||||
}
|
||||
|
||||
void generate503Response(HttpServletRequest request, HttpServletResponse response, String message) {
|
||||
|
||||
try {
|
||||
|
||||
// Disable cache.
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
response.setHeader("Cache-Control", "no-cache,no-store");
|
||||
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
|
||||
response.getWriter().println(message);
|
||||
} catch (Exception ex) {
|
||||
PULL_LOG.error(ex.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Long> getRetainIps() {
|
||||
return retainIps;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class ExternalDataSourceServiceImpl implements DataSourceService {
|
||||
private static final int TRANSACTION_QUERY_TIMEOUT = 5;
|
||||
|
||||
private static final int DB_MASTER_SELECT_THRESHOLD = 1;
|
||||
|
||||
|
||||
private static final String DB_LOAD_ERROR_MSG = "[db-load-error]load jdbc.properties error";
|
||||
|
||||
private List<HikariDataSource> dataSourceList = new ArrayList<>();
|
||||
@ -106,17 +106,17 @@ public class ExternalDataSourceServiceImpl implements DataSourceService {
|
||||
|
||||
// Transaction timeout needs to be distinguished from ordinary operations.
|
||||
tjt.setTimeout(TRANSACTION_QUERY_TIMEOUT);
|
||||
|
||||
|
||||
dataSourceType = DatasourcePlatformUtil.getDatasourcePlatform(defaultDataSourceType);
|
||||
|
||||
|
||||
if (PropertyUtil.isUseExternalDB()) {
|
||||
try {
|
||||
reload();
|
||||
} catch (IOException e) {
|
||||
FATAL_LOG.error("[ExternalDataSourceService] datasource reload error", e);
|
||||
throw new RuntimeException(DB_LOAD_ERROR_MSG);
|
||||
throw new RuntimeException(DB_LOAD_ERROR_MSG, e);
|
||||
}
|
||||
|
||||
|
||||
if (this.dataSourceList.size() > DB_MASTER_SELECT_THRESHOLD) {
|
||||
ConfigExecutor.scheduleConfigTask(new SelectMasterTask(), 10, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
@ -129,7 +129,7 @@ public class ExternalDataSourceServiceImpl implements DataSourceService {
|
||||
try {
|
||||
final List<JdbcTemplate> testJtListNew = new ArrayList<JdbcTemplate>();
|
||||
final List<Boolean> isHealthListNew = new ArrayList<Boolean>();
|
||||
|
||||
|
||||
List<HikariDataSource> dataSourceListNew = new ExternalDataSourceProperties()
|
||||
.build(EnvUtil.getEnvironment(), (dataSource) -> {
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||
@ -138,7 +138,6 @@ public class ExternalDataSourceServiceImpl implements DataSourceService {
|
||||
testJtListNew.add(jdbcTemplate);
|
||||
isHealthListNew.add(Boolean.TRUE);
|
||||
});
|
||||
|
||||
final List<HikariDataSource> dataSourceListOld = dataSourceList;
|
||||
final List<JdbcTemplate> testJtListOld = testJtList;
|
||||
dataSourceList = dataSourceListNew;
|
||||
|
@ -0,0 +1,19 @@
|
||||
#
|
||||
#
|
||||
# Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.config.server.service.LongPollingConnectionMetricsCollector
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConfigPublishGroupKeyParserTest {
|
||||
|
||||
private ConfigPublishGroupKeyParser configPublishGroupKeyParser;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configPublishGroupKeyParser = new ConfigPublishGroupKeyParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
ConfigPublishRequest configPublishRequest = new ConfigPublishRequest();
|
||||
configPublishRequest.setContent("content");
|
||||
configPublishRequest.setRequestId("requestId");
|
||||
configPublishRequest.setGroup("group");
|
||||
configPublishRequest.setCasMd5("md5");
|
||||
configPublishRequest.setDataId("dataId");
|
||||
configPublishRequest.setTenant("tenant");
|
||||
MonitorKey parse = configPublishGroupKeyParser.parse(configPublishRequest);
|
||||
Assert.assertEquals("dataId+group+tenant", parse.getKey());
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConfigPublishGroupParserTest {
|
||||
|
||||
private ConfigPublishGroupParser configPublishGroupParser;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configPublishGroupParser = new ConfigPublishGroupParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
ConfigPublishRequest configPublishRequest = new ConfigPublishRequest();
|
||||
configPublishRequest.setContent("content");
|
||||
configPublishRequest.setRequestId("requestId");
|
||||
configPublishRequest.setGroup("group");
|
||||
configPublishRequest.setCasMd5("md5");
|
||||
configPublishRequest.setDataId("dataId");
|
||||
configPublishRequest.setTenant("tenant");
|
||||
MonitorKey parse = configPublishGroupParser.parse(configPublishRequest);
|
||||
Assert.assertEquals("group", parse.getKey());
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConfigQueryGroupKeyParserTest {
|
||||
|
||||
private ConfigQueryGroupKeyParser configQueryGroupKeyParser;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configQueryGroupKeyParser = new ConfigQueryGroupKeyParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
ConfigQueryRequest configQueryRequest = new ConfigQueryRequest();
|
||||
configQueryRequest.setRequestId("requestId");
|
||||
configQueryRequest.setGroup("group");
|
||||
configQueryRequest.setDataId("dataId");
|
||||
configQueryRequest.setTenant("tenant");
|
||||
MonitorKey parse = configQueryGroupKeyParser.parse(configQueryRequest);
|
||||
Assert.assertEquals("dataId+group+tenant", parse.getKey());
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest;
|
||||
import com.alibaba.nacos.core.remote.control.MonitorKey;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConfigQueryGroupParserTest {
|
||||
|
||||
private ConfigQueryGroupParser configQueryGroupParser;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configQueryGroupParser = new ConfigQueryGroupParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
ConfigQueryRequest configQueryRequest = new ConfigQueryRequest();
|
||||
configQueryRequest.setRequestId("requestId");
|
||||
configQueryRequest.setGroup("group");
|
||||
configQueryRequest.setDataId("dataId");
|
||||
configQueryRequest.setTenant("tenant");
|
||||
MonitorKey parse = configQueryGroupParser.parse(configQueryRequest);
|
||||
Assert.assertEquals("group", parse.getKey());
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.config.server.remote;
|
||||
|
||||
import com.alibaba.nacos.api.config.remote.response.ConfigQueryResponse;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent;
|
||||
import com.alibaba.nacos.config.server.utils.GroupKey2;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControlRuleChangeEvent;
|
||||
import com.alibaba.nacos.core.remote.event.ConnectionLimitRuleChangeEvent;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class InternalConfigChangeNotifierTest {
|
||||
|
||||
private InternalConfigChangeNotifier internalConfigChangeNotifier;
|
||||
|
||||
@Mock
|
||||
private ConfigQueryRequestHandler configQueryRequestHandler;
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException, NacosException {
|
||||
internalConfigChangeNotifier = new InternalConfigChangeNotifier();
|
||||
|
||||
ReflectionTestUtils.setField(internalConfigChangeNotifier, "configQueryRequestHandler", configQueryRequestHandler);
|
||||
|
||||
when(configQueryRequestHandler.handle(Mockito.any(), Mockito.any())).thenReturn(ConfigQueryResponse.buildSuccessResponse("content"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnEvent() {
|
||||
final String groupKey = GroupKey2.getKey("nacos.internal.tps.control_rule_1", "nacos", "tenant");
|
||||
final String limitGroupKey = GroupKey2.getKey("nacos.internal.tps.nacos.internal.connection.limit.rule", "nacos", "tenant");
|
||||
|
||||
NotifyCenter.registerSubscriber(new Subscriber() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
ConnectionLimitRuleChangeEvent connectionLimitRuleChangeEvent = (ConnectionLimitRuleChangeEvent) event;
|
||||
Assert.assertEquals("content", connectionLimitRuleChangeEvent.getLimitRule());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return ConnectionLimitRuleChangeEvent.class;
|
||||
}
|
||||
});
|
||||
|
||||
NotifyCenter.registerSubscriber(new Subscriber() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
TpsControlRuleChangeEvent tpsControlRuleChangeEvent = (TpsControlRuleChangeEvent) event;
|
||||
Assert.assertEquals("content", tpsControlRuleChangeEvent.getRuleContent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return TpsControlRuleChangeEvent.class;
|
||||
}
|
||||
});
|
||||
|
||||
internalConfigChangeNotifier.onEvent(new LocalDataChangeEvent(groupKey));
|
||||
internalConfigChangeNotifier.onEvent(new LocalDataChangeEvent(limitGroupKey));
|
||||
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -20,7 +20,6 @@ import com.alibaba.nacos.config.server.model.event.LocalDataChangeEvent;
|
||||
import com.alibaba.nacos.config.server.utils.GroupKey2;
|
||||
import com.alibaba.nacos.core.remote.ConnectionManager;
|
||||
import com.alibaba.nacos.core.remote.RpcPushService;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -36,9 +35,6 @@ public class RpcConfigChangeNotifierTest {
|
||||
|
||||
private RpcConfigChangeNotifier rpcConfigChangeNotifier;
|
||||
|
||||
@Mock
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
@Mock
|
||||
private ConfigChangeListenContext configChangeListenContext;
|
||||
|
||||
@ -52,7 +48,6 @@ public class RpcConfigChangeNotifierTest {
|
||||
public void setUp() {
|
||||
rpcConfigChangeNotifier = new RpcConfigChangeNotifier();
|
||||
|
||||
ReflectionTestUtils.setField(rpcConfigChangeNotifier, "tpsMonitorManager", tpsMonitorManager);
|
||||
ReflectionTestUtils.setField(rpcConfigChangeNotifier, "configChangeListenContext", configChangeListenContext);
|
||||
ReflectionTestUtils.setField(rpcConfigChangeNotifier, "rpcPushService", rpcPushService);
|
||||
ReflectionTestUtils.setField(rpcConfigChangeNotifier, "connectionManager", connectionManager);
|
||||
@ -61,7 +56,8 @@ public class RpcConfigChangeNotifierTest {
|
||||
@Test
|
||||
public void testOnEvent() {
|
||||
final String groupKey = GroupKey2.getKey("nacos.internal.tps.control_rule_1", "nacos", "tenant");
|
||||
final String limitGroupKey = GroupKey2.getKey("nacos.internal.tps.nacos.internal.connection.limit.rule", "nacos", "tenant");
|
||||
final String limitGroupKey = GroupKey2
|
||||
.getKey("nacos.internal.tps.nacos.internal.connection.limit.rule", "nacos", "tenant");
|
||||
List<String> betaIps = new ArrayList<>();
|
||||
|
||||
betaIps.add("1.1.1.1");
|
||||
|
@ -34,7 +34,6 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -68,9 +67,9 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Mock
|
||||
private BiConsumer<Boolean, Throwable> biConsumer;
|
||||
|
||||
@Mock
|
||||
private File file;
|
||||
|
||||
/* @Mock
|
||||
private File file;
|
||||
*/
|
||||
@Mock
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@ -78,10 +77,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
public void setUp() {
|
||||
ReflectionTestUtils.setField(operate, "jdbcTemplate", jdbcTemplate);
|
||||
ReflectionTestUtils.setField(operate, "transactionTemplate", transactionTemplate);
|
||||
when(file.exists()).thenReturn(true);
|
||||
when(file.isDirectory()).thenReturn(false);
|
||||
when(file.canRead()).thenReturn(true);
|
||||
when(file.getPath()).thenReturn("test");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -100,7 +96,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[]{configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(jdbcTemplate.queryForObject(sql, args, ConfigInfo.class)).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(sql, args, ConfigInfo.class), configInfo);
|
||||
}
|
||||
@ -112,7 +108,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[]{configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(jdbcTemplate.queryForObject(eq(sql), eq(args), any(RowMapper.class))).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(sql, args, rowMapper), configInfo);
|
||||
}
|
||||
@ -133,7 +129,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[]{configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(tempJdbcTemplate.queryForObject(sql, args, ConfigInfo.class)).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(tempJdbcTemplate, sql, args, ConfigInfo.class), configInfo);
|
||||
}
|
||||
@ -145,7 +141,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[]{configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(tempJdbcTemplate.queryForObject(eq(sql), eq(args), any(RowMapper.class))).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(tempJdbcTemplate, sql, args, rowMapper), configInfo);
|
||||
}
|
||||
@ -153,7 +149,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Test
|
||||
public void testQueryMany1() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[]{1, 2};
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
ConfigInfo configInfo1 = new ConfigInfo();
|
||||
configInfo1.setId(1);
|
||||
ConfigInfo configInfo2 = new ConfigInfo();
|
||||
@ -168,7 +164,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Test
|
||||
public void testQueryMany2() {
|
||||
final String sql = "SELECT id, data_id, group_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[]{1, 2};
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
|
||||
final List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
Map<String, Object> map1 = new HashMap<>();
|
||||
@ -191,7 +187,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Test
|
||||
public void testQueryMany3() {
|
||||
String sql = "SELECT data_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
Object[] args = new Object[]{1, 2};
|
||||
Object[] args = new Object[] {1, 2};
|
||||
String dataId1 = "test1";
|
||||
String dataId2 = "test2";
|
||||
List<String> resultList = new ArrayList<>();
|
||||
@ -205,18 +201,18 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Test
|
||||
public void testQueryMany4() {
|
||||
final String sql = "SELECT data_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[]{1, 2};
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
final List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
Map<String, Object> map1 = new HashMap<>();
|
||||
map1.put("id", 1);
|
||||
map1.put("data_id", "test");
|
||||
map1.put("group_id", "test");
|
||||
|
||||
|
||||
final Map<String, Object> map2 = new HashMap<>();
|
||||
map1.put("id", 2);
|
||||
map1.put("data_id", "test");
|
||||
map1.put("group_id", "test");
|
||||
|
||||
|
||||
resultList.add(map1);
|
||||
resultList.add(map2);
|
||||
|
||||
@ -227,7 +223,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Test
|
||||
public void testQueryMany5() {
|
||||
String sql = "SELECT data_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
Object[] args = new Object[]{1, 2};
|
||||
Object[] args = new Object[] {1, 2};
|
||||
String dataId1 = "test1";
|
||||
String dataId2 = "test2";
|
||||
List<String> resultList = new ArrayList<>();
|
||||
@ -241,7 +237,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
@Test
|
||||
public void testQueryMany6() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[]{1, 2};
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
ConfigInfo configInfo1 = new ConfigInfo();
|
||||
configInfo1.setId(1);
|
||||
ConfigInfo configInfo2 = new ConfigInfo();
|
||||
@ -269,7 +265,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[]{1};
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
@ -282,7 +278,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[]{1};
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
@ -295,7 +291,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[]{1};
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
@ -308,7 +304,7 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[]{1};
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
@ -337,10 +333,10 @@ public class StandaloneDatabaseOperateImplTest {
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[]{1};
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(tempJdbcTemplate.batchUpdate(sql)).thenReturn(new int[]{1});
|
||||
when(tempJdbcTemplate.batchUpdate(sql)).thenReturn(new int[] {1});
|
||||
Assert.assertTrue(operate.doDataImport(tempJdbcTemplate, modifyRequests));
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,8 @@ import com.alibaba.nacos.consistency.entity.WriteRequest;
|
||||
|
||||
/**
|
||||
* Can be discovered through SPI or Spring, This interface is just a function definition interface. Different
|
||||
* consistency protocols have their own LogDispatcher. It is not recommended to directly implement this interface.
|
||||
* consistency protocols have their pwd
|
||||
* LogDispatcher. It is not recommended to directly implement this interface.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
|
@ -35,6 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>nacos-config</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
|
@ -34,7 +34,7 @@ server.port=8848
|
||||
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
|
||||
# spring.datasource.platform=mysql
|
||||
# nacos.plugin.datasource.log.enabled=true
|
||||
|
||||
spring.sql.init.platform=mysql
|
||||
### Count of DB:
|
||||
# db.num=1
|
||||
|
||||
@ -104,7 +104,10 @@ server.tomcat.basedir=file:.
|
||||
#*************** Access Control Related Configurations ***************#
|
||||
### If enable spring security, this option is deprecated in 1.2.0:
|
||||
#spring.security.enabled=false
|
||||
|
||||
db.num=1
|
||||
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=10000&autoReconnect=true
|
||||
db.user=root
|
||||
db.password=11021102
|
||||
### The ignore urls of auth, is deprecated in 1.2.0:
|
||||
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
|
||||
|
||||
|
@ -170,5 +170,14 @@
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-testing</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-contrl-plugin</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -154,8 +154,10 @@ public class ClusterRpcClientProxy extends MemberChangeListener {
|
||||
* Using {@link EnvUtil#getAvailableProcessors(int)} to build cluster clients' grpc thread pool.
|
||||
*/
|
||||
private RpcClient buildRpcClient(ConnectionType type, Map<String, String> labels, String memberClientKey) {
|
||||
return RpcClientFactory.createClusterClient(memberClientKey, type,
|
||||
EnvUtil.getAvailableProcessors(2), EnvUtil.getAvailableProcessors(8), labels);
|
||||
RpcClient clusterClient = RpcClientFactory
|
||||
.createClusterClient(memberClientKey, type, EnvUtil.getAvailableProcessors(2),
|
||||
EnvUtil.getAvailableProcessors(8), labels);
|
||||
return clusterClient;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -12,9 +13,10 @@
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
package com.alibaba.nacos.core.control;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -28,18 +30,19 @@ import java.lang.annotation.RetentionPolicy;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TpsControl {
|
||||
|
||||
|
||||
/**
|
||||
* The action type of the request.
|
||||
* alias name for control point.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* The point name should applied for.
|
||||
*
|
||||
* @return action type, default READ
|
||||
*/
|
||||
String pointName();
|
||||
|
||||
/**
|
||||
* Resource name parser. Should have lower priority than resource().
|
||||
*
|
||||
* @return class type of resource parser
|
||||
*/
|
||||
Class[] parsers() default {};
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -12,9 +13,10 @@
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
package com.alibaba.nacos.core.control;
|
||||
|
||||
/**
|
||||
* tps control manager.
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.http;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* http tps check request parser.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class HttpTpsCheckRequestParser {
|
||||
|
||||
public HttpTpsCheckRequestParser() {
|
||||
registerParser();
|
||||
}
|
||||
|
||||
public void registerParser() {
|
||||
HttpTpsCheckRequestParserRegistry.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse tps check request.
|
||||
*
|
||||
* @param httpServletRequest http request.
|
||||
* @return
|
||||
*/
|
||||
public abstract TpsCheckRequest parse(HttpServletRequest httpServletRequest);
|
||||
|
||||
/**
|
||||
* get point name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getPointName();
|
||||
|
||||
/**
|
||||
* get name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.http;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* http tps check request parse registry.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class HttpTpsCheckRequestParserRegistry {
|
||||
|
||||
static final Map<String, HttpTpsCheckRequestParser> PARSER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* register httpTpsCheckParser.
|
||||
*
|
||||
* @param httpTpsCheckParser httpTpsCheckParser.
|
||||
*/
|
||||
public static synchronized void register(HttpTpsCheckRequestParser httpTpsCheckParser) {
|
||||
HttpTpsCheckRequestParser prevTpsCheckParser = PARSER_MAP.put(httpTpsCheckParser.getName(), httpTpsCheckParser);
|
||||
if (prevTpsCheckParser != null) {
|
||||
Loggers.CONTROL.info("HttpTpsCheckRequestParser name {}, point name {} will be replaced with {}",
|
||||
httpTpsCheckParser.getName(), prevTpsCheckParser.getPointName(),
|
||||
httpTpsCheckParser.getClass().getSimpleName());
|
||||
} else {
|
||||
Loggers.CONTROL.info("HttpTpsCheckRequestParser register parser {} of name {},point name {}",
|
||||
httpTpsCheckParser.getClass().getSimpleName(), httpTpsCheckParser.getName(),
|
||||
httpTpsCheckParser.getPointName());
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpTpsCheckRequestParser getParser(String pointName) {
|
||||
return PARSER_MAP.get(pointName);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.http;
|
||||
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControlConfig;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* RequestHandlerRegistry.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: RequestHandlerRegistry.java, v 0.1 2020年07月13日 8:24 PM liuzunfei Exp $
|
||||
*/
|
||||
@Service
|
||||
public class HttpTpsPointRegistry implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
RequestMappingHandlerMapping requestMapping = event.getApplicationContext()
|
||||
.getBean(RequestMappingHandlerMapping.class);
|
||||
Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods();
|
||||
for (HandlerMethod handlerMethod : handlerMethods.values()) {
|
||||
Method method = handlerMethod.getMethod();
|
||||
if (method.isAnnotationPresent(TpsControl.class) && TpsControlConfig.isTpsControlEnabled()) {
|
||||
TpsControl tpsControl = method.getAnnotation(TpsControl.class);
|
||||
String pointName = tpsControl.pointName();
|
||||
ControlManagerCenter.getInstance().getTpsControlManager().registerTpsPoint(pointName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.http;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControlConfig;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.tps.response.TpsCheckResponse;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* nacos http control interceptor.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class NacosHttpTpsControlInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final String X_REAL_IP = "X-Real-IP";
|
||||
|
||||
private static final String X_FORWARDED_FOR = "X-Forwarded-For";
|
||||
|
||||
private static final String X_FORWARDED_FOR_SPLIT_SYMBOL = ",";
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
try {
|
||||
if (handler instanceof HandlerMethod) {
|
||||
Method method = ((HandlerMethod) handler).getMethod();
|
||||
if (method.isAnnotationPresent(TpsControl.class) && TpsControlConfig.isTpsControlEnabled()) {
|
||||
|
||||
TpsControl tpsControl = method.getAnnotation(TpsControl.class);
|
||||
String pointName = tpsControl.pointName();
|
||||
HttpTpsCheckRequestParser parser = HttpTpsCheckRequestParserRegistry.getParser(pointName);
|
||||
TpsCheckRequest httpTpsCheckRequest = null;
|
||||
if (parser != null) {
|
||||
httpTpsCheckRequest = parser.parse(request);
|
||||
}
|
||||
if (httpTpsCheckRequest == null) {
|
||||
httpTpsCheckRequest = new TpsCheckRequest();
|
||||
}
|
||||
|
||||
httpTpsCheckRequest.setPointName(pointName);
|
||||
TpsCheckResponse checkResponse = ControlManagerCenter.getInstance().getTpsControlManager()
|
||||
.check(httpTpsCheckRequest);
|
||||
if (!checkResponse.isSuccess()) {
|
||||
generate503Response(request, response, checkResponse.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.TPS.error("Error to check tps control", throwable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getRemoteIp(HttpServletRequest request) {
|
||||
String xForwardedFor = request.getHeader(X_FORWARDED_FOR);
|
||||
if (!StringUtils.isBlank(xForwardedFor)) {
|
||||
return xForwardedFor.split(X_FORWARDED_FOR_SPLIT_SYMBOL)[0].trim();
|
||||
}
|
||||
String nginxHeader = request.getHeader(X_REAL_IP);
|
||||
return StringUtils.isBlank(nginxHeader) ? request.getRemoteAddr() : nginxHeader;
|
||||
}
|
||||
|
||||
void generate503Response(HttpServletRequest request, HttpServletResponse response, String message) {
|
||||
|
||||
try {
|
||||
// Disable cache.
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
response.setHeader("Cache-Control", "no-cache,no-store");
|
||||
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
|
||||
response.getWriter().println(message);
|
||||
} catch (Exception ex) {
|
||||
Loggers.TPS.error("Error to generate tps 503 response", ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.http;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* http tps control configurer.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@Component
|
||||
public class NacosHttpTpsControlWebMvcConfigurer implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new NacosHttpTpsControlInterceptor());
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.remote;
|
||||
|
||||
import com.alibaba.nacos.api.remote.request.Request;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
|
||||
/**
|
||||
* remote tps check request parser.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class RemoteTpsCheckRequestParser {
|
||||
|
||||
public RemoteTpsCheckRequestParser() {
|
||||
RemoteTpsCheckRequestParserRegistry.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse tps check request.
|
||||
*
|
||||
* @param request request.
|
||||
* @param meta meta.
|
||||
* @return
|
||||
*/
|
||||
public abstract TpsCheckRequest parse(Request request, RequestMeta meta);
|
||||
|
||||
/**
|
||||
* get point name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getPointName();
|
||||
|
||||
/**
|
||||
* get name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getName();
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.remote;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* remote tps check request parser registry.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class RemoteTpsCheckRequestParserRegistry {
|
||||
|
||||
static final Map<String, RemoteTpsCheckRequestParser> PARSER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* register remoteTpsCheckParser.
|
||||
*
|
||||
* @param remoteTpsCheckParser remoteTpsCheckParser.
|
||||
*/
|
||||
public static void register(RemoteTpsCheckRequestParser remoteTpsCheckParser) {
|
||||
RemoteTpsCheckRequestParser prevRemoteTpsCheckParser = PARSER_MAP
|
||||
.put(remoteTpsCheckParser.getName(), remoteTpsCheckParser);
|
||||
if (prevRemoteTpsCheckParser != null) {
|
||||
Loggers.CONTROL.info("RemoteTpsCheckRequestParser name {},point name {} will be replaced with {}",
|
||||
remoteTpsCheckParser.getName(), remoteTpsCheckParser.getPointName(),
|
||||
remoteTpsCheckParser.getClass().getSimpleName());
|
||||
} else {
|
||||
Loggers.CONTROL.info("RemoteTpsCheckRequestParser register parser {} of name {},point name {}",
|
||||
remoteTpsCheckParser.getClass().getSimpleName(), remoteTpsCheckParser.getName(),
|
||||
remoteTpsCheckParser.getPointName());
|
||||
}
|
||||
}
|
||||
|
||||
public static RemoteTpsCheckRequestParser getParser(String name) {
|
||||
return PARSER_MAP.get(name);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.control.remote;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.request.Request;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.remote.response.Response;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControlConfig;
|
||||
import com.alibaba.nacos.core.remote.AbstractRequestFilter;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsControlManager;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.tps.response.TpsCheckResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* tps control point.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: TpsControlRequestFilter.java, v 0.1 2021年01月09日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
@Service
|
||||
public class TpsControlRequestFilter extends AbstractRequestFilter {
|
||||
|
||||
TpsControlManager tpsControlManager = ControlManagerCenter.getInstance().getTpsControlManager();
|
||||
|
||||
@Override
|
||||
protected Response filter(Request request, RequestMeta meta, Class handlerClazz) {
|
||||
|
||||
Method method = null;
|
||||
try {
|
||||
method = getHandleMethod(handlerClazz);
|
||||
} catch (NacosException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(TpsControl.class) && TpsControlConfig.isTpsControlEnabled()) {
|
||||
|
||||
try {
|
||||
TpsControl tpsControl = method.getAnnotation(TpsControl.class);
|
||||
String pointName = tpsControl.pointName();
|
||||
TpsCheckRequest tpsCheckRequest = null;
|
||||
String parseName = StringUtils.isBlank(tpsControl.name()) ? pointName : tpsControl.name();
|
||||
RemoteTpsCheckRequestParser parser = RemoteTpsCheckRequestParserRegistry.getParser(parseName);
|
||||
if (parser != null) {
|
||||
tpsCheckRequest = parser.parse(request, meta);
|
||||
}
|
||||
if (tpsCheckRequest == null) {
|
||||
tpsCheckRequest = new TpsCheckRequest();
|
||||
}
|
||||
tpsCheckRequest.setPointName(pointName);
|
||||
|
||||
TpsCheckResponse check = tpsControlManager.check(tpsCheckRequest);
|
||||
|
||||
if (!check.isSuccess()) {
|
||||
Response response;
|
||||
try {
|
||||
response = super.getDefaultResponseInstance(handlerClazz);
|
||||
response.setErrorInfo(NacosException.OVER_THRESHOLD,
|
||||
"Tps Flow restricted:" + check.getMessage());
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
com.alibaba.nacos.plugin.control.Loggers.TPS
|
||||
.warn("Tps check fail , request: {},exception:{}", request.getClass().getSimpleName(),
|
||||
e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
com.alibaba.nacos.plugin.control.Loggers.TPS
|
||||
.warn("Tps check exception , request: {},exception:{}", request.getClass().getSimpleName(),
|
||||
throwable);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -12,53 +13,35 @@
|
||||
* 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.alibaba.nacos.core.remote;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.RemoteConstants;
|
||||
import com.alibaba.nacos.api.remote.RequestCallBack;
|
||||
import com.alibaba.nacos.api.remote.RpcScheduledExecutor;
|
||||
import com.alibaba.nacos.api.remote.request.ClientDetectionRequest;
|
||||
import com.alibaba.nacos.api.remote.request.ConnectResetRequest;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.remote.response.Response;
|
||||
import com.alibaba.nacos.api.utils.NetUtils;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.remote.exception.ConnectionAlreadyClosedException;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.common.utils.VersionUtils;
|
||||
import com.alibaba.nacos.core.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.core.remote.event.ConnectionLimitRuleChangeEvent;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.file.FileChangeEvent;
|
||||
import com.alibaba.nacos.sys.file.FileWatcher;
|
||||
import com.alibaba.nacos.sys.file.WatchFileCenter;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import com.alibaba.nacos.plugin.control.connection.request.ConnectionCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.connection.response.ConnectionCheckResponse;
|
||||
import com.alibaba.nacos.plugin.control.connection.rule.ConnectionControlRule;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -69,37 +52,20 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @version $Id: ConnectionManager.java, v 0.1 2020年07月13日 7:07 PM liuzunfei Exp $
|
||||
*/
|
||||
@Service
|
||||
public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent> {
|
||||
public class ConnectionManager {
|
||||
|
||||
public static final String RULE_FILE_NAME = "limitRule";
|
||||
|
||||
/**
|
||||
* 4 times of client keep alive.
|
||||
*/
|
||||
private static final long KEEP_ALIVE_TIME = 20000L;
|
||||
|
||||
/**
|
||||
* connection limit rule.
|
||||
*/
|
||||
private ConnectionLimitRule connectionLimitRule = new ConnectionLimitRule();
|
||||
|
||||
/**
|
||||
* current loader adjust count,only effective once,use to re balance.
|
||||
*/
|
||||
private int loadClient = -1;
|
||||
|
||||
String redirectAddress = null;
|
||||
private static final Logger LOGGER = com.alibaba.nacos.plugin.control.Loggers.CONNECTION;
|
||||
|
||||
private Map<String, AtomicInteger> connectionForClientIp = new ConcurrentHashMap<>(16);
|
||||
|
||||
Map<String, Connection> connections = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private RuntimeConnectionEjector runtimeConnectionEjector;
|
||||
|
||||
private ClientConnectionEventListenerRegistry clientConnectionEventListenerRegistry;
|
||||
|
||||
public ConnectionManager() {
|
||||
NotifyCenter.registerToPublisher(ConnectionLimitRuleChangeEvent.class, NotifyCenter.ringBufferSize);
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
public ConnectionManager(ClientConnectionEventListenerRegistry clientConnectionEventListenerRegistry) {
|
||||
this.clientConnectionEventListenerRegistry = clientConnectionEventListenerRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,18 +75,10 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
* @return
|
||||
*/
|
||||
public boolean traced(String clientIp) {
|
||||
return connectionLimitRule != null && connectionLimitRule.getMonitorIpList() != null && connectionLimitRule
|
||||
.getMonitorIpList().contains(clientIp);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void initLimitRue() {
|
||||
try {
|
||||
loadRuleFromLocal();
|
||||
registerFileWatch();
|
||||
} catch (Exception e) {
|
||||
Loggers.REMOTE.warn("Fail to init limit rue from local ,error= ", e);
|
||||
}
|
||||
ConnectionControlRule connectionControlRule = ControlManagerCenter.getInstance().getConnectionControlManager()
|
||||
.getConnectionLimitRule();
|
||||
return connectionControlRule != null && connectionControlRule.getMonitorIpList() != null
|
||||
&& connectionControlRule.getMonitorIpList().contains(clientIp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,22 +100,26 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
public synchronized boolean register(String connectionId, Connection connection) {
|
||||
|
||||
if (connection.isConnected()) {
|
||||
String clientIp = connection.getMetaInfo().clientIp;
|
||||
if (connections.containsKey(connectionId)) {
|
||||
return true;
|
||||
}
|
||||
if (!checkLimit(connection)) {
|
||||
if (checkLimit(connection)) {
|
||||
return false;
|
||||
}
|
||||
if (traced(connection.getMetaInfo().clientIp)) {
|
||||
if (traced(clientIp)) {
|
||||
connection.setTraced(true);
|
||||
}
|
||||
connections.put(connectionId, connection);
|
||||
connectionForClientIp.get(connection.getMetaInfo().clientIp).getAndIncrement();
|
||||
if (!connectionForClientIp.containsKey(clientIp)) {
|
||||
connectionForClientIp.put(clientIp, new AtomicInteger(0));
|
||||
}
|
||||
connectionForClientIp.get(clientIp).getAndIncrement();
|
||||
|
||||
clientConnectionEventListenerRegistry.notifyClientConnected(connection);
|
||||
Loggers.REMOTE_DIGEST
|
||||
.info("new connection registered successfully, connectionId = {},connection={} ", connectionId,
|
||||
connection);
|
||||
|
||||
LOGGER.info("new connection registered successfully, connectionId = {},connection={} ", connectionId,
|
||||
connection);
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -166,49 +128,16 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
}
|
||||
|
||||
private boolean checkLimit(Connection connection) {
|
||||
String clientIp = connection.getMetaInfo().clientIp;
|
||||
|
||||
if (connection.getMetaInfo().isClusterSource()) {
|
||||
if (!connectionForClientIp.containsKey(clientIp)) {
|
||||
connectionForClientIp.putIfAbsent(clientIp, new AtomicInteger(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isOverLimit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!connectionForClientIp.containsKey(clientIp)) {
|
||||
connectionForClientIp.putIfAbsent(clientIp, new AtomicInteger(0));
|
||||
}
|
||||
|
||||
AtomicInteger currentCount = connectionForClientIp.get(clientIp);
|
||||
|
||||
if (connectionLimitRule != null) {
|
||||
// 1.check rule of specific client ip limit.
|
||||
if (connectionLimitRule.getCountLimitPerClientIp().containsKey(clientIp)) {
|
||||
Integer integer = connectionLimitRule.getCountLimitPerClientIp().get(clientIp);
|
||||
if (integer != null && integer >= 0) {
|
||||
return currentCount.get() < integer;
|
||||
}
|
||||
}
|
||||
// 2.check rule of specific client app limit.
|
||||
String appName = connection.getMetaInfo().getAppName();
|
||||
if (StringUtils.isNotBlank(appName) && connectionLimitRule.getCountLimitPerClientApp()
|
||||
.containsKey(appName)) {
|
||||
Integer integerApp = connectionLimitRule.getCountLimitPerClientApp().get(appName);
|
||||
if (integerApp != null && integerApp >= 0) {
|
||||
return currentCount.get() < integerApp;
|
||||
}
|
||||
}
|
||||
|
||||
// 3.check rule of default client ip.
|
||||
int countLimitPerClientIpDefault = connectionLimitRule.getCountLimitPerClientIpDefault();
|
||||
return countLimitPerClientIpDefault <= 0 || currentCount.get() < countLimitPerClientIpDefault;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
ConnectionMeta metaInfo = connection.getMetaInfo();
|
||||
ConnectionCheckRequest connectionCheckRequest = new ConnectionCheckRequest(metaInfo.getClientIp(),
|
||||
metaInfo.getAppName(), metaInfo.getLabel(RemoteConstants.LABEL_SOURCE));
|
||||
connectionCheckRequest.setLabels(connection.getLabels());
|
||||
ConnectionCheckResponse checkResponse = ControlManagerCenter.getInstance().getConnectionControlManager()
|
||||
.check(connectionCheckRequest);
|
||||
return !checkResponse.isSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,7 +157,7 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
}
|
||||
}
|
||||
remove.close();
|
||||
Loggers.REMOTE_DIGEST.info("[{}]Connection unregistered successfully. ", connectionId);
|
||||
LOGGER.info("[{}]Connection unregistered successfully. ", connectionId);
|
||||
clientConnectionEventListenerRegistry.notifyClientDisConnected(remove);
|
||||
}
|
||||
}
|
||||
@ -261,6 +190,34 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
return connections;
|
||||
}
|
||||
|
||||
/**
|
||||
* init connection ejector.
|
||||
*/
|
||||
public void initConnectionEjector() {
|
||||
String connectionRuntimeEjector = null;
|
||||
try {
|
||||
connectionRuntimeEjector = ControlConfigs.getInstance().getConnectionRuntimeEjector();
|
||||
Collection<RuntimeConnectionEjector> ejectors = NacosServiceLoader.load(RuntimeConnectionEjector.class);
|
||||
for (RuntimeConnectionEjector runtimeConnectionEjectorLoad : ejectors) {
|
||||
if (runtimeConnectionEjectorLoad.getName().equalsIgnoreCase(connectionRuntimeEjector)) {
|
||||
Loggers.CONNECTION.info("Found connection runtime ejector for name {}", connectionRuntimeEjector);
|
||||
runtimeConnectionEjectorLoad.setConnectionManager(this);
|
||||
runtimeConnectionEjector = runtimeConnectionEjectorLoad;
|
||||
}
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.CONNECTION.warn("Fail to load runtime ejector ", throwable);
|
||||
}
|
||||
|
||||
if (runtimeConnectionEjector == null) {
|
||||
Loggers.CONNECTION
|
||||
.info("Fail to find connection runtime ejector for name {},use default", connectionRuntimeEjector);
|
||||
NacosRuntimeConnectionEjector nacosRuntimeConnectionEjector = new NacosRuntimeConnectionEjector();
|
||||
nacosRuntimeConnectionEjector.setConnectionManager(this);
|
||||
runtimeConnectionEjector = nacosRuntimeConnectionEjector;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get current connections count.
|
||||
*
|
||||
@ -288,211 +245,17 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
|
||||
initConnectionEjector();
|
||||
// Start UnHealthy Connection Expel Task.
|
||||
RpcScheduledExecutor.COMMON_SERVER_EXECUTOR.scheduleWithFixedDelay(() -> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//reset loader client
|
||||
|
||||
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);
|
||||
}
|
||||
runtimeConnectionEjector.doEject();
|
||||
}, 1000L, 3000L, TimeUnit.MILLISECONDS);
|
||||
|
||||
}
|
||||
|
||||
private RequestMeta buildMeta() {
|
||||
RequestMeta meta = new RequestMeta();
|
||||
meta.setClientVersion(VersionUtils.getFullClientVersion());
|
||||
meta.setClientIp(NetUtils.localIP());
|
||||
return meta;
|
||||
}
|
||||
|
||||
public void loadCount(int loadClient, String redirectAddress) {
|
||||
this.loadClient = loadClient;
|
||||
this.redirectAddress = redirectAddress;
|
||||
runtimeConnectionEjector.setLoadClient(loadClient);
|
||||
runtimeConnectionEjector.setRedirectAddress(redirectAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -517,7 +280,7 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
} catch (ConnectionAlreadyClosedException e) {
|
||||
unregister(connectionId);
|
||||
} catch (Exception e) {
|
||||
Loggers.REMOTE.error("error occurs when expel connection, connectionId: {} ", connectionId, e);
|
||||
LOGGER.error("error occurs when expel connection, connectionId: {} ", connectionId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -572,188 +335,7 @@ public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent
|
||||
return connections;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if over limit.
|
||||
*
|
||||
* @return over limit or not.
|
||||
*/
|
||||
private boolean isOverLimit() {
|
||||
return connectionLimitRule.countLimit > 0 && currentSdkClientCount() >= connectionLimitRule.getCountLimit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ConnectionLimitRuleChangeEvent event) {
|
||||
String limitRule = event.getLimitRule();
|
||||
Loggers.REMOTE.info("connection limit rule change event receive :{}", limitRule);
|
||||
|
||||
try {
|
||||
ConnectionLimitRule connectionLimitRule = JacksonUtils.toObj(limitRule, ConnectionLimitRule.class);
|
||||
if (connectionLimitRule != null) {
|
||||
this.connectionLimitRule = connectionLimitRule;
|
||||
|
||||
try {
|
||||
saveRuleToLocal(this.connectionLimitRule);
|
||||
} catch (Exception e) {
|
||||
Loggers.REMOTE.warn("Fail to save rule to local error is ", e);
|
||||
}
|
||||
} else {
|
||||
Loggers.REMOTE.info("Parse rule is null,Ignore illegal rule :{}", limitRule);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Loggers.REMOTE.error("Fail to parse connection limit rule :{}", limitRule, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return ConnectionLimitRuleChangeEvent.class;
|
||||
}
|
||||
|
||||
static class ConnectionLimitRule {
|
||||
|
||||
private Set<String> monitorIpList = new HashSet<>();
|
||||
|
||||
private int countLimit = -1;
|
||||
|
||||
private int countLimitPerClientIpDefault = -1;
|
||||
|
||||
private Map<String, Integer> countLimitPerClientIp = new HashMap<>();
|
||||
|
||||
private Map<String, Integer> countLimitPerClientApp = new HashMap<>();
|
||||
|
||||
public int getCountLimit() {
|
||||
return countLimit;
|
||||
}
|
||||
|
||||
public void setCountLimit(int countLimit) {
|
||||
this.countLimit = countLimit;
|
||||
}
|
||||
|
||||
public int getCountLimitPerClientIpDefault() {
|
||||
return countLimitPerClientIpDefault;
|
||||
}
|
||||
|
||||
public void setCountLimitPerClientIpDefault(int countLimitPerClientIpDefault) {
|
||||
this.countLimitPerClientIpDefault = countLimitPerClientIpDefault;
|
||||
}
|
||||
|
||||
public int getCountLimitOfIp(String clientIp) {
|
||||
if (countLimitPerClientIp.containsKey(clientIp)) {
|
||||
Integer integer = countLimitPerClientIp.get(clientIp);
|
||||
if (integer != null && integer >= 0) {
|
||||
return integer;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getCountLimitOfApp(String appName) {
|
||||
if (countLimitPerClientApp.containsKey(appName)) {
|
||||
Integer integer = countLimitPerClientApp.get(appName);
|
||||
if (integer != null && integer >= 0) {
|
||||
return integer;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getCountLimitPerClientIp() {
|
||||
return countLimitPerClientIp;
|
||||
}
|
||||
|
||||
public void setCountLimitPerClientIp(Map<String, Integer> countLimitPerClientIp) {
|
||||
this.countLimitPerClientIp = countLimitPerClientIp;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getCountLimitPerClientApp() {
|
||||
return countLimitPerClientApp;
|
||||
}
|
||||
|
||||
public void setCountLimitPerClientApp(Map<String, Integer> countLimitPerClientApp) {
|
||||
this.countLimitPerClientApp = countLimitPerClientApp;
|
||||
}
|
||||
|
||||
public Set<String> getMonitorIpList() {
|
||||
return monitorIpList;
|
||||
}
|
||||
|
||||
public void setMonitorIpList(Set<String> monitorIpList) {
|
||||
this.monitorIpList = monitorIpList;
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionLimitRule getConnectionLimitRule() {
|
||||
return connectionLimitRule;
|
||||
}
|
||||
|
||||
private synchronized void loadRuleFromLocal() throws Exception {
|
||||
File limitFile = getRuleFile();
|
||||
if (!limitFile.exists()) {
|
||||
limitFile.createNewFile();
|
||||
}
|
||||
|
||||
String ruleContent = DiskUtils.readFile(limitFile);
|
||||
ConnectionLimitRule connectionLimitRule = StringUtils.isBlank(ruleContent) ? new ConnectionLimitRule()
|
||||
: JacksonUtils.toObj(ruleContent, ConnectionLimitRule.class);
|
||||
// apply rule.
|
||||
if (connectionLimitRule != null) {
|
||||
this.connectionLimitRule = connectionLimitRule;
|
||||
Set<String> monitorIpList = connectionLimitRule.monitorIpList;
|
||||
for (Connection connection : this.connections.values()) {
|
||||
String clientIp = connection.getMetaInfo().getClientIp();
|
||||
if (!CollectionUtils.isEmpty(monitorIpList) && monitorIpList.contains(clientIp)) {
|
||||
connection.setTraced(true);
|
||||
} else {
|
||||
connection.setTraced(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loggers.REMOTE.info("Init loader limit rule from local,rule={}", ruleContent);
|
||||
|
||||
}
|
||||
|
||||
private synchronized void saveRuleToLocal(ConnectionLimitRule limitRule) throws IOException {
|
||||
|
||||
File limitFile = getRuleFile();
|
||||
if (!limitFile.exists()) {
|
||||
limitFile.createNewFile();
|
||||
}
|
||||
DiskUtils.writeFile(limitFile, JacksonUtils.toJson(limitRule).getBytes(Constants.ENCODE), false);
|
||||
}
|
||||
|
||||
private File getRuleFile() {
|
||||
File baseDir = new File(EnvUtil.getNacosHome(), "data" + File.separator + "loader" + File.separator);
|
||||
if (!baseDir.exists()) {
|
||||
baseDir.mkdir();
|
||||
}
|
||||
return new File(baseDir, RULE_FILE_NAME);
|
||||
}
|
||||
|
||||
private void registerFileWatch() {
|
||||
try {
|
||||
String tpsPath = Paths.get(EnvUtil.getNacosHome(), "data", "loader").toString();
|
||||
WatchFileCenter.registerWatcher(tpsPath, new FileWatcher() {
|
||||
@Override
|
||||
public void onChange(FileChangeEvent event) {
|
||||
try {
|
||||
String fileName = event.getContext().toString();
|
||||
if (RULE_FILE_NAME.equals(fileName)) {
|
||||
loadRuleFromLocal();
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.REMOTE.warn("Fail to load rule from local", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interest(String context) {
|
||||
return RULE_FILE_NAME.equals(context);
|
||||
}
|
||||
});
|
||||
} catch (NacosException e) {
|
||||
Loggers.REMOTE.warn("Register connection rule fail ", e);
|
||||
}
|
||||
public Map<String, AtomicInteger> getConnectionForClientIp() {
|
||||
return connectionForClientIp;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package com.alibaba.nacos.core.remote;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.remote.request.HealthCheckRequest;
|
||||
import com.alibaba.nacos.api.remote.response.HealthCheckResponse;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.connection.ConnectionMetricsCollector;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
|
||||
/**
|
||||
* long connection metrics collector.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class LongConnectionMetricsCollector implements ConnectionMetricsCollector {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "long_connection";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalCount() {
|
||||
return ApplicationUtils.getBean(ConnectionManager.class).currentClientsCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCountForIp(String ip) {
|
||||
ConnectionManager connectionManager = ApplicationUtils.getBean(ConnectionManager.class);
|
||||
if (connectionManager.getConnectionForClientIp().containsKey(ip)) {
|
||||
return connectionManager.getConnectionForClientIp().get(ip).intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote;
|
||||
|
||||
import com.alibaba.nacos.core.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* nacos runtime connection ejector.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class NacosRuntimeConnectionEjector extends RuntimeConnectionEjector {
|
||||
|
||||
public NacosRuntimeConnectionEjector() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* eject connections on runtime.
|
||||
*/
|
||||
public void doEject() {
|
||||
try {
|
||||
|
||||
Map<String, Connection> connections = connectionManager.connections;
|
||||
int totalCount = connections.size();
|
||||
Loggers.CONNECTION.info("Connection check task start");
|
||||
MetricsMonitor.getLongConnectionMonitor().set(totalCount);
|
||||
int currentSdkClientCount = connectionManager.currentSdkClientCount();
|
||||
|
||||
Loggers.CONNECTION
|
||||
.info("Long connection metrics detail ,Total count ={}, sdkCount={},clusterCount={}", totalCount,
|
||||
currentSdkClientCount, (totalCount - currentSdkClientCount));
|
||||
|
||||
Loggers.CONNECTION.info("Connection check task end");
|
||||
|
||||
} catch (Throwable e) {
|
||||
Loggers.CONNECTION.error("Error occurs during connection check... ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "nacos";
|
||||
}
|
||||
}
|
@ -18,11 +18,9 @@ package com.alibaba.nacos.core.remote;
|
||||
|
||||
import com.alibaba.nacos.api.remote.request.Request;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControl;
|
||||
import com.alibaba.nacos.core.remote.control.TpsControlConfig;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorPoint;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.alibaba.nacos.core.control.TpsControl;
|
||||
import com.alibaba.nacos.core.control.TpsControlConfig;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -45,9 +43,6 @@ public class RequestHandlerRegistry implements ApplicationListener<ContextRefres
|
||||
|
||||
Map<String, RequestHandler> registryHandlers = new HashMap<>();
|
||||
|
||||
@Autowired
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
/**
|
||||
* Get Request Handler By request Type.
|
||||
*
|
||||
@ -82,8 +77,7 @@ public class RequestHandlerRegistry implements ApplicationListener<ContextRefres
|
||||
if (method.isAnnotationPresent(TpsControl.class) && TpsControlConfig.isTpsControlEnabled()) {
|
||||
TpsControl tpsControl = method.getAnnotation(TpsControl.class);
|
||||
String pointName = tpsControl.pointName();
|
||||
TpsMonitorPoint tpsMonitorPoint = new TpsMonitorPoint(pointName);
|
||||
tpsMonitorManager.registerTpsControlPoint(tpsMonitorPoint);
|
||||
ControlManagerCenter.getInstance().getTpsControlManager().registerTpsPoint(pointName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignore.
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote;
|
||||
|
||||
/**
|
||||
* runtime connection ejector.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class RuntimeConnectionEjector {
|
||||
|
||||
/**
|
||||
* 4 times of client keep alive.
|
||||
*/
|
||||
public static final long KEEP_ALIVE_TIME = 20000L;
|
||||
|
||||
/**
|
||||
* current loader adjust count,only effective once,use to re balance.
|
||||
*/
|
||||
private int loadClient = -1;
|
||||
|
||||
String redirectAddress = null;
|
||||
|
||||
protected ConnectionManager connectionManager;
|
||||
|
||||
public RuntimeConnectionEjector() {
|
||||
}
|
||||
|
||||
public ConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
|
||||
public void setConnectionManager(ConnectionManager connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* eject runtime connection.
|
||||
*/
|
||||
public abstract void doEject();
|
||||
|
||||
public int getLoadClient() {
|
||||
return loadClient;
|
||||
}
|
||||
|
||||
public void setLoadClient(int loadClient) {
|
||||
this.loadClient = loadClient;
|
||||
}
|
||||
|
||||
public String getRedirectAddress() {
|
||||
return redirectAddress;
|
||||
}
|
||||
|
||||
public void setRedirectAddress(String redirectAddress) {
|
||||
this.redirectAddress = redirectAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* get name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getName();
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
|
||||
/**
|
||||
* MonitorType.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: MonitorKey.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class MonitorKey {
|
||||
|
||||
String key;
|
||||
|
||||
public MonitorKey() {
|
||||
|
||||
}
|
||||
|
||||
public MonitorKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* get monitor key type.
|
||||
*
|
||||
* @return type.
|
||||
*/
|
||||
public abstract String getType();
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String build() {
|
||||
return this.getType() + Constants.COLON + this.getKey();
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* MatchMode.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: MatchMode.java, v 0.1 2021年01月22日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AbstractClassShouldStartWithAbstractNamingRule", "PMD.UndefineMagicConstantRule"})
|
||||
public class MonitorKeyMatcher {
|
||||
|
||||
/**
|
||||
* if provided monitor key match this monitor ,with monitor type.
|
||||
*
|
||||
* @param monitorKey monitorKey.
|
||||
* @return type matched result.
|
||||
*/
|
||||
public static boolean matchWithType(String pattern, String monitorKey) {
|
||||
String[] typeInPattern = pattern.split(Constants.COLON);
|
||||
String[] typeInMonitorKey = monitorKey.split(Constants.COLON);
|
||||
if (!Objects.equals(typeInPattern[0], typeInMonitorKey[0])) {
|
||||
return false;
|
||||
}
|
||||
return match(pattern.substring(pattern.indexOf(Constants.COLON)),
|
||||
monitorKey.substring(monitorKey.indexOf(Constants.COLON)));
|
||||
}
|
||||
|
||||
/**
|
||||
* if provided monitor key match this monitor.
|
||||
*
|
||||
* @param monitorKey monitorKey.
|
||||
* @return matched result.
|
||||
*/
|
||||
public static boolean match(String pattern, String monitorKey) {
|
||||
pattern = pattern.trim();
|
||||
monitorKey = monitorKey.trim();
|
||||
//"AB",equals.
|
||||
if (!pattern.contains(Constants.ALL_PATTERN)) {
|
||||
return pattern.equals(monitorKey.trim());
|
||||
}
|
||||
//"*",match all.
|
||||
if (pattern.equals(Constants.ALL_PATTERN)) {
|
||||
return true;
|
||||
}
|
||||
String[] split = pattern.split("\\" + Constants.ALL_PATTERN);
|
||||
|
||||
if (split.length == 1) {
|
||||
//"A*",prefix match.
|
||||
return monitorKey.startsWith(split[0]);
|
||||
} else if (split.length == 2) {
|
||||
//"*A",postfix match.
|
||||
if (StringUtils.isBlank(split[0])) {
|
||||
return monitorKey.endsWith(split[1]);
|
||||
}
|
||||
return monitorKey.startsWith(split[0]) && monitorKey.endsWith(split[1]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.request.Request;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.remote.response.Response;
|
||||
import com.alibaba.nacos.core.remote.AbstractRequestFilter;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* tps control point.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: TpsControlRequestFilter.java, v 0.1 2021年01月09日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
@Service
|
||||
public class TpsControlRequestFilter extends AbstractRequestFilter {
|
||||
|
||||
@Autowired
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
@Override
|
||||
protected Response filter(Request request, RequestMeta meta, Class handlerClazz) {
|
||||
|
||||
Method method = null;
|
||||
try {
|
||||
method = getHandleMethod(handlerClazz);
|
||||
} catch (NacosException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(TpsControl.class) && TpsControlConfig.isTpsControlEnabled()) {
|
||||
|
||||
TpsControl tpsControl = method.getAnnotation(TpsControl.class);
|
||||
|
||||
String pointName = tpsControl.pointName();
|
||||
Class[] parsers = tpsControl.parsers();
|
||||
List<MonitorKey> monitorKeys = new ArrayList<>();
|
||||
monitorKeys.add(new ClientIpMonitorKey(meta.getClientIp()));
|
||||
if (parsers != null) {
|
||||
for (Class clazz : parsers) {
|
||||
try {
|
||||
if (MonitorKeyParser.class.isAssignableFrom(clazz)) {
|
||||
MonitorKey parseKey = ((MonitorKeyParser) (clazz.newInstance())).parse(request, meta);
|
||||
if (parseKey != null) {
|
||||
monitorKeys.add(parseKey);
|
||||
}
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean pass = tpsMonitorManager.applyTps(pointName, meta.getConnectionId(), monitorKeys);
|
||||
|
||||
if (!pass) {
|
||||
Response response;
|
||||
try {
|
||||
response = super.getDefaultResponseInstance(handlerClazz);
|
||||
response.setErrorInfo(NacosException.OVER_THRESHOLD, "Tps Flow restricted");
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
Loggers.TPS_CONTROL_DETAIL
|
||||
.warn("Tps monitor fail , request: {},exception:{}", request.getClass().getSimpleName(), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* tps control point.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: TpsControlPoint.java, v 0.1 2021年01月09日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class TpsControlRule {
|
||||
|
||||
private String pointName;
|
||||
|
||||
private Rule pointRule;
|
||||
|
||||
/**
|
||||
* Pattern,Rule map.
|
||||
*/
|
||||
private Map<String, Rule> monitorKeyRule = new HashMap<>();
|
||||
|
||||
public String getPointName() {
|
||||
return pointName;
|
||||
}
|
||||
|
||||
public void setPointName(String pointName) {
|
||||
this.pointName = pointName;
|
||||
}
|
||||
|
||||
public Rule getPointRule() {
|
||||
return pointRule;
|
||||
}
|
||||
|
||||
public void setPointRule(Rule pointRule) {
|
||||
this.pointRule = pointRule;
|
||||
}
|
||||
|
||||
public Map<String, Rule> getMonitorKeyRule() {
|
||||
return monitorKeyRule;
|
||||
}
|
||||
|
||||
public void setMonitorKeyRule(Map<String, Rule> monitorKeyRule) {
|
||||
this.monitorKeyRule = monitorKeyRule;
|
||||
}
|
||||
|
||||
public static class Rule {
|
||||
|
||||
long maxCount = -1;
|
||||
|
||||
TimeUnit period = TimeUnit.SECONDS;
|
||||
|
||||
public static final String MODEL_FUZZY = "FUZZY";
|
||||
|
||||
public static final String MODEL_PROTO = "PROTO";
|
||||
|
||||
String model = MODEL_FUZZY;
|
||||
|
||||
/**
|
||||
* monitor/intercept.
|
||||
*/
|
||||
String monitorType = "";
|
||||
|
||||
public Rule() {
|
||||
|
||||
}
|
||||
|
||||
public boolean isFuzzyModel() {
|
||||
return MODEL_FUZZY.equalsIgnoreCase(model);
|
||||
}
|
||||
|
||||
public boolean isProtoModel() {
|
||||
return MODEL_PROTO.equalsIgnoreCase(model);
|
||||
}
|
||||
|
||||
public Rule(long maxCount, TimeUnit period, String model, String monitorType) {
|
||||
this.maxCount = maxCount;
|
||||
this.period = period;
|
||||
this.model = model;
|
||||
this.monitorType = monitorType;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public TimeUnit getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public void setPeriod(TimeUnit period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public long getMaxCount() {
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
public void setMaxCount(long maxCount) {
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
public String getMonitorType() {
|
||||
return monitorType;
|
||||
}
|
||||
|
||||
public void setMonitorType(String monitorType) {
|
||||
this.monitorType = monitorType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Rule{" + "maxTps=" + maxCount + ", monitorType='" + monitorType + '\'' + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TpsControlRule{" + "pointName='" + pointName + '\'' + ", pointRule=" + pointRule + ", monitorKeyRule="
|
||||
+ monitorKeyRule + '}';
|
||||
}
|
||||
}
|
@ -1,328 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.common.executor.ExecutorFactory;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.common.utils.ThreadUtils;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.file.FileChangeEvent;
|
||||
import com.alibaba.nacos.sys.file.FileWatcher;
|
||||
import com.alibaba.nacos.sys.file.WatchFileCenter;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* tps control manager.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: TpsControlManager.java, v 0.1 2021年01月09日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
@Service
|
||||
public class TpsMonitorManager extends Subscriber<TpsControlRuleChangeEvent> implements DisposableBean {
|
||||
|
||||
public final Map<String, TpsMonitorPoint> points = new ConcurrentHashMap<>(16);
|
||||
|
||||
private static ScheduledExecutorService executorService = ExecutorFactory.newSingleScheduledExecutorService(r -> {
|
||||
Thread thread = new Thread(r, "nacos.core.remote.tps.control.reporter");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
|
||||
public TpsMonitorManager() {
|
||||
NotifyCenter.registerToPublisher(TpsControlRuleChangeEvent.class, NotifyCenter.ringBufferSize);
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
executorService.scheduleWithFixedDelay(new TpsMonitorReporter(), 0, 900, TimeUnit.MILLISECONDS);
|
||||
registerFileWatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* register point.
|
||||
*
|
||||
* @param tpsMonitorPoint tps point.
|
||||
*/
|
||||
public void registerTpsControlPoint(TpsMonitorPoint tpsMonitorPoint) {
|
||||
Loggers.TPS_CONTROL
|
||||
.info("Register tps control,pointName={}, point={} ", tpsMonitorPoint.getPointName(), tpsMonitorPoint);
|
||||
try {
|
||||
loadRuleFromLocal(tpsMonitorPoint);
|
||||
} catch (IOException e) {
|
||||
Loggers.TPS_CONTROL
|
||||
.error("Fail to init rule from local,pointName={},error={}", tpsMonitorPoint.getPointName(), e);
|
||||
}
|
||||
points.putIfAbsent(tpsMonitorPoint.getPointName(), tpsMonitorPoint);
|
||||
|
||||
}
|
||||
|
||||
private void registerFileWatch() {
|
||||
try {
|
||||
String tpsPath = Paths.get(EnvUtil.getNacosHome(), "data" + File.separator + "tps" + File.separator)
|
||||
.toString();
|
||||
checkBaseDir();
|
||||
WatchFileCenter.registerWatcher(tpsPath, new FileWatcher() {
|
||||
@Override
|
||||
public void onChange(FileChangeEvent event) {
|
||||
String fileName = event.getContext().toString();
|
||||
try {
|
||||
|
||||
if (points.get(fileName) != null) {
|
||||
loadRuleFromLocal(points.get(fileName));
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.TPS_CONTROL
|
||||
.warn("Fail to load rule from local,pointName={},error={}", fileName, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interest(String context) {
|
||||
for (String pointName : points.keySet()) {
|
||||
if (context.equals(pointName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} catch (NacosException e) {
|
||||
Loggers.TPS_CONTROL.warn("Register fire watch fail.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* apply tps.
|
||||
*
|
||||
* @param clientIp clientIp.
|
||||
* @param pointName pointName.
|
||||
* @return pass or not.
|
||||
*/
|
||||
public boolean applyTpsForClientIp(String pointName, String connectionId, String clientIp) {
|
||||
if (points.containsKey(pointName)) {
|
||||
|
||||
return points.get(pointName).applyTps(connectionId, Arrays.asList(new ClientIpMonitorKey(clientIp)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply tps.
|
||||
*
|
||||
* @param pointName pointName.
|
||||
* @param monitorKeyList monitorKeyList.
|
||||
* @return pass or not.
|
||||
*/
|
||||
public boolean applyTps(String pointName, String connectionId, List<MonitorKey> monitorKeyList) {
|
||||
if (points.containsKey(pointName)) {
|
||||
return points.get(pointName).applyTps(connectionId, monitorKeyList);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(TpsControlRuleChangeEvent event) {
|
||||
if (event == null) {
|
||||
Loggers.TPS_CONTROL.info("Tps control rule change event receive, but event is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Loggers.TPS_CONTROL
|
||||
.info("Tps control rule change event receive, pointName={}, ruleContent={} ", event.getPointName(),
|
||||
event.ruleContent);
|
||||
if (event.getPointName() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
TpsControlRule tpsControlRule = StringUtils.isBlank(event.ruleContent) ? new TpsControlRule()
|
||||
: JacksonUtils.toObj(event.ruleContent, TpsControlRule.class);
|
||||
if (!points.containsKey(event.getPointName())) {
|
||||
Loggers.TPS_CONTROL.info("Tps control rule change event ignore, pointName={} ", event.getPointName());
|
||||
return;
|
||||
}
|
||||
|
||||
saveRuleToLocal(event.getPointName(), tpsControlRule);
|
||||
} catch (Exception e) {
|
||||
Loggers.TPS_CONTROL.warn("Tps control rule apply error, error= ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return TpsControlRuleChangeEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (executorService == null) {
|
||||
return;
|
||||
}
|
||||
ThreadUtils.shutdownThreadPool(executorService);
|
||||
}
|
||||
|
||||
class TpsMonitorReporter implements Runnable {
|
||||
|
||||
long lastReportSecond = 0L;
|
||||
|
||||
long lastReportMinutes = 0L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
Set<Map.Entry<String, TpsMonitorPoint>> entries = points.entrySet();
|
||||
|
||||
long tempSecond = 0L;
|
||||
long tempMinutes = 0L;
|
||||
|
||||
String formatString = TpsMonitorPoint.getTimeFormatOfSecond(now - 1000L);
|
||||
for (Map.Entry<String, TpsMonitorPoint> entry : entries) {
|
||||
TpsMonitorPoint value = entry.getValue();
|
||||
//get last second
|
||||
TpsRecorder.TpsSlot pointSlot = value.getTpsRecorder().getPoint(now - 1000L);
|
||||
if (pointSlot == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//already reported.
|
||||
if (lastReportSecond != 0L && lastReportSecond == pointSlot.time) {
|
||||
continue;
|
||||
}
|
||||
String point = entry.getKey();
|
||||
tempSecond = pointSlot.time;
|
||||
stringBuilder.append(point).append('|').append("point|").append(value.getTpsRecorder().period)
|
||||
.append('|').append(formatString).append('|')
|
||||
.append(pointSlot.getCountHolder(point).count.get()).append('|')
|
||||
.append(pointSlot.getCountHolder(point).interceptedCount.get()).append('\n');
|
||||
for (Map.Entry<String, TpsRecorder> monitorKeyEntry : value.monitorKeysRecorder.entrySet()) {
|
||||
String monitorPattern = monitorKeyEntry.getKey();
|
||||
TpsRecorder ipRecord = monitorKeyEntry.getValue();
|
||||
TpsRecorder.TpsSlot keySlot = ipRecord.getPoint(now - ipRecord.period.toMillis(1));
|
||||
if (keySlot == null) {
|
||||
continue;
|
||||
}
|
||||
//already reported.
|
||||
if (ipRecord.period == TimeUnit.SECONDS) {
|
||||
if (lastReportSecond != 0L && lastReportSecond == keySlot.time) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ipRecord.period == TimeUnit.MINUTES) {
|
||||
if (lastReportMinutes != 0L && lastReportMinutes == keySlot.time) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
String timeFormatOfSecond = TpsMonitorPoint.getTimeFormatOfSecond(keySlot.time);
|
||||
tempMinutes = keySlot.time;
|
||||
if (ipRecord.isProtoModel()) {
|
||||
Map<String, TpsRecorder.SlotCountHolder> keySlots = ((TpsRecorder.MultiKeyTpsSlot) keySlot).keySlots;
|
||||
for (Map.Entry<String, TpsRecorder.SlotCountHolder> slotCountHolder : keySlots.entrySet()) {
|
||||
stringBuilder.append(point).append('|').append(monitorPattern).append('|')
|
||||
.append(ipRecord.period).append('|').append(timeFormatOfSecond).append('|')
|
||||
.append(slotCountHolder.getKey()).append('|')
|
||||
.append(slotCountHolder.getValue().count).append('|')
|
||||
.append(slotCountHolder.getValue().interceptedCount).append('\n');
|
||||
}
|
||||
|
||||
} else {
|
||||
stringBuilder.append(point).append('|').append(monitorPattern).append('|')
|
||||
.append(ipRecord.period).append('|').append(timeFormatOfSecond).append('|')
|
||||
.append(keySlot.getCountHolder(point).count.get()).append('|')
|
||||
.append(keySlot.getCountHolder(point).interceptedCount.get()).append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tempSecond > 0) {
|
||||
lastReportSecond = tempSecond;
|
||||
}
|
||||
if (tempMinutes > 0) {
|
||||
lastReportMinutes = tempMinutes;
|
||||
}
|
||||
if (stringBuilder.length() > 0) {
|
||||
Loggers.TPS_CONTROL_DIGEST.info("Tps reporting...\n" + stringBuilder.toString());
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.TPS_CONTROL_DIGEST.error("Tps reporting error", throwable);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void loadRuleFromLocal(TpsMonitorPoint tpsMonitorPoint) throws IOException {
|
||||
|
||||
File pointFile = getRuleFile(tpsMonitorPoint.getPointName());
|
||||
if (!pointFile.exists()) {
|
||||
pointFile.createNewFile();
|
||||
}
|
||||
String ruleContent = DiskUtils.readFile(pointFile);
|
||||
TpsControlRule tpsControlRule = StringUtils.isBlank(ruleContent) ? new TpsControlRule()
|
||||
: JacksonUtils.toObj(ruleContent, TpsControlRule.class);
|
||||
Loggers.TPS_CONTROL.info("Load rule from local,pointName={}, ruleContent={} ", tpsMonitorPoint.getPointName(),
|
||||
ruleContent);
|
||||
tpsMonitorPoint.applyRule(tpsControlRule);
|
||||
|
||||
}
|
||||
|
||||
private synchronized void saveRuleToLocal(String pointName, TpsControlRule tpsControlRule) throws IOException {
|
||||
try {
|
||||
File pointFile = getRuleFile(pointName);
|
||||
if (!pointFile.exists()) {
|
||||
pointFile.createNewFile();
|
||||
}
|
||||
String content = JacksonUtils.toJson(tpsControlRule);
|
||||
DiskUtils.writeFile(pointFile, content.getBytes(StandardCharsets.UTF_8), false);
|
||||
Loggers.TPS_CONTROL.info("Save rule to local,pointName={}, ruleContent ={} ", pointName, content);
|
||||
} catch (IOException e) {
|
||||
Loggers.TPS_CONTROL
|
||||
.warn("Tps control rule persist fail, pointName={},error={} ", pointName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getRuleFile(String pointName) {
|
||||
File baseDir = checkBaseDir();
|
||||
return new File(baseDir, pointName);
|
||||
}
|
||||
|
||||
private File checkBaseDir() {
|
||||
File baseDir = new File(EnvUtil.getNacosHome(), "data" + File.separator + "tps" + File.separator);
|
||||
if (!baseDir.exists()) {
|
||||
baseDir.mkdirs();
|
||||
}
|
||||
return baseDir;
|
||||
}
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* tps control point.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: TpsControlPoint.java, v 0.1 2021年01月09日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class TpsMonitorPoint {
|
||||
|
||||
public static final int DEFAULT_RECORD_SIZE = 10;
|
||||
|
||||
private static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DATETIME_PATTERN)
|
||||
.withZone(ZoneId.systemDefault()).withLocale(Locale.getDefault());
|
||||
|
||||
private long startTime;
|
||||
|
||||
private String pointName;
|
||||
|
||||
private TpsRecorder tpsRecorder;
|
||||
|
||||
public Map<String, TpsRecorder> monitorKeysRecorder = new HashMap<>();
|
||||
|
||||
public TpsMonitorPoint(String pointName) {
|
||||
this(pointName, -1, "monitor");
|
||||
}
|
||||
|
||||
public TpsMonitorPoint(String pointName, int maxTps, String monitorType) {
|
||||
// trim to second,uniform all tps control.
|
||||
this.startTime = getTrimMillsOfSecond(System.currentTimeMillis());
|
||||
this.pointName = pointName;
|
||||
this.tpsRecorder = new TpsRecorder(startTime, TimeUnit.SECONDS, TpsControlRule.Rule.MODEL_FUZZY,
|
||||
DEFAULT_RECORD_SIZE);
|
||||
this.tpsRecorder.setMaxCount(maxTps);
|
||||
this.tpsRecorder.setMonitorType(monitorType);
|
||||
}
|
||||
|
||||
/**
|
||||
* get trim mills of second.
|
||||
*
|
||||
* @param timeStamp timestamp milliseconds.
|
||||
* @return mills of second.
|
||||
*/
|
||||
public static long getTrimMillsOfSecond(long timeStamp) {
|
||||
return timeStamp - timeStamp % 1_000L;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get trim mills of second.
|
||||
*
|
||||
* @param timeStamp timestamp milliseconds.
|
||||
* @return minis of minute.
|
||||
*/
|
||||
public static long getTrimMillsOfMinute(long timeStamp) {
|
||||
return timeStamp - timeStamp % 60_000L;
|
||||
}
|
||||
|
||||
/**
|
||||
* get trim mills of second.
|
||||
*
|
||||
* @param timeStamp timestamp milliseconds.
|
||||
* @return mills of hour.
|
||||
*/
|
||||
public static long getTrimMillsOfHour(long timeStamp) {
|
||||
return timeStamp - timeStamp % 3_600_000L;
|
||||
}
|
||||
|
||||
/**
|
||||
* get format string for "yyyy-MM-dd HH:mm:ss".
|
||||
*
|
||||
* @param timeStamp timestamp milliseconds.
|
||||
* @return datetime string.
|
||||
*/
|
||||
public static String getTimeFormatOfSecond(long timeStamp) {
|
||||
return DATETIME_FORMATTER.format(Instant.ofEpochMilli(timeStamp));
|
||||
}
|
||||
|
||||
private void stopAllMonitorClient() {
|
||||
monitorKeysRecorder.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* increase tps.
|
||||
*
|
||||
* @param monitorKeys monitorKeys.
|
||||
* @return check current tps is allowed.
|
||||
*/
|
||||
public boolean applyTps(String connectionId, List<MonitorKey> monitorKeys) {
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
TpsRecorder.TpsSlot currentTps = tpsRecorder.createSlotIfAbsent(now);
|
||||
|
||||
//1.check monitor keys.
|
||||
List<TpsRecorder.SlotCountHolder> passedSlots = new ArrayList<>();
|
||||
for (MonitorKey monitorKey : monitorKeys) {
|
||||
for (Map.Entry<String, TpsRecorder> entry : monitorKeysRecorder.entrySet()) {
|
||||
if (MonitorKeyMatcher.matchWithType(entry.getKey(), monitorKey.build())) {
|
||||
TpsRecorder tpsRecorderKey = entry.getValue();
|
||||
TpsRecorder.TpsSlot currentKeySlot = tpsRecorderKey.createSlotIfAbsent(now);
|
||||
long maxTpsCount = tpsRecorderKey.getMaxCount();
|
||||
TpsRecorder.SlotCountHolder countHolder = currentKeySlot.getCountHolder(monitorKey.build());
|
||||
boolean overLimit = maxTpsCount >= 0 && countHolder.count.longValue() >= maxTpsCount;
|
||||
if (overLimit) {
|
||||
Loggers.TPS_CONTROL_DETAIL
|
||||
.info("[{}]Tps over limit ,pointName=[{}],barrier=[{}],monitorModel={},maxTps={}",
|
||||
connectionId, this.getPointName(), entry.getKey(),
|
||||
tpsRecorderKey.getMonitorType(), maxTpsCount + "/" + tpsRecorderKey.period);
|
||||
if (tpsRecorderKey.isInterceptMode()) {
|
||||
currentKeySlot.getCountHolder(monitorKey.build()).interceptedCount.incrementAndGet();
|
||||
currentTps.getCountHolder(monitorKey.build()).interceptedCount.incrementAndGet();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
passedSlots.add(countHolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//2.check total tps.
|
||||
long maxTps = tpsRecorder.getMaxCount();
|
||||
boolean overLimit = maxTps >= 0 && currentTps.getCountHolder(pointName).count.longValue() >= maxTps;
|
||||
if (overLimit) {
|
||||
Loggers.TPS_CONTROL_DETAIL
|
||||
.info("[{}]Tps over limit ,pointName=[{}],barrier=[{}],monitorType={}", connectionId,
|
||||
this.getPointName(), "pointRule", tpsRecorder.getMonitorType());
|
||||
if (tpsRecorder.isInterceptMode()) {
|
||||
currentTps.getCountHolder(pointName).interceptedCount.incrementAndGet();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
currentTps.getCountHolder(pointName).count.incrementAndGet();
|
||||
for (TpsRecorder.SlotCountHolder passedTpsSlot : passedSlots) {
|
||||
passedTpsSlot.count.incrementAndGet();
|
||||
}
|
||||
//3.check pass.
|
||||
return true;
|
||||
}
|
||||
|
||||
public TpsRecorder getTpsRecorder() {
|
||||
return tpsRecorder;
|
||||
}
|
||||
|
||||
public String getPointName() {
|
||||
return pointName;
|
||||
}
|
||||
|
||||
public void setPointName(String pointName) {
|
||||
this.pointName = pointName;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply tps control rule to this point.
|
||||
*
|
||||
* @param newControlRule controlRule.
|
||||
*/
|
||||
public synchronized void applyRule(TpsControlRule newControlRule) {
|
||||
|
||||
Loggers.TPS_CONTROL.info("Apply tps control rule parse start,pointName=[{}] ", this.getPointName());
|
||||
|
||||
//1.reset all monitor point for null.
|
||||
if (newControlRule == null) {
|
||||
Loggers.TPS_CONTROL.info("Clear all tps control rule ,pointName=[{}] ", this.getPointName());
|
||||
this.tpsRecorder.clearLimitRule();
|
||||
this.stopAllMonitorClient();
|
||||
return;
|
||||
}
|
||||
|
||||
//2.check point rule.
|
||||
TpsControlRule.Rule newPointRule = newControlRule.getPointRule();
|
||||
if (newPointRule == null) {
|
||||
Loggers.TPS_CONTROL.info("Clear point control rule ,pointName=[{}] ", this.getPointName());
|
||||
this.tpsRecorder.clearLimitRule();
|
||||
} else {
|
||||
Loggers.TPS_CONTROL.info("Update point control rule ,pointName=[{}],original maxTps={}, new maxTps={}"
|
||||
+ ",original monitorType={}, original monitorType={}, ", this.getPointName(),
|
||||
this.tpsRecorder.getMaxCount(), newPointRule.maxCount, this.tpsRecorder.getMonitorType(),
|
||||
newPointRule.monitorType);
|
||||
|
||||
this.tpsRecorder.setMaxCount(newPointRule.maxCount);
|
||||
this.tpsRecorder.setMonitorType(newPointRule.monitorType);
|
||||
}
|
||||
|
||||
//3.check monitor key rules.
|
||||
Map<String, TpsControlRule.Rule> newMonitorKeyRules = newControlRule.getMonitorKeyRule();
|
||||
//3.1 clear all monitor keys.
|
||||
if (newMonitorKeyRules == null || newMonitorKeyRules.isEmpty()) {
|
||||
Loggers.TPS_CONTROL
|
||||
.info("Clear point control rule for monitorKeys, pointName=[{}] ", this.getPointName());
|
||||
this.stopAllMonitorClient();
|
||||
} else {
|
||||
Map<String, TpsRecorder> monitorKeysRecorderCurrent = this.monitorKeysRecorder;
|
||||
|
||||
for (Map.Entry<String, TpsControlRule.Rule> newMonitorRule : newMonitorKeyRules.entrySet()) {
|
||||
if (newMonitorRule.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
boolean checkPattern = newMonitorRule.getKey() != null;
|
||||
if (!checkPattern) {
|
||||
Loggers.TPS_CONTROL.info("Invalid monitor rule, pointName=[{}] ,monitorRule={} ,Ignore this.",
|
||||
this.getPointName(), newMonitorRule.getKey());
|
||||
continue;
|
||||
}
|
||||
TpsControlRule.Rule newRule = newMonitorRule.getValue();
|
||||
if (newRule.period == null) {
|
||||
newRule.period = TimeUnit.SECONDS;
|
||||
}
|
||||
|
||||
if (newRule.model == null) {
|
||||
newRule.model = TpsControlRule.Rule.MODEL_FUZZY;
|
||||
}
|
||||
|
||||
//update rule.
|
||||
if (monitorKeysRecorderCurrent.containsKey(newMonitorRule.getKey())) {
|
||||
TpsRecorder tpsRecorder = monitorKeysRecorderCurrent.get(newMonitorRule.getKey());
|
||||
Loggers.TPS_CONTROL
|
||||
.info("Update point control rule for client ip ,pointName=[{}],monitorKey=[{}],original maxTps={}"
|
||||
+ ", new maxTps={},original monitorType={}, new monitorType={}, ",
|
||||
this.getPointName(), newMonitorRule.getKey(), tpsRecorder.getMaxCount(),
|
||||
newRule.maxCount, tpsRecorder.getMonitorType(), newRule.monitorType);
|
||||
|
||||
if (!Objects.equals(tpsRecorder.period, newRule.period) || !Objects
|
||||
.equals(tpsRecorder.getModel(), newRule.model)) {
|
||||
TpsRecorder tpsRecorderNew = new TpsRecorder(startTime, newRule.period, newRule.model,
|
||||
DEFAULT_RECORD_SIZE);
|
||||
tpsRecorderNew.setMaxCount(newRule.maxCount);
|
||||
tpsRecorderNew.setMonitorType(newRule.monitorType);
|
||||
monitorKeysRecorderCurrent.put(newMonitorRule.getKey(), tpsRecorderNew);
|
||||
} else {
|
||||
tpsRecorder.setMaxCount(newRule.maxCount);
|
||||
tpsRecorder.setMonitorType(newRule.monitorType);
|
||||
}
|
||||
|
||||
} else {
|
||||
Loggers.TPS_CONTROL
|
||||
.info("Add point control rule for client ip ,pointName=[{}],monitorKey=[{}], new maxTps={}, new monitorType={}, ",
|
||||
this.getPointName(), newMonitorRule.getKey(), newMonitorRule.getValue().maxCount,
|
||||
newMonitorRule.getValue().monitorType);
|
||||
// add rule
|
||||
TpsRecorder tpsRecorderAdd = new TpsRecorder(startTime, newRule.period, newRule.model,
|
||||
DEFAULT_RECORD_SIZE);
|
||||
tpsRecorderAdd.setMaxCount(newRule.maxCount);
|
||||
tpsRecorderAdd.setMonitorType(newRule.monitorType);
|
||||
monitorKeysRecorderCurrent.put(newMonitorRule.getKey(), tpsRecorderAdd);
|
||||
}
|
||||
}
|
||||
|
||||
//delete rule.
|
||||
Iterator<Map.Entry<String, TpsRecorder>> iteratorCurrent = monitorKeysRecorderCurrent.entrySet().iterator();
|
||||
while (iteratorCurrent.hasNext()) {
|
||||
Map.Entry<String, TpsRecorder> next1 = iteratorCurrent.next();
|
||||
if (!newMonitorKeyRules.containsKey(next1.getKey())) {
|
||||
Loggers.TPS_CONTROL.info("Delete point control rule for pointName=[{}] ,monitorKey=[{}]",
|
||||
this.getPointName(), next1.getKey());
|
||||
iteratorCurrent.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* tps record.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: TpsRecorder.java, v 0.1 2021年01月09日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
public class TpsRecorder {
|
||||
|
||||
private long startTime;
|
||||
|
||||
TimeUnit period;
|
||||
|
||||
private int slotSize;
|
||||
|
||||
private List<TpsSlot> slotList;
|
||||
|
||||
private long maxCount = -1;
|
||||
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* monitor/intercept.
|
||||
*/
|
||||
private String monitorType = MonitorType.MONITOR.type;
|
||||
|
||||
public TpsRecorder(long startTime, TimeUnit period, String model, int recordSize) {
|
||||
|
||||
this.startTime = startTime;
|
||||
if (period.equals(TimeUnit.MINUTES)) {
|
||||
this.startTime = TpsMonitorPoint.getTrimMillsOfMinute(startTime);
|
||||
}
|
||||
if (period.equals(TimeUnit.HOURS)) {
|
||||
this.startTime = TpsMonitorPoint.getTrimMillsOfHour(startTime);
|
||||
}
|
||||
this.period = period;
|
||||
this.model = model;
|
||||
this.slotSize = recordSize + 1;
|
||||
slotList = new ArrayList<>(slotSize);
|
||||
for (int i = 0; i < slotSize; i++) {
|
||||
slotList.add(isProtoModel() ? new MultiKeyTpsSlot() : new TpsSlot());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProtoModel() {
|
||||
return TpsControlRule.Rule.MODEL_PROTO.equalsIgnoreCase(this.model);
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
/**
|
||||
* get slot of the timestamp second,create if not exist.
|
||||
*
|
||||
* @param timeStamp the timestamp second.
|
||||
* @return tps slot.
|
||||
*/
|
||||
public TpsSlot createSlotIfAbsent(long timeStamp) {
|
||||
long distance = timeStamp - startTime;
|
||||
|
||||
long diff = (distance < 0 ? distance + period.toMillis(1) * slotSize : distance) / period.toMillis(1);
|
||||
long currentWindowTime = startTime + diff * period.toMillis(1);
|
||||
int index = (int) diff % slotSize;
|
||||
if (slotList.get(index).time != currentWindowTime) {
|
||||
slotList.get(index).reset(currentWindowTime);
|
||||
}
|
||||
return slotList.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* get slot of the timestamp second,read only ,return nul if not exist.
|
||||
*
|
||||
* @param timeStamp the timestamp second.
|
||||
* @return tps slot.
|
||||
*/
|
||||
public TpsSlot getPoint(long timeStamp) {
|
||||
long distance = timeStamp - startTime;
|
||||
long diff = (distance < 0 ? distance + period.toMillis(1) * slotSize : distance) / period.toMillis(1);
|
||||
long currentWindowTime = startTime + diff * period.toMillis(1);
|
||||
int index = (int) diff % slotSize;
|
||||
TpsSlot tpsSlot = slotList.get(index);
|
||||
if (tpsSlot.time != currentWindowTime) {
|
||||
return null;
|
||||
}
|
||||
return tpsSlot;
|
||||
}
|
||||
|
||||
public long getMaxCount() {
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
public void setMaxCount(long maxCount) {
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
public boolean isInterceptMode() {
|
||||
return MonitorType.INTERCEPT.type.equals(this.monitorType);
|
||||
}
|
||||
|
||||
/**
|
||||
* clearLimitRule.
|
||||
*/
|
||||
public void clearLimitRule() {
|
||||
this.setMonitorType(MonitorType.MONITOR.type);
|
||||
this.setMaxCount(-1);
|
||||
}
|
||||
|
||||
public String getMonitorType() {
|
||||
return monitorType;
|
||||
}
|
||||
|
||||
public void setMonitorType(String monitorType) {
|
||||
this.monitorType = monitorType;
|
||||
}
|
||||
|
||||
static class TpsSlot {
|
||||
|
||||
long time = 0L;
|
||||
|
||||
private SlotCountHolder countHolder = new SlotCountHolder();
|
||||
|
||||
public SlotCountHolder getCountHolder(String key) {
|
||||
return countHolder;
|
||||
}
|
||||
|
||||
public void reset(long second) {
|
||||
synchronized (this) {
|
||||
if (this.time != second) {
|
||||
this.time = second;
|
||||
countHolder.count.set(0L);
|
||||
countHolder.interceptedCount.set(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TpsSlot{" + "time=" + time + ", countHolder=" + countHolder + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MultiKeyTpsSlot extends TpsSlot {
|
||||
|
||||
Map<String, SlotCountHolder> keySlots = new HashMap<>(16);
|
||||
|
||||
@Override
|
||||
public SlotCountHolder getCountHolder(String key) {
|
||||
if (!keySlots.containsKey(key)) {
|
||||
keySlots.putIfAbsent(key, new SlotCountHolder());
|
||||
}
|
||||
return keySlots.get(key);
|
||||
}
|
||||
|
||||
public Map<String, SlotCountHolder> getKeySlots() {
|
||||
return keySlots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(long second) {
|
||||
synchronized (this) {
|
||||
if (this.time != second) {
|
||||
this.time = second;
|
||||
keySlots.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MultiKeyTpsSlot{" + "time=" + time + "}'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SlotCountHolder {
|
||||
|
||||
AtomicLong count = new AtomicLong();
|
||||
|
||||
AtomicLong interceptedCount = new AtomicLong();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + count + "|" + interceptedCount + '}';
|
||||
}
|
||||
}
|
||||
|
||||
public List<TpsSlot> getSlotList() {
|
||||
return slotList;
|
||||
}
|
||||
}
|
@ -21,7 +21,6 @@ import com.alibaba.nacos.api.remote.RemoteConstants;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.remote.request.ServerLoaderInfoRequest;
|
||||
import com.alibaba.nacos.api.remote.response.ServerLoaderInfoResponse;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.core.remote.ConnectionManager;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
@ -51,7 +50,6 @@ public class ServerLoaderInfoRequestHandler extends RequestHandler<ServerLoaderI
|
||||
filter.put(RemoteConstants.LABEL_SOURCE, RemoteConstants.LABEL_SOURCE_SDK);
|
||||
serverLoaderInfoResponse
|
||||
.putMetricsValue("sdkConCount", String.valueOf(connectionManager.currentClientsCount(filter)));
|
||||
serverLoaderInfoResponse.putMetricsValue("limitRule", JacksonUtils.toJson(connectionManager.getConnectionLimitRule()));
|
||||
serverLoaderInfoResponse.putMetricsValue("load", String.valueOf(EnvUtil.getLoad()));
|
||||
serverLoaderInfoResponse.putMetricsValue("cpu", String.valueOf(EnvUtil.getCpu()));
|
||||
|
||||
|
@ -44,13 +44,6 @@ public class Loggers {
|
||||
|
||||
public static final Logger REMOTE_DIGEST = LoggerFactory.getLogger("com.alibaba.nacos.core.remote.digest");
|
||||
|
||||
public static final Logger TPS_CONTROL_DIGEST = LoggerFactory
|
||||
.getLogger("com.alibaba.nacos.core.remote.control.digest");
|
||||
|
||||
public static final Logger TPS_CONTROL = LoggerFactory.getLogger("com.alibaba.nacos.core.remote.control");
|
||||
|
||||
public static final Logger TPS_CONTROL_DETAIL = LoggerFactory.getLogger("com.alibaba.nacos.core.remote.control.detail");
|
||||
|
||||
public static void setLogLevel(String logName, String level) {
|
||||
|
||||
switch (logName) {
|
||||
|
@ -138,15 +138,15 @@
|
||||
</appender>
|
||||
|
||||
<!--TPS control -->
|
||||
<appender name="tps-control"
|
||||
<appender name="plugin-control-connection"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/tps-control.log</file>
|
||||
<file>${LOG_HOME}/plugin-control-connection.log</file>
|
||||
<append>true</append>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/tps-control.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<fileNamePattern>${LOG_HOME}/plugin-control-connection.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<maxFileSize>2GB</maxFileSize>
|
||||
<maxHistory>7</maxHistory>
|
||||
<totalSizeCap>7GB</totalSizeCap>
|
||||
<totalSizeCap>2GB</totalSizeCap>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
@ -154,15 +154,15 @@
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="tps-control-detail"
|
||||
<appender name="plugin-control-tps"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/tps-control-detail.log</file>
|
||||
<file>${LOG_HOME}/plugin-control-tps.log</file>
|
||||
<append>true</append>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/tps-control-detail.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<fileNamePattern>${LOG_HOME}/plugin-control-tps.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<maxFileSize>2GB</maxFileSize>
|
||||
<maxHistory>7</maxHistory>
|
||||
<totalSizeCap>7GB</totalSizeCap>
|
||||
<totalSizeCap>2GB</totalSizeCap>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
@ -171,14 +171,14 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="tps-control-digest"
|
||||
<appender name="plugin-control"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/tps-control-digest.log</file>
|
||||
<file>${LOG_HOME}/plugin-control.log</file>
|
||||
<append>true</append>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/tps-control-digest.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<fileNamePattern>${LOG_HOME}/plugin-control.%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<maxFileSize>2GB</maxFileSize>
|
||||
<maxHistory>7</maxHistory>
|
||||
<maxHistory>14</maxHistory>
|
||||
<totalSizeCap>7GB</totalSizeCap>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
</rollingPolicy>
|
||||
@ -261,18 +261,18 @@
|
||||
</logger>
|
||||
|
||||
<!-- TPS Control-->
|
||||
<logger name="com.alibaba.nacos.core.remote.control.digest" additivity="false">
|
||||
<logger name="com.alibaba.nacos.plugin.control" additivity="false">
|
||||
<level value="DEBUG"/>
|
||||
<appender-ref ref="tps-control-digest"/>
|
||||
<appender-ref ref="plugin-control"/>
|
||||
</logger>
|
||||
<logger name="com.alibaba.nacos.core.remote.control.detail" additivity="false">
|
||||
<logger name="com.alibaba.nacos.plugin.control.tps" additivity="false">
|
||||
<level value="DEBUG"/>
|
||||
<appender-ref ref="tps-control-detail"/>
|
||||
<appender-ref ref="plugin-control-tps"/>
|
||||
</logger>
|
||||
|
||||
<logger name="com.alibaba.nacos.core.remote.control" additivity="false">
|
||||
<logger name="com.alibaba.nacos.plugin.control.connection" additivity="false">
|
||||
<level value="DEBUG"/>
|
||||
<appender-ref ref="tps-control"/>
|
||||
<appender-ref ref="plugin-control-connection"/>
|
||||
</logger>
|
||||
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
#
|
||||
#
|
||||
# Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.core.remote.LongConnectionMetricsCollector
|
@ -19,24 +19,24 @@ package com.alibaba.nacos.core.remote;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.RemoteConstants;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.core.remote.event.ConnectionLimitRuleChangeEvent;
|
||||
import com.alibaba.nacos.core.remote.grpc.GrpcConnection;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.file.WatchFileCenter;
|
||||
import io.grpc.netty.shaded.io.netty.channel.Channel;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -54,7 +54,7 @@ public class ConnectionManagerTest {
|
||||
private ConnectionManager connectionManager;
|
||||
|
||||
@Mock
|
||||
private ClientConnectionEventListenerRegistry registry;
|
||||
private ClientConnectionEventListenerRegistry clientConnectionEventListenerRegistry;
|
||||
|
||||
@InjectMocks
|
||||
private GrpcConnection connection;
|
||||
@ -69,6 +69,22 @@ public class ConnectionManagerTest {
|
||||
|
||||
private String clientIp = "1.1.1.1";
|
||||
|
||||
static MockedStatic<ControlConfigs> propertyUtilMockedStatic;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
propertyUtilMockedStatic = Mockito.mockStatic(ControlConfigs.class);
|
||||
propertyUtilMockedStatic.when(ControlConfigs::getInstance).thenReturn(new ControlConfigs());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
if (propertyUtilMockedStatic != null) {
|
||||
propertyUtilMockedStatic.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// create base file path
|
||||
@ -78,9 +94,9 @@ public class ConnectionManagerTest {
|
||||
}
|
||||
connectId = UUID.randomUUID().toString();
|
||||
connectionManager.start();
|
||||
connectionManager.initLimitRue();
|
||||
Mockito.when(channel.isOpen()).thenReturn(true);
|
||||
Mockito.when(channel.isActive()).thenReturn(true);
|
||||
|
||||
connectionMeta.clientIp = clientIp;
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
labels.put("key", "value");
|
||||
@ -95,11 +111,6 @@ public class ConnectionManagerTest {
|
||||
public void tearDown() {
|
||||
connectionManager.unregister(connectId);
|
||||
|
||||
String tpsPath = Paths.get(EnvUtil.getNacosHome(), "data", "loader").toString();
|
||||
WatchFileCenter.deregisterAllWatcher(tpsPath);
|
||||
|
||||
NotifyCenter.deregisterSubscriber(connectionManager);
|
||||
NotifyCenter.deregisterPublisher(ConnectionLimitRuleChangeEvent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -109,7 +120,7 @@ public class ConnectionManagerTest {
|
||||
|
||||
@Test
|
||||
public void testTraced() {
|
||||
Assert.assertTrue(connectionManager.traced(clientIp));
|
||||
Assert.assertFalse(connectionManager.traced(clientIp));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -155,24 +166,5 @@ public class ConnectionManagerTest {
|
||||
Assert.assertEquals(1, connectionManager.currentSdkClientCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnEvent() {
|
||||
try {
|
||||
String limitRule = "{\"monitorIpList\": [\"1.1.1.1\", \"2.2.2.2\"], \"countLimit\": 1}";
|
||||
ConnectionLimitRuleChangeEvent limitRuleChangeEvent = new ConnectionLimitRuleChangeEvent(limitRule);
|
||||
connectionManager.onEvent(limitRuleChangeEvent);
|
||||
|
||||
ConnectionManager.ConnectionLimitRule connectionLimitRule = connectionManager.getConnectionLimitRule();
|
||||
Assert.assertEquals(1, connectionLimitRule.getCountLimit());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSubscribeType() {
|
||||
Assert.assertEquals(ConnectionLimitRuleChangeEvent.class, connectionManager.subscribeType());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
package com.alibaba.nacos.core.remote;
|
||||
|
||||
import com.alibaba.nacos.api.remote.request.HealthCheckRequest;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -45,9 +44,6 @@ public class RequestHandlerRegistryTest {
|
||||
@InjectMocks
|
||||
private RequestHandlerRegistry registry;
|
||||
|
||||
@Mock
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
@InjectMocks
|
||||
private ContextRefreshedEvent contextRefreshedEvent;
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* ${@link MonitorKeyMatcher} unit tests.
|
||||
*
|
||||
* @author chenglu
|
||||
* @date 2021-06-18 13:11
|
||||
*/
|
||||
public class MonitorKeyMatcherTest {
|
||||
|
||||
@Test
|
||||
public void testWithMatchType() {
|
||||
boolean match1 = MonitorKeyMatcher.matchWithType("A:*", "A:ddd");
|
||||
Assert.assertTrue(match1);
|
||||
|
||||
boolean match2 = MonitorKeyMatcher.matchWithType("A:*a", "A:dda");
|
||||
Assert.assertTrue(match2);
|
||||
|
||||
boolean match3 = MonitorKeyMatcher.matchWithType("A:a*", "A:add");
|
||||
Assert.assertTrue(match3);
|
||||
|
||||
boolean match4 = MonitorKeyMatcher.matchWithType("A:add", "A:add");
|
||||
Assert.assertTrue(match4);
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TpsMonitorManagerTest {
|
||||
|
||||
static TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws InterruptedException {
|
||||
tpsMonitorManager = new TpsMonitorManager();
|
||||
TpsMonitorPoint publish = new TpsMonitorPoint("configPublish");
|
||||
tpsMonitorManager.registerTpsControlPoint(publish);
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
TpsControlRule rule = new TpsControlRule();
|
||||
rule.setPointRule(new TpsControlRule.Rule(5000, TimeUnit.SECONDS, "SUM", "intercept"));
|
||||
rule.getMonitorKeyRule()
|
||||
.putIfAbsent("testKey:a*b", new TpsControlRule.Rule(500, TimeUnit.SECONDS, "EACH", "intercept"));
|
||||
rule.getMonitorKeyRule()
|
||||
.putIfAbsent("testKey:*", new TpsControlRule.Rule(2000000, TimeUnit.SECONDS, "SUM", "intercept"));
|
||||
publish.applyRule(rule);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws InterruptedException {
|
||||
// make sure different case will not effect each other.
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTps() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String value = "atg" + (new Random().nextInt(100) + 2) + "efb";
|
||||
boolean pass = tpsMonitorManager
|
||||
.applyTps("configPublish", "testconnectionId", CollectionUtils.list(new TestKey(value)));
|
||||
assertTrue(pass);
|
||||
try {
|
||||
Thread.sleep(1L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTpsWithOverFlow() {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
String value = "atg" + (new Random().nextInt(100) + 2) + "efb";
|
||||
boolean pass = tpsMonitorManager
|
||||
.applyTps("configPublish", "testconnectionId", CollectionUtils.list(new TestKey(value)));
|
||||
if (!pass) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Assert.fail("fail to limit.");
|
||||
}
|
||||
|
||||
class TestKey extends MonitorKey {
|
||||
|
||||
public TestKey(String key) {
|
||||
setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "testKey";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link TpsMonitorPoint} unit tests.
|
||||
*
|
||||
* @author chenglu
|
||||
* @date 2021-06-18 14:02
|
||||
*/
|
||||
public class TpsMonitorPointTest {
|
||||
|
||||
@Test
|
||||
public void testStaticMethod() {
|
||||
//2022-08-23 14:23:53
|
||||
assertEquals(1661235833000L, TpsMonitorPoint.getTrimMillsOfSecond(1661235833111L));
|
||||
//2022-08-23 14:23:00
|
||||
assertEquals(1661235780000L, TpsMonitorPoint.getTrimMillsOfMinute(1661235833111L));
|
||||
//2022-08-23 14:00:00
|
||||
assertEquals(1661234400000L, TpsMonitorPoint.getTrimMillsOfHour(1661235833111L));
|
||||
|
||||
assertEquals(LocalDateTime.of(2022, 8, 23, 14, 23, 53).atZone(ZoneOffset.ofHours(8))
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())
|
||||
.withLocale(Locale.getDefault())), TpsMonitorPoint.getTimeFormatOfSecond(1661235833111L));
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.core.remote.control;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* {@link TpsRecorder} unit test.
|
||||
*
|
||||
* @author chenglu
|
||||
* @date 2021-06-21 18:23
|
||||
*/
|
||||
public class TpsRecorderTest {
|
||||
|
||||
TpsRecorder tpsRecorder;
|
||||
|
||||
long start;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
start = System.currentTimeMillis();
|
||||
tpsRecorder = new TpsRecorder(start, TimeUnit.SECONDS, TpsControlRule.Rule.MODEL_PROTO, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTpsSlot() {
|
||||
long current = start + 100;
|
||||
TpsRecorder.TpsSlot tpsSlot = tpsRecorder.createSlotIfAbsent(start);
|
||||
Assert.assertNotNull(tpsSlot);
|
||||
|
||||
TpsRecorder.TpsSlot tpsSlot1 = tpsRecorder.getPoint(current);
|
||||
Assert.assertNotNull(tpsSlot1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonitorType() {
|
||||
Assert.assertTrue(tpsRecorder.isProtoModel());
|
||||
|
||||
Assert.assertEquals(MonitorType.MONITOR.type, tpsRecorder.getMonitorType());
|
||||
|
||||
tpsRecorder.clearLimitRule();
|
||||
|
||||
Assert.assertFalse(tpsRecorder.isInterceptMode());
|
||||
}
|
||||
}
|
@ -49,7 +49,6 @@ public class ServerLoaderInfoRequestHandlerTest {
|
||||
public void testHandle() {
|
||||
Mockito.when(connectionManager.currentClientsCount()).thenReturn(1);
|
||||
Mockito.when(connectionManager.currentClientsCount(Mockito.any())).thenReturn(1);
|
||||
Mockito.when(connectionManager.getConnectionLimitRule()).thenReturn(null);
|
||||
|
||||
ServerLoaderInfoRequest request = new ServerLoaderInfoRequest();
|
||||
RequestMeta meta = new RequestMeta();
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
package com.alibaba.nacos.naming.monitor;
|
||||
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorPoint;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsControlManager;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
|
||||
/**
|
||||
* Tps and flow control monitor singleton for Naming.
|
||||
@ -29,30 +29,29 @@ public class NamingTpsMonitor {
|
||||
|
||||
private static final NamingTpsMonitor INSTANCE = new NamingTpsMonitor();
|
||||
|
||||
private final TpsMonitorManager tpsMonitorManager;
|
||||
private final TpsControlManager tpsControlManager = ControlManagerCenter.getInstance().getTpsControlManager();
|
||||
|
||||
private NamingTpsMonitor() {
|
||||
this.tpsMonitorManager = ApplicationUtils.getBean(TpsMonitorManager.class);
|
||||
registerPushMonitorPoint();
|
||||
registerDistroMonitorPoint();
|
||||
}
|
||||
|
||||
private void registerPushMonitorPoint() {
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_RPC_PUSH.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_RPC_PUSH_SUCCESS.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_RPC_PUSH_FAIL.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_UDP_PUSH.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_UDP_PUSH_SUCCESS.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_UDP_PUSH_FAIL.name()));
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_RPC_PUSH.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_RPC_PUSH_SUCCESS.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_RPC_PUSH_FAIL.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_UDP_PUSH.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_UDP_PUSH_SUCCESS.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_UDP_PUSH_FAIL.name());
|
||||
}
|
||||
|
||||
private void registerDistroMonitorPoint() {
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_DISTRO_SYNC.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_DISTRO_SYNC_SUCCESS.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_DISTRO_SYNC_FAIL.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_DISTRO_VERIFY.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_DISTRO_VERIFY_SUCCESS.name()));
|
||||
tpsMonitorManager.registerTpsControlPoint(new TpsMonitorPoint(TpsMonitorItem.NAMING_DISTRO_VERIFY_FAIL.name()));
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_DISTRO_SYNC.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_DISTRO_SYNC_SUCCESS.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_DISTRO_SYNC_FAIL.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_DISTRO_VERIFY.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_DISTRO_VERIFY_SUCCESS.name());
|
||||
tpsControlManager.registerTpsPoint(TpsMonitorItem.NAMING_DISTRO_VERIFY_FAIL.name());
|
||||
}
|
||||
|
||||
public static NamingTpsMonitor getInstance() {
|
||||
@ -66,8 +65,8 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void rpcPushSuccess(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_RPC_PUSH.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_RPC_PUSH_SUCCESS.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_RPC_PUSH.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_RPC_PUSH_SUCCESS.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,8 +76,8 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void rpcPushFail(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_RPC_PUSH.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_RPC_PUSH_FAIL.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_RPC_PUSH.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_RPC_PUSH_FAIL.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,8 +87,9 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void udpPushSuccess(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_UDP_PUSH.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_UDP_PUSH_SUCCESS.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_UDP_PUSH.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager
|
||||
.check(new TpsCheckRequest(TpsMonitorItem.NAMING_UDP_PUSH_SUCCESS.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,8 +99,8 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void udpPushFail(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_UDP_PUSH.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_UDP_PUSH_FAIL.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_UDP_PUSH.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_UDP_PUSH_FAIL.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,8 +110,9 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void distroSyncSuccess(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_SYNC.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_SYNC_SUCCESS.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_SYNC.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager
|
||||
.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_SYNC_SUCCESS.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,8 +122,9 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void distroSyncFail(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_SYNC.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_SYNC_FAIL.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_SYNC.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager
|
||||
.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_SYNC_FAIL.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,8 +134,9 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void distroVerifySuccess(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_VERIFY.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_VERIFY_SUCCESS.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_VERIFY.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager
|
||||
.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_VERIFY_SUCCESS.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,7 +146,9 @@ public class NamingTpsMonitor {
|
||||
* @param clientIp client ip
|
||||
*/
|
||||
public static void distroVerifyFail(String clientId, String clientIp) {
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_VERIFY.name(), clientId, clientIp);
|
||||
INSTANCE.tpsMonitorManager.applyTpsForClientIp(TpsMonitorItem.NAMING_DISTRO_VERIFY_FAIL.name(), clientId, clientIp);
|
||||
INSTANCE.tpsControlManager.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_VERIFY.name(), clientId, clientIp));
|
||||
INSTANCE.tpsControlManager
|
||||
.check(new TpsCheckRequest(TpsMonitorItem.NAMING_DISTRO_VERIFY_FAIL.name(), clientId, clientIp));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
import com.alibaba.nacos.core.distributed.distro.exception.DistroException;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import com.alibaba.nacos.naming.cluster.remote.response.DistroDataResponse;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
@ -61,9 +60,6 @@ public class DistroClientTransportAgentTest {
|
||||
@Mock
|
||||
ServerMemberManager memberManager;
|
||||
|
||||
@Mock
|
||||
TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
@Mock
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@ -79,7 +75,6 @@ public class DistroClientTransportAgentTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
when(context.getBean(TpsMonitorManager.class)).thenReturn(tpsMonitorManager);
|
||||
ApplicationUtils.injectContext(context);
|
||||
EnvUtil.setEnvironment(new MockEnvironment());
|
||||
member = new Member();
|
||||
@ -95,7 +90,6 @@ public class DistroClientTransportAgentTest {
|
||||
return null;
|
||||
}).when(clusterRpcClientProxy).asyncRequest(eq(member), any(), any());
|
||||
// When run all project, the TpsNamingMonitor will be init by other unit test, will throw UnnecessaryStubbingException.
|
||||
ApplicationUtils.getBean(TpsMonitorManager.class);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -18,9 +18,9 @@ package com.alibaba.nacos.naming.push.v2.hook;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.naming.pojo.Subscriber;
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsControlManager;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -49,7 +49,7 @@ public class NacosMonitorPushResultHookTest {
|
||||
private Subscriber subscriber;
|
||||
|
||||
@Mock
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
private TpsControlManager tpsControlManager;
|
||||
|
||||
@Mock
|
||||
private ConfigurableApplicationContext context;
|
||||
@ -72,7 +72,7 @@ public class NacosMonitorPushResultHookTest {
|
||||
when(pushResult.getData()).thenReturn(serviceInfo);
|
||||
when(pushResult.getSubscriber()).thenReturn(subscriber);
|
||||
ApplicationUtils.injectContext(context);
|
||||
when(context.getBean(TpsMonitorManager.class)).thenReturn(tpsMonitorManager);
|
||||
when(context.getBean(TpsControlManager.class)).thenReturn(tpsControlManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -17,7 +17,6 @@
|
||||
package com.alibaba.nacos.naming.push.v2.task;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.alibaba.nacos.core.remote.control.TpsMonitorManager;
|
||||
import com.alibaba.nacos.naming.core.v2.client.Client;
|
||||
import com.alibaba.nacos.naming.core.v2.client.manager.ClientManager;
|
||||
import com.alibaba.nacos.naming.core.v2.index.ClientServiceIndexesManager;
|
||||
@ -66,9 +65,6 @@ public class PushExecuteTaskTest {
|
||||
@Mock
|
||||
private ServiceStorage serviceStorage;
|
||||
|
||||
@Mock
|
||||
private TpsMonitorManager tpsMonitorManager;
|
||||
|
||||
@Mock
|
||||
private NamingMetadataManager metadataManager;
|
||||
|
||||
@ -95,7 +91,6 @@ public class PushExecuteTaskTest {
|
||||
when(delayTaskExecuteEngine.getMetadataManager()).thenReturn(metadataManager);
|
||||
when(metadataManager.getServiceMetadata(service)).thenReturn(Optional.empty());
|
||||
ApplicationUtils.injectContext(context);
|
||||
when(context.getBean(TpsMonitorManager.class)).thenReturn(tpsMonitorManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
45
plugin/control/pom.xml
Normal file
45
plugin/control/pom.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>nacos-plugin</artifactId>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>nacos-contrl-plugin</artifactId>
|
||||
<name>nacos-control-plugin ${project.version}</name>
|
||||
<url>http://nacos.io</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-common</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-sys</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control;
|
||||
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import com.alibaba.nacos.plugin.control.connection.ConnectionControlManager;
|
||||
import com.alibaba.nacos.plugin.control.connection.nacos.NacosConnectionControlManager;
|
||||
import com.alibaba.nacos.plugin.control.event.ConnectionLimitRuleChangeEvent;
|
||||
import com.alibaba.nacos.plugin.control.event.TpsControlRuleChangeEvent;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.NacosRuleParser;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.RuleParser;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.RuleStorageProxy;
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsControlManager;
|
||||
import com.alibaba.nacos.plugin.control.tps.nacos.NacosTpsControlManager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* control manager center.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class ControlManagerCenter {
|
||||
|
||||
static ControlManagerCenter instance = null;
|
||||
|
||||
private TpsControlManager tpsControlManager;
|
||||
|
||||
private ConnectionControlManager connectionControlManager;
|
||||
|
||||
private RuleParser ruleParser;
|
||||
|
||||
private RuleStorageProxy ruleStorageProxy;
|
||||
|
||||
private void initRuleParser() {
|
||||
Collection<RuleParser> ruleParsers = NacosServiceLoader.load(RuleParser.class);
|
||||
String ruleParserName = ControlConfigs.getInstance().getRuleParser();
|
||||
|
||||
for (RuleParser ruleParserInternal : ruleParsers) {
|
||||
if (ruleParserInternal.getName().equalsIgnoreCase(ruleParserName)) {
|
||||
Loggers.CONTROL.info("Found rule parser of name={},class={}", ruleParserName,
|
||||
ruleParserInternal.getClass().getSimpleName());
|
||||
ruleParser = ruleParserInternal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ruleParser == null) {
|
||||
Loggers.CONTROL.warn("Fail to rule parser of name :" + ruleParserName);
|
||||
ruleParser = new NacosRuleParser();
|
||||
}
|
||||
|
||||
Collection<ConnectionControlManager> connectionControlManagers = NacosServiceLoader
|
||||
.load(ConnectionControlManager.class);
|
||||
String connectionManagerName = ControlConfigs.getInstance().getConnectionManager();
|
||||
|
||||
for (ConnectionControlManager connectionControlManagerInternal : connectionControlManagers) {
|
||||
if (connectionControlManagerInternal.getName().equalsIgnoreCase(connectionManagerName)) {
|
||||
Loggers.CONTROL.info("Found rule parser of name={},class={}", ruleParserName,
|
||||
connectionControlManagerInternal.getClass().getSimpleName());
|
||||
connectionControlManager = connectionControlManagerInternal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (connectionControlManager == null) {
|
||||
Loggers.CONTROL.warn("Fail to rule parser of name :" + ruleParserName);
|
||||
connectionControlManager = new NacosConnectionControlManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initConnectionManager() {
|
||||
|
||||
Collection<ConnectionControlManager> connectionControlManagers = NacosServiceLoader
|
||||
.load(ConnectionControlManager.class);
|
||||
String connectionManagerName = ControlConfigs.getInstance().getConnectionManager();
|
||||
|
||||
for (ConnectionControlManager connectionControlManagerInternal : connectionControlManagers) {
|
||||
if (connectionControlManagerInternal.getName().equalsIgnoreCase(connectionManagerName)) {
|
||||
Loggers.CONTROL.info("Found connection control manager of name={},class={}", connectionManagerName,
|
||||
connectionControlManagerInternal.getClass().getSimpleName());
|
||||
connectionControlManager = connectionControlManagerInternal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (connectionControlManager == null) {
|
||||
Loggers.CONTROL.warn("Fail to connection control manager of name :" + connectionManagerName);
|
||||
connectionControlManager = new NacosConnectionControlManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initTpsControlManager() {
|
||||
|
||||
Collection<TpsControlManager> tpsControlManagers = NacosServiceLoader.load(TpsControlManager.class);
|
||||
String tpsManagerName = ControlConfigs.getInstance().getTpsManager();
|
||||
|
||||
for (TpsControlManager tpsControlManagerInternal : tpsControlManagers) {
|
||||
if (tpsControlManagerInternal.getName().equalsIgnoreCase(tpsManagerName)) {
|
||||
Loggers.CONTROL.info("Found tps control manager of name={},class={}", tpsManagerName,
|
||||
tpsControlManagerInternal.getClass().getSimpleName());
|
||||
tpsControlManager = tpsControlManagerInternal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tpsControlManager == null) {
|
||||
Loggers.CONTROL.warn("Fail to found tps control manager of name :" + tpsManagerName);
|
||||
tpsControlManager = new NacosTpsControlManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ControlManagerCenter() {
|
||||
initTpsControlManager();
|
||||
initRuleParser();
|
||||
initConnectionManager();
|
||||
ruleStorageProxy = new RuleStorageProxy();
|
||||
}
|
||||
|
||||
public RuleStorageProxy getRuleStorageProxy() {
|
||||
return ruleStorageProxy;
|
||||
}
|
||||
|
||||
public RuleParser getRuleParser() {
|
||||
return ruleParser;
|
||||
}
|
||||
|
||||
public TpsControlManager getTpsControlManager() {
|
||||
return tpsControlManager;
|
||||
}
|
||||
|
||||
public ConnectionControlManager getConnectionControlManager() {
|
||||
return connectionControlManager;
|
||||
}
|
||||
|
||||
public static final ControlManagerCenter getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ControlManagerCenter.class) {
|
||||
if (instance == null) {
|
||||
instance = new ControlManagerCenter();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void reloadTpsControlRule(String pointName, boolean external) {
|
||||
NotifyCenter.publishEvent(new TpsControlRuleChangeEvent(pointName, external));
|
||||
}
|
||||
|
||||
public void reloadConnectionControlRule(boolean external) {
|
||||
NotifyCenter.publishEvent(new ConnectionLimitRuleChangeEvent(external));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* cotrol loggers.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class Loggers {
|
||||
|
||||
public static final Logger CONTROL = LoggerFactory.getLogger("com.alibaba.nacos.plugin.control");
|
||||
|
||||
public static final Logger TPS = LoggerFactory.getLogger("com.alibaba.nacos.plugin.control.tps");
|
||||
|
||||
public static final Logger CONNECTION = LoggerFactory.getLogger("com.alibaba.nacos.plugin.control.connection");
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.configs;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* control configs params.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@Component
|
||||
public class ControlConfigs {
|
||||
|
||||
private static ControlConfigs instance = null;
|
||||
|
||||
public static ControlConfigs getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ControlConfigs.class) {
|
||||
try {
|
||||
instance = ApplicationUtils.getBean(ControlConfigs.class);
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.CONTROL
|
||||
.warn("Fail to get control configs bean from spring context,use default constructor instance",
|
||||
throwable);
|
||||
}
|
||||
if (instance == null) {
|
||||
instance = new ControlConfigs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void setInstance(ControlConfigs instance) {
|
||||
ControlConfigs.instance = instance;
|
||||
}
|
||||
|
||||
@Value("${nacos.plugin.control.tps.barrier.creator:nacos}")
|
||||
private String tpsBarrierCreator = "nacos";
|
||||
|
||||
@Value("${nacos.plugin.control.tps.barrier.rule.creator:nacos}")
|
||||
private String tpsRuleBarrierCreator = "nacos";
|
||||
|
||||
@Value("${nacos.plugin.control.connection.runtime.ejector:nacos}")
|
||||
private String connectionRuntimeEjector = "nacos";
|
||||
|
||||
@Value("${nacos.plugin.control.connection.manager:nacos}")
|
||||
private String connectionManager = "nacos";
|
||||
|
||||
@Value("${nacos.plugin.control.tps.manager:nacos}")
|
||||
private String tpsManager = "nacos";
|
||||
|
||||
@Value("${nacos.plugin.control.rule.external.storage:}")
|
||||
private String ruleExternalStorage = "";
|
||||
|
||||
@Value("${nacos.plugin.control.rule.parser:nacos}")
|
||||
private String ruleParser = "nacos";
|
||||
|
||||
public String getTpsBarrierCreator() {
|
||||
return tpsBarrierCreator;
|
||||
}
|
||||
|
||||
public void setTpsBarrierCreator(String tpsBarrierCreator) {
|
||||
this.tpsBarrierCreator = tpsBarrierCreator;
|
||||
}
|
||||
|
||||
public String getTpsRuleBarrierCreator() {
|
||||
return tpsRuleBarrierCreator;
|
||||
}
|
||||
|
||||
public void setTpsRuleBarrierCreator(String tpsRuleBarrierCreator) {
|
||||
this.tpsRuleBarrierCreator = tpsRuleBarrierCreator;
|
||||
}
|
||||
|
||||
public String getRuleExternalStorage() {
|
||||
return ruleExternalStorage;
|
||||
}
|
||||
|
||||
public void setRuleExternalStorage(String ruleExternalStorage) {
|
||||
this.ruleExternalStorage = ruleExternalStorage;
|
||||
}
|
||||
|
||||
public String getRuleParser() {
|
||||
return ruleParser;
|
||||
}
|
||||
|
||||
public void setRuleParser(String ruleParser) {
|
||||
this.ruleParser = ruleParser;
|
||||
}
|
||||
|
||||
public String getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
|
||||
public void setConnectionManager(String connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
public String getConnectionRuntimeEjector() {
|
||||
return connectionRuntimeEjector;
|
||||
}
|
||||
|
||||
public void setConnectionRuntimeEjector(String connectionRuntimeEjector) {
|
||||
this.connectionRuntimeEjector = connectionRuntimeEjector;
|
||||
}
|
||||
|
||||
public String getTpsManager() {
|
||||
return tpsManager;
|
||||
}
|
||||
|
||||
public void setTpsManager(String tpsManager) {
|
||||
this.tpsManager = tpsManager;
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection;
|
||||
|
||||
import com.alibaba.nacos.common.executor.ExecutorFactory;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.connection.request.ConnectionCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.connection.response.ConnectionCheckResponse;
|
||||
import com.alibaba.nacos.plugin.control.connection.rule.ConnectionControlRule;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.RuleParserProxy;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.RuleStorageProxy;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* connection control manager.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class ConnectionControlManager {
|
||||
|
||||
protected ConnectionControlRule connectionControlRule;
|
||||
|
||||
protected Collection<ConnectionMetricsCollector> metricsCollectorList;
|
||||
|
||||
/**
|
||||
* get manager name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
private ScheduledExecutorService executorService;
|
||||
|
||||
public ConnectionControlManager() {
|
||||
metricsCollectorList = NacosServiceLoader.load(ConnectionMetricsCollector.class);
|
||||
Loggers.CONTROL.info("Load connection metrics collector,size={},{}", metricsCollectorList.size(),
|
||||
metricsCollectorList);
|
||||
initConnectionRule();
|
||||
if (!metricsCollectorList.isEmpty()) {
|
||||
initExecuteService();
|
||||
startConnectionMetricsReport();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initExecuteService() {
|
||||
executorService = ExecutorFactory.newSingleScheduledExecutorService(r -> {
|
||||
Thread thread = new Thread(r, "nacos.plugin.control.connection.reporter");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
}
|
||||
|
||||
private void startConnectionMetricsReport() {
|
||||
executorService.scheduleWithFixedDelay(new ConnectionMetricsReporter(), 0, 3000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void initConnectionRule() {
|
||||
RuleStorageProxy ruleStorageProxy = RuleStorageProxy.getInstance();
|
||||
String localRuleContent = ruleStorageProxy.getLocalDiskStorage().getConnectionRule();
|
||||
if (StringUtils.isNotBlank(localRuleContent)) {
|
||||
Loggers.CONTROL.info("Found local disk connection rule content on start up,value ={}", localRuleContent);
|
||||
} else if (ruleStorageProxy.getExternalStorage() != null
|
||||
&& ruleStorageProxy.getExternalStorage().getConnectionRule() != null) {
|
||||
localRuleContent = ruleStorageProxy.getExternalStorage().getConnectionRule();
|
||||
if (StringUtils.isNotBlank(localRuleContent)) {
|
||||
Loggers.CONTROL
|
||||
.info("Found persist disk connection rule content on start up ,value ={}", localRuleContent);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(localRuleContent)) {
|
||||
connectionControlRule = RuleParserProxy.getInstance().parseConnectionRule(localRuleContent);
|
||||
Loggers.CONTROL.info("init connection rule end");
|
||||
|
||||
} else {
|
||||
Loggers.CONTROL.info("No connection rule content found ,use default empty rule ");
|
||||
connectionControlRule = new ConnectionControlRule();
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionControlRule getConnectionLimitRule() {
|
||||
return connectionControlRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply connection rule.
|
||||
*
|
||||
* @param connectionControlRule not null.
|
||||
*/
|
||||
public abstract void applyConnectionLimitRule(ConnectionControlRule connectionControlRule);
|
||||
|
||||
/**
|
||||
* check connection allowed.
|
||||
*
|
||||
* @param connectionCheckRequest connectionCheckRequest.
|
||||
* @return
|
||||
*/
|
||||
public abstract ConnectionCheckResponse check(ConnectionCheckRequest connectionCheckRequest);
|
||||
|
||||
class ConnectionMetricsReporter implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Map<String, Integer> metricsTotalCount = metricsCollectorList.stream().collect(
|
||||
Collectors.toMap(ConnectionMetricsCollector::getName, ConnectionMetricsCollector::getTotalCount));
|
||||
int totalCount = metricsTotalCount.values().stream().mapToInt(Integer::intValue).sum();
|
||||
|
||||
Loggers.CONNECTION.info(String.format("ConnectionMetrics, totalCount = %s, detail = %s", totalCount,
|
||||
metricsTotalCount.toString()));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection;
|
||||
|
||||
/**
|
||||
* connection count metrics collector.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public interface ConnectionMetricsCollector {
|
||||
|
||||
/**
|
||||
* get collector name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* get total count.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getTotalCount();
|
||||
|
||||
/**
|
||||
* get count for ip.
|
||||
*
|
||||
* @param ip ip.
|
||||
* @return
|
||||
*/
|
||||
int getCountForIp(String ip);
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection.nacos;
|
||||
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.connection.ConnectionControlManager;
|
||||
import com.alibaba.nacos.plugin.control.connection.request.ConnectionCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.connection.response.ConnectionCheckCode;
|
||||
import com.alibaba.nacos.plugin.control.connection.response.ConnectionCheckResponse;
|
||||
import com.alibaba.nacos.plugin.control.connection.rule.ConnectionControlRule;
|
||||
|
||||
/**
|
||||
* connection control manager.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class NacosConnectionControlManager extends ConnectionControlManager {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "nacos";
|
||||
}
|
||||
|
||||
public NacosConnectionControlManager() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyConnectionLimitRule(ConnectionControlRule connectionControlRule) {
|
||||
super.connectionControlRule = connectionControlRule;
|
||||
Loggers.CONTROL.info("Connection control rule updated to ->" + (this.connectionControlRule == null ? null
|
||||
: JacksonUtils.toJson(this.connectionControlRule)));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionCheckResponse check(ConnectionCheckRequest connectionCheckRequest) {
|
||||
ConnectionCheckResponse connectionCheckResponse = new ConnectionCheckResponse();
|
||||
connectionCheckResponse.setSuccess(true);
|
||||
connectionCheckResponse.setCode(ConnectionCheckCode.CHECK_SKIP);
|
||||
return connectionCheckResponse;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection.request;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* connection check request.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class ConnectionCheckRequest {
|
||||
|
||||
String clientIp;
|
||||
|
||||
String appName;
|
||||
|
||||
String source;
|
||||
|
||||
Map<String, String> labels;
|
||||
|
||||
public ConnectionCheckRequest(String clientIp, String appName, String source) {
|
||||
this.appName = appName;
|
||||
this.clientIp = clientIp;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Map<String, String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void setLabels(Map<String, String> labels) {
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
public String getClientIp() {
|
||||
return clientIp;
|
||||
}
|
||||
|
||||
public void setClientIp(String clientIp) {
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection.response;
|
||||
|
||||
/**
|
||||
* conection check code.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class ConnectionCheckCode {
|
||||
|
||||
/**
|
||||
* check pass.
|
||||
*/
|
||||
public static final int PASS_BY_TOTAL = 200;
|
||||
|
||||
/**
|
||||
* skip.
|
||||
*/
|
||||
public static final int CHECK_SKIP = 100;
|
||||
|
||||
/**
|
||||
* deny by total over limit.
|
||||
*/
|
||||
public static final int DENY_BY_TOTAL_OVER = 300;
|
||||
|
||||
/**
|
||||
* pass by monitor type.
|
||||
*/
|
||||
public static final int PASS_BY_MONITOR = 205;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection.response;
|
||||
|
||||
/**
|
||||
* connection check response.
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class ConnectionCheckResponse {
|
||||
|
||||
private boolean success;
|
||||
|
||||
private String message;
|
||||
|
||||
private int code;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.connection.rule;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* connection control rule.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class ConnectionControlRule {
|
||||
|
||||
private Set<String> monitorIpList = new HashSet<>();
|
||||
|
||||
private int countLimit = -1;
|
||||
|
||||
public int getCountLimit() {
|
||||
return countLimit;
|
||||
}
|
||||
|
||||
public void setCountLimit(int countLimit) {
|
||||
this.countLimit = countLimit;
|
||||
}
|
||||
|
||||
public Set<String> getMonitorIpList() {
|
||||
return monitorIpList;
|
||||
}
|
||||
|
||||
public void setMonitorIpList(Set<String> monitorIpList) {
|
||||
this.monitorIpList = monitorIpList;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.core.remote.event;
|
||||
package com.alibaba.nacos.plugin.control.event;
|
||||
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
|
||||
@ -24,17 +24,17 @@ import com.alibaba.nacos.common.notify.Event;
|
||||
*/
|
||||
public class ConnectionLimitRuleChangeEvent extends Event {
|
||||
|
||||
String limitRule;
|
||||
private boolean external;
|
||||
|
||||
public ConnectionLimitRuleChangeEvent(String limitRule) {
|
||||
this.limitRule = limitRule;
|
||||
public ConnectionLimitRuleChangeEvent(boolean external) {
|
||||
this.external = external;
|
||||
}
|
||||
|
||||
public String getLimitRule() {
|
||||
return limitRule;
|
||||
public boolean isExternal() {
|
||||
return external;
|
||||
}
|
||||
|
||||
public void setLimitRule(String limitRule) {
|
||||
this.limitRule = limitRule;
|
||||
public void setExternal(boolean external) {
|
||||
this.external = external;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.core.remote.control;
|
||||
package com.alibaba.nacos.plugin.control.event;
|
||||
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
|
||||
@ -26,13 +26,13 @@ import com.alibaba.nacos.common.notify.Event;
|
||||
*/
|
||||
public class TpsControlRuleChangeEvent extends Event {
|
||||
|
||||
String pointName;
|
||||
private String pointName;
|
||||
|
||||
String ruleContent;
|
||||
private boolean external;
|
||||
|
||||
public TpsControlRuleChangeEvent(String pointName, String ruleContent) {
|
||||
public TpsControlRuleChangeEvent(String pointName, boolean external) {
|
||||
this.pointName = pointName;
|
||||
this.ruleContent = ruleContent;
|
||||
this.external = external;
|
||||
}
|
||||
|
||||
public String getPointName() {
|
||||
@ -43,11 +43,11 @@ public class TpsControlRuleChangeEvent extends Event {
|
||||
this.pointName = pointName;
|
||||
}
|
||||
|
||||
public String getRuleContent() {
|
||||
return ruleContent;
|
||||
public boolean isExternal() {
|
||||
return external;
|
||||
}
|
||||
|
||||
public void setRuleContent(String ruleContent) {
|
||||
this.ruleContent = ruleContent;
|
||||
public void setExternal(boolean external) {
|
||||
this.external = external;
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.control.ControlManagerCenter;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.connection.rule.ConnectionControlRule;
|
||||
import com.alibaba.nacos.plugin.control.event.ConnectionLimitRuleChangeEvent;
|
||||
import com.alibaba.nacos.plugin.control.event.TpsControlRuleChangeEvent;
|
||||
import com.alibaba.nacos.plugin.control.tps.rule.TpsControlRule;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* control rule activator.
|
||||
* @author shiyiyue
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class ControlRuleChangeActivator {
|
||||
|
||||
private static final Logger LOGGER = Loggers.CONTROL;
|
||||
|
||||
TpsRuleChangeSubscriber tpsRuleChangeSubscriber = new TpsRuleChangeSubscriber();
|
||||
|
||||
ConnectionRuleChangeSubscriber connectionRuleChangeSubscriber = new ConnectionRuleChangeSubscriber();
|
||||
|
||||
public ControlRuleChangeActivator() {
|
||||
NotifyCenter.registerSubscriber(tpsRuleChangeSubscriber);
|
||||
NotifyCenter.registerSubscriber(connectionRuleChangeSubscriber);
|
||||
}
|
||||
|
||||
class TpsRuleChangeSubscriber extends Subscriber<TpsControlRuleChangeEvent> {
|
||||
|
||||
@Override
|
||||
public void onEvent(TpsControlRuleChangeEvent event) {
|
||||
String pointName = event.getPointName();
|
||||
LOGGER.info("Tps control rule change event receive,pointName={}, external={} ", pointName,
|
||||
event.isExternal());
|
||||
if (event == null || event.getPointName() == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
RuleStorageProxy ruleStorageProxy = ControlManagerCenter.getInstance().getRuleStorageProxy();
|
||||
|
||||
if (event.isExternal()) {
|
||||
if (ruleStorageProxy.getExternalStorage() != null) {
|
||||
String persistTpsRule = ruleStorageProxy.getExternalStorage().getTpsRule(pointName);
|
||||
ruleStorageProxy.getLocalDiskStorage().saveTpsRule(pointName, persistTpsRule);
|
||||
} else {
|
||||
Loggers.CONTROL
|
||||
.info("No external rule storage found,will load local disk instead,point name={}",
|
||||
event.getPointName());
|
||||
}
|
||||
|
||||
}
|
||||
String tpsRuleContent = ruleStorageProxy.getLocalDiskStorage().getTpsRule(pointName);
|
||||
|
||||
TpsControlRule tpsControlRule = StringUtils.isBlank(tpsRuleContent) ? new TpsControlRule()
|
||||
: ControlManagerCenter.getInstance().getRuleParser().parseTpsRule(tpsRuleContent);
|
||||
|
||||
ControlManagerCenter.getInstance().getTpsControlManager().applyTpsRule(pointName, tpsControlRule);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Tps control rule apply error ,error= ", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return TpsControlRuleChangeEvent.class;
|
||||
}
|
||||
}
|
||||
|
||||
class ConnectionRuleChangeSubscriber extends Subscriber<ConnectionLimitRuleChangeEvent> {
|
||||
|
||||
@Override
|
||||
public void onEvent(ConnectionLimitRuleChangeEvent event) {
|
||||
LOGGER.info("connection limit rule change event receive ,external:{}", event.isExternal());
|
||||
|
||||
try {
|
||||
|
||||
RuleStorageProxy ruleStorageProxy = ControlManagerCenter.getInstance().getRuleStorageProxy();
|
||||
|
||||
if (event.isExternal()) {
|
||||
if (ruleStorageProxy.getExternalStorage() != null) {
|
||||
String connectionRule = ruleStorageProxy.getExternalStorage().getConnectionRule();
|
||||
ruleStorageProxy.getLocalDiskStorage().saveConnectionRule(connectionRule);
|
||||
} else {
|
||||
Loggers.CONTROL.info("No external rule storage found,will load local disk instead");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
String limitRule = ruleStorageProxy.getLocalDiskStorage().getConnectionRule();
|
||||
|
||||
Loggers.CONTROL.info("start to apply connection rule content " + limitRule);
|
||||
|
||||
ConnectionControlRule connectionControlRule =
|
||||
StringUtils.isBlank(limitRule) ? new ConnectionControlRule()
|
||||
: ControlManagerCenter.getInstance().getRuleParser().parseConnectionRule(limitRule);
|
||||
Loggers.CONTROL.info("end to apply connection rule content ");
|
||||
|
||||
if (connectionControlRule != null) {
|
||||
ControlManagerCenter.getInstance().getConnectionControlManager()
|
||||
.applyConnectionLimitRule(connectionControlRule);
|
||||
} else {
|
||||
LOGGER.info("Parse rule is null,Ignore illegal rule :{}", limitRule);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Fail to parse connection limit rule ,persit:{}", event.isExternal(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return ConnectionLimitRuleChangeEvent.class;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
/**
|
||||
* external rule storage.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public interface ExternalRuleStorage extends RuleStorage {
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* local disk storage.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class LocalDiskRuleStorage implements RuleStorage {
|
||||
|
||||
LocalDiskRuleStorage() {
|
||||
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Loggers.CONTROL;
|
||||
|
||||
private File checkTpsBaseDir() {
|
||||
File baseDir = new File(EnvUtil.getNacosHome(), "data" + File.separator + "tps" + File.separator);
|
||||
if (!baseDir.exists()) {
|
||||
baseDir.mkdirs();
|
||||
}
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
private File getConnectionRuleFile() {
|
||||
File baseDir = new File(EnvUtil.getNacosHome(), "data" + File.separator + "connection" + File.separator);
|
||||
if (!baseDir.exists()) {
|
||||
baseDir.mkdir();
|
||||
}
|
||||
return new File(baseDir, "limitRule");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "localdisk";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConnectionRule(String ruleContent) throws IOException {
|
||||
File pointFile = getConnectionRuleFile();
|
||||
if (!pointFile.exists()) {
|
||||
pointFile.createNewFile();
|
||||
}
|
||||
DiskUtils.writeFile(pointFile, ruleContent.getBytes(Constants.ENCODE), false);
|
||||
LOGGER.info("Save connection rule to local,pointName={}, ruleContent ={} ", ruleContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionRule() {
|
||||
File connectionRuleFile = getConnectionRuleFile();
|
||||
if (!connectionRuleFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return DiskUtils.readFile(connectionRuleFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveTpsRule(String pointName, String ruleContent) throws IOException {
|
||||
File file = checkTpsBaseDir();
|
||||
File tpsFile = new File(file, pointName);
|
||||
if (!tpsFile.exists()) {
|
||||
tpsFile.createNewFile();
|
||||
}
|
||||
if (ruleContent == null) {
|
||||
DiskUtils.deleteQuietly(tpsFile);
|
||||
} else {
|
||||
DiskUtils.writeFile(tpsFile, ruleContent.getBytes(Constants.ENCODE), false);
|
||||
LOGGER.info("Save tps rule to local,pointName={}, ruleContent ={} ", pointName, ruleContent);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTpsRule(String pointName) {
|
||||
File file = checkTpsBaseDir();
|
||||
File tpsFile = new File(file, pointName);
|
||||
if (!tpsFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return DiskUtils.readFile(tpsFile);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.control.connection.rule.ConnectionControlRule;
|
||||
import com.alibaba.nacos.plugin.control.tps.rule.TpsControlRule;
|
||||
|
||||
/**
|
||||
* nacos rule parser.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class NacosRuleParser implements RuleParser {
|
||||
|
||||
@Override
|
||||
public TpsControlRule parseTpsRule(String ruleContent) {
|
||||
|
||||
return StringUtils.isBlank(ruleContent) ? new TpsControlRule()
|
||||
: JacksonUtils.toObj(ruleContent, TpsControlRule.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionControlRule parseConnectionRule(String ruleContent) {
|
||||
return StringUtils.isBlank(ruleContent) ? new ConnectionControlRule()
|
||||
: JacksonUtils.toObj(ruleContent, ConnectionControlRule.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "nacos";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.connection.rule.ConnectionControlRule;
|
||||
import com.alibaba.nacos.plugin.control.tps.rule.TpsControlRule;
|
||||
|
||||
/**
|
||||
* parse rule content from raw string.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public interface RuleParser {
|
||||
|
||||
/**
|
||||
* parse tps rule content.
|
||||
*
|
||||
* @param ruleContent ruleContent.
|
||||
* @return
|
||||
*/
|
||||
TpsControlRule parseTpsRule(String ruleContent);
|
||||
|
||||
/**
|
||||
* parse connection rule.
|
||||
*
|
||||
* @param ruleContent ruleContent.
|
||||
* @return
|
||||
*/
|
||||
ConnectionControlRule parseConnectionRule(String ruleContent);
|
||||
|
||||
/**
|
||||
* get name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getName();
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* rule parser proxy.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class RuleParserProxy {
|
||||
|
||||
private static final Logger LOGGER = Loggers.CONTROL;
|
||||
|
||||
private static RuleParser instance;
|
||||
|
||||
static {
|
||||
Collection<RuleParser> ruleParsers = NacosServiceLoader.load(RuleParser.class);
|
||||
String ruleParserName = ControlConfigs.getInstance().getRuleParser();
|
||||
|
||||
for (RuleParser ruleParser : ruleParsers) {
|
||||
if (ruleParser.getName().equalsIgnoreCase(ruleParserName)) {
|
||||
LOGGER.info("Found rule parser of name={},class={}", ruleParserName,
|
||||
ruleParser.getClass().getSimpleName());
|
||||
instance = ruleParser;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (instance == null) {
|
||||
LOGGER.warn("Fail to rule parser of name :" + ruleParserName);
|
||||
instance = new NacosRuleParser();
|
||||
}
|
||||
}
|
||||
|
||||
public static RuleParser getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
/**
|
||||
* rule storage.
|
||||
*
|
||||
* @author shiyiyue
|
||||
* @date 2022-10-26 11:43:00
|
||||
*/
|
||||
public interface RuleStorage {
|
||||
|
||||
/**
|
||||
* get storage name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* save connection rule to storage.
|
||||
*
|
||||
* @param ruleContent rule content.
|
||||
* @throws Exception exception.
|
||||
*/
|
||||
void saveConnectionRule(String ruleContent) throws Exception;
|
||||
|
||||
/**
|
||||
* get connection rule.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getConnectionRule();
|
||||
|
||||
/**
|
||||
* save tps rule.
|
||||
*
|
||||
* @param pointName point name.
|
||||
* @param ruleContent rule content.
|
||||
* @throws Exception exception.
|
||||
*/
|
||||
void saveTpsRule(String pointName, String ruleContent) throws Exception;
|
||||
|
||||
/**
|
||||
* get tps rule.
|
||||
*
|
||||
* @param pointName point name.
|
||||
* @return
|
||||
*/
|
||||
String getTpsRule(String pointName);
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.ruleactivator;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* rule storage proxy.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class RuleStorageProxy {
|
||||
|
||||
private static final Logger LOGGER = Loggers.CONTROL;
|
||||
|
||||
private static final RuleStorageProxy INSTANCE = new RuleStorageProxy();
|
||||
|
||||
private LocalDiskRuleStorage localDiskRuleStorage = new LocalDiskRuleStorage();
|
||||
|
||||
private ExternalRuleStorage externalRuleStorage = null;
|
||||
|
||||
public RuleStorageProxy() {
|
||||
Collection<ExternalRuleStorage> persistRuleActivators = NacosServiceLoader.load(ExternalRuleStorage.class);
|
||||
String rulePersistActivator = ControlConfigs.getInstance().getRuleExternalStorage();
|
||||
|
||||
for (ExternalRuleStorage persistRuleActivator : persistRuleActivators) {
|
||||
if (persistRuleActivator.getName().equalsIgnoreCase(rulePersistActivator)) {
|
||||
LOGGER.info("Found persist rule storage of name :" + rulePersistActivator);
|
||||
externalRuleStorage = persistRuleActivator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (externalRuleStorage == null && StringUtils.isNotBlank(rulePersistActivator)) {
|
||||
LOGGER.error("Fail to found persist rule storage of name :" + rulePersistActivator);
|
||||
}
|
||||
}
|
||||
|
||||
public RuleStorage getLocalDiskStorage() {
|
||||
return localDiskRuleStorage;
|
||||
}
|
||||
|
||||
public RuleStorage getExternalStorage() {
|
||||
return externalRuleStorage;
|
||||
}
|
||||
|
||||
public static final RuleStorageProxy getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.core.remote.control;
|
||||
package com.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
/**
|
||||
* MonitorType.
|
||||
@ -40,16 +40,4 @@ public enum MonitorType {
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.tps.request.BarrierCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.tps.response.TpsCheckResponse;
|
||||
import com.alibaba.nacos.plugin.control.tps.rule.RuleDetail;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* rule barrier.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class RuleBarrier {
|
||||
|
||||
private TimeUnit period;
|
||||
|
||||
private String pointName;
|
||||
|
||||
private long maxCount;
|
||||
|
||||
private String ruleName;
|
||||
|
||||
/**
|
||||
* monitor/intercept.
|
||||
*/
|
||||
private String monitorType = MonitorType.MONITOR.type;
|
||||
|
||||
public String getRuleName() {
|
||||
return ruleName;
|
||||
}
|
||||
|
||||
public void setRuleName(String ruleName) {
|
||||
this.ruleName = ruleName;
|
||||
}
|
||||
|
||||
public String getPointName() {
|
||||
return pointName;
|
||||
}
|
||||
|
||||
public void setPointName(String pointName) {
|
||||
this.pointName = pointName;
|
||||
}
|
||||
|
||||
public TimeUnit getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public void setPeriod(TimeUnit period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* get barrier name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getBarrierName();
|
||||
|
||||
public long getMaxCount() {
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
public void setMaxCount(long maxCount) {
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
public String getMonitorType() {
|
||||
return monitorType;
|
||||
}
|
||||
|
||||
public void setMonitorType(String monitorType) {
|
||||
this.monitorType = monitorType;
|
||||
}
|
||||
|
||||
public boolean isMonitorType() {
|
||||
return MonitorType.MONITOR.type.equalsIgnoreCase(this.monitorType);
|
||||
}
|
||||
|
||||
public String getLimitMsg() {
|
||||
return String.format("[Period:%s,MaxCount:%s]", period, maxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* apply tps.
|
||||
*
|
||||
* @param barrierCheckRequest barrierCheckRequest.
|
||||
* @return
|
||||
*/
|
||||
public abstract TpsCheckResponse applyTps(BarrierCheckRequest barrierCheckRequest);
|
||||
|
||||
/**
|
||||
* apply rule detail.
|
||||
*
|
||||
* @param ruleDetail ruleDetail.
|
||||
*/
|
||||
public abstract void applyRuleDetail(RuleDetail ruleDetail);
|
||||
|
||||
/**
|
||||
* get metrics.
|
||||
*
|
||||
* @param timeStamp timeStamp.
|
||||
* @return
|
||||
*/
|
||||
public abstract TpsMetrics getMetrics(long timeStamp);
|
||||
|
||||
/**
|
||||
* clear limit rule.
|
||||
*/
|
||||
public void clearLimitRule() {
|
||||
this.maxCount = -1;
|
||||
this.monitorType = MonitorType.MONITOR.getType();
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* rule barrier creator.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public interface RuleBarrierCreator {
|
||||
|
||||
/**
|
||||
* create a count for time unit period.
|
||||
*
|
||||
* @param pointName pointName.
|
||||
* @param ruleName ruleName.
|
||||
* @param period period.
|
||||
* @return
|
||||
*/
|
||||
RuleBarrier createRuleBarrier(String pointName, String ruleName, TimeUnit period);
|
||||
|
||||
/**
|
||||
* rate count creator name.
|
||||
*
|
||||
* @return name.
|
||||
*/
|
||||
String name();
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import com.alibaba.nacos.plugin.control.tps.nacos.LocalSimpleCountBarrierCreator;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.tps.response.TpsCheckResponse;
|
||||
import com.alibaba.nacos.plugin.control.tps.rule.TpsControlRule;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* tps barrier for tps point.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class TpsBarrier {
|
||||
|
||||
protected String pointName;
|
||||
|
||||
protected RuleBarrier pointBarrier;
|
||||
|
||||
public TpsBarrier(String pointName) {
|
||||
this.pointName = pointName;
|
||||
pointBarrier = ruleBarrierCreator.createRuleBarrier(pointName, pointName, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
protected static RuleBarrierCreator ruleBarrierCreator;
|
||||
|
||||
static {
|
||||
String tpsBarrierCreator = ControlConfigs.getInstance().getTpsBarrierCreator();
|
||||
Collection<RuleBarrierCreator> loadedCreators = NacosServiceLoader.load(RuleBarrierCreator.class);
|
||||
for (RuleBarrierCreator barrierCreator : loadedCreators) {
|
||||
if (tpsBarrierCreator.equalsIgnoreCase(barrierCreator.name())) {
|
||||
Loggers.CONTROL.info("Found tps rule creator of name : {}", tpsBarrierCreator);
|
||||
ruleBarrierCreator = barrierCreator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ruleBarrierCreator == null) {
|
||||
Loggers.CONTROL.warn("Fail to found tps rule creator of name : {},use default local simple creator",
|
||||
tpsBarrierCreator);
|
||||
ruleBarrierCreator = LocalSimpleCountBarrierCreator.getInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void setRuleBarrierCreator(RuleBarrierCreator ruleBarrierCreatorInstance) {
|
||||
ruleBarrierCreator = ruleBarrierCreatorInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply tps.
|
||||
*
|
||||
* @param tpsCheckRequest tpsCheckRequest.
|
||||
* @return check current tps is allowed.
|
||||
*/
|
||||
public abstract TpsCheckResponse applyTps(TpsCheckRequest tpsCheckRequest);
|
||||
|
||||
public RuleBarrier getPointBarrier() {
|
||||
return pointBarrier;
|
||||
}
|
||||
|
||||
public String getPointName() {
|
||||
return pointName;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply rule.
|
||||
*
|
||||
* @param newControlRule newControlRule.
|
||||
*/
|
||||
public abstract void applyRule(TpsControlRule newControlRule);
|
||||
}
|
@ -14,26 +14,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.core.remote.control;
|
||||
package com.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
/**
|
||||
* MonitorType.
|
||||
* tps barrier creator.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: MonitorType.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class MonitorKeyParser {
|
||||
public interface TpsBarrierCreator {
|
||||
|
||||
/**
|
||||
* parse monitor key.
|
||||
* get name.
|
||||
*
|
||||
* @param arg0 parameters.
|
||||
* @return monitor key.
|
||||
* @return
|
||||
*/
|
||||
public abstract MonitorKey parse(Object... arg0);
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* create tps barrier.
|
||||
*
|
||||
* @param pointName pointName.
|
||||
* @return
|
||||
*/
|
||||
TpsBarrier createTpsBarrier(String pointName);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.configs.ControlConfigs;
|
||||
import com.alibaba.nacos.plugin.control.tps.nacos.DefaultNacosTpsBarrierCreator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* tps barrier creator proxy.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class TpsBarrierCreatorProxy {
|
||||
|
||||
static TpsBarrierCreator tpsBarrierCreator;
|
||||
|
||||
static {
|
||||
String tpsRuleBarrierCreator = null;
|
||||
try {
|
||||
tpsRuleBarrierCreator = ControlConfigs.getInstance().getTpsRuleBarrierCreator();
|
||||
Collection<TpsBarrierCreator> loadedCreators = NacosServiceLoader.load(TpsBarrierCreator.class);
|
||||
for (TpsBarrierCreator barrierCreator : loadedCreators) {
|
||||
if (tpsRuleBarrierCreator.equalsIgnoreCase(barrierCreator.getName())) {
|
||||
Loggers.CONTROL.info("Found tps barrier creator of name : {}", tpsRuleBarrierCreator);
|
||||
tpsBarrierCreator = barrierCreator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Loggers.CONTROL.warn("Fail to load tpsRuleBarrierCreator ", throwable);
|
||||
}
|
||||
if (tpsBarrierCreator == null) {
|
||||
Loggers.CONTROL.warn("Fail to found tps barrier creator of name : {},use default local simple creator",
|
||||
tpsRuleBarrierCreator);
|
||||
tpsBarrierCreator = new DefaultNacosTpsBarrierCreator();
|
||||
}
|
||||
}
|
||||
|
||||
public static TpsBarrierCreator getTpsBarrierCreator() {
|
||||
return tpsBarrierCreator;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.control.Loggers;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.RuleParserProxy;
|
||||
import com.alibaba.nacos.plugin.control.ruleactivator.RuleStorageProxy;
|
||||
import com.alibaba.nacos.plugin.control.tps.request.TpsCheckRequest;
|
||||
import com.alibaba.nacos.plugin.control.tps.response.TpsCheckResponse;
|
||||
import com.alibaba.nacos.plugin.control.tps.rule.TpsControlRule;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* abstract tps control manager.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class TpsControlManager {
|
||||
|
||||
/**
|
||||
* apple tps rule.
|
||||
*
|
||||
* @param pointName pointName.
|
||||
*/
|
||||
public abstract void registerTpsPoint(String pointName);
|
||||
|
||||
protected void initTpsRule(String pointName) {
|
||||
RuleStorageProxy ruleStorageProxy = RuleStorageProxy.getInstance();
|
||||
|
||||
String localRuleContent = ruleStorageProxy.getLocalDiskStorage().getTpsRule(pointName);
|
||||
if (StringUtils.isNotBlank(localRuleContent)) {
|
||||
Loggers.CONTROL.info("Found local disk tps control rule of {},content ={}", pointName, localRuleContent);
|
||||
} else if (ruleStorageProxy.getExternalStorage() != null
|
||||
&& ruleStorageProxy.getExternalStorage().getTpsRule(pointName) != null) {
|
||||
localRuleContent = ruleStorageProxy.getExternalStorage().getTpsRule(pointName);
|
||||
if (StringUtils.isNotBlank(localRuleContent)) {
|
||||
Loggers.CONTROL.info("Found external tps control rule of {},content ={}", pointName, localRuleContent);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(localRuleContent)) {
|
||||
TpsControlRule tpsLimitRule = RuleParserProxy.getInstance().parseTpsRule(localRuleContent);
|
||||
this.applyTpsRule(pointName, tpsLimitRule);
|
||||
} else {
|
||||
Loggers.CONTROL.info("No tps control rule of {} found ", pointName, localRuleContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get points.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract Map<String, TpsBarrier> getPoints();
|
||||
|
||||
/**
|
||||
* get rules.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract Map<String, TpsControlRule> getRules();
|
||||
|
||||
/**
|
||||
* apple tps rule.
|
||||
*
|
||||
* @param pointName pointName.
|
||||
* @param rule rule.
|
||||
*/
|
||||
public abstract void applyTpsRule(String pointName, TpsControlRule rule);
|
||||
|
||||
/**
|
||||
* check tps result.
|
||||
*
|
||||
* @param tpsRequest TpsRequest.
|
||||
* @return check current tps is allowed.
|
||||
*/
|
||||
public abstract TpsCheckResponse check(TpsCheckRequest tpsRequest);
|
||||
|
||||
/**
|
||||
* get control manager name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract String getName();
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* tps metrics.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class TpsMetrics {
|
||||
|
||||
private String pointName;
|
||||
|
||||
private String type;
|
||||
|
||||
private long timeStamp;
|
||||
|
||||
private TimeUnit period;
|
||||
|
||||
private Counter counter;
|
||||
|
||||
public TpsMetrics(String pointName, String type, long timeStamp, TimeUnit period) {
|
||||
this.pointName = pointName;
|
||||
this.type = type;
|
||||
this.timeStamp = timeStamp;
|
||||
this.period = period;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TpsMetrics{" + "pointName='" + pointName + '\'' + ", type='" + type + '\'' + ", timeStamp=" + timeStamp
|
||||
+ ", period=" + period + ", counter=" + counter + '}';
|
||||
}
|
||||
|
||||
public String getTimeFormatOfSecond(long timeStamp) {
|
||||
String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timeStamp));
|
||||
return format;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
|
||||
return String.join("|", pointName, type, period.name(), getTimeFormatOfSecond(timeStamp),
|
||||
String.valueOf(counter.passCount), String.valueOf(counter.deniedCount));
|
||||
}
|
||||
|
||||
public String getPointName() {
|
||||
return pointName;
|
||||
}
|
||||
|
||||
public void setPointName(String pointName) {
|
||||
this.pointName = pointName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public long getTimeStamp() {
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
public void setTimeStamp(long timeStamp) {
|
||||
this.timeStamp = timeStamp;
|
||||
}
|
||||
|
||||
public TimeUnit getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public void setPeriod(TimeUnit period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public Counter getCounter() {
|
||||
return counter;
|
||||
}
|
||||
|
||||
public void setCounter(Counter counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
public static class Counter {
|
||||
|
||||
private long passCount;
|
||||
|
||||
private long deniedCount;
|
||||
|
||||
public Counter(long passCount, long deniedCount) {
|
||||
this.passCount = passCount;
|
||||
this.deniedCount = deniedCount;
|
||||
}
|
||||
|
||||
public long getPassCount() {
|
||||
return passCount;
|
||||
}
|
||||
|
||||
public void setPassCount(long passCount) {
|
||||
this.passCount = passCount;
|
||||
}
|
||||
|
||||
public long getDeniedCount() {
|
||||
return deniedCount;
|
||||
}
|
||||
|
||||
public void setDeniedCount(long deniedCount) {
|
||||
this.deniedCount = deniedCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + "passCount=" + passCount + ", deniedCount=" + deniedCount + '}';
|
||||
}
|
||||
|
||||
public String getSimpleLog() {
|
||||
return String.join("|", String.valueOf(passCount), String.valueOf(deniedCount));
|
||||
}
|
||||
}
|
||||
}
|
@ -14,31 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.core.remote.control;
|
||||
package com.alibaba.nacos.plugin.control.tps.nacos;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsBarrier;
|
||||
import com.alibaba.nacos.plugin.control.tps.TpsBarrierCreator;
|
||||
|
||||
/**
|
||||
* ConnectionIdMonitorKey.
|
||||
* default nacos tps barrier creator.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ConnectionIdMonitorKey.java, v 0.1 2021年01月20日 20:38 PM liuzunfei Exp $
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class ConnectionIdMonitorKey extends MonitorKey {
|
||||
public class DefaultNacosTpsBarrierCreator implements TpsBarrierCreator {
|
||||
|
||||
private static final String TYPE = "connectionId";
|
||||
|
||||
String key;
|
||||
|
||||
public ConnectionIdMonitorKey() {
|
||||
|
||||
}
|
||||
|
||||
public ConnectionIdMonitorKey(String clientIp) {
|
||||
this.key = clientIp;
|
||||
@Override
|
||||
public String getName() {
|
||||
return "nacos";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
public TpsBarrier createTpsBarrier(String pointName) {
|
||||
return new NacosTpsBarrier(pointName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps.nacos;
|
||||
|
||||
import com.alibaba.nacos.plugin.control.tps.RuleBarrier;
|
||||
import com.alibaba.nacos.plugin.control.tps.RuleBarrierCreator;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* local simple count barrier creator.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class LocalSimpleCountBarrierCreator implements RuleBarrierCreator {
|
||||
|
||||
private static final LocalSimpleCountBarrierCreator INSTANCE = new LocalSimpleCountBarrierCreator();
|
||||
|
||||
public LocalSimpleCountBarrierCreator() {
|
||||
}
|
||||
|
||||
public static final LocalSimpleCountBarrierCreator getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleBarrier createRuleBarrier(String pointName, String ruleName, TimeUnit period) {
|
||||
return new LocalSimpleCountRuleBarrier(pointName, ruleName, period);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "localsimplecountor";
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.alibaba.nacos.plugin.control.tps.nacos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* local simple count rate counter.
|
||||
*
|
||||
* @author shiyiyue
|
||||
*/
|
||||
public class LocalSimpleCountRateCounter extends RateCounter {
|
||||
|
||||
private static final int DEFAULT_RECORD_SIZE = 10;
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
private List<TpsSlot> slotList;
|
||||
|
||||
public LocalSimpleCountRateCounter(String name, TimeUnit period) {
|
||||
super(name, period);
|
||||
slotList = new ArrayList<>(DEFAULT_RECORD_SIZE);
|
||||
for (int i = 0; i < DEFAULT_RECORD_SIZE; i++) {
|
||||
slotList.add(new TpsSlot());
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (period == TimeUnit.SECONDS) {
|
||||
startTime = RateCounter.getTrimMillsOfSecond(now);
|
||||
} else if (period == TimeUnit.MINUTES) {
|
||||
startTime = RateCounter.getTrimMillsOfMinute(now);
|
||||
} else if (period == TimeUnit.HOURS) {
|
||||
startTime = RateCounter.getTrimMillsOfHour(now);
|
||||
} else {
|
||||
//second default
|
||||
getTrimMillsOfSecond(now);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long add(long timestamp, long count) {
|
||||
return createSlotIfAbsent(timestamp).countHolder.count.addAndGet(count);
|
||||
}
|
||||
|
||||
public void minus(long timestamp, long count) {
|
||||
AtomicLong currentCount = createSlotIfAbsent(timestamp).countHolder.count;
|
||||
currentCount.addAndGet(count * -1);
|
||||
}
|
||||
|
||||
public long getCount(long timestamp) {
|
||||
TpsSlot point = getPoint(timestamp);
|
||||
return point == null ? 0L : point.countHolder.count.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* get slot of the timestamp second,read only ,return nul if not exist.
|
||||
*
|
||||
* @param timeStamp the timestamp second.
|
||||
* @return tps slot.
|
||||
*/
|
||||
private TpsSlot getPoint(long timeStamp) {
|
||||
long distance = timeStamp - startTime;
|
||||
long diff = (distance < 0 ? distance + getPeriod().toMillis(1) * DEFAULT_RECORD_SIZE : distance) / getPeriod()
|
||||
.toMillis(1);
|
||||
long currentWindowTime = startTime + diff * getPeriod().toMillis(1);
|
||||
int index = (int) diff % DEFAULT_RECORD_SIZE;
|
||||
TpsSlot tpsSlot = slotList.get(index);
|
||||
if (tpsSlot.time != currentWindowTime) {
|
||||
return null;
|
||||
}
|
||||
return tpsSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* get slot of the timestamp second,create if not exist.
|
||||
*
|
||||
* @param timeStamp the timestamp second.
|
||||
* @return tps slot.
|
||||
*/
|
||||
public TpsSlot createSlotIfAbsent(long timeStamp) {
|
||||
long distance = timeStamp - startTime;
|
||||
|
||||
long diff = (distance < 0 ? distance + getPeriod().toMillis(1) * DEFAULT_RECORD_SIZE : distance) / getPeriod()
|
||||
.toMillis(1);
|
||||
long currentWindowTime = startTime + diff * getPeriod().toMillis(1);
|
||||
int index = (int) diff % DEFAULT_RECORD_SIZE;
|
||||
TpsSlot tpsSlot = slotList.get(index);
|
||||
if (tpsSlot.time != currentWindowTime) {
|
||||
tpsSlot.reset(currentWindowTime);
|
||||
}
|
||||
return slotList.get(index);
|
||||
}
|
||||
|
||||
static class TpsSlot {
|
||||
|
||||
long time = 0L;
|
||||
|
||||
private SlotCountHolder countHolder = new SlotCountHolder();
|
||||
|
||||
public void reset(long second) {
|
||||
synchronized (this) {
|
||||
if (this.time != second) {
|
||||
this.time = second;
|
||||
countHolder.count.set(0L);
|
||||
countHolder.interceptedCount.set(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TpsSlot{" + "time=" + time + ", countHolder=" + countHolder + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SlotCountHolder {
|
||||
|
||||
AtomicLong count = new AtomicLong();
|
||||
|
||||
AtomicLong interceptedCount = new AtomicLong();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + count + "|" + interceptedCount + '}';
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user