Skip to content

Commit

Permalink
Refactor control plugin (alibaba#11169)
Browse files Browse the repository at this point in the history
* Refactor control plugin.

* For checkstyle.
  • Loading branch information
KomachiSion authored Sep 21, 2023
1 parent a843736 commit 0c44dce
Show file tree
Hide file tree
Showing 26 changed files with 315 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
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;
Expand All @@ -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();
Expand Down Expand Up @@ -143,6 +146,9 @@ public void initClassMethod(Set<Class<?>> classesList) {
* @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()) {
Expand All @@ -156,12 +162,22 @@ private void initClassMethod(Class<?> clazz) {
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) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Loading

0 comments on commit 0c44dce

Please sign in to comment.