Refactor control plugin (#11169)

* Refactor control plugin.

* For checkstyle.
This commit is contained in:
杨翊 SionYang 2023-09-21 13:47:28 +08:00 committed by GitHub
parent a84373644f
commit 0c44dce0cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 315 additions and 170 deletions

View File

@ -31,12 +31,15 @@ public class RpcScheduledExecutor extends ScheduledThreadPoolExecutor {
public static final RpcScheduledExecutor TIMEOUT_SCHEDULER = new RpcScheduledExecutor(1,
"com.alibaba.nacos.remote.TimerScheduler");
public static final RpcScheduledExecutor CONTROL_SCHEDULER = new RpcScheduledExecutor(1,
"com.alibaba.nacos.control.DelayScheduler");
public static final RpcScheduledExecutor COMMON_SERVER_EXECUTOR = new RpcScheduledExecutor(1,
"com.alibaba.nacos.remote.ServerCommonScheduler");
public RpcScheduledExecutor(int corePoolSize, final String threadName) {
super(corePoolSize, new ThreadFactory() {
private AtomicLong index = new AtomicLong();
private final AtomicLong index = new AtomicLong();
@Override
public Thread newThread(Runnable r) {

View File

@ -112,7 +112,7 @@
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-contrl-plugin</artifactId>
<artifactId>nacos-control-plugin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>

View File

@ -154,7 +154,7 @@
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-contrl-plugin</artifactId>
<artifactId>nacos-control-plugin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>

View File

@ -41,6 +41,7 @@ import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -64,6 +65,8 @@ public class ControllerMethodsCache {
private final ConcurrentMap<String, List<RequestMappingInfo>> urlLookup = new ConcurrentHashMap<>();
private final Set<Class> scannedClass = new HashSet<>();
public Method getMethod(HttpServletRequest request) {
String path = getPath(request);
String httpMethod = request.getMethod();
@ -143,6 +146,9 @@ public class ControllerMethodsCache {
* @param clazz {@link Class}
*/
private void initClassMethod(Class<?> clazz) {
if (scannedClass.contains(clazz)) {
return;
}
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
for (String classPath : requestMapping.value()) {
for (Method method : clazz.getMethods()) {
@ -156,12 +162,22 @@ public class ControllerMethodsCache {
requestMethods = new RequestMethod[1];
requestMethods[0] = RequestMethod.GET;
}
for (String methodPath : requestMapping.value()) {
String urlKey = requestMethods[0].name() + REQUEST_PATH_SEPARATOR + classPath + methodPath;
addUrlAndMethodRelation(urlKey, requestMapping.params(), method);
// FIXME: vipserver needs multiple http methods mapping
for (RequestMethod requestMethod : requestMethods) {
String[] value = requestMapping.value();
if (value.length > 0) {
for (String methodPath : requestMapping.value()) {
String urlKey = requestMethod.name() + REQUEST_PATH_SEPARATOR + classPath + methodPath;
addUrlAndMethodRelation(urlKey, requestMapping.params(), method);
}
} else {
String urlKey = requestMethod.name() + REQUEST_PATH_SEPARATOR + classPath;
addUrlAndMethodRelation(urlKey, requestMapping.params(), method);
}
}
}
}
scannedClass.add(clazz);
}
private void parseSubAnnotations(Method method, String classPath) {

View File

@ -1,90 +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.control.http;
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 {
@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;
}
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);
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 1999-2023 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.code.ControllerMethodsCache;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Nacos http tps control cut point filter registration.
*
* @author xiweng.yy
*/
@Configuration
public class NacosHttpTpsControlRegistration {
@Bean
public FilterRegistrationBean<NacosHttpTpsFilter> tpsFilterRegistration(NacosHttpTpsFilter tpsFilter) {
FilterRegistrationBean<NacosHttpTpsFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(tpsFilter);
//nacos naming
registration.addUrlPatterns("/v1/ns/*", "/v2/ns/*");
//nacos config
registration.addUrlPatterns("/v1/cs/*", "/v2/cs/*");
registration.setName("tpsFilter");
registration.setOrder(6);
return registration;
}
@Bean
public NacosHttpTpsFilter tpsFilter(ControllerMethodsCache methodsCache) {
return new NacosHttpTpsFilter(methodsCache);
}
}

View File

@ -1,37 +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.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());
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 1999-2023 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.api.remote.RpcScheduledExecutor;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
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 javax.servlet.AsyncContext;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* Nacos http tps control cut point filter.
*
* @author xiweng.yy
*/
public class NacosHttpTpsFilter implements Filter {
private ControllerMethodsCache controllerMethodsCache;
public NacosHttpTpsFilter(ControllerMethodsCache controllerMethodsCache) {
this.controllerMethodsCache = controllerMethodsCache;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
Method method = controllerMethodsCache.getMethod(httpServletRequest);
try {
if (method != null && method.isAnnotationPresent(TpsControl.class)
&& TpsControlConfig.isTpsControlEnabled()) {
TpsControl tpsControl = method.getAnnotation(TpsControl.class);
String pointName = tpsControl.pointName();
String parserName = StringUtils.isBlank(tpsControl.name()) ? pointName : tpsControl.name();
HttpTpsCheckRequestParser parser = HttpTpsCheckRequestParserRegistry.getParser(parserName);
TpsCheckRequest httpTpsCheckRequest = null;
if (parser != null) {
httpTpsCheckRequest = parser.parse(httpServletRequest);
}
if (httpTpsCheckRequest == null) {
httpTpsCheckRequest = new TpsCheckRequest();
}
if (StringUtils.isBlank(httpTpsCheckRequest.getPointName())) {
httpTpsCheckRequest.setPointName(pointName);
}
TpsCheckResponse checkResponse = ControlManagerCenter.getInstance().getTpsControlManager()
.check(httpTpsCheckRequest);
if (!checkResponse.isSuccess()) {
AsyncContext asyncContext = httpServletRequest.startAsync();
asyncContext.setTimeout(0);
RpcScheduledExecutor.CONTROL_SCHEDULER.schedule(
() -> generate503Response(httpServletRequest, response, checkResponse.getMessage(),
asyncContext), 1000L, TimeUnit.MILLISECONDS);
return;
}
}
} catch (Throwable throwable) {
Loggers.TPS.warn("Fail to http tps check", throwable);
}
filterChain.doFilter(httpServletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
void generate503Response(HttpServletRequest request, HttpServletResponse response, String message,
AsyncContext asyncContext) {
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.getOutputStream().println(message);
asyncContext.complete();
} catch (Exception ex) {
Loggers.TPS.error("Error to generate tps 503 response", ex);
}
}
}

View File

@ -69,7 +69,9 @@ public class TpsControlRequestFilter extends AbstractRequestFilter {
if (tpsCheckRequest == null) {
tpsCheckRequest = new TpsCheckRequest();
}
tpsCheckRequest.setPointName(pointName);
if (StringUtils.isBlank(tpsCheckRequest.getPointName())) {
tpsCheckRequest.setPointName(pointName);
}
TpsCheckResponse check = tpsControlManager.check(tpsCheckRequest);

View File

@ -17,32 +17,25 @@
package com.alibaba.nacos.core.monitor;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import java.util.concurrent.ConcurrentHashMap;
/**
* Metrics unified usage center.
*
* <p>
* FIXME: Bad implemetation, force depend prometheus. No need to new {@link CompositeMeterRegistry}, only should use
* {@link io.micrometer.core.instrument.Metrics#globalRegistry}. If need to distinguish different scope or module, use
* name of meters is enough.
* </p>
*
* @author <a href="mailto:liuyixiao0821@gmail.com">liuyixiao</a>
* @author xiweng.yy
*/
@SuppressWarnings("all")
public final class NacosMeterRegistryCenter {
// stable registries.
public static final String CORE_STABLE_REGISTRY = "CORE_STABLE_REGISTRY";
public static final String CONFIG_STABLE_REGISTRY = "CONFIG_STABLE_REGISTRY";
@ -50,31 +43,33 @@ public final class NacosMeterRegistryCenter {
public static final String NAMING_STABLE_REGISTRY = "NAMING_STABLE_REGISTRY";
// dynamic registries.
public static final String TOPN_CONFIG_CHANGE_REGISTRY = "TOPN_CONFIG_CHANGE_REGISTRY";
public static final String TOPN_SERVICE_CHANGE_REGISTRY = "TOPN_SERVICE_CHANGE_REGISTRY";
// control plugin registeres.
public static final String CONTROL_DENIED_REGISTRY = "CONTROL_DENIED_REGISTRY";
private static final ConcurrentHashMap<String, CompositeMeterRegistry> METER_REGISTRIES = new ConcurrentHashMap<>();
private static PrometheusMeterRegistry PROMETHEUS_METER_REGISTRY = null;
private static CompositeMeterRegistry METER_REGISTRY = null;
static {
try {
PROMETHEUS_METER_REGISTRY = ApplicationUtils.getBean(PrometheusMeterRegistry.class);
METER_REGISTRY = Metrics.globalRegistry;
} catch (Throwable t) {
Loggers.CORE.warn("Metrics init failed :", t);
}
registry(CORE_STABLE_REGISTRY, CONFIG_STABLE_REGISTRY, NAMING_STABLE_REGISTRY, TOPN_CONFIG_CHANGE_REGISTRY,
TOPN_SERVICE_CHANGE_REGISTRY);
TOPN_SERVICE_CHANGE_REGISTRY, CONTROL_DENIED_REGISTRY);
}
private static void registry(String... names) {
for (String name : names) {
CompositeMeterRegistry compositeMeterRegistry = new CompositeMeterRegistry();
if (PROMETHEUS_METER_REGISTRY != null) {
compositeMeterRegistry.add(PROMETHEUS_METER_REGISTRY);
if (METER_REGISTRY != null) {
compositeMeterRegistry.add(METER_REGISTRY);
}
METER_REGISTRIES.put(name, compositeMeterRegistry);
}

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.core.remote.grpc;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.grpc.auto.Payload;
import com.alibaba.nacos.api.grpc.auto.RequestGrpc;
import com.alibaba.nacos.api.remote.RpcScheduledExecutor;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.api.remote.request.ServerCheckRequest;
@ -36,6 +37,8 @@ import io.grpc.stub.StreamObserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* rpc request acceptor of grpc.
*
@ -166,8 +169,17 @@ public class GrpcRequestAcceptor extends RequestGrpc.RequestImplBase {
Response response = requestHandler.handleRequest(request, requestMeta);
Payload payloadResponse = GrpcUtils.convert(response);
traceIfNecessary(payloadResponse, false);
responseObserver.onNext(payloadResponse);
responseObserver.onCompleted();
if (response.getErrorCode() == NacosException.OVER_THRESHOLD) {
RpcScheduledExecutor.CONTROL_SCHEDULER.schedule(() -> {
traceIfNecessary(payloadResponse, false);
responseObserver.onNext(payloadResponse);
responseObserver.onCompleted();
}, 1000L, TimeUnit.MILLISECONDS);
} else {
traceIfNecessary(payloadResponse, false);
responseObserver.onNext(payloadResponse);
responseObserver.onCompleted();
}
} catch (Throwable e) {
Loggers.REMOTE_DIGEST
.error("[{}] Fail to handle request from connection [{}] ,error message :{}", "grpc", connectionId,

View File

@ -31,6 +31,7 @@ import com.alibaba.nacos.common.trace.event.naming.UpdateInstanceTraceEvent;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.InstanceOperator;
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
@ -100,6 +101,7 @@ public class InstanceController {
*/
@CanDistro
@PostMapping
@TpsControl(pointName = "NamingInstanceRegister", name = "HttpNamingInstanceRegister")
@Secured(action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
@ -127,6 +129,7 @@ public class InstanceController {
*/
@CanDistro
@DeleteMapping
@TpsControl(pointName = "NamingInstanceDeregister", name = "HttpNamingInstanceDeregister")
@Secured(action = ActionTypes.WRITE)
public String deregister(HttpServletRequest request) throws Exception {
Instance instance = HttpRequestInstanceBuilder.newBuilder()
@ -151,6 +154,7 @@ public class InstanceController {
*/
@CanDistro
@PutMapping
@TpsControl(pointName = "NamingInstanceUpdate", name = "HttpNamingInstanceUpdate")
@Secured(action = ActionTypes.WRITE)
public String update(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
@ -175,6 +179,7 @@ public class InstanceController {
*/
@CanDistro
@PutMapping(value = "/metadata/batch")
@TpsControl(pointName = "NamingInstanceMetadataUpdate", name = "HttpNamingInstanceMetadataBatchUpdate")
@Secured(action = ActionTypes.WRITE)
public ObjectNode batchUpdateInstanceMetadata(HttpServletRequest request) throws Exception {
final String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,
@ -208,6 +213,7 @@ public class InstanceController {
*/
@CanDistro
@DeleteMapping("/metadata/batch")
@TpsControl(pointName = "NamingInstanceMetadataUpdate", name = "HttpNamingInstanceMetadataBatchUpdate")
@Secured(action = ActionTypes.WRITE)
public ObjectNode batchDeleteInstanceMetadata(HttpServletRequest request) throws Exception {
final String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,
@ -303,6 +309,7 @@ public class InstanceController {
* @throws Exception any error during list
*/
@GetMapping("/list")
@TpsControl(pointName = "NamingServiceSubscribe", name = "HttpNamingServiceSubscribe")
@Secured(action = ActionTypes.READ)
public Object list(HttpServletRequest request) throws Exception {
@ -330,6 +337,7 @@ public class InstanceController {
* @throws Exception any error during get
*/
@GetMapping
@TpsControl(pointName = "NamingInstanceQuery", name = "HttpNamingInstanceQuery")
@Secured(action = ActionTypes.READ)
public ObjectNode detail(HttpServletRequest request) throws Exception {
@ -363,6 +371,7 @@ public class InstanceController {
*/
@CanDistro
@PutMapping("/beat")
@TpsControl(pointName = "HttpHealthCheck", name = "HttpHealthCheck")
@Secured(action = ActionTypes.WRITE)
public ObjectNode beat(HttpServletRequest request) throws Exception {

View File

@ -31,6 +31,7 @@ import com.alibaba.nacos.common.trace.event.naming.UpdateServiceTraceEvent;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.NumberUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.ServiceOperator;
import com.alibaba.nacos.naming.core.ServiceOperatorV2Impl;
@ -93,6 +94,7 @@ public class ServiceController {
* @throws Exception exception
*/
@PostMapping
@TpsControl(pointName = "NamingServiceRegister", name = "HttpNamingServiceRegister")
@Secured(action = ActionTypes.WRITE)
public String create(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName,
@ -119,6 +121,7 @@ public class ServiceController {
* @throws Exception exception
*/
@DeleteMapping
@TpsControl(pointName = "NamingServiceDeregister", name = "HttpNamingServiceDeregister")
@Secured(action = ActionTypes.WRITE)
public String remove(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName) throws Exception {
@ -138,6 +141,7 @@ public class ServiceController {
* @throws NacosException nacos exception
*/
@GetMapping
@TpsControl(pointName = "NamingServiceQuery", name = "HttpNamingServiceQuery")
@Secured(action = ActionTypes.READ)
public ObjectNode detail(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName) throws NacosException {
@ -152,6 +156,7 @@ public class ServiceController {
* @throws Exception exception
*/
@GetMapping("/list")
@TpsControl(pointName = "NamingServiceListQuery", name = "HttpNamingServiceListQuery")
@Secured(action = ActionTypes.READ)
public ObjectNode list(HttpServletRequest request) throws Exception {
final int pageNo = NumberUtils.toInt(WebUtils.required(request, "pageNo"));
@ -176,6 +181,7 @@ public class ServiceController {
* @throws Exception exception
*/
@PutMapping
@TpsControl(pointName = "NamingServiceUpdate", name = "HttpNamingServiceUpdate")
@Secured(action = ActionTypes.WRITE)
public String update(HttpServletRequest request) throws Exception {
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);

View File

@ -36,6 +36,7 @@ import com.alibaba.nacos.common.trace.event.naming.RegisterInstanceTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.UpdateInstanceTraceEvent;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
import com.alibaba.nacos.naming.core.InstancePatchObject;
import com.alibaba.nacos.naming.healthcheck.RsInfo;
@ -97,6 +98,7 @@ public class InstanceControllerV2 {
*/
@CanDistro
@PostMapping
@TpsControl(pointName = "NamingInstanceRegister", name = "HttpNamingInstanceRegister")
@Secured(action = ActionTypes.WRITE)
public Result<String> register(InstanceForm instanceForm) throws NacosException {
// check param
@ -118,6 +120,7 @@ public class InstanceControllerV2 {
*/
@CanDistro
@DeleteMapping
@TpsControl(pointName = "NamingInstanceDeregister", name = "HttpNamingInstanceDeregister")
@Secured(action = ActionTypes.WRITE)
public Result<String> deregister(InstanceForm instanceForm) throws NacosException {
// check param
@ -138,6 +141,7 @@ public class InstanceControllerV2 {
*/
@CanDistro
@PutMapping
@TpsControl(pointName = "NamingInstanceUpdate", name = "HttpNamingInstanceUpdate")
@Secured(action = ActionTypes.WRITE)
public Result<String> update(InstanceForm instanceForm) throws NacosException {
// check param
@ -159,6 +163,7 @@ public class InstanceControllerV2 {
*/
@CanDistro
@PutMapping(value = "/metadata/batch")
@TpsControl(pointName = "NamingInstanceMetadataUpdate", name = "HttpNamingInstanceMetadataBatchUpdate")
@Secured(action = ActionTypes.WRITE)
public Result<InstanceMetadataBatchOperationVo> batchUpdateInstanceMetadata(InstanceMetadataBatchOperationForm form)
throws NacosException {
@ -181,6 +186,7 @@ public class InstanceControllerV2 {
*/
@CanDistro
@DeleteMapping("/metadata/batch")
@TpsControl(pointName = "NamingInstanceMetadataUpdate", name = "HttpNamingInstanceMetadataBatchUpdate")
@Secured(action = ActionTypes.WRITE)
public Result<InstanceMetadataBatchOperationVo> batchDeleteInstanceMetadata(InstanceMetadataBatchOperationForm form)
throws NacosException {
@ -272,6 +278,7 @@ public class InstanceControllerV2 {
* @param clientVersion [header] clientVersion
*/
@GetMapping("/list")
@TpsControl(pointName = "NamingServiceSubscribe", name = "HttpNamingServiceSubscribe")
@Secured(action = ActionTypes.READ)
public Result<ServiceInfo> list(
@RequestParam(value = "namespaceId", defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@ -306,6 +313,7 @@ public class InstanceControllerV2 {
* @throws NacosException any error during get
*/
@GetMapping
@TpsControl(pointName = "NamingInstanceQuery", name = "HttpNamingInstanceQuery")
@Secured(action = ActionTypes.READ)
public Result<InstanceDetailInfoVo> detail(
@RequestParam(value = "namespaceId", defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@ -344,6 +352,7 @@ public class InstanceControllerV2 {
*/
@CanDistro
@PutMapping("/beat")
@TpsControl(pointName = "HttpHealthCheck", name = "HttpHealthCheck")
@Secured(action = ActionTypes.WRITE)
public ObjectNode beat(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName, @RequestParam(defaultValue = StringUtils.EMPTY) String ip,

View File

@ -30,6 +30,7 @@ import com.alibaba.nacos.common.trace.event.naming.RegisterServiceTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.UpdateServiceTraceEvent;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.naming.core.ServiceOperatorV2Impl;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
@ -79,6 +80,7 @@ public class ServiceControllerV2 {
* Create a new service. This API will create a persistence service.
*/
@PostMapping()
@TpsControl(pointName = "NamingServiceRegister", name = "HttpNamingServiceRegister")
@Secured(action = ActionTypes.WRITE)
public Result<String> create(ServiceForm serviceForm) throws Exception {
serviceForm.validate();
@ -99,6 +101,7 @@ public class ServiceControllerV2 {
* Remove service.
*/
@DeleteMapping()
@TpsControl(pointName = "NamingServiceDeregister", name = "HttpNamingServiceDeregister")
@Secured(action = ActionTypes.WRITE)
public Result<String> remove(
@RequestParam(value = "namespaceId", defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@ -115,6 +118,7 @@ public class ServiceControllerV2 {
* Get detail of service.
*/
@GetMapping()
@TpsControl(pointName = "NamingServiceQuery", name = "HttpNamingServiceQuery")
@Secured(action = ActionTypes.READ)
public Result<ServiceDetailInfo> detail(
@RequestParam(value = "namespaceId", defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@ -130,6 +134,7 @@ public class ServiceControllerV2 {
* List all service names.
*/
@GetMapping("/list")
@TpsControl(pointName = "NamingServiceListQuery", name = "HttpNamingServiceListQuery")
@Secured(action = ActionTypes.READ)
public Result<ServiceNameView> list(
@RequestParam(value = "namespaceId", required = false, defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@ -150,6 +155,7 @@ public class ServiceControllerV2 {
* Update service.
*/
@PutMapping()
@TpsControl(pointName = "NamingServiceUpdate", name = "HttpNamingServiceUpdate")
@Secured(action = ActionTypes.WRITE)
public Result<String> update(ServiceForm serviceForm) throws Exception {
serviceForm.validate();

View File

@ -43,7 +43,7 @@ public class NamingDynamicMeterRefreshService {
* refresh service change count top n per 30s.
*/
@Scheduled(cron = "0/30 * * * * *")
public void refreshTopnConfigChangeCount() {
public void refreshTopnServiceChangeCount() {
NacosMeterRegistryCenter.clear(TOPN_SERVICE_CHANGE_REGISTRY);
List<Pair<String, AtomicInteger>> topnServiceChangeCount = MetricsMonitor.getServiceChangeCount()
.getTopNCounter(SERVICE_CHANGE_N);
@ -52,6 +52,7 @@ public class NamingDynamicMeterRefreshService {
tags.add(new ImmutableTag("service", serviceChangeCount.getFirst()));
NacosMeterRegistryCenter.gauge(TOPN_SERVICE_CHANGE_REGISTRY, "service_change_count", tags, serviceChangeCount.getSecond());
}
MetricsMonitor.getServiceChangeCount().removeAll();
}
/**

View File

@ -22,6 +22,7 @@ import com.alibaba.nacos.api.naming.remote.request.BatchInstanceRequest;
import com.alibaba.nacos.api.naming.remote.response.BatchInstanceResponse;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.remote.RequestHandler;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.core.v2.service.impl.EphemeralClientOperationServiceImpl;
@ -44,6 +45,7 @@ public class BatchInstanceRequestHandler extends RequestHandler<BatchInstanceReq
}
@Override
@TpsControl(pointName = "RemoteNamingInstanceBatchRegister", name = "RemoteNamingInstanceBatchRegister")
@Secured(action = ActionTypes.WRITE)
public BatchInstanceResponse handle(BatchInstanceRequest request, RequestMeta meta) throws NacosException {
Service service = Service.newService(request.getNamespace(), request.getGroupName(), request.getServiceName(),

View File

@ -26,6 +26,7 @@ import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.trace.DeregisterInstanceReason;
import com.alibaba.nacos.common.trace.event.naming.DeregisterInstanceTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.RegisterInstanceTraceEvent;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.remote.RequestHandler;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.core.v2.service.impl.EphemeralClientOperationServiceImpl;
@ -48,6 +49,7 @@ public class InstanceRequestHandler extends RequestHandler<InstanceRequest, Inst
}
@Override
@TpsControl(pointName = "RemoteNamingInstanceRegisterDeregister", name = "RemoteNamingInstanceRegisterDeregister")
@Secured(action = ActionTypes.WRITE)
public InstanceResponse handle(InstanceRequest request, RequestMeta meta) throws NacosException {
Service service = Service

View File

@ -21,6 +21,7 @@ import com.alibaba.nacos.api.naming.remote.request.ServiceListRequest;
import com.alibaba.nacos.api.naming.remote.response.ServiceListResponse;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.remote.RequestHandler;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
@ -43,6 +44,7 @@ import java.util.Objects;
public class ServiceListRequestHandler extends RequestHandler<ServiceListRequest, ServiceListResponse> {
@Override
@TpsControl(pointName = "RemoteNamingServiceListQuery", name = "RemoteNamingServiceListQuery")
@Secured(action = ActionTypes.READ)
public ServiceListResponse handle(ServiceListRequest request, RequestMeta meta) throws NacosException {
Collection<Service> serviceSet = ServiceManager.getInstance().getSingletons(request.getNamespace());

View File

@ -22,6 +22,7 @@ import com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest;
import com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.remote.RequestHandler;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
@ -49,6 +50,7 @@ public class ServiceQueryRequestHandler extends RequestHandler<ServiceQueryReque
}
@Override
@TpsControl(pointName = "RemoteNamingServiceQuery", name = "RemoteNamingServiceQuery")
@Secured(action = ActionTypes.READ)
public QueryServiceResponse handle(ServiceQueryRequest request, RequestMeta meta) throws NacosException {
String namespaceId = request.getNamespace();

View File

@ -27,6 +27,7 @@ import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.trace.event.naming.SubscribeServiceTraceEvent;
import com.alibaba.nacos.common.trace.event.naming.UnsubscribeServiceTraceEvent;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.remote.RequestHandler;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
@ -60,6 +61,7 @@ public class SubscribeServiceRequestHandler extends RequestHandler<SubscribeServ
}
@Override
@TpsControl(pointName = "RemoteNamingServiceSubscribeUnSubscribe", name = "RemoteNamingServiceSubscribeUnsubscribe")
@Secured(action = ActionTypes.READ)
public SubscribeServiceResponse handle(SubscribeServiceRequest request, RequestMeta meta) throws NacosException {
String namespaceId = request.getNamespace();

View File

@ -62,21 +62,20 @@ public class ClientAttributesFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String uri = request.getRequestURI();
String method = request.getMethod();
try {
try {
if ((UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_NAMING_CONTEXT
+ UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT).equals(request.getRequestURI())
&& request.getMethod().equals(HttpMethod.POST)) {
if (isRegisterInstanceUri(uri, method)) {
//register
ClientAttributes requestClientAttributes = getClientAttributes(request);
threadLocalClientAttributes.set(requestClientAttributes);
} else if ((UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_NAMING_CONTEXT
+ UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT + BEAT_URI).equals(request.getRequestURI())) {
} else if (isBeatUri(uri, method)) {
//beat
String ip = WebUtils.optional(request, IP, StringUtils.EMPTY);
int port = Integer.parseInt(WebUtils.optional(request, PORT, ZERO));
String clientId = IpPortBasedClient.getClientId(ip + InternetAddressUtil.IP_PORT_SPLITER + port,
true);
String clientId = IpPortBasedClient
.getClientId(ip + InternetAddressUtil.IP_PORT_SPLITER + port, true);
IpPortBasedClient client = (IpPortBasedClient) clientManager.getClient(clientId);
if (client != null) {
ClientAttributes requestClientAttributes = getClientAttributes(request);
@ -101,6 +100,21 @@ public class ClientAttributesFilter implements Filter {
}
}
private boolean isBeatUri(String uri, String httpMethod) {
return ((UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_NAMING_CONTEXT
+ UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT + BEAT_URI).equals(uri) || (
UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.DEFAULT_NACOS_NAMING_CONTEXT_V2
+ UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT + BEAT_URI).equals(uri)) && HttpMethod.PUT
.equals(httpMethod);
}
private boolean isRegisterInstanceUri(String uri, String httpMethod) {
return ((UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_NAMING_CONTEXT
+ UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT).equals(uri) || (UtilsAndCommons.NACOS_SERVER_CONTEXT
+ UtilsAndCommons.DEFAULT_NACOS_NAMING_CONTEXT_V2 + UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT)
.equals(uri)) && HttpMethod.POST.equals(httpMethod);
}
private static boolean canUpdateClientAttributes(IpPortBasedClient client,
ClientAttributes requestClientAttributes) {
if (requestClientAttributes.getClientAttribute(HttpHeaderConsts.CLIENT_VERSION_HEADER) == null) {

View File

@ -28,9 +28,9 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class NamingConfig {
private static final String UTL_PATTERNS = "/v1/ns/*";
private static final String URL_PATTERNS = "/v1/ns/*";
private static final String UTL_PATTERNS_V2 = "/v2/ns/*";
private static final String URL_PATTERNS_V2 = "/v2/ns/*";
private static final String DISTRO_FILTER = "distroFilter";
@ -46,7 +46,7 @@ public class NamingConfig {
public FilterRegistrationBean<DistroFilter> distroFilterRegistration() {
FilterRegistrationBean<DistroFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(distroFilter());
registration.addUrlPatterns(UTL_PATTERNS);
registration.addUrlPatterns(URL_PATTERNS);
registration.setName(DISTRO_FILTER);
registration.setOrder(7);
return registration;
@ -56,7 +56,7 @@ public class NamingConfig {
public FilterRegistrationBean<ServiceNameFilter> serviceNameFilterRegistration() {
FilterRegistrationBean<ServiceNameFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(serviceNameFilter());
registration.addUrlPatterns(UTL_PATTERNS);
registration.addUrlPatterns(URL_PATTERNS);
registration.setName(SERVICE_NAME_FILTER);
registration.setOrder(5);
return registration;
@ -66,7 +66,7 @@ public class NamingConfig {
public FilterRegistrationBean<TrafficReviseFilter> trafficReviseFilterRegistration() {
FilterRegistrationBean<TrafficReviseFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(trafficReviseFilter());
registration.addUrlPatterns(UTL_PATTERNS);
registration.addUrlPatterns(URL_PATTERNS);
registration.setName(TRAFFIC_REVISE_FILTER);
registration.setOrder(1);
return registration;
@ -76,7 +76,7 @@ public class NamingConfig {
public FilterRegistrationBean<ClientAttributesFilter> clientAttributesFilterRegistration() {
FilterRegistrationBean<ClientAttributesFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(clientAttributesFilter());
registration.addUrlPatterns(UTL_PATTERNS);
registration.addUrlPatterns(URL_PATTERNS, URL_PATTERNS_V2);
registration.setName(CLIENT_ATTRIBUTES_FILTER);
registration.setOrder(8);
return registration;
@ -86,8 +86,7 @@ public class NamingConfig {
public FilterRegistrationBean<NamingParamCheckFilter> paramCheckFilterRegistration() {
FilterRegistrationBean<NamingParamCheckFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(namingParamCheckFilter());
registration.addUrlPatterns(UTL_PATTERNS);
registration.addUrlPatterns(UTL_PATTERNS_V2);
registration.addUrlPatterns(URL_PATTERNS, URL_PATTERNS_V2);
registration.setName(NAMING_PARAM_CHECK_FILTER);
registration.setOrder(10);
return registration;

View File

@ -26,7 +26,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-contrl-plugin</artifactId>
<artifactId>nacos-control-plugin</artifactId>
<name>nacos-control-plugin ${project.version}</name>
<url>https://nacos.io</url>

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.plugin.control.connection.response;
/**
* connection check response.
*
* @author shiyiyue
*/
public class ConnectionCheckResponse {
@ -28,6 +29,8 @@ public class ConnectionCheckResponse {
private int code;
private String limitMessage;
public boolean isSuccess() {
return success;
}
@ -51,4 +54,12 @@ public class ConnectionCheckResponse {
public void setCode(int code) {
this.code = code;
}
public String getLimitMessage() {
return limitMessage;
}
public void setLimitMessage(String limitMessage) {
this.limitMessage = limitMessage;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
* Copyright 1999-2023 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.
@ -16,10 +16,13 @@
package com.alibaba.nacos.plugin.control.tps;
import com.alibaba.nacos.common.utils.JacksonUtils;
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.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
@ -95,7 +98,11 @@ public abstract class RuleBarrier {
}
public String getLimitMsg() {
return String.format("[Period:%s,MaxCount:%s]", period, maxCount);
Map<String, String> limitMsg = new HashMap<>(3);
limitMsg.put("deniedType", "point");
limitMsg.put("period", period.toString());
limitMsg.put("limitCount", String.valueOf(maxCount));
return JacksonUtils.toJson(limitMsg);
}
/**