mirror of
https://gitee.com/dromara/RuoYi-Cloud-Plus.git
synced 2026-03-22 10:47:17 +08:00
update 重构 ruoyi-nacos 使用官方依赖整合 升级 2.1.2 版本
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
<spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
|
||||
<sentinel.version>1.8.6</sentinel.version>
|
||||
<seata.version>1.5.2</seata.version>
|
||||
<nacos.client.version>2.1.1</nacos.client.version>
|
||||
<nacos.client.version>2.1.2</nacos.client.version>
|
||||
<nacos.config.version>2.0.4</nacos.config.version>
|
||||
<dubbo.version>3.1.0</dubbo.version>
|
||||
<spring.context.support.version>1.0.11</spring.context.support.version>
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<nacos.version>2.1.1</nacos.version>
|
||||
<nacos.version>2.1.2</nacos.version>
|
||||
<nacos.lib.path>${project.basedir}/src/main/resources/lib</nacos.lib.path>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.springboot.nacos</groupId>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-all</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<type>pom</type>
|
||||
@@ -44,25 +45,174 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.springboot.nacos</groupId>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-auth</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-auth-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-cmdb</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-cmdb-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-config</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-config-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-consistency</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-consistency-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-core</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-core-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-istio</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-istio-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-naming</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-naming-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-plugin-default-impl</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-plugin-default-impl-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-sys</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${nacos.lib.path}/nacos-sys-${nacos.version}.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-common</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springboot.nacos</groupId>
|
||||
<artifactId>nacos-naming</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springboot.nacos</groupId>
|
||||
<artifactId>nacos-plugin-default-impl</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springboot.nacos</groupId>
|
||||
<artifactId>nacos-istio</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.caucho</groupId>
|
||||
<artifactId>hessian</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derby</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alipay.sofa</groupId>
|
||||
<artifactId>jraft-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alipay.sofa</groupId>
|
||||
<artifactId>rpc-grpc-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javatuples</groupId>
|
||||
<artifactId>javatuples</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-influx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-elastic</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.envoyproxy.controlplane</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>0.1.27</version>
|
||||
</dependency>
|
||||
|
||||
<!-- log -->
|
||||
@@ -106,6 +256,10 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<!-- 作用:项目打成jar的同时将本地jar包也引入进去 -->
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -42,10 +42,10 @@ import java.time.ZoneId;
|
||||
@EnableScheduling
|
||||
@PropertySource("/application.properties")
|
||||
public class ConsoleConfig {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ControllerMethodsCache methodsCache;
|
||||
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
@@ -56,7 +56,7 @@ public class ConsoleConfig {
|
||||
methodsCache.initClassMethod("com.alibaba.nacos.config.server.controller");
|
||||
methodsCache.initClassMethod("com.alibaba.nacos.console.controller");
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
@@ -69,12 +69,12 @@ public class ConsoleConfig {
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public XssFilter xssFilter() {
|
||||
return new XssFilter();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(ZoneId.systemDefault().toString());
|
||||
|
||||
@@ -1,32 +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.ability;
|
||||
|
||||
import com.alibaba.nacos.api.ability.ServerAbilities;
|
||||
|
||||
/**
|
||||
* Server ability initializer for remote.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class RemoteAbilityInitializer implements ServerAbilityInitializer {
|
||||
|
||||
@Override
|
||||
public void initialize(ServerAbilities abilities) {
|
||||
abilities.getRemoteAbility().setSupportRemoteConnection(true);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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.ability;
|
||||
|
||||
import com.alibaba.nacos.api.ability.ServerAbilities;
|
||||
import com.alibaba.nacos.api.ability.initializer.AbilityInitializer;
|
||||
|
||||
/**
|
||||
* Nacos server ability initializer.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface ServerAbilityInitializer extends AbilityInitializer<ServerAbilities> {
|
||||
|
||||
/**
|
||||
* Initialize server abilities content.
|
||||
*
|
||||
* @param abilities server abilities
|
||||
*/
|
||||
@Override
|
||||
void initialize(ServerAbilities abilities);
|
||||
}
|
||||
@@ -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.ability;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Nacos server ability initializer holder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class ServerAbilityInitializerHolder {
|
||||
|
||||
private static final ServerAbilityInitializerHolder INSTANCE = new ServerAbilityInitializerHolder();
|
||||
|
||||
private final Collection<ServerAbilityInitializer> initializers;
|
||||
|
||||
private ServerAbilityInitializerHolder() {
|
||||
initializers = new HashSet<>();
|
||||
for (ServerAbilityInitializer each : NacosServiceLoader.load(ServerAbilityInitializer.class)) {
|
||||
Loggers.CORE.info("Load {} for ServerAbilityInitializer", each.getClass().getCanonicalName());
|
||||
initializers.add(each);
|
||||
}
|
||||
}
|
||||
|
||||
public static ServerAbilityInitializerHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public Collection<ServerAbilityInitializer> getInitializers() {
|
||||
return initializers;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +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.core.auth;
|
||||
|
||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||
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;
|
||||
|
||||
/**
|
||||
* auth filter config.
|
||||
*
|
||||
* @author mai.jh
|
||||
*/
|
||||
@Configuration
|
||||
public class AuthConfig {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean authFilterRegistration(AuthFilter authFilter) {
|
||||
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(authFilter);
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("authFilter");
|
||||
registration.setOrder(6);
|
||||
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthFilter authFilter(AuthConfigs authConfigs, ControllerMethodsCache methodsCache) {
|
||||
return new AuthFilter(authConfigs, methodsCache);
|
||||
}
|
||||
}
|
||||
@@ -1,164 +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.core.auth;
|
||||
|
||||
import com.alibaba.nacos.auth.HttpProtocolAuthService;
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.code.ControllerMethodsCache;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.core.utils.WebUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.Permission;
|
||||
import com.alibaba.nacos.plugin.auth.api.Resource;
|
||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.sys.env.Constants;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Unified filter to handle authentication and authorization.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class AuthFilter implements Filter {
|
||||
|
||||
private final AuthConfigs authConfigs;
|
||||
|
||||
private final ControllerMethodsCache methodsCache;
|
||||
|
||||
private final HttpProtocolAuthService protocolAuthService;
|
||||
|
||||
public AuthFilter(AuthConfigs authConfigs, ControllerMethodsCache methodsCache) {
|
||||
this.authConfigs = authConfigs;
|
||||
this.methodsCache = methodsCache;
|
||||
this.protocolAuthService = new HttpProtocolAuthService(authConfigs);
|
||||
this.protocolAuthService.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
if (!authConfigs.isAuthEnabled()) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletResponse resp = (HttpServletResponse) response;
|
||||
|
||||
if (authConfigs.isEnableUserAgentAuthWhite()) {
|
||||
String userAgent = WebUtils.getUserAgent(req);
|
||||
if (StringUtils.startsWith(userAgent, Constants.NACOS_SERVER_HEADER)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
} else if (StringUtils.isNotBlank(authConfigs.getServerIdentityKey()) && StringUtils
|
||||
.isNotBlank(authConfigs.getServerIdentityValue())) {
|
||||
String serverIdentity = req.getHeader(authConfigs.getServerIdentityKey());
|
||||
if (StringUtils.isNotBlank(serverIdentity)) {
|
||||
if (authConfigs.getServerIdentityValue().equals(serverIdentity)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
Loggers.AUTH.warn("Invalid server identity value for {} from {}", authConfigs.getServerIdentityKey(),
|
||||
req.getRemoteHost());
|
||||
}
|
||||
} else {
|
||||
resp.sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||
"Invalid server identity key or value, Please make sure set `nacos.core.auth.server.identity.key`"
|
||||
+ " and `nacos.core.auth.server.identity.value`, or open `nacos.core.auth.enable.userAgentAuthWhite`");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Method method = methodsCache.getMethod(req);
|
||||
|
||||
if (method == null) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(Secured.class) && authConfigs.isAuthEnabled()) {
|
||||
|
||||
if (Loggers.AUTH.isDebugEnabled()) {
|
||||
Loggers.AUTH.debug("auth start, request: {} {}", req.getMethod(), req.getRequestURI());
|
||||
}
|
||||
|
||||
Secured secured = method.getAnnotation(Secured.class);
|
||||
if (!protocolAuthService.enableAuth(secured)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
Resource resource = protocolAuthService.parseResource(req, secured);
|
||||
IdentityContext identityContext = protocolAuthService.parseIdentity(req);
|
||||
boolean result = protocolAuthService.validateIdentity(identityContext, resource);
|
||||
if (!result) {
|
||||
// TODO Get reason of failure
|
||||
throw new AccessException("Validate Identity failed.");
|
||||
}
|
||||
injectIdentityId(req, identityContext);
|
||||
String action = secured.action().toString();
|
||||
result = protocolAuthService.validateAuthority(identityContext, new Permission(resource, action));
|
||||
if (!result) {
|
||||
// TODO Get reason of failure
|
||||
throw new AccessException("Validate Authority failed.");
|
||||
}
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
} catch (AccessException e) {
|
||||
if (Loggers.AUTH.isDebugEnabled()) {
|
||||
Loggers.AUTH.debug("access denied, request: {} {}, reason: {}", req.getMethod(), req.getRequestURI(),
|
||||
e.getErrMsg());
|
||||
}
|
||||
resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getErrMsg());
|
||||
} catch (IllegalArgumentException e) {
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, ExceptionUtil.getAllExceptionMsg(e));
|
||||
} catch (Exception e) {
|
||||
Loggers.AUTH.warn("[AUTH-FILTER] Server failed: ", e);
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server failed, " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set identity id to request session, make sure some actual logic can get identity information.
|
||||
*
|
||||
* <p>May be replaced with whole identityContext.
|
||||
*
|
||||
* @param request http request
|
||||
* @param identityContext identity context
|
||||
*/
|
||||
private void injectIdentityId(HttpServletRequest request, IdentityContext identityContext) {
|
||||
String identityId = identityContext
|
||||
.getParameter(com.alibaba.nacos.plugin.auth.constant.Constants.Identity.IDENTITY_ID, StringUtils.EMPTY);
|
||||
request.getSession()
|
||||
.setAttribute(com.alibaba.nacos.plugin.auth.constant.Constants.Identity.IDENTITY_ID, identityId);
|
||||
}
|
||||
}
|
||||
@@ -1,106 +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.auth;
|
||||
|
||||
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.auth.GrpcProtocolAuthService;
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.core.remote.AbstractRequestFilter;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.Permission;
|
||||
import com.alibaba.nacos.plugin.auth.api.Resource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.Constants;
|
||||
import com.alibaba.nacos.plugin.auth.exception.AccessException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* request auth filter for remote.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: RemoteRequestAuthFilter.java, v 0.1 2020年09月14日 12:38 PM liuzunfei Exp $
|
||||
*/
|
||||
@Component
|
||||
public class RemoteRequestAuthFilter extends AbstractRequestFilter {
|
||||
|
||||
private final AuthConfigs authConfigs;
|
||||
|
||||
private final GrpcProtocolAuthService protocolAuthService;
|
||||
|
||||
public RemoteRequestAuthFilter(AuthConfigs authConfigs) {
|
||||
this.authConfigs = authConfigs;
|
||||
this.protocolAuthService = new GrpcProtocolAuthService(authConfigs);
|
||||
this.protocolAuthService.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response filter(Request request, RequestMeta meta, Class handlerClazz) throws NacosException {
|
||||
|
||||
try {
|
||||
|
||||
Method method = getHandleMethod(handlerClazz);
|
||||
if (method.isAnnotationPresent(Secured.class) && authConfigs.isAuthEnabled()) {
|
||||
|
||||
if (Loggers.AUTH.isDebugEnabled()) {
|
||||
Loggers.AUTH.debug("auth start, request: {}", request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
Secured secured = method.getAnnotation(Secured.class);
|
||||
if (!protocolAuthService.enableAuth(secured)) {
|
||||
return null;
|
||||
}
|
||||
String clientIp = meta.getClientIp();
|
||||
request.putHeader(Constants.Identity.X_REAL_IP, clientIp);
|
||||
Resource resource = protocolAuthService.parseResource(request, secured);
|
||||
IdentityContext identityContext = protocolAuthService.parseIdentity(request);
|
||||
boolean result = protocolAuthService.validateIdentity(identityContext, resource);
|
||||
if (!result) {
|
||||
// TODO Get reason of failure
|
||||
throw new AccessException("Validate Identity failed.");
|
||||
}
|
||||
String action = secured.action().toString();
|
||||
result = protocolAuthService.validateAuthority(identityContext, new Permission(resource, action));
|
||||
if (!result) {
|
||||
// TODO Get reason of failure
|
||||
throw new AccessException("Validate Authority failed.");
|
||||
}
|
||||
}
|
||||
} catch (AccessException e) {
|
||||
if (Loggers.AUTH.isDebugEnabled()) {
|
||||
Loggers.AUTH.debug("access denied, request: {}, reason: {}", request.getClass().getSimpleName(),
|
||||
e.getErrMsg());
|
||||
}
|
||||
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
|
||||
defaultResponseInstance.setErrorInfo(NacosException.NO_RIGHT, e.getErrMsg());
|
||||
return defaultResponseInstance;
|
||||
} catch (Exception e) {
|
||||
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
|
||||
|
||||
defaultResponseInstance.setErrorInfo(NacosException.SERVER_ERROR, ExceptionUtil.getAllExceptionMsg(e));
|
||||
return defaultResponseInstance;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,70 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Addressable pattern base class.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public abstract class AbstractMemberLookup implements MemberLookup {
|
||||
|
||||
protected ServerMemberManager memberManager;
|
||||
|
||||
protected AtomicBoolean start = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
public void injectMemberManager(ServerMemberManager memberManager) {
|
||||
this.memberManager = memberManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterLookup(Collection<Member> members) {
|
||||
this.memberManager.memberChange(members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws NacosException {
|
||||
if (start.compareAndSet(true, false)) {
|
||||
doDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws NacosException {
|
||||
if (start.compareAndSet(false, true)) {
|
||||
doStart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* subclass can override this method if need.
|
||||
* @throws NacosException NacosException
|
||||
*/
|
||||
protected abstract void doStart() throws NacosException;
|
||||
|
||||
/**
|
||||
* subclass can override this method if need.
|
||||
* @throws NacosException nacosException
|
||||
*/
|
||||
protected abstract void doDestroy() throws NacosException;
|
||||
}
|
||||
@@ -1,252 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.api.ability.ServerAbilities;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Cluster member node.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class Member implements Comparable<Member>, Cloneable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6061130045021268736L;
|
||||
|
||||
private String ip;
|
||||
|
||||
private int port = -1;
|
||||
|
||||
private volatile NodeState state = NodeState.UP;
|
||||
|
||||
private Map<String, Object> extendInfo = Collections.synchronizedMap(new TreeMap<>());
|
||||
|
||||
private String address = "";
|
||||
|
||||
private transient int failAccessCnt = 0;
|
||||
|
||||
private ServerAbilities abilities = new ServerAbilities();
|
||||
|
||||
public Member() {
|
||||
String prefix = "nacos.core.member.meta.";
|
||||
extendInfo.put(MemberMetaDataConstants.SITE_KEY,
|
||||
EnvUtil.getProperty(prefix + MemberMetaDataConstants.SITE_KEY, "unknow"));
|
||||
extendInfo.put(MemberMetaDataConstants.AD_WEIGHT,
|
||||
EnvUtil.getProperty(prefix + MemberMetaDataConstants.AD_WEIGHT, "0"));
|
||||
extendInfo
|
||||
.put(MemberMetaDataConstants.WEIGHT, EnvUtil.getProperty(prefix + MemberMetaDataConstants.WEIGHT, "1"));
|
||||
}
|
||||
|
||||
public ServerAbilities getAbilities() {
|
||||
return abilities;
|
||||
}
|
||||
|
||||
public void setAbilities(ServerAbilities abilities) {
|
||||
this.abilities = abilities;
|
||||
}
|
||||
|
||||
public static MemberBuilder builder() {
|
||||
return new MemberBuilder();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public NodeState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(NodeState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public Map<String, Object> getExtendInfo() {
|
||||
return extendInfo;
|
||||
}
|
||||
|
||||
public void setExtendInfo(Map<String, Object> extendInfo) {
|
||||
Map<String, Object> newExtendInfo = Collections.synchronizedMap(new TreeMap<>());
|
||||
newExtendInfo.putAll(extendInfo);
|
||||
this.extendInfo = newExtendInfo;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
if (StringUtils.isBlank(address)) {
|
||||
address = ip + ":" + port;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Object getExtendVal(String key) {
|
||||
return extendInfo.get(key);
|
||||
}
|
||||
|
||||
public void setExtendVal(String key, Object value) {
|
||||
extendInfo.put(key, value);
|
||||
}
|
||||
|
||||
public void delExtendVal(String key) {
|
||||
extendInfo.remove(key);
|
||||
}
|
||||
|
||||
public boolean check() {
|
||||
return StringUtils.isNoneBlank(ip, address) && port != -1;
|
||||
}
|
||||
|
||||
public int getFailAccessCnt() {
|
||||
return failAccessCnt;
|
||||
}
|
||||
|
||||
public void setFailAccessCnt(int failAccessCnt) {
|
||||
this.failAccessCnt = failAccessCnt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Member that = (Member) o;
|
||||
if (StringUtils.isAnyBlank(address, that.address)) {
|
||||
return port == that.port && StringUtils.equals(ip, that.ip);
|
||||
}
|
||||
return StringUtils.equals(address, that.address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Member{" + "ip='" + ip + '\'' + ", port=" + port + ", state=" + state + ", extendInfo=" + extendInfo
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(ip, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Member o) {
|
||||
return getAddress().compareTo(o.getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* get a copy.
|
||||
*
|
||||
* @return member.
|
||||
*/
|
||||
public Member copy() {
|
||||
Member copy = null;
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(this);
|
||||
// convert the input stream to member object
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
copy = (Member) ois.readObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
Loggers.CORE.warn("[Member copy] copy failed", e);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static final class MemberBuilder {
|
||||
|
||||
private String ip;
|
||||
|
||||
private int port;
|
||||
|
||||
private NodeState state;
|
||||
|
||||
private Map<String, String> extendInfo = Collections.synchronizedMap(new TreeMap<>());
|
||||
|
||||
private MemberBuilder() {
|
||||
}
|
||||
|
||||
public MemberBuilder ip(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MemberBuilder port(int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MemberBuilder state(NodeState state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MemberBuilder extendInfo(Map<String, String> extendInfo) {
|
||||
this.extendInfo.putAll(extendInfo);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* build Member.
|
||||
*
|
||||
* @return {@link Member}
|
||||
*/
|
||||
public Member build() {
|
||||
Member serverNode = new Member();
|
||||
if (Objects.nonNull(this.extendInfo)) {
|
||||
serverNode.extendInfo.putAll(this.extendInfo);
|
||||
}
|
||||
serverNode.state = this.state;
|
||||
serverNode.ip = this.ip;
|
||||
serverNode.port = this.port;
|
||||
serverNode.address = this.ip + ":" + this.port;
|
||||
return serverNode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
|
||||
/**
|
||||
* Node change listeners.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class MemberChangeListener extends Subscriber<MembersChangeEvent> {
|
||||
|
||||
/**
|
||||
* return NodeChangeEvent.class info.
|
||||
*
|
||||
* @return {@link MembersChangeEvent#getClass()}
|
||||
*/
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return MembersChangeEvent.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to ignore expired events.
|
||||
*
|
||||
* @return default value is {@link Boolean#TRUE}
|
||||
*/
|
||||
@Override
|
||||
public boolean ignoreExpireEvent() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Member node addressing mode.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public interface MemberLookup {
|
||||
|
||||
/**
|
||||
* start.
|
||||
*
|
||||
* @throws NacosException NacosException
|
||||
*/
|
||||
void start() throws NacosException;
|
||||
|
||||
/**
|
||||
* is using address server.
|
||||
*
|
||||
* @return using address server or not.
|
||||
*/
|
||||
boolean useAddressServer();
|
||||
|
||||
/**
|
||||
* Inject the ServerMemberManager property.
|
||||
*
|
||||
* @param memberManager {@link ServerMemberManager}
|
||||
*/
|
||||
void injectMemberManager(ServerMemberManager memberManager);
|
||||
|
||||
/**
|
||||
* The addressing pattern finds cluster nodes.
|
||||
*
|
||||
* @param members {@link Collection}
|
||||
*/
|
||||
void afterLookup(Collection<Member> members);
|
||||
|
||||
/**
|
||||
* Addressing mode closed.
|
||||
*
|
||||
* @throws NacosException NacosException
|
||||
*/
|
||||
void destroy() throws NacosException;
|
||||
|
||||
/**
|
||||
* Some data information about the addressing pattern.
|
||||
*
|
||||
* @return {@link Map}
|
||||
*/
|
||||
default Map<String, Object> info() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +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.core.cluster;
|
||||
|
||||
/**
|
||||
* The necessary metadata information for the node.
|
||||
*
|
||||
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class MemberMetaDataConstants {
|
||||
|
||||
/**
|
||||
* Raft port,This parameter is dropped when RPC is used as a whole.
|
||||
*/
|
||||
public static final String RAFT_PORT = "raftPort";
|
||||
|
||||
public static final String SITE_KEY = "site";
|
||||
|
||||
public static final String AD_WEIGHT = "adWeight";
|
||||
|
||||
public static final String WEIGHT = "weight";
|
||||
|
||||
public static final String LAST_REFRESH_TIME = "lastRefreshTime";
|
||||
|
||||
public static final String VERSION = "version";
|
||||
|
||||
public static final String SUPPORT_REMOTE_C_TYPE = "remoteConnectType";
|
||||
|
||||
public static final String READY_TO_UPGRADE = "readyToUpgrade";
|
||||
|
||||
public static final String[] BASIC_META_KEYS = new String[] {SITE_KEY, AD_WEIGHT, RAFT_PORT, WEIGHT, VERSION,
|
||||
READY_TO_UPGRADE};
|
||||
}
|
||||
@@ -1,301 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.InternetAddressUtil;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Member node tool class.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class MemberUtil {
|
||||
|
||||
protected static final String TARGET_MEMBER_CONNECT_REFUSE_ERRMSG = "Connection refused";
|
||||
|
||||
private static final String SERVER_PORT_PROPERTY = "server.port";
|
||||
|
||||
private static final int DEFAULT_SERVER_PORT = 8848;
|
||||
|
||||
private static final int DEFAULT_RAFT_OFFSET_PORT = 1000;
|
||||
|
||||
private static final String MEMBER_FAIL_ACCESS_CNT_PROPERTY = "nacos.core.member.fail-access-cnt";
|
||||
|
||||
private static final int DEFAULT_MEMBER_FAIL_ACCESS_CNT = 3;
|
||||
|
||||
/**
|
||||
* Information copy.
|
||||
*
|
||||
* @param newMember {@link Member}
|
||||
* @param oldMember {@link Member}
|
||||
*/
|
||||
public static void copy(Member newMember, Member oldMember) {
|
||||
oldMember.setIp(newMember.getIp());
|
||||
oldMember.setPort(newMember.getPort());
|
||||
oldMember.setState(newMember.getState());
|
||||
oldMember.setExtendInfo(newMember.getExtendInfo());
|
||||
oldMember.setAddress(newMember.getAddress());
|
||||
oldMember.setAbilities(newMember.getAbilities());
|
||||
}
|
||||
|
||||
/**
|
||||
* parse ip:port to member.
|
||||
*
|
||||
* @param member ip:port
|
||||
* @return {@link Member}
|
||||
*/
|
||||
@SuppressWarnings("PMD.UndefineMagicConstantRule")
|
||||
public static Member singleParse(String member) {
|
||||
// Nacos default port is 8848
|
||||
int defaultPort = EnvUtil.getProperty(SERVER_PORT_PROPERTY, Integer.class, DEFAULT_SERVER_PORT);
|
||||
// Set the default Raft port information for securit
|
||||
|
||||
String address = member;
|
||||
int port = defaultPort;
|
||||
String[] info = InternetAddressUtil.splitIPPortStr(address);
|
||||
if (info.length > 1) {
|
||||
address = info[0];
|
||||
port = Integer.parseInt(info[1]);
|
||||
}
|
||||
|
||||
Member target = Member.builder().ip(address).port(port).state(NodeState.UP).build();
|
||||
Map<String, Object> extendInfo = new HashMap<>(4);
|
||||
// The Raft Port information needs to be set by default
|
||||
extendInfo.put(MemberMetaDataConstants.RAFT_PORT, String.valueOf(calculateRaftPort(target)));
|
||||
extendInfo.put(MemberMetaDataConstants.READY_TO_UPGRADE, true);
|
||||
target.setExtendInfo(extendInfo);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether the member support long connection or not.
|
||||
*
|
||||
* @param member member instance of server.
|
||||
* @return support long connection or not.
|
||||
*/
|
||||
public static boolean isSupportedLongCon(Member member) {
|
||||
if (member.getAbilities() == null || member.getAbilities().getRemoteAbility() == null) {
|
||||
return false;
|
||||
}
|
||||
return member.getAbilities().getRemoteAbility().isSupportRemoteConnection();
|
||||
}
|
||||
|
||||
public static int calculateRaftPort(Member member) {
|
||||
return member.getPort() - DEFAULT_RAFT_OFFSET_PORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to Member list.
|
||||
*
|
||||
* @param addresses ip list, example [127.0.0.1:8847,127.0.0.1:8848,127.0.0.1:8849]
|
||||
* @return member list
|
||||
*/
|
||||
public static Collection<Member> multiParse(Collection<String> addresses) {
|
||||
List<Member> members = new ArrayList<>(addresses.size());
|
||||
for (String address : addresses) {
|
||||
Member member = singleParse(address);
|
||||
members.add(member);
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Successful processing of the operation on the node.
|
||||
*
|
||||
* @param member {@link Member}
|
||||
*/
|
||||
public static void onSuccess(final ServerMemberManager manager, final Member member) {
|
||||
final NodeState old = member.getState();
|
||||
manager.getMemberAddressInfos().add(member.getAddress());
|
||||
member.setState(NodeState.UP);
|
||||
member.setFailAccessCnt(0);
|
||||
if (!Objects.equals(old, member.getState())) {
|
||||
manager.notifyMemberChange(member);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onFail(final ServerMemberManager manager, final Member member) {
|
||||
// To avoid null pointer judgments, pass in one NONE_EXCEPTION
|
||||
onFail(manager, member, ExceptionUtil.NONE_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Failure processing of the operation on the node.
|
||||
*
|
||||
* @param member {@link Member}
|
||||
* @param ex {@link Throwable}
|
||||
*/
|
||||
public static void onFail(final ServerMemberManager manager, final Member member, Throwable ex) {
|
||||
manager.getMemberAddressInfos().remove(member.getAddress());
|
||||
final NodeState old = member.getState();
|
||||
member.setState(NodeState.SUSPICIOUS);
|
||||
member.setFailAccessCnt(member.getFailAccessCnt() + 1);
|
||||
int maxFailAccessCnt = EnvUtil.getProperty(MEMBER_FAIL_ACCESS_CNT_PROPERTY, Integer.class, DEFAULT_MEMBER_FAIL_ACCESS_CNT);
|
||||
|
||||
// If the number of consecutive failures to access the target node reaches
|
||||
// a maximum, or the link request is rejected, the state is directly down
|
||||
if (member.getFailAccessCnt() > maxFailAccessCnt || StringUtils
|
||||
.containsIgnoreCase(ex.getMessage(), TARGET_MEMBER_CONNECT_REFUSE_ERRMSG)) {
|
||||
member.setState(NodeState.DOWN);
|
||||
}
|
||||
if (!Objects.equals(old, member.getState())) {
|
||||
manager.notifyMemberChange(member);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node list information persistence.
|
||||
*
|
||||
* @param members member list
|
||||
*/
|
||||
public static void syncToFile(Collection<Member> members) {
|
||||
try {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append('#').append(LocalDateTime.now()).append(StringUtils.LF);
|
||||
for (String member : simpleMembers(members)) {
|
||||
builder.append(member).append(StringUtils.LF);
|
||||
}
|
||||
EnvUtil.writeClusterConf(builder.toString());
|
||||
} catch (Throwable ex) {
|
||||
Loggers.CLUSTER.error("cluster member node persistence failed : {}", ExceptionUtil.getAllExceptionMsg(ex));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We randomly pick k nodes.
|
||||
*
|
||||
* @param members member list
|
||||
* @param filter filter {@link Predicate}
|
||||
* @param k node number
|
||||
* @return target members
|
||||
*/
|
||||
@SuppressWarnings("PMD.UndefineMagicConstantRule")
|
||||
public static Collection<Member> kRandom(Collection<Member> members, Predicate<Member> filter, int k) {
|
||||
|
||||
Set<Member> kMembers = new HashSet<>();
|
||||
|
||||
// Here thinking similar consul gossip protocols random k node
|
||||
int totalSize = members.size();
|
||||
Member[] membersArray = members.toArray(new Member[totalSize]);
|
||||
ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
|
||||
for (int i = 0; i < 3 * totalSize && kMembers.size() < k; i++) {
|
||||
int idx = threadLocalRandom.nextInt(totalSize);
|
||||
Member member = membersArray[idx];
|
||||
if (filter.test(member)) {
|
||||
kMembers.add(member);
|
||||
}
|
||||
}
|
||||
|
||||
return kMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default configuration format resolution, only NACos-Server IP or IP :port or hostname: Port information.
|
||||
*/
|
||||
public static Collection<Member> readServerConf(Collection<String> members) {
|
||||
Set<Member> nodes = new HashSet<>();
|
||||
|
||||
for (String member : members) {
|
||||
Member target = singleParse(member);
|
||||
nodes.add(target);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select target members with filter.
|
||||
*
|
||||
* @param members original members
|
||||
* @param filter filter
|
||||
* @return target members
|
||||
*/
|
||||
public static Set<Member> selectTargetMembers(Collection<Member> members, Predicate<Member> filter) {
|
||||
return members.stream().filter(filter).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get address list of members.
|
||||
*
|
||||
* @param members members
|
||||
* @return address list
|
||||
*/
|
||||
public static List<String> simpleMembers(Collection<Member> members) {
|
||||
return members.stream().map(Member::getAddress).sorted()
|
||||
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Judge whether basic info has changed.
|
||||
*
|
||||
* @param actual actual member
|
||||
* @param expected expected member
|
||||
* @return true if all content is same, otherwise false
|
||||
*/
|
||||
public static boolean isBasicInfoChanged(Member actual, Member expected) {
|
||||
if (null == expected) {
|
||||
return null == actual;
|
||||
}
|
||||
if (!expected.getIp().equals(actual.getIp())) {
|
||||
return true;
|
||||
}
|
||||
if (expected.getPort() != actual.getPort()) {
|
||||
return true;
|
||||
}
|
||||
if (!expected.getAddress().equals(actual.getAddress())) {
|
||||
return true;
|
||||
}
|
||||
if (!expected.getState().equals(actual.getState())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!expected.getAbilities().equals(actual.getAbilities())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isBasicInfoChangedInExtendInfo(expected, actual);
|
||||
}
|
||||
|
||||
private static boolean isBasicInfoChangedInExtendInfo(Member expected, Member actual) {
|
||||
for (String each : MemberMetaDataConstants.BASIC_META_KEYS) {
|
||||
if (expected.getExtendInfo().containsKey(each) != actual.getExtendInfo().containsKey(each)) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(expected.getExtendVal(each), actual.getExtendVal(each))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,106 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Publish this event when the node list changes,All interested in the node list change event can listen to this event.
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link com.alibaba.nacos.core.distributed.ProtocolManager}</li>
|
||||
* <li>{@link com.alibaba.nacos.naming.core.DistroMapper}</li>
|
||||
* <li>{@link com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeerSet}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class MembersChangeEvent extends Event {
|
||||
|
||||
private static final long serialVersionUID = 7308126651076668976L;
|
||||
|
||||
private final Collection<Member> members;
|
||||
|
||||
private final Collection<Member> triggers;
|
||||
|
||||
private MembersChangeEvent(Collection<Member> members, Collection<Member> triggers) {
|
||||
this.members = members;
|
||||
this.triggers = new HashSet<>();
|
||||
if (triggers != null) {
|
||||
this.triggers.addAll(triggers);
|
||||
}
|
||||
}
|
||||
|
||||
public static MemberChangeEventBuilder builder() {
|
||||
return new MemberChangeEventBuilder();
|
||||
}
|
||||
|
||||
public Collection<Member> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public boolean hasTriggers() {
|
||||
return !triggers.isEmpty();
|
||||
}
|
||||
|
||||
public Collection<Member> getTriggers() {
|
||||
return triggers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MembersChangeEvent{" + "members=" + members + ", triggers=" + triggers + ", no=" + sequence() + '}';
|
||||
}
|
||||
|
||||
public static final class MemberChangeEventBuilder {
|
||||
|
||||
private Collection<Member> allMembers;
|
||||
|
||||
private Collection<Member> triggers;
|
||||
|
||||
private MemberChangeEventBuilder() {
|
||||
}
|
||||
|
||||
public MemberChangeEventBuilder members(Collection<Member> allMembers) {
|
||||
this.allMembers = allMembers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MemberChangeEventBuilder triggers(Collection<Member> triggers) {
|
||||
this.triggers = triggers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MemberChangeEventBuilder trigger(Member trigger) {
|
||||
this.triggers = Collections.singleton(trigger);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* build MemberChangeEvent.
|
||||
*
|
||||
* @return {@link MembersChangeEvent}
|
||||
*/
|
||||
public MembersChangeEvent build() {
|
||||
return new MembersChangeEvent(allMembers, triggers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +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.core.cluster;
|
||||
|
||||
/**
|
||||
* The life cycle state of a node plays an important role.
|
||||
*
|
||||
* <p>1.3.0 The unified sinking operation should be done first, and the node state
|
||||
* should be radiated out later, mainly for whether the request can be processed and so on</p>
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public enum NodeState {
|
||||
|
||||
/**
|
||||
* Node is starting.
|
||||
*/
|
||||
STARTING,
|
||||
|
||||
/**
|
||||
* Node is up and ready for request.
|
||||
*/
|
||||
UP,
|
||||
|
||||
/**
|
||||
* Node may Crash.
|
||||
*/
|
||||
SUSPICIOUS,
|
||||
|
||||
/**
|
||||
* Node is out of service, something abnormal happened.
|
||||
*/
|
||||
DOWN,
|
||||
|
||||
/**
|
||||
* The Node is isolated.
|
||||
*/
|
||||
ISOLATION,
|
||||
|
||||
}
|
||||
@@ -1,602 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.api.ability.ServerAbilities;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.auth.util.AuthHeaderUtil;
|
||||
import com.alibaba.nacos.common.JustForTest;
|
||||
import com.alibaba.nacos.common.http.Callback;
|
||||
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
|
||||
import com.alibaba.nacos.common.http.HttpUtils;
|
||||
import com.alibaba.nacos.common.http.client.NacosAsyncRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
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.ConcurrentHashSet;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.common.utils.VersionUtils;
|
||||
import com.alibaba.nacos.core.ability.ServerAbilityInitializer;
|
||||
import com.alibaba.nacos.core.ability.ServerAbilityInitializerHolder;
|
||||
import com.alibaba.nacos.core.cluster.lookup.LookupFactory;
|
||||
import com.alibaba.nacos.core.utils.Commons;
|
||||
import com.alibaba.nacos.core.utils.GenericType;
|
||||
import com.alibaba.nacos.core.utils.GlobalExecutor;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.Constants;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.InetUtils;
|
||||
import org.springframework.boot.web.context.WebServerInitializedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.servlet.ServletContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
|
||||
/**
|
||||
* Cluster node management in Nacos.
|
||||
*
|
||||
* <p>{@link ServerMemberManager#init()} Cluster node manager initialization {@link ServerMemberManager#shutdown()} The
|
||||
* cluster node manager is down {@link ServerMemberManager#getSelf()} Gets local node information {@link
|
||||
* ServerMemberManager#getServerList()} Gets the cluster node dictionary {@link ServerMemberManager#getMemberAddressInfos()}
|
||||
* Gets the address information of the healthy member node {@link ServerMemberManager#allMembers()} Gets a list of
|
||||
* member information objects {@link ServerMemberManager#allMembersWithoutSelf()} Gets a list of cluster member nodes
|
||||
* with the exception of this node {@link ServerMemberManager#hasMember(String)} Is there a node {@link
|
||||
* ServerMemberManager#memberChange(Collection)} The final node list changes the method, making the full size more
|
||||
* {@link ServerMemberManager#memberJoin(Collection)} Node join, can automatically trigger {@link
|
||||
* ServerMemberManager#memberLeave(Collection)} When the node leaves, only the interface call can be manually triggered
|
||||
* {@link ServerMemberManager#update(Member)} Update the target node information {@link
|
||||
* ServerMemberManager#isUnHealth(String)} Whether the target node is healthy {@link
|
||||
* ServerMemberManager#initAndStartLookup()} Initializes the addressing mode
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Component(value = "serverMemberManager")
|
||||
public class ServerMemberManager implements ApplicationListener<WebServerInitializedEvent> {
|
||||
|
||||
private final NacosAsyncRestTemplate asyncRestTemplate = HttpClientBeanHolder
|
||||
.getNacosAsyncRestTemplate(Loggers.CORE);
|
||||
|
||||
private static final int DEFAULT_SERVER_PORT = 8848;
|
||||
|
||||
private static final String SERVER_PORT_PROPERTY = "server.port";
|
||||
|
||||
private static final String SPRING_MANAGEMENT_CONTEXT_NAMESPACE = "management";
|
||||
|
||||
private static final String MEMBER_CHANGE_EVENT_QUEUE_SIZE_PROPERTY = "nacos.member-change-event.queue.size";
|
||||
|
||||
private static final int DEFAULT_MEMBER_CHANGE_EVENT_QUEUE_SIZE = 128;
|
||||
|
||||
private static boolean isUseAddressServer = false;
|
||||
|
||||
private static final long DEFAULT_TASK_DELAY_TIME = 5_000L;
|
||||
|
||||
/**
|
||||
* Cluster node list.
|
||||
*/
|
||||
private volatile ConcurrentSkipListMap<String, Member> serverList;
|
||||
|
||||
/**
|
||||
* Is this node in the cluster list.
|
||||
*/
|
||||
private static volatile boolean isInIpList = true;
|
||||
|
||||
/**
|
||||
* port.
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* Address information for the local node.
|
||||
*/
|
||||
private String localAddress;
|
||||
|
||||
/**
|
||||
* Addressing pattern instances.
|
||||
*/
|
||||
private MemberLookup lookup;
|
||||
|
||||
/**
|
||||
* self member obj.
|
||||
*/
|
||||
private volatile Member self;
|
||||
|
||||
/**
|
||||
* here is always the node information of the "UP" state.
|
||||
*/
|
||||
private volatile Set<String> memberAddressInfos = new ConcurrentHashSet<>();
|
||||
|
||||
/**
|
||||
* Broadcast this node element information task.
|
||||
*/
|
||||
private final MemberInfoReportTask infoReportTask = new MemberInfoReportTask();
|
||||
|
||||
public ServerMemberManager(ServletContext servletContext) throws Exception {
|
||||
this.serverList = new ConcurrentSkipListMap<>();
|
||||
EnvUtil.setContextPath(servletContext.getContextPath());
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
protected void init() throws NacosException {
|
||||
Loggers.CORE.info("Nacos-related cluster resource initialization");
|
||||
this.port = EnvUtil.getProperty(SERVER_PORT_PROPERTY, Integer.class, DEFAULT_SERVER_PORT);
|
||||
this.localAddress = InetUtils.getSelfIP() + ":" + port;
|
||||
this.self = MemberUtil.singleParse(this.localAddress);
|
||||
this.self.setExtendVal(MemberMetaDataConstants.VERSION, VersionUtils.version);
|
||||
|
||||
// init abilities.
|
||||
this.self.setAbilities(initMemberAbilities());
|
||||
|
||||
serverList.put(self.getAddress(), self);
|
||||
|
||||
// register NodeChangeEvent publisher to NotifyManager
|
||||
registerClusterEvent();
|
||||
|
||||
// Initializes the lookup mode
|
||||
initAndStartLookup();
|
||||
|
||||
if (serverList.isEmpty()) {
|
||||
throw new NacosException(NacosException.SERVER_ERROR, "cannot get serverlist, so exit.");
|
||||
}
|
||||
|
||||
Loggers.CORE.info("The cluster resource is initialized");
|
||||
}
|
||||
|
||||
private ServerAbilities initMemberAbilities() {
|
||||
ServerAbilities serverAbilities = new ServerAbilities();
|
||||
for (ServerAbilityInitializer each : ServerAbilityInitializerHolder.getInstance().getInitializers()) {
|
||||
each.initialize(serverAbilities);
|
||||
}
|
||||
return serverAbilities;
|
||||
}
|
||||
|
||||
private void initAndStartLookup() throws NacosException {
|
||||
this.lookup = LookupFactory.createLookUp(this);
|
||||
isUseAddressServer = this.lookup.useAddressServer();
|
||||
this.lookup.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* switch look up.
|
||||
*
|
||||
* @param name look up name.
|
||||
* @throws NacosException exception.
|
||||
*/
|
||||
public void switchLookup(String name) throws NacosException {
|
||||
this.lookup = LookupFactory.switchLookup(name, this);
|
||||
isUseAddressServer = this.lookup.useAddressServer();
|
||||
this.lookup.start();
|
||||
}
|
||||
|
||||
private void registerClusterEvent() {
|
||||
// Register node change events
|
||||
NotifyCenter.registerToPublisher(MembersChangeEvent.class,
|
||||
EnvUtil.getProperty(MEMBER_CHANGE_EVENT_QUEUE_SIZE_PROPERTY, Integer.class,
|
||||
DEFAULT_MEMBER_CHANGE_EVENT_QUEUE_SIZE));
|
||||
|
||||
// The address information of this node needs to be dynamically modified
|
||||
// when registering the IP change of this node
|
||||
NotifyCenter.registerSubscriber(new Subscriber<InetUtils.IPChangeEvent>() {
|
||||
@Override
|
||||
public void onEvent(InetUtils.IPChangeEvent event) {
|
||||
String newAddress = event.getNewIP() + ":" + port;
|
||||
ServerMemberManager.this.localAddress = newAddress;
|
||||
EnvUtil.setLocalAddress(localAddress);
|
||||
|
||||
Member self = ServerMemberManager.this.self;
|
||||
self.setIp(event.getNewIP());
|
||||
|
||||
String oldAddress = event.getOldIP() + ":" + port;
|
||||
ServerMemberManager.this.serverList.remove(oldAddress);
|
||||
ServerMemberManager.this.serverList.put(newAddress, self);
|
||||
|
||||
ServerMemberManager.this.memberAddressInfos.remove(oldAddress);
|
||||
ServerMemberManager.this.memberAddressInfos.add(newAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return InetUtils.IPChangeEvent.class;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isUseAddressServer() {
|
||||
return isUseAddressServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* member information update.
|
||||
*
|
||||
* @param newMember {@link Member}
|
||||
* @return update is success
|
||||
*/
|
||||
public boolean update(Member newMember) {
|
||||
Loggers.CLUSTER.debug("member information update : {}", newMember);
|
||||
|
||||
String address = newMember.getAddress();
|
||||
if (!serverList.containsKey(address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
serverList.computeIfPresent(address, (s, member) -> {
|
||||
if (NodeState.DOWN.equals(newMember.getState())) {
|
||||
memberAddressInfos.remove(newMember.getAddress());
|
||||
}
|
||||
boolean isPublishChangeEvent = MemberUtil.isBasicInfoChanged(newMember, member);
|
||||
newMember.setExtendVal(MemberMetaDataConstants.LAST_REFRESH_TIME, System.currentTimeMillis());
|
||||
MemberUtil.copy(newMember, member);
|
||||
if (isPublishChangeEvent) {
|
||||
// member basic data changes and all listeners need to be notified
|
||||
notifyMemberChange(member);
|
||||
}
|
||||
return member;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void notifyMemberChange(Member member) {
|
||||
NotifyCenter.publishEvent(MembersChangeEvent.builder().trigger(member).members(allMembers()).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the node exists within the cluster.
|
||||
*
|
||||
* @param address ip:port
|
||||
* @return is exists
|
||||
*/
|
||||
public boolean hasMember(String address) {
|
||||
boolean result = serverList.containsKey(address);
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If only IP information is passed in, a fuzzy match is required
|
||||
for (Map.Entry<String, Member> entry : serverList.entrySet()) {
|
||||
if (StringUtils.contains(entry.getKey(), address)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<String> getServerListUnhealth() {
|
||||
List<String> unhealthyMembers = new ArrayList<>();
|
||||
for (Member member : this.allMembers()) {
|
||||
NodeState state = member.getState();
|
||||
if (state.equals(NodeState.DOWN)) {
|
||||
unhealthyMembers.add(member.getAddress());
|
||||
}
|
||||
|
||||
}
|
||||
return unhealthyMembers;
|
||||
}
|
||||
|
||||
public MemberLookup getLookup() {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
public Member getSelf() {
|
||||
return this.self;
|
||||
}
|
||||
|
||||
public Member find(String address) {
|
||||
return serverList.get(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* return this cluster all members.
|
||||
*
|
||||
* @return {@link Collection} all member
|
||||
*/
|
||||
public Collection<Member> allMembers() {
|
||||
// We need to do a copy to avoid affecting the real data
|
||||
HashSet<Member> set = new HashSet<>(serverList.values());
|
||||
set.add(self);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* return this cluster all members without self.
|
||||
*
|
||||
* @return {@link Collection} all member without self
|
||||
*/
|
||||
public List<Member> allMembersWithoutSelf() {
|
||||
List<Member> members = new ArrayList<>(serverList.values());
|
||||
members.remove(self);
|
||||
return members;
|
||||
}
|
||||
|
||||
synchronized boolean memberChange(Collection<Member> members) {
|
||||
|
||||
if (members == null || members.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isContainSelfIp = members.stream()
|
||||
.anyMatch(ipPortTmp -> Objects.equals(localAddress, ipPortTmp.getAddress()));
|
||||
|
||||
if (isContainSelfIp) {
|
||||
isInIpList = true;
|
||||
} else {
|
||||
isInIpList = false;
|
||||
members.add(this.self);
|
||||
Loggers.CLUSTER.warn("[serverlist] self ip {} not in serverlist {}", self, members);
|
||||
}
|
||||
|
||||
// If the number of old and new clusters is different, the cluster information
|
||||
// must have changed; if the number of clusters is the same, then compare whether
|
||||
// there is a difference; if there is a difference, then the cluster node changes
|
||||
// are involved and all recipients need to be notified of the node change event
|
||||
|
||||
boolean hasChange = members.size() != serverList.size();
|
||||
ConcurrentSkipListMap<String, Member> tmpMap = new ConcurrentSkipListMap<>();
|
||||
Set<String> tmpAddressInfo = new ConcurrentHashSet<>();
|
||||
for (Member member : members) {
|
||||
final String address = member.getAddress();
|
||||
|
||||
Member existMember = serverList.get(address);
|
||||
if (existMember == null) {
|
||||
hasChange = true;
|
||||
tmpMap.put(address, member);
|
||||
} else {
|
||||
//to keep extendInfo and abilities that report dynamically.
|
||||
tmpMap.put(address, existMember);
|
||||
}
|
||||
|
||||
if (NodeState.UP.equals(member.getState())) {
|
||||
tmpAddressInfo.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
serverList = tmpMap;
|
||||
memberAddressInfos = tmpAddressInfo;
|
||||
|
||||
Collection<Member> finalMembers = allMembers();
|
||||
|
||||
// Persist the current cluster node information to cluster.conf
|
||||
// <important> need to put the event publication into a synchronized block to ensure
|
||||
// that the event publication is sequential
|
||||
if (hasChange) {
|
||||
Loggers.CLUSTER.warn("[serverlist] updated to : {}", finalMembers);
|
||||
MemberUtil.syncToFile(finalMembers);
|
||||
Event event = MembersChangeEvent.builder().members(finalMembers).build();
|
||||
NotifyCenter.publishEvent(event);
|
||||
} else {
|
||||
if (Loggers.CLUSTER.isDebugEnabled()) {
|
||||
Loggers.CLUSTER.debug("[serverlist] not updated, is still : {}", finalMembers);
|
||||
}
|
||||
}
|
||||
|
||||
return hasChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* members join this cluster.
|
||||
*
|
||||
* @param members {@link Collection} new members
|
||||
* @return is success
|
||||
*/
|
||||
public synchronized boolean memberJoin(Collection<Member> members) {
|
||||
Set<Member> set = new HashSet<>(members);
|
||||
set.addAll(allMembers());
|
||||
return memberChange(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* members leave this cluster.
|
||||
*
|
||||
* @param members {@link Collection} wait leave members
|
||||
* @return is success
|
||||
*/
|
||||
public synchronized boolean memberLeave(Collection<Member> members) {
|
||||
Set<Member> set = new HashSet<>(allMembers());
|
||||
set.removeAll(members);
|
||||
return memberChange(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* this member {@link Member#getState()} is health.
|
||||
*
|
||||
* @param address ip:port
|
||||
* @return is health
|
||||
*/
|
||||
public boolean isUnHealth(String address) {
|
||||
Member member = serverList.get(address);
|
||||
if (member == null) {
|
||||
return false;
|
||||
}
|
||||
return !NodeState.UP.equals(member.getState());
|
||||
}
|
||||
|
||||
public boolean isFirstIp() {
|
||||
return Objects.equals(serverList.firstKey(), this.localAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(WebServerInitializedEvent event) {
|
||||
String serverNamespace = event.getApplicationContext().getServerNamespace();
|
||||
if (SPRING_MANAGEMENT_CONTEXT_NAMESPACE.equals(serverNamespace)) {
|
||||
// ignore
|
||||
// fix#issue https://github.com/alibaba/nacos/issues/7230
|
||||
return;
|
||||
}
|
||||
getSelf().setState(NodeState.UP);
|
||||
if (!EnvUtil.getStandaloneMode()) {
|
||||
GlobalExecutor.scheduleByCommon(this.infoReportTask, DEFAULT_TASK_DELAY_TIME);
|
||||
}
|
||||
EnvUtil.setPort(event.getWebServer().getPort());
|
||||
EnvUtil.setLocalAddress(this.localAddress);
|
||||
Loggers.CLUSTER.info("This node is ready to provide external services");
|
||||
}
|
||||
|
||||
/**
|
||||
* ServerMemberManager shutdown.
|
||||
*
|
||||
* @throws NacosException NacosException
|
||||
*/
|
||||
@PreDestroy
|
||||
public void shutdown() throws NacosException {
|
||||
serverList.clear();
|
||||
memberAddressInfos.clear();
|
||||
infoReportTask.shutdown();
|
||||
LookupFactory.destroy();
|
||||
}
|
||||
|
||||
public Set<String> getMemberAddressInfos() {
|
||||
return memberAddressInfos;
|
||||
}
|
||||
|
||||
@JustForTest
|
||||
public void updateMember(Member member) {
|
||||
serverList.put(member.getAddress(), member);
|
||||
}
|
||||
|
||||
@JustForTest
|
||||
public void setMemberAddressInfos(Set<String> memberAddressInfos) {
|
||||
this.memberAddressInfos = memberAddressInfos;
|
||||
}
|
||||
|
||||
@JustForTest
|
||||
public MemberInfoReportTask getInfoReportTask() {
|
||||
return infoReportTask;
|
||||
}
|
||||
|
||||
public Map<String, Member> getServerList() {
|
||||
return Collections.unmodifiableMap(serverList);
|
||||
}
|
||||
|
||||
public static boolean isInIpList() {
|
||||
return isInIpList;
|
||||
}
|
||||
|
||||
// Synchronize the metadata information of a node
|
||||
// A health check of the target node is also attached
|
||||
|
||||
class MemberInfoReportTask extends Task {
|
||||
|
||||
private final GenericType<RestResult<String>> reference = new GenericType<RestResult<String>>() {
|
||||
};
|
||||
|
||||
private int cursor = 0;
|
||||
|
||||
@Override
|
||||
protected void executeBody() {
|
||||
List<Member> members = ServerMemberManager.this.allMembersWithoutSelf();
|
||||
|
||||
if (members.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cursor = (this.cursor + 1) % members.size();
|
||||
Member target = members.get(cursor);
|
||||
|
||||
Loggers.CLUSTER.debug("report the metadata to the node : {}", target.getAddress());
|
||||
|
||||
final String url = HttpUtils
|
||||
.buildUrl(false, target.getAddress(), EnvUtil.getContextPath(), Commons.NACOS_CORE_CONTEXT,
|
||||
"/cluster/report");
|
||||
|
||||
try {
|
||||
Header header = Header.newInstance().addParam(Constants.NACOS_SERVER_HEADER, VersionUtils.version);
|
||||
AuthHeaderUtil.addIdentityToHeader(header);
|
||||
asyncRestTemplate
|
||||
.post(url, header, Query.EMPTY, getSelf(), reference.getType(), new Callback<String>() {
|
||||
@Override
|
||||
public void onReceive(RestResult<String> result) {
|
||||
if (result.getCode() == HttpStatus.NOT_IMPLEMENTED.value()
|
||||
|| result.getCode() == HttpStatus.NOT_FOUND.value()) {
|
||||
Loggers.CLUSTER
|
||||
.warn("{} version is too low, it is recommended to upgrade the version : {}",
|
||||
target, VersionUtils.version);
|
||||
Member memberNew = null;
|
||||
if (target.getExtendVal(MemberMetaDataConstants.VERSION) != null) {
|
||||
memberNew = target.copy();
|
||||
// Clean up remote version info.
|
||||
// This value may still stay in extend info when remote server has been downgraded to old version.
|
||||
memberNew.delExtendVal(MemberMetaDataConstants.VERSION);
|
||||
memberNew.delExtendVal(MemberMetaDataConstants.READY_TO_UPGRADE);
|
||||
Loggers.CLUSTER.warn("{} : Clean up version info,"
|
||||
+ " target has been downgrade to old version.", memberNew);
|
||||
}
|
||||
if (target.getAbilities() != null
|
||||
&& target.getAbilities().getRemoteAbility() != null && target.getAbilities()
|
||||
.getRemoteAbility().isSupportRemoteConnection()) {
|
||||
if (memberNew == null) {
|
||||
memberNew = target.copy();
|
||||
}
|
||||
memberNew.getAbilities().getRemoteAbility().setSupportRemoteConnection(false);
|
||||
Loggers.CLUSTER
|
||||
.warn("{} : Clear support remote connection flag,target may rollback version ",
|
||||
memberNew);
|
||||
}
|
||||
if (memberNew != null) {
|
||||
update(memberNew);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result.ok()) {
|
||||
MemberUtil.onSuccess(ServerMemberManager.this, target);
|
||||
} else {
|
||||
Loggers.CLUSTER.warn("failed to report new info to target node : {}, result : {}",
|
||||
target.getAddress(), result);
|
||||
MemberUtil.onFail(ServerMemberManager.this, target);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
Loggers.CLUSTER.error("failed to report new info to target node : {}, error : {}",
|
||||
target.getAddress(), ExceptionUtil.getAllExceptionMsg(throwable));
|
||||
MemberUtil.onFail(ServerMemberManager.this, target, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
|
||||
}
|
||||
});
|
||||
} catch (Throwable ex) {
|
||||
Loggers.CLUSTER.error("failed to report new info to target node : {}, error : {}", target.getAddress(),
|
||||
ExceptionUtil.getAllExceptionMsg(ex));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
GlobalExecutor.scheduleByCommon(this, 2_000L);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +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.core.cluster;
|
||||
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
/**
|
||||
* task.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class Task implements Runnable {
|
||||
|
||||
protected volatile boolean shutdown = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (shutdown) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
executeBody();
|
||||
} catch (Throwable t) {
|
||||
Loggers.CORE.error("this task execute has error : {}", ExceptionUtil.getStackTrace(t));
|
||||
} finally {
|
||||
if (!shutdown) {
|
||||
after();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task executive.
|
||||
*/
|
||||
protected abstract void executeBody();
|
||||
|
||||
/**
|
||||
* after executeBody should do.
|
||||
*/
|
||||
protected void after() {
|
||||
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,215 +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.core.cluster.lookup;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.utils.GenericType;
|
||||
import com.alibaba.nacos.core.utils.GlobalExecutor;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTP_PREFIX;
|
||||
|
||||
/**
|
||||
* Cluster member addressing mode for the address server.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class AddressServerMemberLookup extends AbstractMemberLookup {
|
||||
|
||||
private final GenericType<String> genericType = new GenericType<String>() { };
|
||||
|
||||
public String domainName;
|
||||
|
||||
public String addressPort;
|
||||
|
||||
public String addressUrl;
|
||||
|
||||
public String envIdUrl;
|
||||
|
||||
public String addressServerUrl;
|
||||
|
||||
private volatile boolean isAddressServerHealth = true;
|
||||
|
||||
private int addressServerFailCount = 0;
|
||||
|
||||
private int maxFailCount = 12;
|
||||
|
||||
private final NacosRestTemplate restTemplate = HttpClientBeanHolder.getNacosRestTemplate(Loggers.CORE);
|
||||
|
||||
private volatile boolean shutdown = false;
|
||||
|
||||
private static final String HEALTH_CHECK_FAIL_COUNT_PROPERTY = "maxHealthCheckFailCount";
|
||||
|
||||
private static final String DEFAULT_HEALTH_CHECK_FAIL_COUNT = "12";
|
||||
|
||||
private static final String DEFAULT_SERVER_DOMAIN = "jmenv.tbsite.net";
|
||||
|
||||
private static final String DEFAULT_SERVER_POINT = "8080";
|
||||
|
||||
private static final int DEFAULT_SERVER_RETRY_TIME = 5;
|
||||
|
||||
private static final long DEFAULT_SYNC_TASK_DELAY_MS = 5_000L;
|
||||
|
||||
private static final String ADDRESS_SERVER_DOMAIN_ENV = "address_server_domain";
|
||||
|
||||
private static final String ADDRESS_SERVER_DOMAIN_PROPERTY = "address.server.domain";
|
||||
|
||||
private static final String ADDRESS_SERVER_PORT_ENV = "address_server_port";
|
||||
|
||||
private static final String ADDRESS_SERVER_PORT_PROPERTY = "address.server.port";
|
||||
|
||||
private static final String ADDRESS_SERVER_URL_ENV = "address_server_url";
|
||||
|
||||
private static final String ADDRESS_SERVER_URL_PROPERTY = "address.server.url";
|
||||
|
||||
private static final String ADDRESS_SERVER_RETRY_PROPERTY = "nacos.core.address-server.retry";
|
||||
|
||||
@Override
|
||||
public void doStart() throws NacosException {
|
||||
this.maxFailCount = Integer.parseInt(EnvUtil.getProperty(HEALTH_CHECK_FAIL_COUNT_PROPERTY, DEFAULT_HEALTH_CHECK_FAIL_COUNT));
|
||||
initAddressSys();
|
||||
run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAddressServer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initAddressSys() {
|
||||
String envDomainName = System.getenv(ADDRESS_SERVER_DOMAIN_ENV);
|
||||
if (StringUtils.isBlank(envDomainName)) {
|
||||
domainName = EnvUtil.getProperty(ADDRESS_SERVER_DOMAIN_PROPERTY, DEFAULT_SERVER_DOMAIN);
|
||||
} else {
|
||||
domainName = envDomainName;
|
||||
}
|
||||
String envAddressPort = System.getenv(ADDRESS_SERVER_PORT_ENV);
|
||||
if (StringUtils.isBlank(envAddressPort)) {
|
||||
addressPort = EnvUtil.getProperty(ADDRESS_SERVER_PORT_PROPERTY, DEFAULT_SERVER_POINT);
|
||||
} else {
|
||||
addressPort = envAddressPort;
|
||||
}
|
||||
String envAddressUrl = System.getenv(ADDRESS_SERVER_URL_ENV);
|
||||
if (StringUtils.isBlank(envAddressUrl)) {
|
||||
addressUrl = EnvUtil.getProperty(ADDRESS_SERVER_URL_PROPERTY, EnvUtil.getContextPath() + "/" + "serverlist");
|
||||
} else {
|
||||
addressUrl = envAddressUrl;
|
||||
}
|
||||
addressServerUrl = HTTP_PREFIX + domainName + ":" + addressPort + addressUrl;
|
||||
envIdUrl = HTTP_PREFIX + domainName + ":" + addressPort + "/env";
|
||||
|
||||
Loggers.CORE.info("ServerListService address-server port:" + addressPort);
|
||||
Loggers.CORE.info("ADDRESS_SERVER_URL:" + addressServerUrl);
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.UndefineMagicConstantRule")
|
||||
private void run() throws NacosException {
|
||||
// With the address server, you need to perform a synchronous member node pull at startup
|
||||
// Repeat three times, successfully jump out
|
||||
boolean success = false;
|
||||
Throwable ex = null;
|
||||
int maxRetry = EnvUtil.getProperty(ADDRESS_SERVER_RETRY_PROPERTY, Integer.class, DEFAULT_SERVER_RETRY_TIME);
|
||||
for (int i = 0; i < maxRetry; i++) {
|
||||
try {
|
||||
syncFromAddressUrl();
|
||||
success = true;
|
||||
break;
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
Loggers.CLUSTER.error("[serverlist] exception, error : {}", ExceptionUtil.getAllExceptionMsg(ex));
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
throw new NacosException(NacosException.SERVER_ERROR, ex);
|
||||
}
|
||||
|
||||
GlobalExecutor.scheduleByCommon(new AddressServerSyncTask(), DEFAULT_SYNC_TASK_DELAY_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDestroy() throws NacosException {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> info() {
|
||||
Map<String, Object> info = new HashMap<>(4);
|
||||
info.put("addressServerHealth", isAddressServerHealth);
|
||||
info.put("addressServerUrl", addressServerUrl);
|
||||
info.put("envIdUrl", envIdUrl);
|
||||
info.put("addressServerFailCount", addressServerFailCount);
|
||||
return info;
|
||||
}
|
||||
|
||||
private void syncFromAddressUrl() throws Exception {
|
||||
RestResult<String> result = restTemplate
|
||||
.get(addressServerUrl, Header.EMPTY, Query.EMPTY, genericType.getType());
|
||||
if (result.ok()) {
|
||||
isAddressServerHealth = true;
|
||||
Reader reader = new StringReader(result.getData());
|
||||
try {
|
||||
afterLookup(MemberUtil.readServerConf(EnvUtil.analyzeClusterConf(reader)));
|
||||
} catch (Throwable e) {
|
||||
Loggers.CLUSTER.error("[serverlist] exception for analyzeClusterConf, error : {}",
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
}
|
||||
addressServerFailCount = 0;
|
||||
} else {
|
||||
addressServerFailCount++;
|
||||
if (addressServerFailCount >= maxFailCount) {
|
||||
isAddressServerHealth = false;
|
||||
}
|
||||
Loggers.CLUSTER.error("[serverlist] failed to get serverlist, error code {}", result.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
class AddressServerSyncTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (shutdown) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
syncFromAddressUrl();
|
||||
} catch (Throwable ex) {
|
||||
addressServerFailCount++;
|
||||
if (addressServerFailCount >= maxFailCount) {
|
||||
isAddressServerHealth = false;
|
||||
}
|
||||
Loggers.CLUSTER.error("[serverlist] exception, error : {}", ExceptionUtil.getAllExceptionMsg(ex));
|
||||
} finally {
|
||||
GlobalExecutor.scheduleByCommon(this, DEFAULT_SYNC_TASK_DELAY_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +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.core.cluster.lookup;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
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.core.utils.Loggers;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Cluster.conf file managed cluster member node addressing pattern.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class FileConfigMemberLookup extends AbstractMemberLookup {
|
||||
|
||||
private static final String DEFAULT_SEARCH_SEQ = "cluster.conf";
|
||||
|
||||
private FileWatcher watcher = new FileWatcher() {
|
||||
@Override
|
||||
public void onChange(FileChangeEvent event) {
|
||||
readClusterConfFromDisk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interest(String context) {
|
||||
return StringUtils.contains(context, DEFAULT_SEARCH_SEQ);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void doStart() throws NacosException {
|
||||
readClusterConfFromDisk();
|
||||
|
||||
// Use the inotify mechanism to monitor file changes and automatically
|
||||
// trigger the reading of cluster.conf
|
||||
try {
|
||||
WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), watcher);
|
||||
} catch (Throwable e) {
|
||||
Loggers.CLUSTER.error("An exception occurred in the launch file monitor : {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAddressServer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDestroy() throws NacosException {
|
||||
WatchFileCenter.deregisterWatcher(EnvUtil.getConfPath(), watcher);
|
||||
}
|
||||
|
||||
private void readClusterConfFromDisk() {
|
||||
Collection<Member> tmpMembers = new ArrayList<>();
|
||||
try {
|
||||
List<String> tmp = EnvUtil.readClusterConf();
|
||||
tmpMembers = MemberUtil.readServerConf(tmp);
|
||||
} catch (Throwable e) {
|
||||
Loggers.CLUSTER
|
||||
.error("nacos-XXXX [serverlist] failed to get serverlist from disk!, error : {}", e.getMessage());
|
||||
}
|
||||
|
||||
afterLookup(tmpMembers);
|
||||
}
|
||||
}
|
||||
@@ -1,181 +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.core.cluster.lookup;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.cluster.MemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An addressing pattern factory, responsible for the creation of all addressing patterns.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public final class LookupFactory {
|
||||
|
||||
private static final String LOOKUP_MODE_TYPE = "nacos.core.member.lookup.type";
|
||||
|
||||
@SuppressWarnings("checkstyle:StaticVariableName")
|
||||
private static MemberLookup LOOK_UP = null;
|
||||
|
||||
private static LookupType currentLookupType = null;
|
||||
|
||||
/**
|
||||
* Create the target addressing pattern.
|
||||
*
|
||||
* @param memberManager {@link ServerMemberManager}
|
||||
* @return {@link MemberLookup}
|
||||
* @throws NacosException NacosException
|
||||
*/
|
||||
public static MemberLookup createLookUp(ServerMemberManager memberManager) throws NacosException {
|
||||
if (!EnvUtil.getStandaloneMode()) {
|
||||
String lookupType = EnvUtil.getProperty(LOOKUP_MODE_TYPE);
|
||||
LookupType type = chooseLookup(lookupType);
|
||||
LOOK_UP = find(type);
|
||||
currentLookupType = type;
|
||||
} else {
|
||||
LOOK_UP = new StandaloneMemberLookup();
|
||||
}
|
||||
LOOK_UP.injectMemberManager(memberManager);
|
||||
Loggers.CLUSTER.info("Current addressing mode selection : {}", LOOK_UP.getClass().getSimpleName());
|
||||
return LOOK_UP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to target addressing mode.
|
||||
*
|
||||
* @param name target member-lookup name
|
||||
* @param memberManager {@link ServerMemberManager}
|
||||
* @return {@link MemberLookup}
|
||||
* @throws NacosException {@link NacosException}
|
||||
*/
|
||||
public static MemberLookup switchLookup(String name, ServerMemberManager memberManager) throws NacosException {
|
||||
LookupType lookupType = LookupType.sourceOf(name);
|
||||
|
||||
if (Objects.isNull(lookupType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The addressing mode exists : " + name + ", just support : [" + Arrays.toString(LookupType.values())
|
||||
+ "]");
|
||||
}
|
||||
|
||||
if (Objects.equals(currentLookupType, lookupType)) {
|
||||
return LOOK_UP;
|
||||
}
|
||||
MemberLookup newLookup = find(lookupType);
|
||||
currentLookupType = lookupType;
|
||||
if (Objects.nonNull(LOOK_UP)) {
|
||||
LOOK_UP.destroy();
|
||||
}
|
||||
LOOK_UP = newLookup;
|
||||
LOOK_UP.injectMemberManager(memberManager);
|
||||
Loggers.CLUSTER.info("Current addressing mode selection : {}", LOOK_UP.getClass().getSimpleName());
|
||||
return LOOK_UP;
|
||||
}
|
||||
|
||||
private static MemberLookup find(LookupType type) {
|
||||
if (LookupType.FILE_CONFIG.equals(type)) {
|
||||
LOOK_UP = new FileConfigMemberLookup();
|
||||
return LOOK_UP;
|
||||
}
|
||||
if (LookupType.ADDRESS_SERVER.equals(type)) {
|
||||
LOOK_UP = new AddressServerMemberLookup();
|
||||
return LOOK_UP;
|
||||
}
|
||||
// unpossible to run here
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
private static LookupType chooseLookup(String lookupType) {
|
||||
if (StringUtils.isNotBlank(lookupType)) {
|
||||
LookupType type = LookupType.sourceOf(lookupType);
|
||||
if (Objects.nonNull(type)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
File file = new File(EnvUtil.getClusterConfFilePath());
|
||||
if (file.exists() || StringUtils.isNotBlank(EnvUtil.getMemberList())) {
|
||||
return LookupType.FILE_CONFIG;
|
||||
}
|
||||
return LookupType.ADDRESS_SERVER;
|
||||
}
|
||||
|
||||
public static MemberLookup getLookUp() {
|
||||
return LOOK_UP;
|
||||
}
|
||||
|
||||
public static void destroy() throws NacosException {
|
||||
Objects.requireNonNull(LOOK_UP).destroy();
|
||||
}
|
||||
|
||||
public enum LookupType {
|
||||
|
||||
/**
|
||||
* File addressing mode.
|
||||
*/
|
||||
FILE_CONFIG(1, "file"),
|
||||
|
||||
/**
|
||||
* Address server addressing mode.
|
||||
*/
|
||||
ADDRESS_SERVER(2, "address-server");
|
||||
|
||||
private final int code;
|
||||
|
||||
private final String name;
|
||||
|
||||
LookupType(int code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* find one {@link LookupType} by name, if not found, return null.
|
||||
*
|
||||
* @param name name
|
||||
* @return {@link LookupType}
|
||||
*/
|
||||
public static LookupType sourceOf(String name) {
|
||||
for (LookupType type : values()) {
|
||||
if (Objects.equals(type.name, name)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +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.core.cluster.lookup;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Member node addressing mode in stand-alone mode.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class StandaloneMemberLookup extends AbstractMemberLookup {
|
||||
|
||||
@Override
|
||||
public void doStart() {
|
||||
String url = EnvUtil.getLocalAddress();
|
||||
afterLookup(MemberUtil.readServerConf(Collections.singletonList(url)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDestroy() throws NacosException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAddressServer() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,243 +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.cluster.remote;
|
||||
|
||||
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.request.Request;
|
||||
import com.alibaba.nacos.api.remote.response.Response;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.remote.ConnectionType;
|
||||
import com.alibaba.nacos.common.remote.client.RpcClient;
|
||||
import com.alibaba.nacos.common.remote.client.RpcClientFactory;
|
||||
import com.alibaba.nacos.common.remote.client.ServerListFactory;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberChangeListener;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.alibaba.nacos.api.exception.NacosException.CLIENT_INVALID_PARAM;
|
||||
|
||||
/**
|
||||
* cluster rpc client proxy.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ClusterRpcClientProxy.java, v 0.1 2020年08月11日 2:11 PM liuzunfei Exp $
|
||||
*/
|
||||
@Service
|
||||
public class ClusterRpcClientProxy extends MemberChangeListener {
|
||||
|
||||
private static final long DEFAULT_REQUEST_TIME_OUT = 3000L;
|
||||
|
||||
@Autowired
|
||||
ServerMemberManager serverMemberManager;
|
||||
|
||||
/**
|
||||
* init after constructor.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
List<Member> members = serverMemberManager.allMembersWithoutSelf();
|
||||
refresh(members);
|
||||
Loggers.CLUSTER
|
||||
.warn("[ClusterRpcClientProxy] success to refresh cluster rpc client on start up,members ={} ",
|
||||
members);
|
||||
} catch (NacosException e) {
|
||||
Loggers.CLUSTER.warn("[ClusterRpcClientProxy] fail to refresh cluster rpc client,{} ", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* init cluster rpc clients.
|
||||
*
|
||||
* @param members cluster server list member list.
|
||||
*/
|
||||
private void refresh(List<Member> members) throws NacosException {
|
||||
|
||||
//ensure to create client of new members
|
||||
for (Member member : members) {
|
||||
|
||||
if (MemberUtil.isSupportedLongCon(member)) {
|
||||
createRpcClientAndStart(member, ConnectionType.GRPC);
|
||||
}
|
||||
}
|
||||
|
||||
//shutdown and remove old members.
|
||||
Set<Map.Entry<String, RpcClient>> allClientEntrys = RpcClientFactory.getAllClientEntries();
|
||||
Iterator<Map.Entry<String, RpcClient>> iterator = allClientEntrys.iterator();
|
||||
List<String> newMemberKeys = members.stream().filter(MemberUtil::isSupportedLongCon)
|
||||
.map(this::memberClientKey).collect(Collectors.toList());
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, RpcClient> next1 = iterator.next();
|
||||
if (next1.getKey().startsWith("Cluster-") && !newMemberKeys.contains(next1.getKey())) {
|
||||
Loggers.CLUSTER.info("member leave,destroy client of member - > : {}", next1.getKey());
|
||||
RpcClientFactory.getClient(next1.getKey()).shutdown();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String memberClientKey(Member member) {
|
||||
return "Cluster-" + member.getAddress();
|
||||
}
|
||||
|
||||
private void createRpcClientAndStart(Member member, ConnectionType type) throws NacosException {
|
||||
Map<String, String> labels = new HashMap<>(2);
|
||||
labels.put(RemoteConstants.LABEL_SOURCE, RemoteConstants.LABEL_SOURCE_CLUSTER);
|
||||
String memberClientKey = memberClientKey(member);
|
||||
RpcClient client = buildRpcClient(type, labels, memberClientKey);
|
||||
if (!client.getConnectionType().equals(type)) {
|
||||
Loggers.CLUSTER.info(",connection type changed,destroy client of member - > : {}", member);
|
||||
RpcClientFactory.destroyClient(memberClientKey);
|
||||
client = buildRpcClient(type, labels, memberClientKey);
|
||||
}
|
||||
|
||||
if (client.isWaitInitiated()) {
|
||||
Loggers.CLUSTER.info("start a new rpc client to member - > : {}", member);
|
||||
|
||||
//one fixed server
|
||||
client.serverListFactory(new ServerListFactory() {
|
||||
@Override
|
||||
public String genNextServer() {
|
||||
return member.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentServer() {
|
||||
return member.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServerList() {
|
||||
return CollectionUtils.list(member.getAddress());
|
||||
}
|
||||
});
|
||||
|
||||
client.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* send request to member.
|
||||
*
|
||||
* @param member member of server.
|
||||
* @param request request.
|
||||
* @return Response response.
|
||||
* @throws NacosException exception may throws.
|
||||
*/
|
||||
public Response sendRequest(Member member, Request request) throws NacosException {
|
||||
return sendRequest(member, request, DEFAULT_REQUEST_TIME_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* send request to member.
|
||||
*
|
||||
* @param member member of server.
|
||||
* @param request request.
|
||||
* @return Response response.
|
||||
* @throws NacosException exception may throws.
|
||||
*/
|
||||
public Response sendRequest(Member member, Request request, long timeoutMills) throws NacosException {
|
||||
RpcClient client = RpcClientFactory.getClient(memberClientKey(member));
|
||||
if (client != null) {
|
||||
return client.request(request, timeoutMills);
|
||||
} else {
|
||||
throw new NacosException(CLIENT_INVALID_PARAM, "No rpc client related to member: " + member);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aync send request to member with callback.
|
||||
*
|
||||
* @param member member of server.
|
||||
* @param request request.
|
||||
* @param callBack RequestCallBack.
|
||||
* @throws NacosException exception may throws.
|
||||
*/
|
||||
public void asyncRequest(Member member, Request request, RequestCallBack callBack) throws NacosException {
|
||||
RpcClient client = RpcClientFactory.getClient(memberClientKey(member));
|
||||
if (client != null) {
|
||||
client.asyncRequest(request, callBack);
|
||||
} else {
|
||||
throw new NacosException(CLIENT_INVALID_PARAM, "No rpc client related to member: " + member);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send request to member.
|
||||
*
|
||||
* @param request request.
|
||||
* @throws NacosException exception may throw.
|
||||
*/
|
||||
public void sendRequestToAllMembers(Request request) throws NacosException {
|
||||
List<Member> members = serverMemberManager.allMembersWithoutSelf();
|
||||
for (Member member1 : members) {
|
||||
sendRequest(member1, request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
try {
|
||||
List<Member> members = serverMemberManager.allMembersWithoutSelf();
|
||||
refresh(members);
|
||||
} catch (NacosException e) {
|
||||
Loggers.CLUSTER.warn("[serverlist] fail to refresh cluster rpc client, event:{}, msg: {} ", event, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether client for member is running.
|
||||
*
|
||||
* @param member member
|
||||
* @return {@code true} if target client is connected, otherwise {@code false}
|
||||
*/
|
||||
public boolean isRunning(Member member) {
|
||||
RpcClient client = RpcClientFactory.getClient(memberClientKey(member));
|
||||
if (null == client) {
|
||||
return false;
|
||||
}
|
||||
return client.isRunning();
|
||||
}
|
||||
}
|
||||
@@ -1,225 +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.core.code;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
|
||||
import com.alibaba.nacos.common.packagescan.DefaultPackageScan;
|
||||
import com.alibaba.nacos.common.utils.ArrayUtils;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.core.code.RequestMappingInfo.RequestMappingInfoComparator;
|
||||
import com.alibaba.nacos.core.code.condition.ParamRequestCondition;
|
||||
import com.alibaba.nacos.core.code.condition.PathRequestCondition;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static com.alibaba.nacos.sys.env.Constants.REQUEST_PATH_SEPARATOR;
|
||||
|
||||
|
||||
/**
|
||||
* Method cache.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Component
|
||||
public class ControllerMethodsCache {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerMethodsCache.class);
|
||||
|
||||
private ConcurrentMap<RequestMappingInfo, Method> methods = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentMap<String, List<RequestMappingInfo>> urlLookup = new ConcurrentHashMap<>();
|
||||
|
||||
public Method getMethod(HttpServletRequest request) {
|
||||
String path = getPath(request);
|
||||
String httpMethod = request.getMethod();
|
||||
String urlKey = httpMethod + REQUEST_PATH_SEPARATOR + path.replaceFirst(EnvUtil.getContextPath(), "");
|
||||
List<RequestMappingInfo> requestMappingInfos = urlLookup.get(urlKey);
|
||||
if (CollectionUtils.isEmpty(requestMappingInfos)) {
|
||||
return null;
|
||||
}
|
||||
List<RequestMappingInfo> matchedInfo = findMatchedInfo(requestMappingInfos, request);
|
||||
if (CollectionUtils.isEmpty(matchedInfo)) {
|
||||
return null;
|
||||
}
|
||||
RequestMappingInfo bestMatch = matchedInfo.get(0);
|
||||
if (matchedInfo.size() > 1) {
|
||||
RequestMappingInfoComparator comparator = new RequestMappingInfoComparator();
|
||||
matchedInfo.sort(comparator);
|
||||
bestMatch = matchedInfo.get(0);
|
||||
RequestMappingInfo secondBestMatch = matchedInfo.get(1);
|
||||
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
|
||||
throw new IllegalStateException(
|
||||
"Ambiguous methods mapped for '" + request.getRequestURI() + "': {" + bestMatch + ", "
|
||||
+ secondBestMatch + "}");
|
||||
}
|
||||
}
|
||||
return methods.get(bestMatch);
|
||||
}
|
||||
|
||||
private String getPath(HttpServletRequest request) {
|
||||
try {
|
||||
return new URI(request.getRequestURI()).getPath();
|
||||
} catch (URISyntaxException e) {
|
||||
LOGGER.error("parse request to path error", e);
|
||||
throw new NacosRuntimeException(NacosException.NOT_FOUND, "Invalid URI");
|
||||
}
|
||||
}
|
||||
|
||||
private List<RequestMappingInfo> findMatchedInfo(List<RequestMappingInfo> requestMappingInfos,
|
||||
HttpServletRequest request) {
|
||||
List<RequestMappingInfo> matchedInfo = new ArrayList<>();
|
||||
for (RequestMappingInfo requestMappingInfo : requestMappingInfos) {
|
||||
ParamRequestCondition matchingCondition = requestMappingInfo.getParamRequestCondition()
|
||||
.getMatchingCondition(request);
|
||||
if (matchingCondition != null) {
|
||||
matchedInfo.add(requestMappingInfo);
|
||||
}
|
||||
}
|
||||
return matchedInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* find target method from this package.
|
||||
*
|
||||
* @param packageName package name
|
||||
*/
|
||||
public void initClassMethod(String packageName) {
|
||||
DefaultPackageScan packageScan = new DefaultPackageScan();
|
||||
Set<Class<Object>> classesList = packageScan.getTypesAnnotatedWith(packageName, RequestMapping.class);
|
||||
for (Class clazz : classesList) {
|
||||
initClassMethod(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find target method from class list.
|
||||
*
|
||||
* @param classesList class list
|
||||
*/
|
||||
public void initClassMethod(Set<Class<?>> classesList) {
|
||||
for (Class clazz : classesList) {
|
||||
initClassMethod(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find target method from target class.
|
||||
*
|
||||
* @param clazz {@link Class}
|
||||
*/
|
||||
private void initClassMethod(Class<?> clazz) {
|
||||
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
|
||||
for (String classPath : requestMapping.value()) {
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (!method.isAnnotationPresent(RequestMapping.class)) {
|
||||
parseSubAnnotations(method, classPath);
|
||||
continue;
|
||||
}
|
||||
requestMapping = method.getAnnotation(RequestMapping.class);
|
||||
RequestMethod[] requestMethods = requestMapping.method();
|
||||
if (requestMethods.length == 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseSubAnnotations(Method method, String classPath) {
|
||||
|
||||
final GetMapping getMapping = method.getAnnotation(GetMapping.class);
|
||||
final PostMapping postMapping = method.getAnnotation(PostMapping.class);
|
||||
final PutMapping putMapping = method.getAnnotation(PutMapping.class);
|
||||
final DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
|
||||
final PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
|
||||
|
||||
if (getMapping != null) {
|
||||
put(RequestMethod.GET, classPath, getMapping.value(), getMapping.params(), method);
|
||||
}
|
||||
|
||||
if (postMapping != null) {
|
||||
put(RequestMethod.POST, classPath, postMapping.value(), postMapping.params(), method);
|
||||
}
|
||||
|
||||
if (putMapping != null) {
|
||||
put(RequestMethod.PUT, classPath, putMapping.value(), putMapping.params(), method);
|
||||
}
|
||||
|
||||
if (deleteMapping != null) {
|
||||
put(RequestMethod.DELETE, classPath, deleteMapping.value(), deleteMapping.params(), method);
|
||||
}
|
||||
|
||||
if (patchMapping != null) {
|
||||
put(RequestMethod.PATCH, classPath, patchMapping.value(), patchMapping.params(), method);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void put(RequestMethod requestMethod, String classPath, String[] requestPaths, String[] requestParams,
|
||||
Method method) {
|
||||
if (ArrayUtils.isEmpty(requestPaths)) {
|
||||
String urlKey = requestMethod.name() + REQUEST_PATH_SEPARATOR + classPath;
|
||||
addUrlAndMethodRelation(urlKey, requestParams, method);
|
||||
return;
|
||||
}
|
||||
for (String requestPath : requestPaths) {
|
||||
String urlKey = requestMethod.name() + REQUEST_PATH_SEPARATOR + classPath + requestPath;
|
||||
addUrlAndMethodRelation(urlKey, requestParams, method);
|
||||
}
|
||||
}
|
||||
|
||||
private void addUrlAndMethodRelation(String urlKey, String[] requestParam, Method method) {
|
||||
RequestMappingInfo requestMappingInfo = new RequestMappingInfo();
|
||||
requestMappingInfo.setPathRequestCondition(new PathRequestCondition(urlKey));
|
||||
requestMappingInfo.setParamRequestCondition(new ParamRequestCondition(requestParam));
|
||||
List<RequestMappingInfo> requestMappingInfos = urlLookup.get(urlKey);
|
||||
if (requestMappingInfos == null) {
|
||||
urlLookup.putIfAbsent(urlKey, new ArrayList<>());
|
||||
requestMappingInfos = urlLookup.get(urlKey);
|
||||
// For issue #4701.
|
||||
String urlKeyBackup = urlKey + "/";
|
||||
urlLookup.putIfAbsent(urlKeyBackup, requestMappingInfos);
|
||||
}
|
||||
requestMappingInfos.add(requestMappingInfo);
|
||||
methods.put(requestMappingInfo, method);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +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.code;
|
||||
|
||||
import com.alibaba.nacos.core.code.condition.ParamRequestCondition;
|
||||
import com.alibaba.nacos.core.code.condition.PathRequestCondition;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Request mapping information. to find the matched method by request
|
||||
*
|
||||
* @author horizonzy
|
||||
* @since 1.3.2
|
||||
*/
|
||||
public class RequestMappingInfo {
|
||||
|
||||
private PathRequestCondition pathRequestCondition;
|
||||
|
||||
private ParamRequestCondition paramRequestCondition;
|
||||
|
||||
public ParamRequestCondition getParamRequestCondition() {
|
||||
return paramRequestCondition;
|
||||
}
|
||||
|
||||
public void setParamRequestCondition(ParamRequestCondition paramRequestCondition) {
|
||||
this.paramRequestCondition = paramRequestCondition;
|
||||
}
|
||||
|
||||
public void setPathRequestCondition(PathRequestCondition pathRequestCondition) {
|
||||
this.pathRequestCondition = pathRequestCondition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RequestMappingInfo{" + "pathRequestCondition=" + pathRequestCondition + ", paramRequestCondition="
|
||||
+ paramRequestCondition + '}';
|
||||
}
|
||||
|
||||
public static class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {
|
||||
|
||||
@Override
|
||||
public int compare(RequestMappingInfo o1, RequestMappingInfo o2) {
|
||||
return Integer.compare(o2.getParamRequestCondition().getExpressions().size(),
|
||||
o1.getParamRequestCondition().getExpressions().size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +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.core.code;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.core.listener.NacosApplicationListener;
|
||||
import org.springframework.boot.ConfigurableBootstrapContext;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.context.event.EventPublishingRunListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.SpringApplicationRunListener} before {@link EventPublishingRunListener} execution.
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @since 0.2.2
|
||||
*/
|
||||
public class SpringApplicationRunListener implements org.springframework.boot.SpringApplicationRunListener, Ordered {
|
||||
|
||||
private final SpringApplication application;
|
||||
|
||||
private final String[] args;
|
||||
|
||||
Collection<NacosApplicationListener> nacosApplicationListeners = NacosServiceLoader.load(NacosApplicationListener.class);
|
||||
|
||||
public SpringApplicationRunListener(SpringApplication application, String[] args) {
|
||||
this.application = application;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void starting(ConfigurableBootstrapContext bootstrapContext) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.starting();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
|
||||
ConfigurableEnvironment environment) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.environmentPrepared(environment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextPrepared(ConfigurableApplicationContext context) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.contextPrepared(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextLoaded(ConfigurableApplicationContext context) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.contextLoaded(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started(ConfigurableApplicationContext context) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.started(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void running(ConfigurableApplicationContext context) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.running(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(ConfigurableApplicationContext context, Throwable exception) {
|
||||
for (NacosApplicationListener nacosApplicationListener : nacosApplicationListeners) {
|
||||
nacosApplicationListener.failed(context, exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Before {@link EventPublishingRunListener}.
|
||||
*
|
||||
* @return HIGHEST_PRECEDENCE
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +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.core.code;
|
||||
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.alibaba.nacos.sys.env.Constants.STANDALONE_MODE_PROPERTY_NAME;
|
||||
import static com.alibaba.nacos.sys.env.Constants.STANDALONE_SPRING_PROFILE;
|
||||
|
||||
/**
|
||||
* Standalone {@link Profile} {@link ApplicationListener} for {@link ApplicationEnvironmentPreparedEvent}.
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @see ConfigurableEnvironment#addActiveProfile(String)
|
||||
* @since 0.2.2
|
||||
*/
|
||||
public class StandaloneProfileApplicationListener
|
||||
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, PriorityOrdered {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StandaloneProfileApplicationListener.class);
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
|
||||
|
||||
ConfigurableEnvironment environment = event.getEnvironment();
|
||||
|
||||
if (environment.getProperty(STANDALONE_MODE_PROPERTY_NAME, boolean.class, false)) {
|
||||
environment.addActiveProfile(STANDALONE_SPRING_PROFILE);
|
||||
}
|
||||
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("Spring Environment's active profiles : {} in standalone mode : {}",
|
||||
Arrays.asList(environment.getActiveProfiles()), EnvUtil.getStandaloneMode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +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.core.code.condition;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* request param info. {@link org.springframework.web.bind.annotation.RequestMapping#params()}
|
||||
*
|
||||
* @author horizonzy
|
||||
* @since 1.3.2
|
||||
*/
|
||||
public class ParamRequestCondition {
|
||||
|
||||
private final Set<ParamExpression> expressions;
|
||||
|
||||
public ParamRequestCondition(String... expressions) {
|
||||
this.expressions = parseExpressions(expressions);
|
||||
}
|
||||
|
||||
private Set<ParamExpression> parseExpressions(String... params) {
|
||||
if (ObjectUtils.isEmpty(params)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<>(params.length);
|
||||
for (String param : params) {
|
||||
expressions.add(new ParamExpression(param));
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
public Set<ParamExpression> getExpressions() {
|
||||
return expressions;
|
||||
}
|
||||
|
||||
public ParamRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
for (ParamExpression expression : this.expressions) {
|
||||
if (!expression.match(request)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParamRequestCondition{" + "expressions=" + expressions + '}';
|
||||
}
|
||||
|
||||
static class ParamExpression {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
private final boolean isNegated;
|
||||
|
||||
ParamExpression(String expression) {
|
||||
int separator = expression.indexOf('=');
|
||||
if (separator == -1) {
|
||||
this.isNegated = expression.startsWith("!");
|
||||
this.name = isNegated ? expression.substring(1) : expression;
|
||||
this.value = null;
|
||||
} else {
|
||||
this.isNegated = (separator > 0) && (expression.charAt(separator - 1) == '!');
|
||||
this.name = isNegated ? expression.substring(0, separator - 1) : expression.substring(0, separator);
|
||||
this.value = expression.substring(separator + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean match(HttpServletRequest request) {
|
||||
boolean isMatch;
|
||||
if (this.value != null) {
|
||||
isMatch = matchValue(request);
|
||||
} else {
|
||||
isMatch = matchName(request);
|
||||
}
|
||||
return this.isNegated != isMatch;
|
||||
}
|
||||
|
||||
private boolean matchName(HttpServletRequest request) {
|
||||
return request.getParameterMap().containsKey(this.name);
|
||||
}
|
||||
|
||||
private boolean matchValue(HttpServletRequest request) {
|
||||
return ObjectUtils.nullSafeEquals(this.value, request.getParameter(this.name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParamExpression{" + "name='" + name + '\'' + ", value='" + value + '\'' + ", isNegated=" + isNegated
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +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.core.code.condition;
|
||||
|
||||
import static com.alibaba.nacos.sys.env.Constants.REQUEST_PATH_SEPARATOR;
|
||||
|
||||
/**
|
||||
* request path info. method:{@link org.springframework.web.bind.annotation.RequestMapping#method()} path: {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#value()} or {@link org.springframework.web.bind.annotation.RequestMapping#value()}
|
||||
*
|
||||
* @author horizonzy
|
||||
* @since 1.3.2
|
||||
*/
|
||||
public class PathRequestCondition {
|
||||
|
||||
private final PathExpression pathExpression;
|
||||
|
||||
public PathRequestCondition(String pathExpression) {
|
||||
this.pathExpression = parseExpressions(pathExpression);
|
||||
}
|
||||
|
||||
private PathExpression parseExpressions(String pathExpression) {
|
||||
String[] split = pathExpression.split(REQUEST_PATH_SEPARATOR);
|
||||
String method = split[0];
|
||||
String path = split[1];
|
||||
return new PathExpression(method, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathRequestCondition{" + "pathExpression=" + pathExpression + '}';
|
||||
}
|
||||
|
||||
static class PathExpression {
|
||||
|
||||
private final String method;
|
||||
|
||||
private final String path;
|
||||
|
||||
PathExpression(String method, String path) {
|
||||
this.method = method;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathExpression{" + "method='" + method + '\'' + ", path='" + path + '\'' + '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +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.config;
|
||||
|
||||
import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
|
||||
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.core.utils.Loggers;
|
||||
|
||||
/**
|
||||
* Nacos abstract dynamic config.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public abstract class AbstractDynamicConfig extends Subscriber<ServerConfigChangeEvent> {
|
||||
|
||||
private final String configName;
|
||||
|
||||
protected AbstractDynamicConfig(String configName) {
|
||||
this.configName = configName;
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ServerConfigChangeEvent event) {
|
||||
resetConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return ServerConfigChangeEvent.class;
|
||||
}
|
||||
|
||||
protected void resetConfig() {
|
||||
try {
|
||||
getConfigFromEnv();
|
||||
Loggers.CORE.info("Get {} config from env, {}", configName, printConfig());
|
||||
} catch (Exception e) {
|
||||
Loggers.CORE.warn("Upgrade {} config from env failed, will use old value", configName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute get config from env actually.
|
||||
*/
|
||||
protected abstract void getConfigFromEnv();
|
||||
|
||||
/**
|
||||
* Print config content.
|
||||
*
|
||||
* @return config content
|
||||
*/
|
||||
protected abstract String printConfig();
|
||||
}
|
||||
@@ -1,88 +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.core.controller;
|
||||
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.core.distributed.ProtocolManager;
|
||||
import com.alibaba.nacos.core.distributed.id.IdGeneratorManager;
|
||||
import com.alibaba.nacos.core.utils.Commons;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Kernel modules operate and maintain HTTP interfaces.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(Commons.NACOS_CORE_CONTEXT + "/ops")
|
||||
public class CoreOpsController {
|
||||
|
||||
private final ProtocolManager protocolManager;
|
||||
|
||||
private final IdGeneratorManager idGeneratorManager;
|
||||
|
||||
public CoreOpsController(ProtocolManager protocolManager, IdGeneratorManager idGeneratorManager) {
|
||||
this.protocolManager = protocolManager;
|
||||
this.idGeneratorManager = idGeneratorManager;
|
||||
}
|
||||
|
||||
// Temporarily overpassed the raft operations interface
|
||||
// {
|
||||
// "groupId": "xxx",
|
||||
// "command": "transferLeader or doSnapshot or resetRaftCluster or removePeer"
|
||||
// "value": "ip:{raft_port}"
|
||||
// }
|
||||
|
||||
@PostMapping(value = "/raft")
|
||||
@Secured(action = ActionTypes.WRITE, resource = "nacos/admin")
|
||||
public RestResult<String> raftOps(@RequestBody Map<String, String> commands) {
|
||||
return protocolManager.getCpProtocol().execute(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current health of the ID generator.
|
||||
*
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@GetMapping(value = "/idInfo")
|
||||
public RestResult<Map<String, Map<Object, Object>>> idInfo() {
|
||||
Map<String, Map<Object, Object>> info = new HashMap<>(10);
|
||||
idGeneratorManager.getGeneratorMap().forEach((resource, idGenerator) -> info.put(resource, idGenerator.info()));
|
||||
return RestResultUtils.success(info);
|
||||
}
|
||||
|
||||
@PutMapping(value = "/log")
|
||||
public String setLogLevel(@RequestParam String logName, @RequestParam String logLevel) {
|
||||
Loggers.setLogLevel(logName, logLevel);
|
||||
return HttpServletResponse.SC_OK + "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,146 +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.core.controller;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.common.utils.LoggerUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.NodeState;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.utils.Commons;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Cluster communication interface.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(Commons.NACOS_CORE_CONTEXT + "/cluster")
|
||||
public class NacosClusterController {
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
public NacosClusterController(ServerMemberManager memberManager) {
|
||||
this.memberManager = memberManager;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/self")
|
||||
public RestResult<Member> self() {
|
||||
return RestResultUtils.success(memberManager.getSelf());
|
||||
}
|
||||
|
||||
/**
|
||||
* The console displays the list of cluster members.
|
||||
*
|
||||
* @param ipKeyWord search keyWord
|
||||
* @return all members
|
||||
*/
|
||||
@GetMapping(value = "/nodes")
|
||||
public RestResult<Collection<Member>> listNodes(
|
||||
@RequestParam(value = "keyword", required = false) String ipKeyWord) {
|
||||
Collection<Member> members = memberManager.allMembers();
|
||||
Collection<Member> result = new ArrayList<>();
|
||||
|
||||
members.stream().sorted().forEach(member -> {
|
||||
if (StringUtils.isBlank(ipKeyWord)) {
|
||||
result.add(member);
|
||||
return;
|
||||
}
|
||||
final String address = member.getAddress();
|
||||
if (StringUtils.equals(address, ipKeyWord) || StringUtils.startsWith(address, ipKeyWord)) {
|
||||
result.add(member);
|
||||
}
|
||||
});
|
||||
|
||||
return RestResultUtils.success(result);
|
||||
}
|
||||
|
||||
// The client can get all the nacos node information in the current
|
||||
// cluster according to this interface
|
||||
|
||||
@GetMapping(value = "/simple/nodes")
|
||||
public RestResult<Collection<String>> listSimpleNodes() {
|
||||
return RestResultUtils.success(memberManager.getMemberAddressInfos());
|
||||
}
|
||||
|
||||
@GetMapping("/health")
|
||||
public RestResult<String> getHealth() {
|
||||
return RestResultUtils.success(memberManager.getSelf().getState().name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Other nodes return their own metadata information.
|
||||
*
|
||||
* @param node {@link Member}
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@PostMapping(value = {"/report"})
|
||||
public RestResult<String> report(@RequestBody Member node) {
|
||||
if (!node.check()) {
|
||||
return RestResultUtils.failedWithMsg(400, "Node information is illegal");
|
||||
}
|
||||
LoggerUtils.printIfDebugEnabled(Loggers.CLUSTER, "node state report, receive info : {}", node);
|
||||
node.setState(NodeState.UP);
|
||||
node.setFailAccessCnt(0);
|
||||
|
||||
boolean result = memberManager.update(node);
|
||||
|
||||
return RestResultUtils.success(Boolean.toString(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Addressing mode switch.
|
||||
*
|
||||
* @param type member-lookup name
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@PostMapping(value = "/switch/lookup")
|
||||
public RestResult<String> switchLookup(@RequestParam(name = "type") String type) {
|
||||
try {
|
||||
memberManager.switchLookup(type);
|
||||
return RestResultUtils.success();
|
||||
} catch (Throwable ex) {
|
||||
return RestResultUtils.failed(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* member leave.
|
||||
*
|
||||
* @param params member ip list, example [ip1:port1,ip2:port2,...]
|
||||
* @return {@link RestResult}
|
||||
* @throws Exception {@link Exception}
|
||||
*/
|
||||
@PostMapping("/server/leave")
|
||||
public RestResult<String> leave(@RequestBody Collection<String> params,
|
||||
@RequestParam(defaultValue = "true") Boolean notifyOtherMembers) throws Exception {
|
||||
return RestResultUtils.failed(405, "/v1/core/cluster/server/leave API not allow to use temporarily.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,414 +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.controller;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.remote.RequestCallBack;
|
||||
import com.alibaba.nacos.api.remote.request.RequestMeta;
|
||||
import com.alibaba.nacos.api.remote.request.ServerLoaderInfoRequest;
|
||||
import com.alibaba.nacos.api.remote.request.ServerReloadRequest;
|
||||
import com.alibaba.nacos.api.remote.response.Response;
|
||||
import com.alibaba.nacos.api.remote.response.ServerLoaderInfoResponse;
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.cluster.remote.ClusterRpcClientProxy;
|
||||
import com.alibaba.nacos.core.remote.Connection;
|
||||
import com.alibaba.nacos.core.remote.ConnectionManager;
|
||||
import com.alibaba.nacos.core.remote.core.ServerLoaderInfoRequestHandler;
|
||||
import com.alibaba.nacos.core.remote.core.ServerReloaderRequestHandler;
|
||||
import com.alibaba.nacos.core.utils.Commons;
|
||||
import com.alibaba.nacos.core.utils.RemoteUtils;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* controller to control server loader.
|
||||
*
|
||||
* @author liuzunfei
|
||||
* @version $Id: ServerLoaderController.java, v 0.1 2020年07月22日 4:28 PM liuzunfei Exp $
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(Commons.NACOS_CORE_CONTEXT_V2 + "/loader")
|
||||
public class ServerLoaderController {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ServerLoaderController.class);
|
||||
|
||||
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 = ",";
|
||||
|
||||
private static final String SUCCESS_RESULT = "Ok";
|
||||
|
||||
private static final String FAIL_RESULT = "Fail";
|
||||
|
||||
private static final String SDK_CONNECTION_COUNT_METRIC = "sdkConCount";
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
private final ServerMemberManager serverMemberManager;
|
||||
|
||||
private final ClusterRpcClientProxy clusterRpcClientProxy;
|
||||
|
||||
private final ServerReloaderRequestHandler serverReloaderRequestHandler;
|
||||
|
||||
private final ServerLoaderInfoRequestHandler serverLoaderInfoRequestHandler;
|
||||
|
||||
public ServerLoaderController(ConnectionManager connectionManager, ServerMemberManager serverMemberManager,
|
||||
ClusterRpcClientProxy clusterRpcClientProxy, ServerReloaderRequestHandler serverReloaderRequestHandler,
|
||||
ServerLoaderInfoRequestHandler serverLoaderInfoRequestHandler) {
|
||||
this.connectionManager = connectionManager;
|
||||
this.serverMemberManager = serverMemberManager;
|
||||
this.clusterRpcClientProxy = clusterRpcClientProxy;
|
||||
this.serverReloaderRequestHandler = serverReloaderRequestHandler;
|
||||
this.serverLoaderInfoRequestHandler = serverLoaderInfoRequestHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current clients.
|
||||
*
|
||||
* @return state json.
|
||||
*/
|
||||
@Secured(resource = Commons.NACOS_CORE_CONTEXT_V2 + "/loader", action = ActionTypes.READ)
|
||||
@GetMapping("/current")
|
||||
public ResponseEntity<Map<String, Connection>> currentClients() {
|
||||
Map<String, Connection> stringConnectionMap = connectionManager.currentClients();
|
||||
return ResponseEntity.ok().body(stringConnectionMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server state of current server.
|
||||
*
|
||||
* @return state json.
|
||||
*/
|
||||
@Secured(resource = Commons.NACOS_CORE_CONTEXT_V2 + "/loader", action = ActionTypes.WRITE)
|
||||
@GetMapping("/reloadCurrent")
|
||||
public ResponseEntity<String> reloadCount(@RequestParam Integer count,
|
||||
@RequestParam(value = "redirectAddress", required = false) String redirectAddress) {
|
||||
connectionManager.loadCount(count, redirectAddress);
|
||||
return ResponseEntity.ok().body("success");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server state of current server.
|
||||
*
|
||||
* @return state json.
|
||||
*/
|
||||
@Secured(resource = Commons.NACOS_CORE_CONTEXT_V2 + "/loader", action = ActionTypes.WRITE)
|
||||
@GetMapping("/smartReloadCluster")
|
||||
public ResponseEntity<String> smartReload(HttpServletRequest request,
|
||||
@RequestParam(value = "loaderFactor", required = false) String loaderFactorStr,
|
||||
@RequestParam(value = "force", required = false) String force) {
|
||||
|
||||
LOGGER.info("Smart reload request receive,requestIp={}", getRemoteIp(request));
|
||||
|
||||
Map<String, Object> serverLoadMetrics = getServerLoadMetrics();
|
||||
Object avgString = serverLoadMetrics.get("avg");
|
||||
List<ServerLoaderMetrics> details = (List<ServerLoaderMetrics>) serverLoadMetrics.get("detail");
|
||||
int avg = Integer.parseInt(avgString.toString());
|
||||
float loaderFactor =
|
||||
StringUtils.isBlank(loaderFactorStr) ? RemoteUtils.LOADER_FACTOR : Float.parseFloat(loaderFactorStr);
|
||||
int overLimitCount = (int) (avg * (1 + loaderFactor));
|
||||
int lowLimitCount = (int) (avg * (1 - loaderFactor));
|
||||
|
||||
List<ServerLoaderMetrics> overLimitServer = new ArrayList<>();
|
||||
List<ServerLoaderMetrics> lowLimitServer = new ArrayList<>();
|
||||
|
||||
for (ServerLoaderMetrics metrics : details) {
|
||||
int sdkCount = Integer.parseInt(metrics.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
|
||||
if (sdkCount > overLimitCount) {
|
||||
overLimitServer.add(metrics);
|
||||
}
|
||||
if (sdkCount < lowLimitCount) {
|
||||
lowLimitServer.add(metrics);
|
||||
}
|
||||
}
|
||||
|
||||
// desc by sdkConCount
|
||||
overLimitServer.sort((o1, o2) -> {
|
||||
Integer sdkCount1 = Integer.valueOf(o1.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
|
||||
Integer sdkCount2 = Integer.valueOf(o2.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
|
||||
return sdkCount1.compareTo(sdkCount2) * -1;
|
||||
});
|
||||
|
||||
LOGGER.info("Over load limit server list ={}", overLimitServer);
|
||||
|
||||
//asc by sdkConCount
|
||||
lowLimitServer.sort((o1, o2) -> {
|
||||
Integer sdkCount1 = Integer.valueOf(o1.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
|
||||
Integer sdkCount2 = Integer.valueOf(o2.getMetric().get(SDK_CONNECTION_COUNT_METRIC));
|
||||
return sdkCount1.compareTo(sdkCount2);
|
||||
});
|
||||
|
||||
LOGGER.info("Low load limit server list ={}", lowLimitServer);
|
||||
AtomicBoolean result = new AtomicBoolean(true);
|
||||
|
||||
for (int i = 0; i < overLimitServer.size() & i < lowLimitServer.size(); i++) {
|
||||
ServerReloadRequest serverLoaderInfoRequest = new ServerReloadRequest();
|
||||
serverLoaderInfoRequest.setReloadCount(overLimitCount);
|
||||
serverLoaderInfoRequest.setReloadServer(lowLimitServer.get(i).address);
|
||||
Member member = serverMemberManager.find(overLimitServer.get(i).address);
|
||||
|
||||
LOGGER.info("Reload task submit ,fromServer ={},toServer={}, ", overLimitServer.get(i).address,
|
||||
lowLimitServer.get(i).address);
|
||||
|
||||
if (serverMemberManager.getSelf().equals(member)) {
|
||||
try {
|
||||
serverReloaderRequestHandler.handle(serverLoaderInfoRequest, new RequestMeta());
|
||||
} catch (NacosException e) {
|
||||
LOGGER.error("Fail to loader self server", e);
|
||||
result.set(false);
|
||||
}
|
||||
} else {
|
||||
|
||||
try {
|
||||
clusterRpcClientProxy.asyncRequest(member, serverLoaderInfoRequest, new RequestCallBack() {
|
||||
@Override
|
||||
public Executor getExecutor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeout() {
|
||||
return 100L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) {
|
||||
if (response == null || !response.isSuccess()) {
|
||||
LOGGER.error("Fail to loader member={},response={}", member.getAddress(), response);
|
||||
result.set(false);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable e) {
|
||||
LOGGER.error("Fail to loader member={}", member.getAddress(), e);
|
||||
result.set(false);
|
||||
}
|
||||
});
|
||||
} catch (NacosException e) {
|
||||
LOGGER.error("Fail to loader member={}", member.getAddress(), e);
|
||||
result.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.ok().body(result.get() ? SUCCESS_RESULT : FAIL_RESULT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get server state of current server.
|
||||
*
|
||||
* @return state json.
|
||||
*/
|
||||
@Secured(resource = Commons.NACOS_CORE_CONTEXT_V2 + "/loader", action = ActionTypes.WRITE)
|
||||
@GetMapping("/reloadClient")
|
||||
public ResponseEntity<String> reloadSingle(@RequestParam String connectionId,
|
||||
@RequestParam(value = "redirectAddress", required = false) String redirectAddress) {
|
||||
connectionManager.loadSingle(connectionId, redirectAddress);
|
||||
return ResponseEntity.ok().body("success");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current clients.
|
||||
*
|
||||
* @return state json.
|
||||
*/
|
||||
@Secured(resource = Commons.NACOS_CORE_CONTEXT_V2 + "/loader", action = ActionTypes.READ)
|
||||
@GetMapping("/cluster")
|
||||
public ResponseEntity<Map<String, Object>> loaderMetrics() {
|
||||
|
||||
Map<String, Object> serverLoadMetrics = getServerLoadMetrics();
|
||||
|
||||
return ResponseEntity.ok().body(serverLoadMetrics);
|
||||
}
|
||||
|
||||
private Map<String, Object> getServerLoadMetrics() {
|
||||
|
||||
List<ServerLoaderMetrics> responseList = new LinkedList<>();
|
||||
|
||||
// default include self.
|
||||
int memberSize = serverMemberManager.allMembersWithoutSelf().size();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(memberSize);
|
||||
for (Member member : serverMemberManager.allMembersWithoutSelf()) {
|
||||
if (MemberUtil.isSupportedLongCon(member)) {
|
||||
ServerLoaderInfoRequest serverLoaderInfoRequest = new ServerLoaderInfoRequest();
|
||||
|
||||
try {
|
||||
clusterRpcClientProxy.asyncRequest(member, serverLoaderInfoRequest, new RequestCallBack() {
|
||||
@Override
|
||||
public Executor getExecutor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeout() {
|
||||
return 200L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) {
|
||||
if (response instanceof ServerLoaderInfoResponse) {
|
||||
ServerLoaderMetrics metrics = new ServerLoaderMetrics();
|
||||
metrics.setAddress(member.getAddress());
|
||||
metrics.setMetric(((ServerLoaderInfoResponse) response).getLoaderMetrics());
|
||||
responseList.add(metrics);
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable e) {
|
||||
LOGGER.error("Get metrics fail,member={}", member.getAddress(), e);
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
});
|
||||
} catch (NacosException e) {
|
||||
LOGGER.error("Get metrics fail,member={}", member.getAddress(), e);
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
} else {
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ServerLoaderInfoResponse handle = serverLoaderInfoRequestHandler
|
||||
.handle(new ServerLoaderInfoRequest(), new RequestMeta());
|
||||
ServerLoaderMetrics metrics = new ServerLoaderMetrics();
|
||||
metrics.setAddress(serverMemberManager.getSelf().getAddress());
|
||||
metrics.setMetric(handle.getLoaderMetrics());
|
||||
responseList.add(metrics);
|
||||
} catch (NacosException e) {
|
||||
LOGGER.error("Get self metrics fail", e);
|
||||
}
|
||||
|
||||
try {
|
||||
countDownLatch.await(1000, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.warn("Get metrics timeout,metrics info may not complete.");
|
||||
}
|
||||
int max = 0;
|
||||
int min = -1;
|
||||
int total = 0;
|
||||
|
||||
for (ServerLoaderMetrics serverLoaderMetrics : responseList) {
|
||||
String sdkConCountStr = serverLoaderMetrics.getMetric().get("sdkConCount");
|
||||
|
||||
if (StringUtils.isNotBlank(sdkConCountStr)) {
|
||||
int sdkConCount = Integer.parseInt(sdkConCountStr);
|
||||
if (max == 0 || max < sdkConCount) {
|
||||
max = sdkConCount;
|
||||
}
|
||||
if (min == -1 || sdkConCount < min) {
|
||||
min = sdkConCount;
|
||||
}
|
||||
total += sdkConCount;
|
||||
}
|
||||
}
|
||||
Map<String, Object> responseMap = new HashMap<>(9);
|
||||
responseList.sort(Comparator.comparing(ServerLoaderMetrics::getAddress));
|
||||
responseMap.put("detail", responseList);
|
||||
responseMap.put("memberCount", serverMemberManager.allMembers().size());
|
||||
responseMap.put("metricsCount", responseList.size());
|
||||
responseMap.put("completed", responseList.size() == serverMemberManager.allMembers().size());
|
||||
responseMap.put("max", max);
|
||||
responseMap.put("min", min);
|
||||
responseMap.put("avg", total / responseList.size());
|
||||
responseMap.put("threshold", total / responseList.size() * 1.1);
|
||||
responseMap.put("total", total);
|
||||
return responseMap;
|
||||
|
||||
}
|
||||
|
||||
class ServerLoaderMetrics {
|
||||
|
||||
String address;
|
||||
|
||||
Map<String, String> metric = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Getter method for property <tt>address</tt>.
|
||||
*
|
||||
* @return property value of address
|
||||
*/
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter method for property <tt>address</tt>.
|
||||
*
|
||||
* @param address value to be assigned to property address
|
||||
*/
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter method for property <tt>metric</tt>.
|
||||
*
|
||||
* @return property value of metric
|
||||
*/
|
||||
public Map<String, String> getMetric() {
|
||||
return metric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter method for property <tt>metric</tt>.
|
||||
*
|
||||
* @param metric value to be assigned to property metric
|
||||
*/
|
||||
public void setMetric(Map<String, String> metric) {
|
||||
this.metric = metric;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,102 +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.core.controller.v2;
|
||||
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
import com.alibaba.nacos.common.Beta;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.core.distributed.ProtocolManager;
|
||||
import com.alibaba.nacos.core.distributed.id.IdGeneratorManager;
|
||||
import com.alibaba.nacos.core.model.request.LogUpdateRequest;
|
||||
import com.alibaba.nacos.core.model.vo.IdGeneratorVO;
|
||||
import com.alibaba.nacos.core.utils.Commons;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Kernel modules operate and maintain HTTP interfaces v2.
|
||||
*
|
||||
* @author wuzhiguo
|
||||
*/
|
||||
@Beta
|
||||
@RestController
|
||||
@RequestMapping(Commons.NACOS_CORE_CONTEXT_V2 + "/ops")
|
||||
public class CoreOpsV2Controller {
|
||||
|
||||
private final ProtocolManager protocolManager;
|
||||
|
||||
private final IdGeneratorManager idGeneratorManager;
|
||||
|
||||
public CoreOpsV2Controller(ProtocolManager protocolManager, IdGeneratorManager idGeneratorManager) {
|
||||
this.protocolManager = protocolManager;
|
||||
this.idGeneratorManager = idGeneratorManager;
|
||||
}
|
||||
|
||||
// Temporarily overpassed the raft operations interface
|
||||
// {
|
||||
// "groupId": "xxx",
|
||||
// "command": "transferLeader or doSnapshot or resetRaftCluster or removePeer"
|
||||
// "value": "ip:{raft_port}"
|
||||
// }
|
||||
|
||||
@PostMapping(value = "/raft")
|
||||
@Secured(action = ActionTypes.WRITE, resource = "nacos/admin")
|
||||
public RestResult<String> raftOps(@RequestBody Map<String, String> commands) {
|
||||
return protocolManager.getCpProtocol().execute(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current health of the ID generator.
|
||||
*
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@GetMapping(value = "/ids")
|
||||
public RestResult<List<IdGeneratorVO>> ids() {
|
||||
List<IdGeneratorVO> result = new ArrayList<>();
|
||||
idGeneratorManager.getGeneratorMap().forEach((resource, idGenerator) -> {
|
||||
IdGeneratorVO vo = new IdGeneratorVO();
|
||||
vo.setResource(resource);
|
||||
|
||||
IdGeneratorVO.IdInfo info = new IdGeneratorVO.IdInfo();
|
||||
info.setCurrentId(idGenerator.currentId());
|
||||
info.setWorkerId(idGenerator.workerId());
|
||||
vo.setInfo(info);
|
||||
|
||||
result.add(vo);
|
||||
});
|
||||
|
||||
return RestResultUtils.success(result);
|
||||
}
|
||||
|
||||
@PutMapping(value = "/log")
|
||||
public RestResult<Void> updateLog(@RequestBody LogUpdateRequest logUpdateRequest) {
|
||||
Loggers.setLogLevel(logUpdateRequest.getLogName(), logUpdateRequest.getLogLevel());
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,161 +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.core.controller.v2;
|
||||
|
||||
import com.alibaba.nacos.common.Beta;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.common.utils.LoggerUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.NodeState;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
|
||||
import com.alibaba.nacos.core.utils.Commons;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Cluster communication interface v2.
|
||||
*
|
||||
* @author wuzhiguo
|
||||
*/
|
||||
@Beta
|
||||
@RestController
|
||||
@RequestMapping(Commons.NACOS_CORE_CONTEXT_V2 + "/cluster")
|
||||
public class NacosClusterV2Controller {
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
public NacosClusterV2Controller(ServerMemberManager memberManager) {
|
||||
this.memberManager = memberManager;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/nodes/self")
|
||||
public RestResult<Member> self() {
|
||||
return RestResultUtils.success(memberManager.getSelf());
|
||||
}
|
||||
|
||||
/**
|
||||
* The console displays the list of cluster members.
|
||||
*
|
||||
* @param address match address
|
||||
* @param state match state
|
||||
* @return members that matches condition
|
||||
*/
|
||||
@GetMapping(value = "/nodes")
|
||||
public RestResult<Collection<Member>> listNodes(@RequestParam(value = "address", required = false) String address,
|
||||
@RequestParam(value = "state", required = false) String state) {
|
||||
|
||||
NodeState nodeState = null;
|
||||
if (StringUtils.isNoneBlank(state)) {
|
||||
try {
|
||||
nodeState = NodeState.valueOf(state.toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return RestResultUtils.failedWithMsg(400, "Illegal state: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<Member> members = memberManager.allMembers();
|
||||
Collection<Member> result = new ArrayList<>();
|
||||
|
||||
for (Member member : members) {
|
||||
if (StringUtils.isNoneBlank(address) && !StringUtils.startsWith(member.getAddress(), address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nodeState != null && member.getState() != nodeState) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(member);
|
||||
}
|
||||
|
||||
return RestResultUtils.success(result);
|
||||
}
|
||||
|
||||
// The client can get all the nacos node information in the current
|
||||
// cluster according to this interface
|
||||
|
||||
/**
|
||||
* Other nodes return their own metadata information.
|
||||
*
|
||||
* @param nodes List of {@link Member}
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@PutMapping(value = "/nodes")
|
||||
public RestResult<Void> updateNodes(@RequestBody List<Member> nodes) {
|
||||
for (Member node : nodes) {
|
||||
if (!node.check()) {
|
||||
LoggerUtils.printIfWarnEnabled(Loggers.CLUSTER, "node information is illegal, ignore node: {}", node);
|
||||
continue;
|
||||
}
|
||||
|
||||
LoggerUtils.printIfDebugEnabled(Loggers.CLUSTER, "node state updating, node: {}", node);
|
||||
node.setState(NodeState.UP);
|
||||
node.setFailAccessCnt(0);
|
||||
|
||||
boolean update = memberManager.update(node);
|
||||
if (!update) {
|
||||
LoggerUtils.printIfErrorEnabled(Loggers.CLUSTER, "node state update failed, node: {}", node);
|
||||
}
|
||||
}
|
||||
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Addressing mode switch.
|
||||
*
|
||||
* @param request {@link LookupUpdateRequest}
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
@PutMapping(value = "/lookup")
|
||||
public RestResult<Void> updateLookup(@RequestBody LookupUpdateRequest request) {
|
||||
try {
|
||||
memberManager.switchLookup(request.getType());
|
||||
return RestResultUtils.success();
|
||||
} catch (Throwable ex) {
|
||||
return RestResultUtils.failed(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* member leave.
|
||||
*
|
||||
* @param addresses member ip list, example [ip1:port1,ip2:port2,...]
|
||||
* @return {@link RestResult}
|
||||
* @throws Exception throw {@link Exception}
|
||||
*/
|
||||
@DeleteMapping("/nodes")
|
||||
public RestResult<Void> deleteNodes(@RequestParam("addresses") List<String> addresses) throws Exception {
|
||||
return RestResultUtils.failed(405, null, "DELETE /v2/core/cluster/nodes API not allow to use temporarily.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +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.core.distributed;
|
||||
|
||||
import com.alibaba.nacos.consistency.Config;
|
||||
import com.alibaba.nacos.consistency.ConsistencyProtocol;
|
||||
import com.alibaba.nacos.consistency.RequestProcessor;
|
||||
import com.alibaba.nacos.consistency.ProtocolMetaData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Consistent protocol base class.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public abstract class AbstractConsistencyProtocol<T extends Config, L extends RequestProcessor>
|
||||
implements ConsistencyProtocol<T, L> {
|
||||
|
||||
protected final ProtocolMetaData metaData = new ProtocolMetaData();
|
||||
|
||||
protected Map<String, L> processorMap = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public void loadLogProcessor(List<L> logProcessors) {
|
||||
logProcessors.forEach(logDispatcher -> processorMap.put(logDispatcher.group(), logDispatcher));
|
||||
}
|
||||
|
||||
protected Map<String, L> allProcessor() {
|
||||
return processorMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMetaData protocolMetaData() {
|
||||
return this.metaData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +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.core.distributed;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.consistency.cp.CPProtocol;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftProtocol;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* consistency configuration.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Configuration
|
||||
public class ConsistencyConfiguration {
|
||||
|
||||
@Bean(value = "strongAgreementProtocol")
|
||||
public CPProtocol strongAgreementProtocol(ServerMemberManager memberManager) throws Exception {
|
||||
final CPProtocol protocol = getProtocol(CPProtocol.class, () -> new JRaftProtocol(memberManager));
|
||||
return protocol;
|
||||
}
|
||||
|
||||
private <T> T getProtocol(Class<T> cls, Callable<T> builder) throws Exception {
|
||||
Collection<T> protocols = NacosServiceLoader.load(cls);
|
||||
|
||||
// Select only the first implementation
|
||||
|
||||
Iterator<T> iterator = protocols.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
return iterator.next();
|
||||
} else {
|
||||
return builder.call();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.core.distributed;
|
||||
|
||||
import com.alibaba.nacos.common.executor.ExecutorFactory;
|
||||
import com.alibaba.nacos.core.utils.ClassUtils;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* ProtocolExecutor.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public final class ProtocolExecutor {
|
||||
|
||||
private static final ExecutorService CP_MEMBER_CHANGE_EXECUTOR = ExecutorFactory.Managed
|
||||
.newSingleExecutorService(ClassUtils.getCanonicalName(ProtocolManager.class));
|
||||
|
||||
private static final ExecutorService AP_MEMBER_CHANGE_EXECUTOR = ExecutorFactory.Managed
|
||||
.newSingleExecutorService(ClassUtils.getCanonicalName(ProtocolManager.class));
|
||||
|
||||
public static void cpMemberChange(Runnable runnable) {
|
||||
CP_MEMBER_CHANGE_EXECUTOR.execute(runnable);
|
||||
}
|
||||
|
||||
public static void apMemberChange(Runnable runnable) {
|
||||
AP_MEMBER_CHANGE_EXECUTOR.execute(runnable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,164 +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.core.distributed;
|
||||
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.consistency.Config;
|
||||
import com.alibaba.nacos.consistency.ap.APProtocol;
|
||||
import com.alibaba.nacos.consistency.cp.CPProtocol;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.MemberChangeListener;
|
||||
import com.alibaba.nacos.core.cluster.MemberMetaDataConstants;
|
||||
import com.alibaba.nacos.core.cluster.MemberUtil;
|
||||
import com.alibaba.nacos.core.cluster.MembersChangeEvent;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.utils.ClassUtils;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Conformance protocol management, responsible for managing the lifecycle of conformance protocols in Nacos.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
@Component(value = "ProtocolManager")
|
||||
public class ProtocolManager extends MemberChangeListener implements DisposableBean {
|
||||
|
||||
private CPProtocol cpProtocol;
|
||||
|
||||
private APProtocol apProtocol;
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
private boolean apInit = false;
|
||||
|
||||
private boolean cpInit = false;
|
||||
|
||||
private Set<Member> oldMembers;
|
||||
|
||||
public ProtocolManager(ServerMemberManager memberManager) {
|
||||
this.memberManager = memberManager;
|
||||
NotifyCenter.registerSubscriber(this);
|
||||
}
|
||||
|
||||
public static Set<String> toAPMembersInfo(Collection<Member> members) {
|
||||
Set<String> nodes = new HashSet<>();
|
||||
members.forEach(member -> nodes.add(member.getAddress()));
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public static Set<String> toCPMembersInfo(Collection<Member> members) {
|
||||
Set<String> nodes = new HashSet<>();
|
||||
members.forEach(member -> {
|
||||
final String ip = member.getIp();
|
||||
final int raftPort = MemberUtil.calculateRaftPort(member);
|
||||
nodes.add(ip + ":" + raftPort);
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public CPProtocol getCpProtocol() {
|
||||
synchronized (this) {
|
||||
if (!cpInit) {
|
||||
initCPProtocol();
|
||||
cpInit = true;
|
||||
}
|
||||
}
|
||||
return cpProtocol;
|
||||
}
|
||||
|
||||
public APProtocol getApProtocol() {
|
||||
synchronized (this) {
|
||||
if (!apInit) {
|
||||
initAPProtocol();
|
||||
apInit = true;
|
||||
}
|
||||
}
|
||||
return apProtocol;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (Objects.nonNull(apProtocol)) {
|
||||
apProtocol.shutdown();
|
||||
}
|
||||
if (Objects.nonNull(cpProtocol)) {
|
||||
cpProtocol.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void initAPProtocol() {
|
||||
ApplicationUtils.getBeanIfExist(APProtocol.class, protocol -> {
|
||||
Class configType = ClassUtils.resolveGenericType(protocol.getClass());
|
||||
Config config = (Config) ApplicationUtils.getBean(configType);
|
||||
injectMembers4AP(config);
|
||||
protocol.init(config);
|
||||
ProtocolManager.this.apProtocol = protocol;
|
||||
});
|
||||
}
|
||||
|
||||
private void initCPProtocol() {
|
||||
ApplicationUtils.getBeanIfExist(CPProtocol.class, protocol -> {
|
||||
Class configType = ClassUtils.resolveGenericType(protocol.getClass());
|
||||
Config config = (Config) ApplicationUtils.getBean(configType);
|
||||
injectMembers4CP(config);
|
||||
protocol.init(config);
|
||||
ProtocolManager.this.cpProtocol = protocol;
|
||||
});
|
||||
}
|
||||
|
||||
private void injectMembers4CP(Config config) {
|
||||
final Member selfMember = memberManager.getSelf();
|
||||
final String self = selfMember.getIp() + ":" + Integer
|
||||
.parseInt(String.valueOf(selfMember.getExtendVal(MemberMetaDataConstants.RAFT_PORT)));
|
||||
Set<String> others = toCPMembersInfo(memberManager.allMembers());
|
||||
config.setMembers(self, others);
|
||||
}
|
||||
|
||||
private void injectMembers4AP(Config config) {
|
||||
final String self = memberManager.getSelf().getAddress();
|
||||
Set<String> others = toAPMembersInfo(memberManager.allMembers());
|
||||
config.setMembers(self, others);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(MembersChangeEvent event) {
|
||||
// Here, the sequence of node change events is very important. For example,
|
||||
// node change event A occurs at time T1, and node change event B occurs at
|
||||
// time T2 after a period of time.
|
||||
// (T1 < T2)
|
||||
// Node change events between different protocols should not block each other.
|
||||
// and we use a single thread pool to inform the consistency layer of node changes,
|
||||
// to avoid multiple tasks simultaneously carrying out the consistency layer of
|
||||
// node changes operation
|
||||
if (Objects.nonNull(apProtocol)) {
|
||||
ProtocolExecutor.apMemberChange(() -> apProtocol.memberChange(toAPMembersInfo(event.getMembers())));
|
||||
}
|
||||
if (Objects.nonNull(cpProtocol)) {
|
||||
ProtocolExecutor.cpMemberChange(() -> cpProtocol.memberChange(toCPMembersInfo(event.getMembers())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +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.core.distributed.distro;
|
||||
|
||||
import com.alibaba.nacos.core.config.AbstractDynamicConfig;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
|
||||
/**
|
||||
* Distro configuration.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroConfig extends AbstractDynamicConfig {
|
||||
|
||||
private static final String DISTRO = "Distro";
|
||||
|
||||
private static final DistroConfig INSTANCE = new DistroConfig();
|
||||
|
||||
private long syncDelayMillis = DistroConstants.DEFAULT_DATA_SYNC_DELAY_MILLISECONDS;
|
||||
|
||||
private long syncTimeoutMillis = DistroConstants.DEFAULT_DATA_SYNC_TIMEOUT_MILLISECONDS;
|
||||
|
||||
private long syncRetryDelayMillis = DistroConstants.DEFAULT_DATA_SYNC_RETRY_DELAY_MILLISECONDS;
|
||||
|
||||
private long verifyIntervalMillis = DistroConstants.DEFAULT_DATA_VERIFY_INTERVAL_MILLISECONDS;
|
||||
|
||||
private long verifyTimeoutMillis = DistroConstants.DEFAULT_DATA_VERIFY_TIMEOUT_MILLISECONDS;
|
||||
|
||||
private long loadDataRetryDelayMillis = DistroConstants.DEFAULT_DATA_LOAD_RETRY_DELAY_MILLISECONDS;
|
||||
|
||||
private long loadDataTimeoutMillis = DistroConstants.DEFAULT_DATA_LOAD_TIMEOUT_MILLISECONDS;
|
||||
|
||||
private DistroConfig() {
|
||||
super(DISTRO);
|
||||
resetConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getConfigFromEnv() {
|
||||
syncDelayMillis = EnvUtil.getProperty(DistroConstants.DATA_SYNC_DELAY_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_SYNC_DELAY_MILLISECONDS);
|
||||
syncTimeoutMillis = EnvUtil.getProperty(DistroConstants.DATA_SYNC_TIMEOUT_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_SYNC_TIMEOUT_MILLISECONDS);
|
||||
syncRetryDelayMillis = EnvUtil.getProperty(DistroConstants.DATA_SYNC_RETRY_DELAY_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_SYNC_RETRY_DELAY_MILLISECONDS);
|
||||
verifyIntervalMillis = EnvUtil.getProperty(DistroConstants.DATA_VERIFY_INTERVAL_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_VERIFY_INTERVAL_MILLISECONDS);
|
||||
verifyTimeoutMillis = EnvUtil.getProperty(DistroConstants.DATA_VERIFY_TIMEOUT_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_VERIFY_TIMEOUT_MILLISECONDS);
|
||||
loadDataRetryDelayMillis = EnvUtil.getProperty(DistroConstants.DATA_LOAD_RETRY_DELAY_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_LOAD_RETRY_DELAY_MILLISECONDS);
|
||||
loadDataTimeoutMillis = EnvUtil.getProperty(DistroConstants.DATA_LOAD_TIMEOUT_MILLISECONDS, Long.class,
|
||||
DistroConstants.DEFAULT_DATA_LOAD_TIMEOUT_MILLISECONDS);
|
||||
}
|
||||
|
||||
public static DistroConfig getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public long getSyncDelayMillis() {
|
||||
return syncDelayMillis;
|
||||
}
|
||||
|
||||
public void setSyncDelayMillis(long syncDelayMillis) {
|
||||
this.syncDelayMillis = syncDelayMillis;
|
||||
}
|
||||
|
||||
public long getSyncTimeoutMillis() {
|
||||
return syncTimeoutMillis;
|
||||
}
|
||||
|
||||
public void setSyncTimeoutMillis(long syncTimeoutMillis) {
|
||||
this.syncTimeoutMillis = syncTimeoutMillis;
|
||||
}
|
||||
|
||||
public long getSyncRetryDelayMillis() {
|
||||
return syncRetryDelayMillis;
|
||||
}
|
||||
|
||||
public void setSyncRetryDelayMillis(long syncRetryDelayMillis) {
|
||||
this.syncRetryDelayMillis = syncRetryDelayMillis;
|
||||
}
|
||||
|
||||
public long getVerifyIntervalMillis() {
|
||||
return verifyIntervalMillis;
|
||||
}
|
||||
|
||||
public void setVerifyIntervalMillis(long verifyIntervalMillis) {
|
||||
this.verifyIntervalMillis = verifyIntervalMillis;
|
||||
}
|
||||
|
||||
public long getVerifyTimeoutMillis() {
|
||||
return verifyTimeoutMillis;
|
||||
}
|
||||
|
||||
public void setVerifyTimeoutMillis(long verifyTimeoutMillis) {
|
||||
this.verifyTimeoutMillis = verifyTimeoutMillis;
|
||||
}
|
||||
|
||||
public long getLoadDataRetryDelayMillis() {
|
||||
return loadDataRetryDelayMillis;
|
||||
}
|
||||
|
||||
public void setLoadDataRetryDelayMillis(long loadDataRetryDelayMillis) {
|
||||
this.loadDataRetryDelayMillis = loadDataRetryDelayMillis;
|
||||
}
|
||||
|
||||
public long getLoadDataTimeoutMillis() {
|
||||
return loadDataTimeoutMillis;
|
||||
}
|
||||
|
||||
public void setLoadDataTimeoutMillis(long loadDataTimeoutMillis) {
|
||||
this.loadDataTimeoutMillis = loadDataTimeoutMillis;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String printConfig() {
|
||||
return "DistroConfig{" + "syncDelayMillis=" + syncDelayMillis + ", syncTimeoutMillis=" + syncTimeoutMillis
|
||||
+ ", syncRetryDelayMillis=" + syncRetryDelayMillis + ", verifyIntervalMillis=" + verifyIntervalMillis
|
||||
+ ", verifyTimeoutMillis=" + verifyTimeoutMillis + ", loadDataRetryDelayMillis="
|
||||
+ loadDataRetryDelayMillis + '}';
|
||||
}
|
||||
}
|
||||
@@ -1,54 +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.distributed.distro;
|
||||
|
||||
/**
|
||||
* Distro constants.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroConstants {
|
||||
|
||||
public static final String DATA_SYNC_DELAY_MILLISECONDS = "nacos.core.protocol.distro.data.sync.delayMs";
|
||||
|
||||
public static final long DEFAULT_DATA_SYNC_DELAY_MILLISECONDS = 1000L;
|
||||
|
||||
public static final String DATA_SYNC_TIMEOUT_MILLISECONDS = "nacos.core.protocol.distro.data.sync.timeoutMs";
|
||||
|
||||
public static final long DEFAULT_DATA_SYNC_TIMEOUT_MILLISECONDS = 3000L;
|
||||
|
||||
public static final String DATA_SYNC_RETRY_DELAY_MILLISECONDS = "nacos.core.protocol.distro.data.sync.retryDelayMs";
|
||||
|
||||
public static final long DEFAULT_DATA_SYNC_RETRY_DELAY_MILLISECONDS = 3000L;
|
||||
|
||||
public static final String DATA_VERIFY_INTERVAL_MILLISECONDS = "nacos.core.protocol.distro.data.verify.intervalMs";
|
||||
|
||||
public static final long DEFAULT_DATA_VERIFY_INTERVAL_MILLISECONDS = 5000L;
|
||||
|
||||
public static final String DATA_VERIFY_TIMEOUT_MILLISECONDS = "nacos.core.protocol.distro.data.verify.timeoutMs";
|
||||
|
||||
public static final long DEFAULT_DATA_VERIFY_TIMEOUT_MILLISECONDS = 3000L;
|
||||
|
||||
public static final String DATA_LOAD_RETRY_DELAY_MILLISECONDS = "nacos.core.protocol.distro.data.load.retryDelayMs";
|
||||
|
||||
public static final long DEFAULT_DATA_LOAD_RETRY_DELAY_MILLISECONDS = 30000L;
|
||||
|
||||
public static final String DATA_LOAD_TIMEOUT_MILLISECONDS = "nacos.core.protocol.distro.data.load.timeoutMs";
|
||||
|
||||
public static final long DEFAULT_DATA_LOAD_TIMEOUT_MILLISECONDS = 30000L;
|
||||
|
||||
}
|
||||
@@ -1,227 +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.core.distributed.distro;
|
||||
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroDataProcessor;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroDataStorage;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
|
||||
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.task.DistroTaskEngineHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTask;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.load.DistroLoadDataTask;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.verify.DistroVerifyTimedTask;
|
||||
import com.alibaba.nacos.core.utils.GlobalExecutor;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Distro protocol.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
@Component
|
||||
public class DistroProtocol {
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
private final DistroComponentHolder distroComponentHolder;
|
||||
|
||||
private final DistroTaskEngineHolder distroTaskEngineHolder;
|
||||
|
||||
private volatile boolean isInitialized = false;
|
||||
|
||||
public DistroProtocol(ServerMemberManager memberManager, DistroComponentHolder distroComponentHolder,
|
||||
DistroTaskEngineHolder distroTaskEngineHolder) {
|
||||
this.memberManager = memberManager;
|
||||
this.distroComponentHolder = distroComponentHolder;
|
||||
this.distroTaskEngineHolder = distroTaskEngineHolder;
|
||||
startDistroTask();
|
||||
}
|
||||
|
||||
private void startDistroTask() {
|
||||
if (EnvUtil.getStandaloneMode()) {
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
startVerifyTask();
|
||||
startLoadTask();
|
||||
}
|
||||
|
||||
private void startLoadTask() {
|
||||
DistroCallback loadCallback = new DistroCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(Throwable throwable) {
|
||||
isInitialized = false;
|
||||
}
|
||||
};
|
||||
GlobalExecutor.submitLoadDataTask(
|
||||
new DistroLoadDataTask(memberManager, distroComponentHolder, DistroConfig.getInstance(), loadCallback));
|
||||
}
|
||||
|
||||
private void startVerifyTask() {
|
||||
GlobalExecutor.schedulePartitionDataTimedSync(new DistroVerifyTimedTask(memberManager, distroComponentHolder,
|
||||
distroTaskEngineHolder.getExecuteWorkersManager()),
|
||||
DistroConfig.getInstance().getVerifyIntervalMillis());
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to sync by configured delay.
|
||||
*
|
||||
* @param distroKey distro key of sync data
|
||||
* @param action the action of data operation
|
||||
*/
|
||||
public void sync(DistroKey distroKey, DataOperation action) {
|
||||
sync(distroKey, action, DistroConfig.getInstance().getSyncDelayMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to sync data to all remote server.
|
||||
*
|
||||
* @param distroKey distro key of sync data
|
||||
* @param action the action of data operation
|
||||
* @param delay delay time for sync
|
||||
*/
|
||||
public void sync(DistroKey distroKey, DataOperation action, long delay) {
|
||||
for (Member each : memberManager.allMembersWithoutSelf()) {
|
||||
syncToTarget(distroKey, action, each.getAddress(), delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to sync to target server.
|
||||
*
|
||||
* @param distroKey distro key of sync data
|
||||
* @param action the action of data operation
|
||||
* @param targetServer target server
|
||||
* @param delay delay time for sync
|
||||
*/
|
||||
public void syncToTarget(DistroKey distroKey, DataOperation action, String targetServer, long delay) {
|
||||
DistroKey distroKeyWithTarget = new DistroKey(distroKey.getResourceKey(), distroKey.getResourceType(),
|
||||
targetServer);
|
||||
DistroDelayTask distroDelayTask = new DistroDelayTask(distroKeyWithTarget, action, delay);
|
||||
distroTaskEngineHolder.getDelayTaskExecuteEngine().addTask(distroKeyWithTarget, distroDelayTask);
|
||||
if (Loggers.DISTRO.isDebugEnabled()) {
|
||||
Loggers.DISTRO.debug("[DISTRO-SCHEDULE] {} to {}", distroKey, targetServer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query data from specified server.
|
||||
*
|
||||
* @param distroKey data key
|
||||
* @return data
|
||||
*/
|
||||
public DistroData queryFromRemote(DistroKey distroKey) {
|
||||
if (null == distroKey.getTargetServer()) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't query data from empty server");
|
||||
return null;
|
||||
}
|
||||
String resourceType = distroKey.getResourceType();
|
||||
DistroTransportAgent transportAgent = distroComponentHolder.findTransportAgent(resourceType);
|
||||
if (null == transportAgent) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't find transport agent for key {}", resourceType);
|
||||
return null;
|
||||
}
|
||||
return transportAgent.getData(distroKey, distroKey.getTargetServer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive synced distro data, find processor to process.
|
||||
*
|
||||
* @param distroData Received data
|
||||
* @return true if handle receive data successfully, otherwise false
|
||||
*/
|
||||
public boolean onReceive(DistroData distroData) {
|
||||
Loggers.DISTRO.info("[DISTRO] Receive distro data type: {}, key: {}", distroData.getType(),
|
||||
distroData.getDistroKey());
|
||||
String resourceType = distroData.getDistroKey().getResourceType();
|
||||
DistroDataProcessor dataProcessor = distroComponentHolder.findDataProcessor(resourceType);
|
||||
if (null == dataProcessor) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't find data process for received data {}", resourceType);
|
||||
return false;
|
||||
}
|
||||
return dataProcessor.processData(distroData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive verify data, find processor to process.
|
||||
*
|
||||
* @param distroData verify data
|
||||
* @param sourceAddress source server address, might be get data from source server
|
||||
* @return true if verify data successfully, otherwise false
|
||||
*/
|
||||
public boolean onVerify(DistroData distroData, String sourceAddress) {
|
||||
if (Loggers.DISTRO.isDebugEnabled()) {
|
||||
Loggers.DISTRO.debug("[DISTRO] Receive verify data type: {}, key: {}", distroData.getType(),
|
||||
distroData.getDistroKey());
|
||||
}
|
||||
String resourceType = distroData.getDistroKey().getResourceType();
|
||||
DistroDataProcessor dataProcessor = distroComponentHolder.findDataProcessor(resourceType);
|
||||
if (null == dataProcessor) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't find verify data process for received data {}", resourceType);
|
||||
return false;
|
||||
}
|
||||
return dataProcessor.processVerifyData(distroData, sourceAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query data of input distro key.
|
||||
*
|
||||
* @param distroKey key of data
|
||||
* @return data
|
||||
*/
|
||||
public DistroData onQuery(DistroKey distroKey) {
|
||||
String resourceType = distroKey.getResourceType();
|
||||
DistroDataStorage distroDataStorage = distroComponentHolder.findDataStorage(resourceType);
|
||||
if (null == distroDataStorage) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't find data storage for received key {}", resourceType);
|
||||
return new DistroData(distroKey, new byte[0]);
|
||||
}
|
||||
return distroDataStorage.getDistroData(distroKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query all datum snapshot.
|
||||
*
|
||||
* @param type datum type
|
||||
* @return all datum snapshot
|
||||
*/
|
||||
public DistroData onSnapshot(String type) {
|
||||
DistroDataStorage distroDataStorage = distroComponentHolder.findDataStorage(type);
|
||||
if (null == distroDataStorage) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't find data storage for received key {}", type);
|
||||
return new DistroData(new DistroKey("snapshot", type), new byte[0]);
|
||||
}
|
||||
return distroDataStorage.getDatumSnapshot();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +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.core.distributed.distro.component;
|
||||
|
||||
/**
|
||||
* Distro callback.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface DistroCallback {
|
||||
|
||||
/**
|
||||
* Callback when distro task execute successfully.
|
||||
*/
|
||||
void onSuccess();
|
||||
|
||||
/**
|
||||
* Callback when distro task execute failed.
|
||||
*
|
||||
* @param throwable throwable if execute failed caused by exception
|
||||
*/
|
||||
void onFailed(Throwable throwable);
|
||||
}
|
||||
@@ -1,76 +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.core.distributed.distro.component;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Distro component holder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
@Component
|
||||
public class DistroComponentHolder {
|
||||
|
||||
private final Map<String, DistroTransportAgent> transportAgentMap = new HashMap<>();
|
||||
|
||||
private final Map<String, DistroDataStorage> dataStorageMap = new HashMap<>();
|
||||
|
||||
private final Map<String, DistroFailedTaskHandler> failedTaskHandlerMap = new HashMap<>();
|
||||
|
||||
private final Map<String, DistroDataProcessor> dataProcessorMap = new HashMap<>();
|
||||
|
||||
public DistroTransportAgent findTransportAgent(String type) {
|
||||
return transportAgentMap.get(type);
|
||||
}
|
||||
|
||||
public void registerTransportAgent(String type, DistroTransportAgent transportAgent) {
|
||||
transportAgentMap.put(type, transportAgent);
|
||||
}
|
||||
|
||||
public DistroDataStorage findDataStorage(String type) {
|
||||
return dataStorageMap.get(type);
|
||||
}
|
||||
|
||||
public void registerDataStorage(String type, DistroDataStorage dataStorage) {
|
||||
dataStorageMap.put(type, dataStorage);
|
||||
}
|
||||
|
||||
public Set<String> getDataStorageTypes() {
|
||||
return dataStorageMap.keySet();
|
||||
}
|
||||
|
||||
public DistroFailedTaskHandler findFailedTaskHandler(String type) {
|
||||
return failedTaskHandlerMap.get(type);
|
||||
}
|
||||
|
||||
public void registerFailedTaskHandler(String type, DistroFailedTaskHandler failedTaskHandler) {
|
||||
failedTaskHandlerMap.put(type, failedTaskHandler);
|
||||
}
|
||||
|
||||
public void registerDataProcessor(DistroDataProcessor dataProcessor) {
|
||||
dataProcessorMap.putIfAbsent(dataProcessor.processType(), dataProcessor);
|
||||
}
|
||||
|
||||
public DistroDataProcessor findDataProcessor(String processType) {
|
||||
return dataProcessorMap.get(processType);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +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.core.distributed.distro.component;
|
||||
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
|
||||
/**
|
||||
* Distro data processor.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface DistroDataProcessor {
|
||||
|
||||
/**
|
||||
* Process type of this processor.
|
||||
*
|
||||
* @return type of this processor
|
||||
*/
|
||||
String processType();
|
||||
|
||||
/**
|
||||
* Process received data.
|
||||
*
|
||||
* @param distroData received data
|
||||
* @return true if process data successfully, otherwise false
|
||||
*/
|
||||
boolean processData(DistroData distroData);
|
||||
|
||||
/**
|
||||
* Process received verify data.
|
||||
*
|
||||
* @param distroData verify data
|
||||
* @param sourceAddress source server address, might be get data from source server
|
||||
* @return true if the data is available, otherwise false
|
||||
*/
|
||||
boolean processVerifyData(DistroData distroData, String sourceAddress);
|
||||
|
||||
/**
|
||||
* Process snapshot data.
|
||||
*
|
||||
* @param distroData snapshot data
|
||||
* @return true if process data successfully, otherwise false
|
||||
*/
|
||||
boolean processSnapshot(DistroData distroData);
|
||||
}
|
||||
@@ -1,66 +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.core.distributed.distro.component;
|
||||
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Distro data storage.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface DistroDataStorage {
|
||||
|
||||
/**
|
||||
* Set this distro data storage has finished initial step.
|
||||
*/
|
||||
void finishInitial();
|
||||
|
||||
/**
|
||||
* Whether this distro data is finished initial.
|
||||
*
|
||||
* <p>If not finished, this data storage should not send verify data to other node.
|
||||
*
|
||||
* @return {@code true} if finished, otherwise false
|
||||
*/
|
||||
boolean isFinishInitial();
|
||||
|
||||
/**
|
||||
* Get distro datum.
|
||||
*
|
||||
* @param distroKey key of distro datum
|
||||
* @return need to sync datum
|
||||
*/
|
||||
DistroData getDistroData(DistroKey distroKey);
|
||||
|
||||
/**
|
||||
* Get all distro datum snapshot.
|
||||
*
|
||||
* @return all datum
|
||||
*/
|
||||
DistroData getDatumSnapshot();
|
||||
|
||||
/**
|
||||
* Get verify datum.
|
||||
*
|
||||
* @return verify datum
|
||||
*/
|
||||
List<DistroData> getVerifyData();
|
||||
}
|
||||
@@ -1,36 +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.core.distributed.distro.component;
|
||||
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
|
||||
/**
|
||||
* Distro failed task handler.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface DistroFailedTaskHandler {
|
||||
|
||||
/**
|
||||
* Build retry task when distro task execute failed.
|
||||
*
|
||||
* @param distroKey distro key of failed task
|
||||
* @param action action of task
|
||||
*/
|
||||
void retry(DistroKey distroKey, DataOperation action);
|
||||
}
|
||||
@@ -1,92 +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.core.distributed.distro.component;
|
||||
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
|
||||
/**
|
||||
* Distro transport agent.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface DistroTransportAgent {
|
||||
|
||||
/**
|
||||
* Whether support transport data with callback.
|
||||
*
|
||||
* @return true if support, otherwise false
|
||||
*/
|
||||
boolean supportCallbackTransport();
|
||||
|
||||
/**
|
||||
* Sync data.
|
||||
*
|
||||
* @param data data
|
||||
* @param targetServer target server
|
||||
* @return true is sync successfully, otherwise false
|
||||
*/
|
||||
boolean syncData(DistroData data, String targetServer);
|
||||
|
||||
/**
|
||||
* Sync data with callback.
|
||||
*
|
||||
* @param data data
|
||||
* @param targetServer target server
|
||||
* @param callback callback
|
||||
* @throws UnsupportedOperationException if method supportCallbackTransport is false, should throw {@code
|
||||
* UnsupportedOperationException}
|
||||
*/
|
||||
void syncData(DistroData data, String targetServer, DistroCallback callback);
|
||||
|
||||
/**
|
||||
* Sync verify data.
|
||||
*
|
||||
* @param verifyData verify data
|
||||
* @param targetServer target server
|
||||
* @return true is verify successfully, otherwise false
|
||||
*/
|
||||
boolean syncVerifyData(DistroData verifyData, String targetServer);
|
||||
|
||||
/**
|
||||
* Sync verify data.
|
||||
*
|
||||
* @param verifyData verify data
|
||||
* @param targetServer target server
|
||||
* @param callback callback
|
||||
* @throws UnsupportedOperationException if method supportCallbackTransport is false, should throw {@code
|
||||
* UnsupportedOperationException}
|
||||
*/
|
||||
void syncVerifyData(DistroData verifyData, String targetServer, DistroCallback callback);
|
||||
|
||||
/**
|
||||
* get Data from target server.
|
||||
*
|
||||
* @param key key of data
|
||||
* @param targetServer target server
|
||||
* @return distro data
|
||||
*/
|
||||
DistroData getData(DistroKey key, String targetServer);
|
||||
|
||||
/**
|
||||
* Get all datum snapshot from target server.
|
||||
*
|
||||
* @param targetServer target server.
|
||||
* @return distro data
|
||||
*/
|
||||
DistroData getDatumSnapshot(String targetServer);
|
||||
}
|
||||
@@ -1,65 +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.core.distributed.distro.entity;
|
||||
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
|
||||
/**
|
||||
* Distro data.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroData {
|
||||
|
||||
private DistroKey distroKey;
|
||||
|
||||
private DataOperation type;
|
||||
|
||||
private byte[] content;
|
||||
|
||||
public DistroData() {
|
||||
}
|
||||
|
||||
public DistroData(DistroKey distroKey, byte[] content) {
|
||||
this.distroKey = distroKey;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public DistroKey getDistroKey() {
|
||||
return distroKey;
|
||||
}
|
||||
|
||||
public void setDistroKey(DistroKey distroKey) {
|
||||
this.distroKey = distroKey;
|
||||
}
|
||||
|
||||
public DataOperation getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(DataOperation type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(byte[] content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +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.core.distributed.distro.entity;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Distro key.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroKey {
|
||||
|
||||
private String resourceKey;
|
||||
|
||||
private String resourceType;
|
||||
|
||||
private String targetServer;
|
||||
|
||||
public DistroKey() {
|
||||
}
|
||||
|
||||
public DistroKey(String resourceKey, String resourceType) {
|
||||
this.resourceKey = resourceKey;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public DistroKey(String resourceKey, String resourceType, String targetServer) {
|
||||
this.resourceKey = resourceKey;
|
||||
this.resourceType = resourceType;
|
||||
this.targetServer = targetServer;
|
||||
}
|
||||
|
||||
public String getResourceKey() {
|
||||
return resourceKey;
|
||||
}
|
||||
|
||||
public void setResourceKey(String resourceKey) {
|
||||
this.resourceKey = resourceKey;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getTargetServer() {
|
||||
return targetServer;
|
||||
}
|
||||
|
||||
public void setTargetServer(String targetServer) {
|
||||
this.targetServer = targetServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
DistroKey distroKey = (DistroKey) o;
|
||||
return Objects.equals(resourceKey, distroKey.resourceKey) && Objects
|
||||
.equals(resourceType, distroKey.resourceType) && Objects.equals(targetServer, distroKey.targetServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(resourceKey, resourceType, targetServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DistroKey{" + "resourceKey='" + resourceKey + '\'' + ", resourceType='" + resourceType + '\''
|
||||
+ ", targetServer='" + targetServer + '\'' + '}';
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.core.distributed.distro.exception;
|
||||
|
||||
/**
|
||||
* Distro exception.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1711141952413139786L;
|
||||
|
||||
public DistroException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DistroException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "[DISTRO-EXCEPTION]" + super.getMessage();
|
||||
}
|
||||
}
|
||||
@@ -1,80 +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.distributed.distro.monitor;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Distro record for monitor.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroRecord {
|
||||
|
||||
private final String type;
|
||||
|
||||
private final AtomicLong totalSyncCount;
|
||||
|
||||
private final AtomicLong successfulSyncCount;
|
||||
|
||||
private final AtomicLong failedSyncCount;
|
||||
|
||||
private final AtomicInteger failedVerifyCount;
|
||||
|
||||
public DistroRecord(String type) {
|
||||
this.type = type;
|
||||
this.totalSyncCount = new AtomicLong();
|
||||
this.successfulSyncCount = new AtomicLong();
|
||||
this.failedSyncCount = new AtomicLong();
|
||||
this.failedVerifyCount = new AtomicInteger();
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void syncSuccess() {
|
||||
successfulSyncCount.incrementAndGet();
|
||||
totalSyncCount.incrementAndGet();
|
||||
}
|
||||
|
||||
public void syncFail() {
|
||||
failedSyncCount.incrementAndGet();
|
||||
totalSyncCount.incrementAndGet();
|
||||
}
|
||||
|
||||
public void verifyFail() {
|
||||
failedVerifyCount.incrementAndGet();
|
||||
}
|
||||
|
||||
public long getTotalSyncCount() {
|
||||
return totalSyncCount.get();
|
||||
}
|
||||
|
||||
public long getSuccessfulSyncCount() {
|
||||
return successfulSyncCount.get();
|
||||
}
|
||||
|
||||
public long getFailedSyncCount() {
|
||||
return failedSyncCount.get();
|
||||
}
|
||||
|
||||
public int getFailedVerifyCount() {
|
||||
return failedVerifyCount.get();
|
||||
}
|
||||
}
|
||||
@@ -1,76 +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.distributed.distro.monitor;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Distro records holder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroRecordsHolder {
|
||||
|
||||
private static final DistroRecordsHolder INSTANCE = new DistroRecordsHolder();
|
||||
|
||||
private final ConcurrentMap<String, DistroRecord> distroRecords;
|
||||
|
||||
private DistroRecordsHolder() {
|
||||
distroRecords = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public static DistroRecordsHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public Optional<DistroRecord> getRecordIfExist(String type) {
|
||||
return Optional.ofNullable(distroRecords.get(type));
|
||||
}
|
||||
|
||||
public DistroRecord getRecord(String type) {
|
||||
distroRecords.computeIfAbsent(type, s -> new DistroRecord(type));
|
||||
return distroRecords.get(type);
|
||||
}
|
||||
|
||||
public long getTotalSyncCount() {
|
||||
final AtomicLong result = new AtomicLong();
|
||||
distroRecords.forEach((s, distroRecord) -> result.addAndGet(distroRecord.getTotalSyncCount()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
public long getSuccessfulSyncCount() {
|
||||
final AtomicLong result = new AtomicLong();
|
||||
distroRecords.forEach((s, distroRecord) -> result.addAndGet(distroRecord.getSuccessfulSyncCount()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
public long getFailedSyncCount() {
|
||||
final AtomicLong result = new AtomicLong();
|
||||
distroRecords.forEach((s, distroRecord) -> result.addAndGet(distroRecord.getFailedSyncCount()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
public int getFailedVerifyCount() {
|
||||
final AtomicInteger result = new AtomicInteger();
|
||||
distroRecords.forEach((s, distroRecord) -> result.addAndGet(distroRecord.getFailedVerifyCount()));
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +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.core.distributed.distro.task;
|
||||
|
||||
import com.alibaba.nacos.common.task.NacosTaskProcessor;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTaskExecuteEngine;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.delay.DistroDelayTaskProcessor;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.execute.DistroExecuteTaskExecuteEngine;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Distro task engine holder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
@Component
|
||||
public class DistroTaskEngineHolder {
|
||||
|
||||
private final DistroDelayTaskExecuteEngine delayTaskExecuteEngine = new DistroDelayTaskExecuteEngine();
|
||||
|
||||
private final DistroExecuteTaskExecuteEngine executeWorkersManager = new DistroExecuteTaskExecuteEngine();
|
||||
|
||||
public DistroTaskEngineHolder(DistroComponentHolder distroComponentHolder) {
|
||||
DistroDelayTaskProcessor defaultDelayTaskProcessor = new DistroDelayTaskProcessor(this, distroComponentHolder);
|
||||
delayTaskExecuteEngine.setDefaultTaskProcessor(defaultDelayTaskProcessor);
|
||||
}
|
||||
|
||||
public DistroDelayTaskExecuteEngine getDelayTaskExecuteEngine() {
|
||||
return delayTaskExecuteEngine;
|
||||
}
|
||||
|
||||
public DistroExecuteTaskExecuteEngine getExecuteWorkersManager() {
|
||||
return executeWorkersManager;
|
||||
}
|
||||
|
||||
public void registerNacosTaskProcessor(Object key, NacosTaskProcessor nacosTaskProcessor) {
|
||||
this.delayTaskExecuteEngine.addProcessor(key, nacosTaskProcessor);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +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.core.distributed.distro.task.delay;
|
||||
|
||||
import com.alibaba.nacos.common.task.AbstractDelayTask;
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
|
||||
/**
|
||||
* Distro delay task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroDelayTask extends AbstractDelayTask {
|
||||
|
||||
private final DistroKey distroKey;
|
||||
|
||||
private DataOperation action;
|
||||
|
||||
private long createTime;
|
||||
|
||||
public DistroDelayTask(DistroKey distroKey, long delayTime) {
|
||||
this(distroKey, DataOperation.CHANGE, delayTime);
|
||||
}
|
||||
|
||||
public DistroDelayTask(DistroKey distroKey, DataOperation action, long delayTime) {
|
||||
this.distroKey = distroKey;
|
||||
this.action = action;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
setLastProcessTime(createTime);
|
||||
setTaskInterval(delayTime);
|
||||
}
|
||||
|
||||
public DistroKey getDistroKey() {
|
||||
return distroKey;
|
||||
}
|
||||
|
||||
public DataOperation getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(AbstractDelayTask task) {
|
||||
if (!(task instanceof DistroDelayTask)) {
|
||||
return;
|
||||
}
|
||||
DistroDelayTask oldTask = (DistroDelayTask) task;
|
||||
if (!action.equals(oldTask.getAction()) && createTime < oldTask.getCreateTime()) {
|
||||
action = oldTask.getAction();
|
||||
createTime = oldTask.getCreateTime();
|
||||
}
|
||||
setLastProcessTime(oldTask.getLastProcessTime());
|
||||
}
|
||||
}
|
||||
@@ -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.core.distributed.distro.task.delay;
|
||||
|
||||
import com.alibaba.nacos.common.task.NacosTaskProcessor;
|
||||
import com.alibaba.nacos.common.task.engine.NacosDelayTaskExecuteEngine;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
/**
|
||||
* Distro delay task execute engine.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroDelayTaskExecuteEngine extends NacosDelayTaskExecuteEngine {
|
||||
|
||||
public DistroDelayTaskExecuteEngine() {
|
||||
super(DistroDelayTaskExecuteEngine.class.getName(), Loggers.DISTRO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProcessor(Object key, NacosTaskProcessor taskProcessor) {
|
||||
Object actualKey = getActualKey(key);
|
||||
super.addProcessor(actualKey, taskProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NacosTaskProcessor getProcessor(Object key) {
|
||||
Object actualKey = getActualKey(key);
|
||||
return super.getProcessor(actualKey);
|
||||
}
|
||||
|
||||
private Object getActualKey(Object key) {
|
||||
return key instanceof DistroKey ? ((DistroKey) key).getResourceType() : key;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +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.core.distributed.distro.task.delay;
|
||||
|
||||
import com.alibaba.nacos.common.task.NacosTask;
|
||||
import com.alibaba.nacos.common.task.NacosTaskProcessor;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.DistroTaskEngineHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.execute.DistroSyncChangeTask;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.execute.DistroSyncDeleteTask;
|
||||
|
||||
/**
|
||||
* Distro delay task processor.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroDelayTaskProcessor implements NacosTaskProcessor {
|
||||
|
||||
private final DistroTaskEngineHolder distroTaskEngineHolder;
|
||||
|
||||
private final DistroComponentHolder distroComponentHolder;
|
||||
|
||||
public DistroDelayTaskProcessor(DistroTaskEngineHolder distroTaskEngineHolder,
|
||||
DistroComponentHolder distroComponentHolder) {
|
||||
this.distroTaskEngineHolder = distroTaskEngineHolder;
|
||||
this.distroComponentHolder = distroComponentHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(NacosTask task) {
|
||||
if (!(task instanceof DistroDelayTask)) {
|
||||
return true;
|
||||
}
|
||||
DistroDelayTask distroDelayTask = (DistroDelayTask) task;
|
||||
DistroKey distroKey = distroDelayTask.getDistroKey();
|
||||
switch (distroDelayTask.getAction()) {
|
||||
case DELETE:
|
||||
DistroSyncDeleteTask syncDeleteTask = new DistroSyncDeleteTask(distroKey, distroComponentHolder);
|
||||
distroTaskEngineHolder.getExecuteWorkersManager().addTask(distroKey, syncDeleteTask);
|
||||
return true;
|
||||
case CHANGE:
|
||||
case ADD:
|
||||
DistroSyncChangeTask syncChangeTask = new DistroSyncChangeTask(distroKey, distroComponentHolder);
|
||||
distroTaskEngineHolder.getExecuteWorkersManager().addTask(distroKey, syncChangeTask);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,138 +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.core.distributed.distro.task.execute;
|
||||
|
||||
import com.alibaba.nacos.common.task.AbstractExecuteTask;
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroFailedTaskHandler;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
import com.alibaba.nacos.core.distributed.distro.monitor.DistroRecord;
|
||||
import com.alibaba.nacos.core.distributed.distro.monitor.DistroRecordsHolder;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
/**
|
||||
* Abstract distro execute task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public abstract class AbstractDistroExecuteTask extends AbstractExecuteTask {
|
||||
|
||||
private final DistroKey distroKey;
|
||||
|
||||
private final DistroComponentHolder distroComponentHolder;
|
||||
|
||||
protected AbstractDistroExecuteTask(DistroKey distroKey, DistroComponentHolder distroComponentHolder) {
|
||||
this.distroKey = distroKey;
|
||||
this.distroComponentHolder = distroComponentHolder;
|
||||
}
|
||||
|
||||
protected DistroKey getDistroKey() {
|
||||
return distroKey;
|
||||
}
|
||||
|
||||
protected DistroComponentHolder getDistroComponentHolder() {
|
||||
return distroComponentHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String type = getDistroKey().getResourceType();
|
||||
DistroTransportAgent transportAgent = distroComponentHolder.findTransportAgent(type);
|
||||
if (null == transportAgent) {
|
||||
Loggers.DISTRO.warn("No found transport agent for type [{}]", type);
|
||||
return;
|
||||
}
|
||||
Loggers.DISTRO.info("[DISTRO-START] {}", toString());
|
||||
if (transportAgent.supportCallbackTransport()) {
|
||||
doExecuteWithCallback(new DistroExecuteCallback());
|
||||
} else {
|
||||
executeDistroTask();
|
||||
}
|
||||
}
|
||||
|
||||
private void executeDistroTask() {
|
||||
try {
|
||||
boolean result = doExecute();
|
||||
if (!result) {
|
||||
handleFailedTask();
|
||||
}
|
||||
Loggers.DISTRO.info("[DISTRO-END] {} result: {}", toString(), result);
|
||||
} catch (Exception e) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Sync data change failed.", e);
|
||||
handleFailedTask();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link DataOperation} for current task.
|
||||
*
|
||||
* @return data operation
|
||||
*/
|
||||
protected abstract DataOperation getDataOperation();
|
||||
|
||||
/**
|
||||
* Do execute for different sub class.
|
||||
*
|
||||
* @return result of execute
|
||||
*/
|
||||
protected abstract boolean doExecute();
|
||||
|
||||
/**
|
||||
* Do execute with callback for different sub class.
|
||||
*
|
||||
* @param callback callback
|
||||
*/
|
||||
protected abstract void doExecuteWithCallback(DistroCallback callback);
|
||||
|
||||
/**
|
||||
* Handle failed task.
|
||||
*/
|
||||
protected void handleFailedTask() {
|
||||
String type = getDistroKey().getResourceType();
|
||||
DistroFailedTaskHandler failedTaskHandler = distroComponentHolder.findFailedTaskHandler(type);
|
||||
if (null == failedTaskHandler) {
|
||||
Loggers.DISTRO.warn("[DISTRO] Can't find failed task for type {}, so discarded", type);
|
||||
return;
|
||||
}
|
||||
failedTaskHandler.retry(getDistroKey(), getDataOperation());
|
||||
}
|
||||
|
||||
private class DistroExecuteCallback implements DistroCallback {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
DistroRecord distroRecord = DistroRecordsHolder.getInstance().getRecord(getDistroKey().getResourceType());
|
||||
distroRecord.syncSuccess();
|
||||
Loggers.DISTRO.info("[DISTRO-END] {} result: true", getDistroKey().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(Throwable throwable) {
|
||||
DistroRecord distroRecord = DistroRecordsHolder.getInstance().getRecord(getDistroKey().getResourceType());
|
||||
distroRecord.syncFail();
|
||||
if (null == throwable) {
|
||||
Loggers.DISTRO.info("[DISTRO-END] {} result: false", getDistroKey().toString());
|
||||
} else {
|
||||
Loggers.DISTRO.warn("[DISTRO] Sync data change failed. key: {}", getDistroKey().toString(), throwable);
|
||||
}
|
||||
handleFailedTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +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.core.distributed.distro.task.execute;
|
||||
|
||||
import com.alibaba.nacos.common.task.engine.NacosExecuteTaskExecuteEngine;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
/**
|
||||
* Distro execute task execute engine.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroExecuteTaskExecuteEngine extends NacosExecuteTaskExecuteEngine {
|
||||
|
||||
public DistroExecuteTaskExecuteEngine() {
|
||||
super(DistroExecuteTaskExecuteEngine.class.getSimpleName(), Loggers.DISTRO);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +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.core.distributed.distro.task.execute;
|
||||
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
/**
|
||||
* Distro sync change task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroSyncChangeTask extends AbstractDistroExecuteTask {
|
||||
|
||||
private static final DataOperation OPERATION = DataOperation.CHANGE;
|
||||
|
||||
public DistroSyncChangeTask(DistroKey distroKey, DistroComponentHolder distroComponentHolder) {
|
||||
super(distroKey, distroComponentHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataOperation getDataOperation() {
|
||||
return OPERATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doExecute() {
|
||||
String type = getDistroKey().getResourceType();
|
||||
DistroData distroData = getDistroData(type);
|
||||
if (null == distroData) {
|
||||
Loggers.DISTRO.warn("[DISTRO] {} with null data to sync, skip", toString());
|
||||
return true;
|
||||
}
|
||||
return getDistroComponentHolder().findTransportAgent(type)
|
||||
.syncData(distroData, getDistroKey().getTargetServer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecuteWithCallback(DistroCallback callback) {
|
||||
String type = getDistroKey().getResourceType();
|
||||
DistroData distroData = getDistroData(type);
|
||||
if (null == distroData) {
|
||||
Loggers.DISTRO.warn("[DISTRO] {} with null data to sync, skip", toString());
|
||||
return;
|
||||
}
|
||||
getDistroComponentHolder().findTransportAgent(type)
|
||||
.syncData(distroData, getDistroKey().getTargetServer(), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DistroSyncChangeTask for " + getDistroKey().toString();
|
||||
}
|
||||
|
||||
private DistroData getDistroData(String type) {
|
||||
DistroData result = getDistroComponentHolder().findDataStorage(type).getDistroData(getDistroKey());
|
||||
if (null != result) {
|
||||
result.setType(OPERATION);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +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.core.distributed.distro.task.execute;
|
||||
|
||||
import com.alibaba.nacos.consistency.DataOperation;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroKey;
|
||||
|
||||
/**
|
||||
* Distro sync delete task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroSyncDeleteTask extends AbstractDistroExecuteTask {
|
||||
|
||||
private static final DataOperation OPERATION = DataOperation.DELETE;
|
||||
|
||||
public DistroSyncDeleteTask(DistroKey distroKey, DistroComponentHolder distroComponentHolder) {
|
||||
super(distroKey, distroComponentHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataOperation getDataOperation() {
|
||||
return OPERATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doExecute() {
|
||||
String type = getDistroKey().getResourceType();
|
||||
DistroData distroData = new DistroData();
|
||||
distroData.setDistroKey(getDistroKey());
|
||||
distroData.setType(OPERATION);
|
||||
return getDistroComponentHolder().findTransportAgent(type)
|
||||
.syncData(distroData, getDistroKey().getTargetServer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecuteWithCallback(DistroCallback callback) {
|
||||
String type = getDistroKey().getResourceType();
|
||||
DistroData distroData = new DistroData();
|
||||
distroData.setDistroKey(getDistroKey());
|
||||
distroData.setType(OPERATION);
|
||||
getDistroComponentHolder().findTransportAgent(type)
|
||||
.syncData(distroData, getDistroKey().getTargetServer(), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DistroSyncDeleteTask for " + getDistroKey().toString();
|
||||
}
|
||||
}
|
||||
@@ -1,138 +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.core.distributed.distro.task.load;
|
||||
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.distro.DistroConfig;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroDataProcessor;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.utils.GlobalExecutor;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Distro load data task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroLoadDataTask implements Runnable {
|
||||
|
||||
private final ServerMemberManager memberManager;
|
||||
|
||||
private final DistroComponentHolder distroComponentHolder;
|
||||
|
||||
private final DistroConfig distroConfig;
|
||||
|
||||
private final DistroCallback loadCallback;
|
||||
|
||||
private final Map<String, Boolean> loadCompletedMap;
|
||||
|
||||
public DistroLoadDataTask(ServerMemberManager memberManager, DistroComponentHolder distroComponentHolder,
|
||||
DistroConfig distroConfig, DistroCallback loadCallback) {
|
||||
this.memberManager = memberManager;
|
||||
this.distroComponentHolder = distroComponentHolder;
|
||||
this.distroConfig = distroConfig;
|
||||
this.loadCallback = loadCallback;
|
||||
loadCompletedMap = new HashMap<>(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
load();
|
||||
if (!checkCompleted()) {
|
||||
GlobalExecutor.submitLoadDataTask(this, distroConfig.getLoadDataRetryDelayMillis());
|
||||
} else {
|
||||
loadCallback.onSuccess();
|
||||
Loggers.DISTRO.info("[DISTRO-INIT] load snapshot data success");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
loadCallback.onFailed(e);
|
||||
Loggers.DISTRO.error("[DISTRO-INIT] load snapshot data failed. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void load() throws Exception {
|
||||
while (memberManager.allMembersWithoutSelf().isEmpty()) {
|
||||
Loggers.DISTRO.info("[DISTRO-INIT] waiting server list init...");
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
while (distroComponentHolder.getDataStorageTypes().isEmpty()) {
|
||||
Loggers.DISTRO.info("[DISTRO-INIT] waiting distro data storage register...");
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
for (String each : distroComponentHolder.getDataStorageTypes()) {
|
||||
if (!loadCompletedMap.containsKey(each) || !loadCompletedMap.get(each)) {
|
||||
loadCompletedMap.put(each, loadAllDataSnapshotFromRemote(each));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadAllDataSnapshotFromRemote(String resourceType) {
|
||||
DistroTransportAgent transportAgent = distroComponentHolder.findTransportAgent(resourceType);
|
||||
DistroDataProcessor dataProcessor = distroComponentHolder.findDataProcessor(resourceType);
|
||||
if (null == transportAgent || null == dataProcessor) {
|
||||
Loggers.DISTRO.warn("[DISTRO-INIT] Can't find component for type {}, transportAgent: {}, dataProcessor: {}",
|
||||
resourceType, transportAgent, dataProcessor);
|
||||
return false;
|
||||
}
|
||||
for (Member each : memberManager.allMembersWithoutSelf()) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
Loggers.DISTRO.info("[DISTRO-INIT] load snapshot {} from {}", resourceType, each.getAddress());
|
||||
DistroData distroData = transportAgent.getDatumSnapshot(each.getAddress());
|
||||
Loggers.DISTRO.info("[DISTRO-INIT] it took {} ms to load snapshot {} from {} and snapshot size is {}.",
|
||||
System.currentTimeMillis() - startTime, resourceType, each.getAddress(),
|
||||
getDistroDataLength(distroData));
|
||||
boolean result = dataProcessor.processSnapshot(distroData);
|
||||
Loggers.DISTRO
|
||||
.info("[DISTRO-INIT] load snapshot {} from {} result: {}", resourceType, each.getAddress(),
|
||||
result);
|
||||
if (result) {
|
||||
distroComponentHolder.findDataStorage(resourceType).finishInitial();
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Loggers.DISTRO.error("[DISTRO-INIT] load snapshot {} from {} failed.", resourceType, each.getAddress(), e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getDistroDataLength(DistroData distroData) {
|
||||
return distroData != null && distroData.getContent() != null ? distroData.getContent().length : 0;
|
||||
}
|
||||
|
||||
private boolean checkCompleted() {
|
||||
if (distroComponentHolder.getDataStorageTypes().size() != loadCompletedMap.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Boolean each : loadCompletedMap.values()) {
|
||||
if (!each) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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.distributed.distro.task.verify;
|
||||
|
||||
import com.alibaba.nacos.common.task.AbstractExecuteTask;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroCallback;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.monitor.DistroRecord;
|
||||
import com.alibaba.nacos.core.distributed.distro.monitor.DistroRecordsHolder;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Execute distro verify task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroVerifyExecuteTask extends AbstractExecuteTask {
|
||||
|
||||
private final DistroTransportAgent transportAgent;
|
||||
|
||||
private final List<DistroData> verifyData;
|
||||
|
||||
private final String targetServer;
|
||||
|
||||
private final String resourceType;
|
||||
|
||||
public DistroVerifyExecuteTask(DistroTransportAgent transportAgent, List<DistroData> verifyData,
|
||||
String targetServer, String resourceType) {
|
||||
this.transportAgent = transportAgent;
|
||||
this.verifyData = verifyData;
|
||||
this.targetServer = targetServer;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (DistroData each : verifyData) {
|
||||
try {
|
||||
if (transportAgent.supportCallbackTransport()) {
|
||||
doSyncVerifyDataWithCallback(each);
|
||||
} else {
|
||||
doSyncVerifyData(each);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Loggers.DISTRO
|
||||
.error("[DISTRO-FAILED] verify data for type {} to {} failed.", resourceType, targetServer, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doSyncVerifyDataWithCallback(DistroData data) {
|
||||
transportAgent.syncVerifyData(data, targetServer, new DistroVerifyCallback());
|
||||
}
|
||||
|
||||
private void doSyncVerifyData(DistroData data) {
|
||||
transportAgent.syncVerifyData(data, targetServer);
|
||||
}
|
||||
|
||||
private class DistroVerifyCallback implements DistroCallback {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
if (Loggers.DISTRO.isDebugEnabled()) {
|
||||
Loggers.DISTRO.debug("[DISTRO] verify data for type {} to {} success", resourceType, targetServer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(Throwable throwable) {
|
||||
DistroRecord distroRecord = DistroRecordsHolder.getInstance().getRecord(resourceType);
|
||||
distroRecord.verifyFail();
|
||||
if (Loggers.DISTRO.isDebugEnabled()) {
|
||||
Loggers.DISTRO
|
||||
.debug("[DISTRO-FAILED] verify data for type {} to {} failed.", resourceType, targetServer,
|
||||
throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +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.core.distributed.distro.task.verify;
|
||||
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroComponentHolder;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroDataStorage;
|
||||
import com.alibaba.nacos.core.distributed.distro.component.DistroTransportAgent;
|
||||
import com.alibaba.nacos.core.distributed.distro.entity.DistroData;
|
||||
import com.alibaba.nacos.core.distributed.distro.task.execute.DistroExecuteTaskExecuteEngine;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Timed to start distro verify task.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DistroVerifyTimedTask implements Runnable {
|
||||
|
||||
private final ServerMemberManager serverMemberManager;
|
||||
|
||||
private final DistroComponentHolder distroComponentHolder;
|
||||
|
||||
private final DistroExecuteTaskExecuteEngine executeTaskExecuteEngine;
|
||||
|
||||
public DistroVerifyTimedTask(ServerMemberManager serverMemberManager, DistroComponentHolder distroComponentHolder,
|
||||
DistroExecuteTaskExecuteEngine executeTaskExecuteEngine) {
|
||||
this.serverMemberManager = serverMemberManager;
|
||||
this.distroComponentHolder = distroComponentHolder;
|
||||
this.executeTaskExecuteEngine = executeTaskExecuteEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
List<Member> targetServer = serverMemberManager.allMembersWithoutSelf();
|
||||
if (Loggers.DISTRO.isDebugEnabled()) {
|
||||
Loggers.DISTRO.debug("server list is: {}", targetServer);
|
||||
}
|
||||
for (String each : distroComponentHolder.getDataStorageTypes()) {
|
||||
verifyForDataStorage(each, targetServer);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Loggers.DISTRO.error("[DISTRO-FAILED] verify task failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyForDataStorage(String type, List<Member> targetServer) {
|
||||
DistroDataStorage dataStorage = distroComponentHolder.findDataStorage(type);
|
||||
if (!dataStorage.isFinishInitial()) {
|
||||
Loggers.DISTRO.warn("data storage {} has not finished initial step, do not send verify data",
|
||||
dataStorage.getClass().getSimpleName());
|
||||
return;
|
||||
}
|
||||
List<DistroData> verifyData = dataStorage.getVerifyData();
|
||||
if (null == verifyData || verifyData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Member member : targetServer) {
|
||||
DistroTransportAgent agent = distroComponentHolder.findTransportAgent(type);
|
||||
if (null == agent) {
|
||||
continue;
|
||||
}
|
||||
executeTaskExecuteEngine.addTask(member.getAddress() + type,
|
||||
new DistroVerifyExecuteTask(agent, verifyData, member.getAddress(), type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +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.core.distributed.id;
|
||||
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.consistency.IdGenerator;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Id generator manager.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Component
|
||||
public class IdGeneratorManager {
|
||||
|
||||
private final Map<String, IdGenerator> generatorMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final Function<String, IdGenerator> supplier;
|
||||
|
||||
public IdGeneratorManager() {
|
||||
this.supplier = s -> {
|
||||
IdGenerator generator;
|
||||
Collection<IdGenerator> idGenerators = NacosServiceLoader.load(IdGenerator.class);
|
||||
Iterator<IdGenerator> iterator = idGenerators.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
generator = iterator.next();
|
||||
} else {
|
||||
generator = new SnowFlowerIdGenerator();
|
||||
}
|
||||
generator.init();
|
||||
return generator;
|
||||
};
|
||||
}
|
||||
|
||||
public void register(String resource) {
|
||||
generatorMap.computeIfAbsent(resource, s -> supplier.apply(resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register resources that need to use the ID generator.
|
||||
*
|
||||
* @param resources resource name list
|
||||
*/
|
||||
public void register(String... resources) {
|
||||
for (String resource : resources) {
|
||||
generatorMap.computeIfAbsent(resource, s -> supplier.apply(resource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* request next id by resource name.
|
||||
*
|
||||
* @param resource resource name
|
||||
* @return id
|
||||
*/
|
||||
public long nextId(String resource) {
|
||||
if (generatorMap.containsKey(resource)) {
|
||||
return generatorMap.get(resource).nextId();
|
||||
}
|
||||
throw new NoSuchElementException(
|
||||
"The resource is not registered with the distributed " + "ID resource for the time being.");
|
||||
}
|
||||
|
||||
public Map<String, IdGenerator> getGeneratorMap() {
|
||||
return generatorMap;
|
||||
}
|
||||
}
|
||||
@@ -1,189 +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.core.distributed.id;
|
||||
|
||||
import com.alibaba.nacos.consistency.IdGenerator;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.InetUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* copy from http://www.cluozy.com/home/hexo/2018/08/11/shariding-JDBC-snowflake/.
|
||||
*
|
||||
* <strong>WorkerId</strong> generation policy: Calculate the InetAddress hashcode
|
||||
*
|
||||
* <p>The repeat rate of the dataCenterId, the value of the maximum dataCenterId times the time of each Raft election.
|
||||
* The
|
||||
* time for raft to select the master is generally measured in seconds. If the interval of an election is 5 seconds, it
|
||||
* will take 150 seconds for the DataCenterId to be repeated. This is still based on the situation that the new master
|
||||
* needs to be selected after each election of the Leader
|
||||
*
|
||||
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class SnowFlowerIdGenerator implements IdGenerator {
|
||||
|
||||
private static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";
|
||||
|
||||
/**
|
||||
* Start time intercept (2018-08-05 08:34)
|
||||
*/
|
||||
public static final long EPOCH = 1533429240000L;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SnowFlowerIdGenerator.class);
|
||||
|
||||
// the bits of sequence
|
||||
private static final long SEQUENCE_BITS = 12L;
|
||||
|
||||
// the bits of workerId
|
||||
private static final long WORKER_ID_BITS = 10L;
|
||||
|
||||
// the mask of sequence (111111111111B = 4095)
|
||||
private static final long SEQUENCE_MASK = 4095L;
|
||||
|
||||
// the left shift bits of workerId equals 12 bits
|
||||
private static final long WORKER_ID_LEFT_SHIFT_BITS = 12L;
|
||||
|
||||
// the left shift bits of timestamp equals 22 bits (WORKER_ID_LEFT_SHIFT_BITS + workerId)
|
||||
private static final long TIMESTAMP_LEFT_SHIFT_BITS = 22L;
|
||||
|
||||
// the max of worker ID is 1024
|
||||
private static final long WORKER_ID_MAX_VALUE = 1024L;
|
||||
|
||||
//CLOCK_REALTIME
|
||||
private final long startWallTime = System.currentTimeMillis();
|
||||
|
||||
//CLOCK_MONOTONIC
|
||||
private final long monotonicStartTime = System.nanoTime();
|
||||
|
||||
private long workerId;
|
||||
|
||||
private long sequence;
|
||||
|
||||
private long lastTime;
|
||||
|
||||
private long currentId;
|
||||
|
||||
{
|
||||
long workerId = EnvUtil.getProperty("nacos.core.snowflake.worker-id", Integer.class, -1);
|
||||
|
||||
if (workerId != -1) {
|
||||
this.workerId = workerId;
|
||||
} else {
|
||||
InetAddress address;
|
||||
try {
|
||||
address = InetAddress.getByName(InetUtils.getSelfIP());
|
||||
} catch (final UnknownHostException e) {
|
||||
throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!", e);
|
||||
}
|
||||
byte[] ipAddressByteArray = address.getAddress();
|
||||
this.workerId = (((ipAddressByteArray[ipAddressByteArray.length - 2] & 0B11) << Byte.SIZE) + (
|
||||
ipAddressByteArray[ipAddressByteArray.length - 1] & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
initialize(workerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentId() {
|
||||
return currentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long workerId() {
|
||||
return workerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long nextId() {
|
||||
long currentMillis = currentTimeMillis();
|
||||
if (this.lastTime == currentMillis) {
|
||||
if (0L == (this.sequence = ++this.sequence & 4095L)) {
|
||||
currentMillis = this.waitUntilNextTime(currentMillis);
|
||||
}
|
||||
} else {
|
||||
this.sequence = 0L;
|
||||
}
|
||||
|
||||
this.lastTime = currentMillis;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("{}-{}-{}", (new SimpleDateFormat(DATETIME_PATTERN)).format(new Date(this.lastTime)),
|
||||
workerId, this.sequence);
|
||||
}
|
||||
|
||||
currentId = currentMillis - EPOCH << 22 | workerId << 12 | this.sequence;
|
||||
return currentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> info() {
|
||||
Map<Object, Object> info = new HashMap<>(4);
|
||||
info.put("currentId", currentId);
|
||||
info.put("workerId", workerId);
|
||||
return info;
|
||||
}
|
||||
|
||||
// ==============================Constructors=====================================
|
||||
|
||||
/**
|
||||
* init
|
||||
*
|
||||
* @param workerId worker id (0~1024)
|
||||
*/
|
||||
public void initialize(long workerId) {
|
||||
if (workerId > WORKER_ID_MAX_VALUE || workerId < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("worker Id can't be greater than %d or less than 0, current workId %d",
|
||||
WORKER_ID_MAX_VALUE, workerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block to the next millisecond until a new timestamp is obtained
|
||||
*
|
||||
* @param lastTimestamp The time intercept of the last ID generated
|
||||
* @return Current timestamp
|
||||
*/
|
||||
private long waitUntilNextTime(long lastTimestamp) {
|
||||
long time;
|
||||
time = currentTimeMillis();
|
||||
while (time <= lastTimestamp) {
|
||||
time = currentTimeMillis();
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
private long currentTimeMillis() {
|
||||
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - monotonicStartTime) + startWallTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.JRaftConstants;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.JRaftOps;
|
||||
import com.alipay.sofa.jraft.CliService;
|
||||
import com.alipay.sofa.jraft.Node;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* JRaft operations interface.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public class JRaftMaintainService {
|
||||
|
||||
private final JRaftServer raftServer;
|
||||
|
||||
public JRaftMaintainService(JRaftServer raftServer) {
|
||||
this.raftServer = raftServer;
|
||||
}
|
||||
|
||||
public RestResult<String> execute(String[] args) {
|
||||
return RestResultUtils.failed("not support yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute relevant commands.
|
||||
*
|
||||
* @param args {@link Map}
|
||||
* @return {@link RestResult}
|
||||
*/
|
||||
public RestResult<String> execute(Map<String, String> args) {
|
||||
final CliService cliService = raftServer.getCliService();
|
||||
if (args.containsKey(JRaftConstants.GROUP_ID)) {
|
||||
final String groupId = args.get(JRaftConstants.GROUP_ID);
|
||||
final Node node = raftServer.findNodeByGroup(groupId);
|
||||
return single(cliService, groupId, node, args);
|
||||
}
|
||||
Map<String, JRaftServer.RaftGroupTuple> tupleMap = raftServer.getMultiRaftGroup();
|
||||
for (Map.Entry<String, JRaftServer.RaftGroupTuple> entry : tupleMap.entrySet()) {
|
||||
final String group = entry.getKey();
|
||||
final Node node = entry.getValue().getNode();
|
||||
RestResult<String> result = single(cliService, group, node, args);
|
||||
if (!result.ok()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
|
||||
private RestResult<String> single(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
try {
|
||||
if (node == null) {
|
||||
return RestResultUtils.failed("not this raft group : " + groupId);
|
||||
}
|
||||
final String command = args.get(JRaftConstants.COMMAND_NAME);
|
||||
JRaftOps ops = JRaftOps.sourceOf(command);
|
||||
if (Objects.isNull(ops)) {
|
||||
return RestResultUtils.failed("Not support command : " + command);
|
||||
}
|
||||
return ops.execute(cliService, groupId, node, args);
|
||||
} catch (Throwable ex) {
|
||||
return RestResultUtils.failed(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,227 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.notify.listener.Subscriber;
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
import com.alibaba.nacos.common.utils.MapUtil;
|
||||
import com.alibaba.nacos.common.utils.ThreadUtils;
|
||||
import com.alibaba.nacos.consistency.ProtocolMetaData;
|
||||
import com.alibaba.nacos.consistency.SerializeFactory;
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.cp.CPProtocol;
|
||||
import com.alibaba.nacos.consistency.cp.RequestProcessor4CP;
|
||||
import com.alibaba.nacos.consistency.cp.MetadataKey;
|
||||
import com.alibaba.nacos.consistency.entity.ReadRequest;
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alibaba.nacos.consistency.entity.WriteRequest;
|
||||
import com.alibaba.nacos.core.cluster.Member;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.AbstractConsistencyProtocol;
|
||||
import com.alibaba.nacos.core.distributed.raft.exception.NoSuchRaftGroupException;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alipay.sofa.jraft.Node;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* A concrete implementation of CP protocol: JRaft.
|
||||
*
|
||||
* <pre>
|
||||
* ┌──────────────────────┐
|
||||
* ┌──────────────────────┐ │ ▼
|
||||
* │ ProtocolManager │ │ ┌───────────────────────────┐
|
||||
* └──────────────────────┘ │ │for p in [LogProcessor4CP] │
|
||||
* │ │ └───────────────────────────┘
|
||||
* ▼ │ │
|
||||
* ┌──────────────────────────────────┐ │ ▼
|
||||
* │ discovery LogProcessor4CP │ │ ┌─────────────────┐
|
||||
* └──────────────────────────────────┘ │ │ get p.group() │
|
||||
* │ │ └─────────────────┘
|
||||
* ▼ │ │
|
||||
* ┌─────────────┐ │ │
|
||||
* │ RaftConfig │ │ ▼
|
||||
* └─────────────┘ │ ┌──────────────────────────────┐
|
||||
* │ │ │ create raft group service │
|
||||
* ▼ │ └──────────────────────────────┘
|
||||
* ┌──────────────────┐ │
|
||||
* │ JRaftProtocol │ │
|
||||
* └──────────────────┘ │
|
||||
* │ │
|
||||
* init() │
|
||||
* │ │
|
||||
* ▼ │
|
||||
* ┌─────────────────┐ │
|
||||
* │ JRaftServer │ │
|
||||
* └─────────────────┘ │
|
||||
* │ │
|
||||
* │ │
|
||||
* ▼ │
|
||||
* ┌────────────────────┐ │
|
||||
* │JRaftServer.start() │ │
|
||||
* └────────────────────┘ │
|
||||
* │ │
|
||||
* └──────────────────┘
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class JRaftProtocol extends AbstractConsistencyProtocol<RaftConfig, RequestProcessor4CP>
|
||||
implements CPProtocol<RaftConfig, RequestProcessor4CP> {
|
||||
|
||||
private final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
private final AtomicBoolean shutdowned = new AtomicBoolean(false);
|
||||
|
||||
private final Serializer serializer = SerializeFactory.getDefault();
|
||||
|
||||
private RaftConfig raftConfig;
|
||||
|
||||
private JRaftServer raftServer;
|
||||
|
||||
private JRaftMaintainService jRaftMaintainService;
|
||||
|
||||
private ServerMemberManager memberManager;
|
||||
|
||||
public JRaftProtocol(ServerMemberManager memberManager) throws Exception {
|
||||
this.memberManager = memberManager;
|
||||
this.raftServer = new JRaftServer();
|
||||
this.jRaftMaintainService = new JRaftMaintainService(raftServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(RaftConfig config) {
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
this.raftConfig = config;
|
||||
NotifyCenter.registerToSharePublisher(RaftEvent.class);
|
||||
this.raftServer.init(this.raftConfig);
|
||||
this.raftServer.start();
|
||||
|
||||
// There is only one consumer to ensure that the internal consumption
|
||||
// is sequential and there is no concurrent competition
|
||||
NotifyCenter.registerSubscriber(new Subscriber<RaftEvent>() {
|
||||
@Override
|
||||
public void onEvent(RaftEvent event) {
|
||||
Loggers.RAFT.info("This Raft event changes : {}", event);
|
||||
final String groupId = event.getGroupId();
|
||||
Map<String, Map<String, Object>> value = new HashMap<>();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
final String leader = event.getLeader();
|
||||
final Long term = event.getTerm();
|
||||
final List<String> raftClusterInfo = event.getRaftClusterInfo();
|
||||
final String errMsg = event.getErrMsg();
|
||||
|
||||
// Leader information needs to be selectively updated. If it is valid data,
|
||||
// the information in the protocol metadata is updated.
|
||||
MapUtil.putIfValNoEmpty(properties, MetadataKey.LEADER_META_DATA, leader);
|
||||
MapUtil.putIfValNoNull(properties, MetadataKey.TERM_META_DATA, term);
|
||||
MapUtil.putIfValNoEmpty(properties, MetadataKey.RAFT_GROUP_MEMBER, raftClusterInfo);
|
||||
MapUtil.putIfValNoEmpty(properties, MetadataKey.ERR_MSG, errMsg);
|
||||
|
||||
value.put(groupId, properties);
|
||||
metaData.load(value);
|
||||
|
||||
// The metadata information is injected into the metadata information of the node
|
||||
injectProtocolMetaData(metaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Event> subscribeType() {
|
||||
return RaftEvent.class;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRequestProcessors(Collection<RequestProcessor4CP> processors) {
|
||||
raftServer.createMultiRaftGroup(processors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getData(ReadRequest request) throws Exception {
|
||||
CompletableFuture<Response> future = aGetData(request);
|
||||
return future.get(5_000L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Response> aGetData(ReadRequest request) {
|
||||
return raftServer.get(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response write(WriteRequest request) throws Exception {
|
||||
CompletableFuture<Response> future = writeAsync(request);
|
||||
// Here you wait for 10 seconds, as long as possible, for the request to complete
|
||||
return future.get(10_000L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Response> writeAsync(WriteRequest request) {
|
||||
return raftServer.commit(request.getGroup(), request, new CompletableFuture<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void memberChange(Set<String> addresses) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (this.raftServer.peerChange(jRaftMaintainService, addresses)) {
|
||||
return;
|
||||
}
|
||||
ThreadUtils.sleep(100L);
|
||||
}
|
||||
Loggers.RAFT.warn("peer removal failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (initialized.get() && shutdowned.compareAndSet(false, true)) {
|
||||
Loggers.RAFT.info("shutdown jraft server");
|
||||
raftServer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResult<String> execute(Map<String, String> args) {
|
||||
return jRaftMaintainService.execute(args);
|
||||
}
|
||||
|
||||
private void injectProtocolMetaData(ProtocolMetaData metaData) {
|
||||
Member member = memberManager.getSelf();
|
||||
member.setExtendVal("raftMetaData", metaData);
|
||||
memberManager.update(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeader(String group) {
|
||||
Node node = raftServer.findNodeByGroup(group);
|
||||
if (node == null) {
|
||||
throw new NoSuchRaftGroupException(group);
|
||||
}
|
||||
return node.isLeader();
|
||||
}
|
||||
}
|
||||
@@ -1,571 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.JustForTest;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
import com.alibaba.nacos.common.utils.InternetAddressUtil;
|
||||
import com.alibaba.nacos.common.utils.LoggerUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.common.utils.ThreadUtils;
|
||||
import com.alibaba.nacos.consistency.ProtoMessageUtil;
|
||||
import com.alibaba.nacos.consistency.RequestProcessor;
|
||||
import com.alibaba.nacos.consistency.SerializeFactory;
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.cp.RequestProcessor4CP;
|
||||
import com.alibaba.nacos.consistency.entity.ReadRequest;
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alibaba.nacos.consistency.exception.ConsistencyException;
|
||||
import com.alibaba.nacos.core.distributed.raft.exception.DuplicateRaftGroupException;
|
||||
import com.alibaba.nacos.core.distributed.raft.exception.JRaftException;
|
||||
import com.alibaba.nacos.core.distributed.raft.exception.NoLeaderException;
|
||||
import com.alibaba.nacos.core.distributed.raft.exception.NoSuchRaftGroupException;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.FailoverClosure;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.FailoverClosureImpl;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.JRaftConstants;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.JRaftUtils;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.RaftExecutor;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.RaftOptionsBuilder;
|
||||
import com.alibaba.nacos.core.monitor.MetricsMonitor;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alipay.sofa.jraft.CliService;
|
||||
import com.alipay.sofa.jraft.Node;
|
||||
import com.alipay.sofa.jraft.RaftGroupService;
|
||||
import com.alipay.sofa.jraft.RaftServiceFactory;
|
||||
import com.alipay.sofa.jraft.RouteTable;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
import com.alipay.sofa.jraft.closure.ReadIndexClosure;
|
||||
import com.alipay.sofa.jraft.conf.Configuration;
|
||||
import com.alipay.sofa.jraft.core.CliServiceImpl;
|
||||
import com.alipay.sofa.jraft.entity.PeerId;
|
||||
import com.alipay.sofa.jraft.entity.Task;
|
||||
import com.alipay.sofa.jraft.error.RaftError;
|
||||
import com.alipay.sofa.jraft.option.CliOptions;
|
||||
import com.alipay.sofa.jraft.option.NodeOptions;
|
||||
import com.alipay.sofa.jraft.option.RaftOptions;
|
||||
import com.alipay.sofa.jraft.rpc.InvokeCallback;
|
||||
import com.alipay.sofa.jraft.rpc.RpcProcessor;
|
||||
import com.alipay.sofa.jraft.rpc.RpcServer;
|
||||
import com.alipay.sofa.jraft.rpc.impl.cli.CliClientServiceImpl;
|
||||
import com.alipay.sofa.jraft.util.BytesUtil;
|
||||
import com.alipay.sofa.jraft.util.Endpoint;
|
||||
import com.google.protobuf.Message;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* JRaft server instance, away from Spring IOC management.
|
||||
*
|
||||
* <p>
|
||||
* Why do we need to create a raft group based on the value of LogProcessor group (), that is, each function module has
|
||||
* its own state machine. Because each LogProcessor corresponds to a different functional module, such as Nacos's naming
|
||||
* module and config module, these two modules are independent of each other and do not affect each other. If we have
|
||||
* only one state machine, it is equal to the log of all functional modules The processing is loaded together. Any
|
||||
* module that has an exception during the log processing and a long block operation will affect the normal operation of
|
||||
* other functional modules.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class JRaftServer {
|
||||
|
||||
// Existential life cycle
|
||||
|
||||
private RpcServer rpcServer;
|
||||
|
||||
private CliClientServiceImpl cliClientService;
|
||||
|
||||
private CliService cliService;
|
||||
|
||||
// Ordinary member variable
|
||||
|
||||
private Map<String, RaftGroupTuple> multiRaftGroup = new ConcurrentHashMap<>();
|
||||
|
||||
private volatile boolean isStarted = false;
|
||||
|
||||
private volatile boolean isShutdown = false;
|
||||
|
||||
private Configuration conf;
|
||||
|
||||
private RpcProcessor userProcessor;
|
||||
|
||||
private NodeOptions nodeOptions;
|
||||
|
||||
private Serializer serializer;
|
||||
|
||||
private Collection<RequestProcessor4CP> processors = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
private String selfIp;
|
||||
|
||||
private int selfPort;
|
||||
|
||||
private RaftConfig raftConfig;
|
||||
|
||||
private PeerId localPeerId;
|
||||
|
||||
private int failoverRetries;
|
||||
|
||||
private int rpcRequestTimeoutMs;
|
||||
|
||||
public JRaftServer() {
|
||||
this.conf = new Configuration();
|
||||
}
|
||||
|
||||
public void setFailoverRetries(int failoverRetries) {
|
||||
this.failoverRetries = failoverRetries;
|
||||
}
|
||||
|
||||
void init(RaftConfig config) {
|
||||
this.raftConfig = config;
|
||||
this.serializer = SerializeFactory.getDefault();
|
||||
Loggers.RAFT.info("Initializes the Raft protocol, raft-config info : {}", config);
|
||||
RaftExecutor.init(config);
|
||||
|
||||
final String self = config.getSelfMember();
|
||||
String[] info = InternetAddressUtil.splitIPPortStr(self);
|
||||
selfIp = info[0];
|
||||
selfPort = Integer.parseInt(info[1]);
|
||||
localPeerId = PeerId.parsePeer(self);
|
||||
nodeOptions = new NodeOptions();
|
||||
|
||||
// Set the election timeout time. The default is 5 seconds.
|
||||
int electionTimeout = Math.max(ConvertUtils.toInt(config.getVal(RaftSysConstants.RAFT_ELECTION_TIMEOUT_MS),
|
||||
RaftSysConstants.DEFAULT_ELECTION_TIMEOUT), RaftSysConstants.DEFAULT_ELECTION_TIMEOUT);
|
||||
|
||||
rpcRequestTimeoutMs = ConvertUtils.toInt(raftConfig.getVal(RaftSysConstants.RAFT_RPC_REQUEST_TIMEOUT_MS),
|
||||
RaftSysConstants.DEFAULT_RAFT_RPC_REQUEST_TIMEOUT_MS);
|
||||
|
||||
nodeOptions.setSharedElectionTimer(true);
|
||||
nodeOptions.setSharedVoteTimer(true);
|
||||
nodeOptions.setSharedStepDownTimer(true);
|
||||
nodeOptions.setSharedSnapshotTimer(true);
|
||||
|
||||
nodeOptions.setElectionTimeoutMs(electionTimeout);
|
||||
RaftOptions raftOptions = RaftOptionsBuilder.initRaftOptions(raftConfig);
|
||||
nodeOptions.setRaftOptions(raftOptions);
|
||||
// open jraft node metrics record function
|
||||
nodeOptions.setEnableMetrics(true);
|
||||
|
||||
CliOptions cliOptions = new CliOptions();
|
||||
|
||||
this.cliService = RaftServiceFactory.createAndInitCliService(cliOptions);
|
||||
this.cliClientService = (CliClientServiceImpl) ((CliServiceImpl) this.cliService).getCliClientService();
|
||||
}
|
||||
|
||||
synchronized void start() {
|
||||
if (!isStarted) {
|
||||
Loggers.RAFT.info("========= The raft protocol is starting... =========");
|
||||
try {
|
||||
// init raft group node
|
||||
com.alipay.sofa.jraft.NodeManager raftNodeManager = com.alipay.sofa.jraft.NodeManager.getInstance();
|
||||
for (String address : raftConfig.getMembers()) {
|
||||
PeerId peerId = PeerId.parsePeer(address);
|
||||
conf.addPeer(peerId);
|
||||
raftNodeManager.addAddress(peerId.getEndpoint());
|
||||
}
|
||||
nodeOptions.setInitialConf(conf);
|
||||
|
||||
rpcServer = JRaftUtils.initRpcServer(this, localPeerId);
|
||||
|
||||
if (!this.rpcServer.init(null)) {
|
||||
Loggers.RAFT.error("Fail to init [BaseRpcServer].");
|
||||
throw new RuntimeException("Fail to init [BaseRpcServer].");
|
||||
}
|
||||
|
||||
// Initialize multi raft group service framework
|
||||
isStarted = true;
|
||||
createMultiRaftGroup(processors);
|
||||
Loggers.RAFT.info("========= The raft protocol start finished... =========");
|
||||
} catch (Exception e) {
|
||||
Loggers.RAFT.error("raft protocol start failure, cause: ", e);
|
||||
throw new JRaftException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void createMultiRaftGroup(Collection<RequestProcessor4CP> processors) {
|
||||
// There is no reason why the LogProcessor cannot be processed because of the synchronization
|
||||
if (!this.isStarted) {
|
||||
this.processors.addAll(processors);
|
||||
return;
|
||||
}
|
||||
|
||||
final String parentPath = Paths.get(EnvUtil.getNacosHome(), "data/protocol/raft").toString();
|
||||
|
||||
for (RequestProcessor4CP processor : processors) {
|
||||
final String groupName = processor.group();
|
||||
if (multiRaftGroup.containsKey(groupName)) {
|
||||
throw new DuplicateRaftGroupException(groupName);
|
||||
}
|
||||
|
||||
// Ensure that each Raft Group has its own configuration and NodeOptions
|
||||
Configuration configuration = conf.copy();
|
||||
NodeOptions copy = nodeOptions.copy();
|
||||
JRaftUtils.initDirectory(parentPath, groupName, copy);
|
||||
|
||||
// Here, the LogProcessor is passed into StateMachine, and when the StateMachine
|
||||
// triggers onApply, the onApply of the LogProcessor is actually called
|
||||
NacosStateMachine machine = new NacosStateMachine(this, processor);
|
||||
|
||||
copy.setFsm(machine);
|
||||
copy.setInitialConf(configuration);
|
||||
|
||||
// Set snapshot interval, default 1800 seconds
|
||||
int doSnapshotInterval = ConvertUtils.toInt(raftConfig.getVal(RaftSysConstants.RAFT_SNAPSHOT_INTERVAL_SECS),
|
||||
RaftSysConstants.DEFAULT_RAFT_SNAPSHOT_INTERVAL_SECS);
|
||||
|
||||
// If the business module does not implement a snapshot processor, cancel the snapshot
|
||||
doSnapshotInterval = CollectionUtils.isEmpty(processor.loadSnapshotOperate()) ? 0 : doSnapshotInterval;
|
||||
|
||||
copy.setSnapshotIntervalSecs(doSnapshotInterval);
|
||||
Loggers.RAFT.info("create raft group : {}", groupName);
|
||||
RaftGroupService raftGroupService = new RaftGroupService(groupName, localPeerId, copy, rpcServer, true);
|
||||
|
||||
// Because BaseRpcServer has been started before, it is not allowed to start again here
|
||||
Node node = raftGroupService.start(false);
|
||||
machine.setNode(node);
|
||||
RouteTable.getInstance().updateConfiguration(groupName, configuration);
|
||||
|
||||
RaftExecutor.executeByCommon(() -> registerSelfToCluster(groupName, localPeerId, configuration));
|
||||
|
||||
// Turn on the leader auto refresh for this group
|
||||
Random random = new Random();
|
||||
long period = nodeOptions.getElectionTimeoutMs() + random.nextInt(5 * 1000);
|
||||
RaftExecutor.scheduleRaftMemberRefreshJob(() -> refreshRouteTable(groupName),
|
||||
nodeOptions.getElectionTimeoutMs(), period, TimeUnit.MILLISECONDS);
|
||||
multiRaftGroup.put(groupName, new RaftGroupTuple(node, processor, raftGroupService, machine));
|
||||
}
|
||||
}
|
||||
|
||||
CompletableFuture<Response> get(final ReadRequest request) {
|
||||
final String group = request.getGroup();
|
||||
CompletableFuture<Response> future = new CompletableFuture<>();
|
||||
final RaftGroupTuple tuple = findTupleByGroup(group);
|
||||
if (Objects.isNull(tuple)) {
|
||||
future.completeExceptionally(new NoSuchRaftGroupException(group));
|
||||
return future;
|
||||
}
|
||||
final Node node = tuple.node;
|
||||
final RequestProcessor processor = tuple.processor;
|
||||
try {
|
||||
node.readIndex(BytesUtil.EMPTY_BYTES, new ReadIndexClosure() {
|
||||
@Override
|
||||
public void run(Status status, long index, byte[] reqCtx) {
|
||||
if (status.isOk()) {
|
||||
try {
|
||||
Response response = processor.onRequest(request);
|
||||
future.complete(response);
|
||||
} catch (Throwable t) {
|
||||
MetricsMonitor.raftReadIndexFailed();
|
||||
future.completeExceptionally(new ConsistencyException(
|
||||
"The conformance protocol is temporarily unavailable for reading", t));
|
||||
}
|
||||
return;
|
||||
}
|
||||
MetricsMonitor.raftReadIndexFailed();
|
||||
Loggers.RAFT.error("ReadIndex has error : {}, go to Leader read.", status.getErrorMsg());
|
||||
MetricsMonitor.raftReadFromLeader();
|
||||
readFromLeader(request, future);
|
||||
}
|
||||
});
|
||||
return future;
|
||||
} catch (Throwable e) {
|
||||
MetricsMonitor.raftReadFromLeader();
|
||||
Loggers.RAFT.warn("Raft linear read failed, go to Leader read logic : {}", e.toString());
|
||||
// run raft read
|
||||
readFromLeader(request, future);
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFromLeader(final ReadRequest request, final CompletableFuture<Response> future) {
|
||||
commit(request.getGroup(), request, future);
|
||||
}
|
||||
|
||||
public CompletableFuture<Response> commit(final String group, final Message data,
|
||||
final CompletableFuture<Response> future) {
|
||||
LoggerUtils.printIfDebugEnabled(Loggers.RAFT, "data requested this time : {}", data);
|
||||
final RaftGroupTuple tuple = findTupleByGroup(group);
|
||||
if (tuple == null) {
|
||||
future.completeExceptionally(new IllegalArgumentException("No corresponding Raft Group found : " + group));
|
||||
return future;
|
||||
}
|
||||
|
||||
FailoverClosureImpl closure = new FailoverClosureImpl(future);
|
||||
|
||||
final Node node = tuple.node;
|
||||
if (node.isLeader()) {
|
||||
// The leader node directly applies this request
|
||||
applyOperation(node, data, closure);
|
||||
} else {
|
||||
// Forward to Leader for request processing
|
||||
invokeToLeader(group, data, rpcRequestTimeoutMs, closure);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add yourself to the Raft cluster
|
||||
*
|
||||
* @param groupId raft group
|
||||
* @param selfIp local raft node address
|
||||
* @param conf {@link Configuration} without self info
|
||||
* @return join success
|
||||
*/
|
||||
void registerSelfToCluster(String groupId, PeerId selfIp, Configuration conf) {
|
||||
for (; ; ) {
|
||||
try {
|
||||
List<PeerId> peerIds = cliService.getPeers(groupId, conf);
|
||||
if (peerIds.contains(selfIp)) {
|
||||
return;
|
||||
}
|
||||
Status status = cliService.addPeer(groupId, conf, selfIp);
|
||||
if (status.isOk()) {
|
||||
return;
|
||||
}
|
||||
Loggers.RAFT.warn("Failed to join the cluster, retry...");
|
||||
} catch (Exception e) {
|
||||
Loggers.RAFT.error("Failed to join the cluster, retry...", e);
|
||||
}
|
||||
ThreadUtils.sleep(1_000L);
|
||||
}
|
||||
}
|
||||
|
||||
protected PeerId getLeader(final String raftGroupId) {
|
||||
return RouteTable.getInstance().selectLeader(raftGroupId);
|
||||
}
|
||||
|
||||
synchronized void shutdown() {
|
||||
if (isShutdown) {
|
||||
return;
|
||||
}
|
||||
isShutdown = true;
|
||||
try {
|
||||
Loggers.RAFT.info("========= The raft protocol is starting to close =========");
|
||||
|
||||
for (Map.Entry<String, RaftGroupTuple> entry : multiRaftGroup.entrySet()) {
|
||||
final RaftGroupTuple tuple = entry.getValue();
|
||||
final Node node = tuple.getNode();
|
||||
tuple.node.shutdown();
|
||||
tuple.raftGroupService.shutdown();
|
||||
}
|
||||
|
||||
cliService.shutdown();
|
||||
cliClientService.shutdown();
|
||||
|
||||
Loggers.RAFT.info("========= The raft protocol has been closed =========");
|
||||
} catch (Throwable t) {
|
||||
Loggers.RAFT.error("There was an error in the raft protocol shutdown, cause: ", t);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyOperation(Node node, Message data, FailoverClosure closure) {
|
||||
final Task task = new Task();
|
||||
task.setDone(new NacosClosure(data, status -> {
|
||||
NacosClosure.NacosStatus nacosStatus = (NacosClosure.NacosStatus) status;
|
||||
closure.setThrowable(nacosStatus.getThrowable());
|
||||
closure.setResponse(nacosStatus.getResponse());
|
||||
closure.run(nacosStatus);
|
||||
}));
|
||||
|
||||
// add request type field at the head of task data.
|
||||
byte[] requestTypeFieldBytes = new byte[2];
|
||||
requestTypeFieldBytes[0] = ProtoMessageUtil.REQUEST_TYPE_FIELD_TAG;
|
||||
if (data instanceof ReadRequest) {
|
||||
requestTypeFieldBytes[1] = ProtoMessageUtil.REQUEST_TYPE_READ;
|
||||
} else {
|
||||
requestTypeFieldBytes[1] = ProtoMessageUtil.REQUEST_TYPE_WRITE;
|
||||
}
|
||||
|
||||
byte[] dataBytes = data.toByteArray();
|
||||
task.setData((ByteBuffer) ByteBuffer.allocate(requestTypeFieldBytes.length + dataBytes.length)
|
||||
.put(requestTypeFieldBytes).put(dataBytes).position(0));
|
||||
node.apply(task);
|
||||
}
|
||||
|
||||
private void invokeToLeader(final String group, final Message request, final int timeoutMillis,
|
||||
FailoverClosure closure) {
|
||||
try {
|
||||
final Endpoint leaderIp = Optional.ofNullable(getLeader(group))
|
||||
.orElseThrow(() -> new NoLeaderException(group)).getEndpoint();
|
||||
cliClientService.getRpcClient().invokeAsync(leaderIp, request, new InvokeCallback() {
|
||||
@Override
|
||||
public void complete(Object o, Throwable ex) {
|
||||
if (Objects.nonNull(ex)) {
|
||||
closure.setThrowable(ex);
|
||||
closure.run(new Status(RaftError.UNKNOWN, ex.getMessage()));
|
||||
return;
|
||||
}
|
||||
if (!((Response)o).getSuccess()) {
|
||||
closure.setThrowable(new IllegalStateException(((Response) o).getErrMsg()));
|
||||
closure.run(new Status(RaftError.UNKNOWN, ((Response) o).getErrMsg()));
|
||||
return;
|
||||
}
|
||||
closure.setResponse((Response) o);
|
||||
closure.run(Status.OK());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor executor() {
|
||||
return RaftExecutor.getRaftCliServiceExecutor();
|
||||
}
|
||||
}, timeoutMillis);
|
||||
} catch (Exception e) {
|
||||
closure.setThrowable(e);
|
||||
closure.run(new Status(RaftError.UNKNOWN, e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
boolean peerChange(JRaftMaintainService maintainService, Set<String> newPeers) {
|
||||
// This is only dealing with node deletion, the Raft protocol, where the node adds itself to the cluster when it starts up
|
||||
Set<String> oldPeers = new HashSet<>(this.raftConfig.getMembers());
|
||||
this.raftConfig.setMembers(localPeerId.toString(), newPeers);
|
||||
oldPeers.removeAll(newPeers);
|
||||
if (oldPeers.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<String> waitRemove = oldPeers;
|
||||
AtomicInteger successCnt = new AtomicInteger(0);
|
||||
multiRaftGroup.forEach(new BiConsumer<String, RaftGroupTuple>() {
|
||||
@Override
|
||||
public void accept(String group, RaftGroupTuple tuple) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put(JRaftConstants.GROUP_ID, group);
|
||||
params.put(JRaftConstants.COMMAND_NAME, JRaftConstants.REMOVE_PEERS);
|
||||
params.put(JRaftConstants.COMMAND_VALUE, StringUtils.join(waitRemove, StringUtils.COMMA));
|
||||
RestResult<String> result = maintainService.execute(params);
|
||||
if (result.ok()) {
|
||||
successCnt.incrementAndGet();
|
||||
} else {
|
||||
Loggers.RAFT.error("Node removal failed : {}", result);
|
||||
}
|
||||
}
|
||||
});
|
||||
return successCnt.get() == multiRaftGroup.size();
|
||||
}
|
||||
|
||||
void refreshRouteTable(String group) {
|
||||
if (isShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String groupName = group;
|
||||
Status status = null;
|
||||
try {
|
||||
RouteTable instance = RouteTable.getInstance();
|
||||
Configuration oldConf = instance.getConfiguration(groupName);
|
||||
String oldLeader = Optional.ofNullable(instance.selectLeader(groupName)).orElse(PeerId.emptyPeer())
|
||||
.getEndpoint().toString();
|
||||
// fix issue #3661 https://github.com/alibaba/nacos/issues/3661
|
||||
status = instance.refreshLeader(this.cliClientService, groupName, rpcRequestTimeoutMs);
|
||||
if (!status.isOk()) {
|
||||
Loggers.RAFT.error("Fail to refresh leader for group : {}, status is : {}", groupName, status);
|
||||
}
|
||||
status = instance.refreshConfiguration(this.cliClientService, groupName, rpcRequestTimeoutMs);
|
||||
if (!status.isOk()) {
|
||||
Loggers.RAFT
|
||||
.error("Fail to refresh route configuration for group : {}, status is : {}", groupName, status);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Loggers.RAFT.error("Fail to refresh raft metadata info for group : {}, error is : {}", groupName, e);
|
||||
}
|
||||
}
|
||||
|
||||
public RaftGroupTuple findTupleByGroup(final String group) {
|
||||
RaftGroupTuple tuple = multiRaftGroup.get(group);
|
||||
return tuple;
|
||||
}
|
||||
|
||||
public Node findNodeByGroup(final String group) {
|
||||
final RaftGroupTuple tuple = multiRaftGroup.get(group);
|
||||
if (Objects.nonNull(tuple)) {
|
||||
return tuple.node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, RaftGroupTuple> getMultiRaftGroup() {
|
||||
return multiRaftGroup;
|
||||
}
|
||||
|
||||
@JustForTest
|
||||
void mockMultiRaftGroup(Map<String, RaftGroupTuple> map) {
|
||||
this.multiRaftGroup = map;
|
||||
}
|
||||
|
||||
CliService getCliService() {
|
||||
return cliService;
|
||||
}
|
||||
|
||||
public static class RaftGroupTuple {
|
||||
|
||||
private RequestProcessor processor;
|
||||
|
||||
private Node node;
|
||||
|
||||
private RaftGroupService raftGroupService;
|
||||
|
||||
private NacosStateMachine machine;
|
||||
|
||||
@JustForTest
|
||||
public RaftGroupTuple() {
|
||||
}
|
||||
|
||||
public RaftGroupTuple(Node node, RequestProcessor processor, RaftGroupService raftGroupService,
|
||||
NacosStateMachine machine) {
|
||||
this.node = node;
|
||||
this.processor = processor;
|
||||
this.raftGroupService = raftGroupService;
|
||||
this.machine = machine;
|
||||
}
|
||||
|
||||
public Node getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public RequestProcessor getProcessor() {
|
||||
return processor;
|
||||
}
|
||||
|
||||
public RaftGroupService getRaftGroupService() {
|
||||
return raftGroupService;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.consistency.snapshot.LocalFileMeta;
|
||||
import com.alipay.sofa.jraft.Closure;
|
||||
import com.alipay.sofa.jraft.entity.LocalFileMetaOutter;
|
||||
import com.alipay.sofa.jraft.storage.snapshot.SnapshotReader;
|
||||
import com.alipay.sofa.jraft.storage.snapshot.SnapshotWriter;
|
||||
import com.google.protobuf.ZeroByteStringHelper;
|
||||
|
||||
/**
|
||||
* JRaft snapshot operation.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
interface JSnapshotOperation {
|
||||
|
||||
/**
|
||||
* do snapshot save operation.
|
||||
*
|
||||
* @param writer {@link SnapshotWriter}
|
||||
* @param done {@link Closure}
|
||||
*/
|
||||
void onSnapshotSave(SnapshotWriter writer, Closure done);
|
||||
|
||||
/**
|
||||
* do snapshot load operation.
|
||||
*
|
||||
* @param reader {@link SnapshotReader}
|
||||
* @return operation label
|
||||
*/
|
||||
boolean onSnapshotLoad(SnapshotReader reader);
|
||||
|
||||
/**
|
||||
* return actually snapshot executor.
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
String info();
|
||||
|
||||
/**
|
||||
* Metadata information for snapshot files.
|
||||
*
|
||||
* @param metadata meta data
|
||||
* @return {@link LocalFileMetaOutter.LocalFileMeta}
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
default LocalFileMetaOutter.LocalFileMeta buildMetadata(final LocalFileMeta metadata) throws Exception {
|
||||
return metadata == null ? null : LocalFileMetaOutter.LocalFileMeta.newBuilder()
|
||||
.setUserMeta(ZeroByteStringHelper.wrap(JacksonUtils.toJsonBytes(metadata))).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,159 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alipay.sofa.jraft.Closure;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
import com.alipay.sofa.jraft.error.RaftError;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
/**
|
||||
* implement jraft closure.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class NacosClosure implements Closure {
|
||||
|
||||
private Message message;
|
||||
|
||||
private Closure closure;
|
||||
|
||||
private NacosStatus nacosStatus = new NacosStatus();
|
||||
|
||||
public NacosClosure(Message message, Closure closure) {
|
||||
this.message = message;
|
||||
this.closure = closure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Status status) {
|
||||
nacosStatus.setStatus(status);
|
||||
closure.run(nacosStatus);
|
||||
clear();
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
message = null;
|
||||
closure = null;
|
||||
nacosStatus = null;
|
||||
}
|
||||
|
||||
public void setResponse(Response response) {
|
||||
this.nacosStatus.setResponse(response);
|
||||
}
|
||||
|
||||
public void setThrowable(Throwable throwable) {
|
||||
this.nacosStatus.setThrowable(throwable);
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
// Pass the Throwable inside the state machine to the outer layer
|
||||
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public static class NacosStatus extends Status {
|
||||
|
||||
private Status status;
|
||||
|
||||
private Response response = null;
|
||||
|
||||
private Throwable throwable = null;
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
status.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOk() {
|
||||
return status.isOk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCode() {
|
||||
return status.getCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCode(int code) {
|
||||
status.setCode(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaftError getRaftError() {
|
||||
return status.getRaftError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setError(int code, String fmt, Object... args) {
|
||||
status.setError(code, fmt, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setError(RaftError error, String fmt, Object... args) {
|
||||
status.setError(error, fmt, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return status.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status copy() {
|
||||
NacosStatus copy = new NacosStatus();
|
||||
copy.status = this.status;
|
||||
copy.response = this.response;
|
||||
copy.throwable = this.throwable;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMsg() {
|
||||
return status.getErrorMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrorMsg(String errMsg) {
|
||||
status.setErrorMsg(errMsg);
|
||||
}
|
||||
|
||||
public Response getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(Response response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
public void setThrowable(Throwable throwable) {
|
||||
this.throwable = throwable;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,321 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.LoggerUtils;
|
||||
import com.alibaba.nacos.consistency.RequestProcessor;
|
||||
import com.alibaba.nacos.consistency.ProtoMessageUtil;
|
||||
import com.alibaba.nacos.consistency.cp.RequestProcessor4CP;
|
||||
import com.alibaba.nacos.consistency.entity.ReadRequest;
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alibaba.nacos.consistency.entity.WriteRequest;
|
||||
import com.alibaba.nacos.consistency.exception.ConsistencyException;
|
||||
import com.alibaba.nacos.consistency.snapshot.LocalFileMeta;
|
||||
import com.alibaba.nacos.consistency.snapshot.Reader;
|
||||
import com.alibaba.nacos.consistency.snapshot.SnapshotOperation;
|
||||
import com.alibaba.nacos.consistency.snapshot.Writer;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.JRaftUtils;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alipay.sofa.jraft.Closure;
|
||||
import com.alipay.sofa.jraft.Iterator;
|
||||
import com.alipay.sofa.jraft.Node;
|
||||
import com.alipay.sofa.jraft.RouteTable;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
import com.alipay.sofa.jraft.conf.Configuration;
|
||||
import com.alipay.sofa.jraft.core.StateMachineAdapter;
|
||||
import com.alipay.sofa.jraft.entity.LeaderChangeContext;
|
||||
import com.alipay.sofa.jraft.entity.LocalFileMetaOutter;
|
||||
import com.alipay.sofa.jraft.error.RaftError;
|
||||
import com.alipay.sofa.jraft.error.RaftException;
|
||||
import com.alipay.sofa.jraft.storage.snapshot.SnapshotReader;
|
||||
import com.alipay.sofa.jraft.storage.snapshot.SnapshotWriter;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* JRaft StateMachine implemented.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
class NacosStateMachine extends StateMachineAdapter {
|
||||
|
||||
protected final JRaftServer server;
|
||||
|
||||
protected final RequestProcessor processor;
|
||||
|
||||
private final AtomicBoolean isLeader = new AtomicBoolean(false);
|
||||
|
||||
private final String groupId;
|
||||
|
||||
private Collection<JSnapshotOperation> operations;
|
||||
|
||||
private Node node;
|
||||
|
||||
private volatile long term = -1;
|
||||
|
||||
private volatile String leaderIp = "unknown";
|
||||
|
||||
NacosStateMachine(JRaftServer server, RequestProcessor4CP processor) {
|
||||
this.server = server;
|
||||
this.processor = processor;
|
||||
this.groupId = processor.group();
|
||||
adapterToJRaftSnapshot(processor.loadSnapshotOperate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApply(Iterator iter) {
|
||||
int index = 0;
|
||||
int applied = 0;
|
||||
Message message;
|
||||
NacosClosure closure = null;
|
||||
try {
|
||||
while (iter.hasNext()) {
|
||||
Status status = Status.OK();
|
||||
try {
|
||||
if (iter.done() != null) {
|
||||
closure = (NacosClosure) iter.done();
|
||||
message = closure.getMessage();
|
||||
} else {
|
||||
final ByteBuffer data = iter.getData();
|
||||
message = ProtoMessageUtil.parse(data.array());
|
||||
if (message instanceof ReadRequest) {
|
||||
//'iter.done() == null' means current node is follower, ignore read operation
|
||||
applied++;
|
||||
index++;
|
||||
iter.next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LoggerUtils.printIfDebugEnabled(Loggers.RAFT, "receive log : {}", message);
|
||||
|
||||
if (message instanceof WriteRequest) {
|
||||
Response response = processor.onApply((WriteRequest) message);
|
||||
postProcessor(response, closure);
|
||||
}
|
||||
|
||||
if (message instanceof ReadRequest) {
|
||||
Response response = processor.onRequest((ReadRequest) message);
|
||||
postProcessor(response, closure);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
index++;
|
||||
status.setError(RaftError.UNKNOWN, e.toString());
|
||||
Optional.ofNullable(closure).ifPresent(closure1 -> closure1.setThrowable(e));
|
||||
throw e;
|
||||
} finally {
|
||||
Optional.ofNullable(closure).ifPresent(closure1 -> closure1.run(status));
|
||||
}
|
||||
|
||||
applied++;
|
||||
index++;
|
||||
iter.next();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Loggers.RAFT.error("processor : {}, stateMachine meet critical error: {}.", processor, t);
|
||||
iter.setErrorAndRollback(index - applied,
|
||||
new Status(RaftError.ESTATEMACHINE, "StateMachine meet critical error: %s.",
|
||||
ExceptionUtil.getStackTrace(t)));
|
||||
}
|
||||
}
|
||||
|
||||
public void setNode(Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSnapshotSave(SnapshotWriter writer, Closure done) {
|
||||
for (JSnapshotOperation operation : operations) {
|
||||
try {
|
||||
operation.onSnapshotSave(writer, done);
|
||||
} catch (Throwable t) {
|
||||
Loggers.RAFT.error("There was an error saving the snapshot , error : {}, operation : {}", t,
|
||||
operation.info());
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSnapshotLoad(SnapshotReader reader) {
|
||||
for (JSnapshotOperation operation : operations) {
|
||||
try {
|
||||
if (!operation.onSnapshotLoad(reader)) {
|
||||
Loggers.RAFT.error("Snapshot load failed on : {}", operation.info());
|
||||
return false;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Loggers.RAFT.error("Snapshot load failed on : {}, has error : {}", operation.info(), t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeaderStart(final long term) {
|
||||
super.onLeaderStart(term);
|
||||
this.term = term;
|
||||
this.isLeader.set(true);
|
||||
this.leaderIp = node.getNodeId().getPeerId().getEndpoint().toString();
|
||||
NotifyCenter.publishEvent(
|
||||
RaftEvent.builder().groupId(groupId).leader(leaderIp).term(term).raftClusterInfo(allPeers()).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeaderStop(final Status status) {
|
||||
super.onLeaderStop(status);
|
||||
this.isLeader.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartFollowing(LeaderChangeContext ctx) {
|
||||
this.term = ctx.getTerm();
|
||||
this.leaderIp = ctx.getLeaderId().getEndpoint().toString();
|
||||
NotifyCenter.publishEvent(
|
||||
RaftEvent.builder().groupId(groupId).leader(leaderIp).term(ctx.getTerm()).raftClusterInfo(allPeers())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationCommitted(Configuration conf) {
|
||||
NotifyCenter.publishEvent(
|
||||
RaftEvent.builder().groupId(groupId).raftClusterInfo(JRaftUtils.toStrings(conf.getPeers())).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(RaftException e) {
|
||||
super.onError(e);
|
||||
processor.onError(e);
|
||||
NotifyCenter.publishEvent(
|
||||
RaftEvent.builder().groupId(groupId).leader(leaderIp).term(term).raftClusterInfo(allPeers())
|
||||
.errMsg(e.toString())
|
||||
.build());
|
||||
}
|
||||
|
||||
public boolean isLeader() {
|
||||
return isLeader.get();
|
||||
}
|
||||
|
||||
private List<String> allPeers() {
|
||||
if (node == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (node.isLeader()) {
|
||||
return JRaftUtils.toStrings(node.listPeers());
|
||||
}
|
||||
|
||||
return JRaftUtils.toStrings(RouteTable.getInstance().getConfiguration(node.getGroupId()).getPeers());
|
||||
}
|
||||
|
||||
private void postProcessor(Response data, NacosClosure closure) {
|
||||
if (Objects.nonNull(closure)) {
|
||||
closure.setResponse(data);
|
||||
}
|
||||
}
|
||||
|
||||
public long getTerm() {
|
||||
return term;
|
||||
}
|
||||
|
||||
private void adapterToJRaftSnapshot(Collection<SnapshotOperation> userOperates) {
|
||||
List<JSnapshotOperation> tmp = new ArrayList<>();
|
||||
|
||||
for (SnapshotOperation item : userOperates) {
|
||||
|
||||
if (item == null) {
|
||||
Loggers.RAFT.error("Existing SnapshotOperation for null");
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp.add(new JSnapshotOperation() {
|
||||
|
||||
@Override
|
||||
public void onSnapshotSave(SnapshotWriter writer, Closure done) {
|
||||
final Writer wCtx = new Writer(writer.getPath());
|
||||
|
||||
// Do a layer of proxy operation to shield different Raft
|
||||
// components from implementing snapshots
|
||||
|
||||
final BiConsumer<Boolean, Throwable> callFinally = (result, t) -> {
|
||||
boolean[] results = new boolean[wCtx.listFiles().size()];
|
||||
int[] index = new int[] {0};
|
||||
wCtx.listFiles().forEach((file, meta) -> {
|
||||
try {
|
||||
results[index[0]++] = writer.addFile(file, buildMetadata(meta));
|
||||
} catch (Exception e) {
|
||||
throw new ConsistencyException(e);
|
||||
}
|
||||
});
|
||||
final Status status = result
|
||||
&& !Arrays.asList(results).stream().anyMatch(Boolean.FALSE::equals) ? Status.OK()
|
||||
: new Status(RaftError.EIO, "Fail to compress snapshot at %s, error is %s",
|
||||
writer.getPath(), t == null ? "" : t.getMessage());
|
||||
done.run(status);
|
||||
};
|
||||
item.onSnapshotSave(wCtx, callFinally);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSnapshotLoad(SnapshotReader reader) {
|
||||
final Map<String, LocalFileMeta> metaMap = new HashMap<>(reader.listFiles().size());
|
||||
for (String fileName : reader.listFiles()) {
|
||||
final LocalFileMetaOutter.LocalFileMeta meta = (LocalFileMetaOutter.LocalFileMeta) reader
|
||||
.getFileMeta(fileName);
|
||||
|
||||
byte[] bytes = meta.getUserMeta().toByteArray();
|
||||
|
||||
final LocalFileMeta fileMeta;
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
fileMeta = new LocalFileMeta();
|
||||
} else {
|
||||
fileMeta = JacksonUtils.toObj(bytes, LocalFileMeta.class);
|
||||
}
|
||||
|
||||
metaMap.put(fileName, fileMeta);
|
||||
}
|
||||
final Reader rCtx = new Reader(reader.getPath(), metaMap);
|
||||
return item.onSnapshotLoad(rCtx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String info() {
|
||||
return item.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.operations = Collections.unmodifiableList(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.consistency.Config;
|
||||
import com.alibaba.nacos.consistency.cp.RequestProcessor4CP;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* raft config.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "nacos.core.protocol.raft")
|
||||
public class RaftConfig implements Config<RequestProcessor4CP> {
|
||||
|
||||
private static final long serialVersionUID = 9174789390266064002L;
|
||||
|
||||
private Map<String, String> data = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private String selfAddress;
|
||||
|
||||
private Set<String> members = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
@Override
|
||||
public void setMembers(String self, Set<String> members) {
|
||||
this.selfAddress = self;
|
||||
this.members.clear();
|
||||
this.members.addAll(members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelfMember() {
|
||||
return selfAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMembers(Set<String> members) {
|
||||
this.members.addAll(members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMembers(Set<String> members) {
|
||||
this.members.removeAll(members);
|
||||
}
|
||||
|
||||
public Map<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(Map<String, String> data) {
|
||||
this.data = Collections.synchronizedMap(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVal(String key, String value) {
|
||||
data.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVal(String key) {
|
||||
return data.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValOfDefault(String key, String defaultVal) {
|
||||
return data.getOrDefault(key, defaultVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return JacksonUtils.toJson(data);
|
||||
} catch (Exception e) {
|
||||
return String.valueOf(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.notify.Event;
|
||||
|
||||
/**
|
||||
* The RAFT protocol runs an exception event. If this event is published, it means that the current raft Group cannot
|
||||
* continue to run normally
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class RaftErrorEvent extends Event {
|
||||
|
||||
private static final long serialVersionUID = 3016514657754158167L;
|
||||
|
||||
private String groupName;
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
}
|
||||
@@ -1,144 +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.core.distributed.raft;
|
||||
|
||||
import com.alibaba.nacos.common.notify.SlowEvent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Changes to metadata information during the raft protocol run.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class RaftEvent extends SlowEvent {
|
||||
|
||||
private static final long serialVersionUID = -4304258594602886451L;
|
||||
|
||||
private String groupId;
|
||||
|
||||
private String leader = null;
|
||||
|
||||
private Long term = null;
|
||||
|
||||
private String errMsg = "";
|
||||
|
||||
private List<String> raftClusterInfo = Collections.emptyList();
|
||||
|
||||
public static RaftEventBuilder builder() {
|
||||
return new RaftEventBuilder();
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getLeader() {
|
||||
return leader;
|
||||
}
|
||||
|
||||
public void setLeader(String leader) {
|
||||
this.leader = leader;
|
||||
}
|
||||
|
||||
public Long getTerm() {
|
||||
return term;
|
||||
}
|
||||
|
||||
public void setTerm(Long term) {
|
||||
this.term = term;
|
||||
}
|
||||
|
||||
public List<String> getRaftClusterInfo() {
|
||||
return raftClusterInfo;
|
||||
}
|
||||
|
||||
public void setRaftClusterInfo(List<String> raftClusterInfo) {
|
||||
this.raftClusterInfo = raftClusterInfo;
|
||||
}
|
||||
|
||||
public String getErrMsg() {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
public void setErrMsg(String errMsg) {
|
||||
this.errMsg = errMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RaftEvent{" + "groupId='" + groupId + '\'' + ", leader='" + leader + '\'' + ", term=" + term
|
||||
+ ", raftClusterInfo=" + raftClusterInfo + '}';
|
||||
}
|
||||
|
||||
public static final class RaftEventBuilder {
|
||||
|
||||
private String groupId;
|
||||
|
||||
private String leader;
|
||||
|
||||
private Long term = null;
|
||||
|
||||
private List<String> raftClusterInfo = Collections.emptyList();
|
||||
|
||||
private String errMsg = "";
|
||||
|
||||
private RaftEventBuilder() {
|
||||
}
|
||||
|
||||
public RaftEventBuilder groupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RaftEventBuilder leader(String leader) {
|
||||
this.leader = leader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RaftEventBuilder term(long term) {
|
||||
this.term = term;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RaftEventBuilder raftClusterInfo(List<String> raftClusterInfo) {
|
||||
this.raftClusterInfo = raftClusterInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RaftEventBuilder errMsg(String errMsg) {
|
||||
this.errMsg = errMsg;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RaftEvent build() {
|
||||
RaftEvent raftEvent = new RaftEvent();
|
||||
raftEvent.setGroupId(groupId);
|
||||
raftEvent.setLeader(leader);
|
||||
raftEvent.setTerm(term);
|
||||
raftEvent.setRaftClusterInfo(raftClusterInfo);
|
||||
raftEvent.setErrMsg(errMsg);
|
||||
return raftEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,234 +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.core.distributed.raft;
|
||||
|
||||
/**
|
||||
* jraft system constants.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public final class RaftSysConstants {
|
||||
|
||||
// ========= default setting value ========= //
|
||||
|
||||
/**
|
||||
* {@link RaftSysConstants#RAFT_ELECTION_TIMEOUT_MS}
|
||||
*/
|
||||
public static final int DEFAULT_ELECTION_TIMEOUT = 5000;
|
||||
|
||||
/**
|
||||
* {@link RaftSysConstants#RAFT_SNAPSHOT_INTERVAL_SECS}
|
||||
*/
|
||||
public static final int DEFAULT_RAFT_SNAPSHOT_INTERVAL_SECS = 30 * 60;
|
||||
|
||||
/**
|
||||
* {@link RaftSysConstants#RAFT_CLI_SERVICE_THREAD_NUM}
|
||||
*/
|
||||
public static final int DEFAULT_RAFT_CLI_SERVICE_THREAD_NUM = 8;
|
||||
|
||||
/**
|
||||
* {@link RaftSysConstants#RAFT_READ_INDEX_TYPE}
|
||||
*/
|
||||
public static final String DEFAULT_READ_INDEX_TYPE = "ReadOnlySafe";
|
||||
|
||||
/**
|
||||
* {@link RaftSysConstants#RAFT_RPC_REQUEST_TIMEOUT_MS}
|
||||
*/
|
||||
public static final int DEFAULT_RAFT_RPC_REQUEST_TIMEOUT_MS = 5000;
|
||||
|
||||
/**
|
||||
* The maximum size of each file RPC (snapshot copy) request between nodes is 128 K by default 节点之间每次文件 RPC
|
||||
* (snapshot拷贝)请求的最大大小,默认为 128 K
|
||||
*/
|
||||
public static final int DEFAULT_MAX_BYTE_COUNT_PER_RPC = 128 * 1024;
|
||||
|
||||
/**
|
||||
* The maximum number of logs sent from the leader to the followers is 1024 by default 从 leader 往 follower
|
||||
* 发送的最大日志个数,默认 1024
|
||||
*/
|
||||
public static final int DEFAULT_MAX_ENTRIES_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* The maximum body size of the log sent from the leader to the followers is 512K by default 从 leader 往 follower
|
||||
* 发送日志的最大 body 大小,默认 512K
|
||||
*/
|
||||
public static final int DEFAULT_MAX_BODY_SIZE = 512 * 1024;
|
||||
|
||||
/**
|
||||
* The maximum size of the log storage buffer is 256K by default 日志存储缓冲区最大大小,默认256K
|
||||
*/
|
||||
public static final int DEFAULT_MAX_APPEND_BUFFER_SIZE = 256 * 1024;
|
||||
|
||||
/**
|
||||
* The election timer interval will be a random maximum outside the specified time, 1 second by default
|
||||
* 选举定时器间隔会在指定时间之外随机的最大范围,默认1秒
|
||||
*/
|
||||
public static final int DEFAULT_MAX_ELECTION_DELAY_MS = 1000;
|
||||
|
||||
/**
|
||||
* Specifies the ratio of the election timeout to the heartbeat interval. Heartbeat interval is equal to the
|
||||
* electionTimeoutMs/electionHeartbeatFactor, default one of 10 points. 指定选举超时时间和心跳间隔时间之间的比值。心跳间隔等于electionTimeoutMs/electionHeartbeatFactor,默认10分之一。
|
||||
*/
|
||||
public static final int DEFAULT_ELECTION_HEARTBEAT_FACTOR = 10;
|
||||
|
||||
/**
|
||||
* The tasks submitted to the leader will accumulate one batch into the maximum batch size stored in the log, and 32
|
||||
* tasks will be assigned by default 向 leader 提交的任务累积一个批次刷入日志存储的最大批次大小,默认 32 个任务
|
||||
*/
|
||||
public static final int DEFAULT_APPLY_BATCH = 32;
|
||||
|
||||
/**
|
||||
* Call fsync when necessary when writing log, meta information, and it should always be true 写入日志、元信息的时候必要的时候调用
|
||||
* fsync,通常都应该为 true
|
||||
*/
|
||||
public static final boolean DEFAULT_SYNC = true;
|
||||
|
||||
/**
|
||||
* If fsync is called by writing snapshot/raft information, the default is false. If sync is true, it is better to
|
||||
* respect sync 写入 snapshot/raft 元信息是否调用 fsync,默认为 false,在 sync 为 true 的情况下,优选尊重 sync
|
||||
*/
|
||||
public static final boolean DEFAULT_SYNC_META = false;
|
||||
|
||||
/**
|
||||
* Internal disruptor buffer size, need to be appropriately adjusted for high write throughput applications, default
|
||||
* 16384 内部 disruptor buffer 大小,如果是写入吞吐量较高的应用,需要适当调高该值,默认 16384
|
||||
*/
|
||||
public static final int DEFAULT_DISRUPTOR_BUFFER_SIZE = 16384;
|
||||
|
||||
/**
|
||||
* Whether to enable replicated pipeline request optimization by default 是否启用复制的 pipeline 请求优化,默认打开
|
||||
*/
|
||||
public static final boolean DEFAULT_REPLICATOR_PIPELINE = true;
|
||||
|
||||
/**
|
||||
* Maximum in-flight requests with pipeline requests enabled, 256 by default 在启用 pipeline 请求情况下,最大 in-flight
|
||||
* 请求数,默认256
|
||||
*/
|
||||
public static final int DEFAULT_MAX_REPLICATOR_INFLIGHT_MSGS = 256;
|
||||
|
||||
/**
|
||||
* Whether LogEntry checksum is enabled 是否启用 LogEntry checksum
|
||||
*/
|
||||
public static final boolean DEFAULT_ENABLE_LOG_ENTRY_CHECKSUM = false;
|
||||
|
||||
// ========= setting key ========= //
|
||||
|
||||
/**
|
||||
* Election timeout in milliseconds
|
||||
*/
|
||||
public static final String RAFT_ELECTION_TIMEOUT_MS = "election_timeout_ms";
|
||||
|
||||
/**
|
||||
* Snapshot interval in seconds
|
||||
*/
|
||||
public static final String RAFT_SNAPSHOT_INTERVAL_SECS = "snapshot_interval_secs";
|
||||
|
||||
/**
|
||||
* Requested retries
|
||||
*/
|
||||
public static final String REQUEST_FAILOVER_RETRIES = "request_failoverRetries";
|
||||
|
||||
/**
|
||||
* raft internal worker threads
|
||||
*/
|
||||
public static final String RAFT_CORE_THREAD_NUM = "core_thread_num";
|
||||
|
||||
/**
|
||||
* Number of threads required for raft business request processing
|
||||
*/
|
||||
public static final String RAFT_CLI_SERVICE_THREAD_NUM = "cli_service_thread_num";
|
||||
|
||||
/**
|
||||
* raft linear read strategy, defaults to read_index read
|
||||
*/
|
||||
public static final String RAFT_READ_INDEX_TYPE = "read_index_type";
|
||||
|
||||
/**
|
||||
* rpc request timeout, default 5 seconds
|
||||
*/
|
||||
public static final String RAFT_RPC_REQUEST_TIMEOUT_MS = "rpc_request_timeout_ms";
|
||||
|
||||
/**
|
||||
* Maximum size of each file RPC (snapshot copy) request between nodes, default is 128 K
|
||||
*/
|
||||
public static final String MAX_BYTE_COUNT_PER_RPC = "max_byte_count_per_rpc";
|
||||
|
||||
/**
|
||||
* Maximum number of logs sent from leader to follower, default is 1024
|
||||
*/
|
||||
public static final String MAX_ENTRIES_SIZE = "max_entries_size";
|
||||
|
||||
/**
|
||||
* Maximum body size for sending logs from leader to follower, default is 512K
|
||||
*/
|
||||
public static final String MAX_BODY_SIZE = "max_body_size";
|
||||
|
||||
/**
|
||||
* Maximum log storage buffer size, default 256K
|
||||
*/
|
||||
public static final String MAX_APPEND_BUFFER_SIZE = "max_append_buffer_size";
|
||||
|
||||
/**
|
||||
* Election timer interval will be a random maximum outside the specified time, default is 1 second
|
||||
*/
|
||||
public static final String MAX_ELECTION_DELAY_MS = "max_election_delay_ms";
|
||||
|
||||
/**
|
||||
* Specify the ratio between election timeout and heartbeat interval. Heartbeat interval is equal to
|
||||
* electionTimeoutMs/electionHeartbeatFactor,One tenth by default.
|
||||
*/
|
||||
public static final String ELECTION_HEARTBEAT_FACTOR = "election_heartbeat_factor";
|
||||
|
||||
/**
|
||||
* The tasks submitted to the leader accumulate the maximum batch size of a batch flush log storage. The default is
|
||||
* 32 tasks.
|
||||
*/
|
||||
public static final String APPLY_BATCH = "apply_batch";
|
||||
|
||||
/**
|
||||
* Call fsync when necessary when writing logs and meta information, usually should be true
|
||||
*/
|
||||
public static final String SYNC = "sync";
|
||||
|
||||
/**
|
||||
* Whether to write snapshot / raft meta-information to call fsync. The default is false. When sync is true, it is
|
||||
* preferred to respect sync.
|
||||
*/
|
||||
public static final String SYNC_META = "sync_meta";
|
||||
|
||||
/**
|
||||
* Internal disruptor buffer size. For applications with high write throughput, you need to increase this value. The
|
||||
* default value is 16384.
|
||||
*/
|
||||
public static final String DISRUPTOR_BUFFER_SIZE = "disruptor_buffer_size";
|
||||
|
||||
/**
|
||||
* Whether to enable replication of pipeline request optimization, which is enabled by default
|
||||
*/
|
||||
public static final String REPLICATOR_PIPELINE = "replicator_pipeline";
|
||||
|
||||
/**
|
||||
* Maximum number of in-flight requests with pipeline requests enabled, default is 256
|
||||
*/
|
||||
public static final String MAX_REPLICATOR_INFLIGHT_MSGS = "max_replicator_inflight_msgs";
|
||||
|
||||
/**
|
||||
* Whether to enable LogEntry checksum
|
||||
*/
|
||||
public static final String ENABLE_LOG_ENTRY_CHECKSUM = "enable_log_entry_checksum";
|
||||
}
|
||||
@@ -1,31 +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.core.distributed.raft.exception;
|
||||
|
||||
/**
|
||||
* Duplicate groupId when creating Raft Group throws this exception.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class DuplicateRaftGroupException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -6276695537457486790L;
|
||||
|
||||
public DuplicateRaftGroupException(String group) {
|
||||
super("The Raft Group [" + group + "] is already used");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +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.core.distributed.raft.exception;
|
||||
|
||||
/**
|
||||
* Abnormal JRaft.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public class JRaftException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 8802314713344513544L;
|
||||
|
||||
public JRaftException() {
|
||||
}
|
||||
|
||||
public JRaftException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JRaftException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public JRaftException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public JRaftException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +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.core.distributed.raft.exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown if the current Raft Group Cluster does not elect a leader.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class NoLeaderException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1755681688785678765L;
|
||||
|
||||
public NoLeaderException() {
|
||||
}
|
||||
|
||||
public NoLeaderException(String group) {
|
||||
super("The Raft Group [" + group + "] did not find the Leader node");
|
||||
}
|
||||
|
||||
public NoLeaderException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NoLeaderException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NoLeaderException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +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.core.distributed.raft.exception;
|
||||
|
||||
/**
|
||||
* no this raft group exception.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class NoSuchRaftGroupException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1755681688785678765L;
|
||||
|
||||
public NoSuchRaftGroupException() {
|
||||
}
|
||||
|
||||
public NoSuchRaftGroupException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NoSuchRaftGroupException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NoSuchRaftGroupException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NoSuchRaftGroupException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +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.core.distributed.raft.processor;
|
||||
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alibaba.nacos.core.distributed.raft.utils.FailoverClosure;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
import com.alipay.sofa.jraft.rpc.RpcContext;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* abstract rpc processor.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public abstract class AbstractProcessor {
|
||||
|
||||
private final Serializer serializer;
|
||||
|
||||
public AbstractProcessor(Serializer serializer) {
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
protected void handleRequest(final JRaftServer server, final String group, final RpcContext rpcCtx, Message message) {
|
||||
try {
|
||||
final JRaftServer.RaftGroupTuple tuple = server.findTupleByGroup(group);
|
||||
if (Objects.isNull(tuple)) {
|
||||
rpcCtx.sendResponse(Response.newBuilder().setSuccess(false)
|
||||
.setErrMsg("Could not find the corresponding Raft Group : " + group).build());
|
||||
return;
|
||||
}
|
||||
if (tuple.getNode().isLeader()) {
|
||||
execute(server, rpcCtx, message, tuple);
|
||||
} else {
|
||||
rpcCtx.sendResponse(
|
||||
Response.newBuilder().setSuccess(false).setErrMsg("Could not find leader : " + group).build());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Loggers.RAFT.error("handleRequest has error : ", e);
|
||||
rpcCtx.sendResponse(Response.newBuilder().setSuccess(false).setErrMsg(e.toString()).build());
|
||||
}
|
||||
}
|
||||
|
||||
protected void execute(JRaftServer server, final RpcContext asyncCtx, final Message message,
|
||||
final JRaftServer.RaftGroupTuple tuple) {
|
||||
FailoverClosure closure = new FailoverClosure() {
|
||||
|
||||
Response data;
|
||||
|
||||
Throwable ex;
|
||||
|
||||
@Override
|
||||
public void setResponse(Response data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThrowable(Throwable throwable) {
|
||||
this.ex = throwable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Status status) {
|
||||
if (Objects.nonNull(ex)) {
|
||||
Loggers.RAFT.error("execute has error : ", ex);
|
||||
asyncCtx.sendResponse(Response.newBuilder().setErrMsg(ex.toString()).setSuccess(false).build());
|
||||
} else {
|
||||
asyncCtx.sendResponse(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
server.applyOperation(tuple.getNode(), message, closure);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +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.core.distributed.raft.processor;
|
||||
|
||||
import com.alibaba.nacos.consistency.ProtoMessageUtil;
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.entity.GetRequest;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alipay.sofa.jraft.rpc.RpcContext;
|
||||
import com.alipay.sofa.jraft.rpc.RpcProcessor;
|
||||
|
||||
/**
|
||||
* deal with {@link GetRequest}.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public class NacosGetRequestProcessor extends AbstractProcessor implements RpcProcessor<GetRequest> {
|
||||
|
||||
private static final String INTEREST_NAME = GetRequest.class.getName();
|
||||
|
||||
private final JRaftServer server;
|
||||
|
||||
public NacosGetRequestProcessor(JRaftServer server, Serializer serializer) {
|
||||
super(serializer);
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(final RpcContext rpcCtx, GetRequest request) {
|
||||
handleRequest(server, request.getGroup(), rpcCtx, ProtoMessageUtil.convertToReadRequest(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String interest() {
|
||||
return INTEREST_NAME;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +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.core.distributed.raft.processor;
|
||||
|
||||
import com.alibaba.nacos.consistency.ProtoMessageUtil;
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.entity.Log;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alipay.sofa.jraft.rpc.RpcContext;
|
||||
import com.alipay.sofa.jraft.rpc.RpcProcessor;
|
||||
|
||||
/**
|
||||
* deal with {@link Log}.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public class NacosLogProcessor extends AbstractProcessor implements RpcProcessor<Log> {
|
||||
|
||||
private static final String INTEREST_NAME = Log.class.getName();
|
||||
|
||||
private final JRaftServer server;
|
||||
|
||||
public NacosLogProcessor(JRaftServer server, Serializer serializer) {
|
||||
super(serializer);
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(final RpcContext rpcCtx, Log log) {
|
||||
handleRequest(server, log.getGroup(), rpcCtx, ProtoMessageUtil.convertToWriteRequest(log));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String interest() {
|
||||
return INTEREST_NAME;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.core.distributed.raft.processor;
|
||||
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.entity.ReadRequest;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alipay.sofa.jraft.rpc.RpcContext;
|
||||
import com.alipay.sofa.jraft.rpc.RpcProcessor;
|
||||
|
||||
/**
|
||||
* nacos request processor for {@link ReadRequest}.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class NacosReadRequestProcessor extends AbstractProcessor implements RpcProcessor<ReadRequest> {
|
||||
|
||||
private static final String INTEREST_NAME = ReadRequest.class.getName();
|
||||
|
||||
private final JRaftServer server;
|
||||
|
||||
public NacosReadRequestProcessor(JRaftServer server, Serializer serializer) {
|
||||
super(serializer);
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(RpcContext rpcCtx, ReadRequest request) {
|
||||
handleRequest(server, request.getGroup(), rpcCtx, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String interest() {
|
||||
return INTEREST_NAME;
|
||||
}
|
||||
}
|
||||
@@ -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.core.distributed.raft.processor;
|
||||
|
||||
import com.alibaba.nacos.consistency.Serializer;
|
||||
import com.alibaba.nacos.consistency.entity.WriteRequest;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alipay.sofa.jraft.rpc.RpcContext;
|
||||
import com.alipay.sofa.jraft.rpc.RpcProcessor;
|
||||
|
||||
/**
|
||||
* nacos request processor for {@link WriteRequest}.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class NacosWriteRequestProcessor extends AbstractProcessor implements RpcProcessor<WriteRequest> {
|
||||
|
||||
private static final String INTEREST_NAME = WriteRequest.class.getName();
|
||||
|
||||
private final JRaftServer server;
|
||||
|
||||
public NacosWriteRequestProcessor(JRaftServer server, Serializer serializer) {
|
||||
super(serializer);
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(RpcContext rpcCtx, WriteRequest request) {
|
||||
handleRequest(server, request.getGroup(), rpcCtx, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String interest() {
|
||||
return INTEREST_NAME;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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.core.distributed.raft.utils;
|
||||
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alipay.sofa.jraft.Closure;
|
||||
|
||||
/**
|
||||
* Failure callback based on Closure.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public interface FailoverClosure extends Closure {
|
||||
|
||||
/**
|
||||
* Set the return interface if needed.
|
||||
*
|
||||
* @param response {@link Response} data
|
||||
*/
|
||||
void setResponse(Response response);
|
||||
|
||||
/**
|
||||
* Catch exception.
|
||||
*
|
||||
* @param throwable {@link Throwable}
|
||||
*/
|
||||
void setThrowable(Throwable throwable);
|
||||
|
||||
}
|
||||
@@ -1,64 +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.core.distributed.raft.utils;
|
||||
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alibaba.nacos.consistency.exception.ConsistencyException;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Closure with internal retry mechanism.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class FailoverClosureImpl implements FailoverClosure {
|
||||
|
||||
private final CompletableFuture<Response> future;
|
||||
|
||||
private volatile Response data;
|
||||
|
||||
private volatile Throwable throwable;
|
||||
|
||||
public FailoverClosureImpl(final CompletableFuture<Response> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Response data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThrowable(Throwable throwable) {
|
||||
this.throwable = throwable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Status status) {
|
||||
if (status.isOk()) {
|
||||
future.complete(data);
|
||||
return;
|
||||
}
|
||||
final Throwable throwable = this.throwable;
|
||||
future.completeExceptionally(Objects.nonNull(throwable) ? new ConsistencyException(throwable.getMessage())
|
||||
: new ConsistencyException("operation failure"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +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.core.distributed.raft.utils;
|
||||
|
||||
/**
|
||||
* constant.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public class JRaftConstants {
|
||||
|
||||
public static final String JRAFT_EXTEND_INFO_KEY = JRaftLogOperation.class.getCanonicalName();
|
||||
|
||||
public static final String GROUP_ID = "groupId";
|
||||
|
||||
public static final String COMMAND_NAME = "command";
|
||||
|
||||
public static final String COMMAND_VALUE = "value";
|
||||
|
||||
public static final String TRANSFER_LEADER = "transferLeader";
|
||||
|
||||
public static final String RESET_RAFT_CLUSTER = "restRaftCluster";
|
||||
|
||||
public static final String DO_SNAPSHOT = "doSnapshot";
|
||||
|
||||
public static final String REMOVE_PEER = "removePeer";
|
||||
|
||||
public static final String REMOVE_PEERS = "removePeers";
|
||||
|
||||
public static final String CHANGE_PEERS = "changePeers";
|
||||
|
||||
/**
|
||||
* resetPeers.
|
||||
*/
|
||||
public static final String RESET_PEERS = "resetPeers";
|
||||
|
||||
}
|
||||
@@ -1,31 +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.core.distributed.raft.utils;
|
||||
|
||||
/**
|
||||
* JRaft for additional information on logging operations.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public class JRaftLogOperation {
|
||||
|
||||
public static final String MODIFY_OPERATION = "modify";
|
||||
|
||||
public static final String READ_OPERATION = "read";
|
||||
|
||||
}
|
||||
@@ -1,189 +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.core.distributed.raft.utils;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alipay.sofa.jraft.CliService;
|
||||
import com.alipay.sofa.jraft.JRaftUtils;
|
||||
import com.alipay.sofa.jraft.Node;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
import com.alipay.sofa.jraft.conf.Configuration;
|
||||
import com.alipay.sofa.jraft.entity.PeerId;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* jraft maintain service.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public enum JRaftOps {
|
||||
|
||||
TRANSFER_LEADER(JRaftConstants.TRANSFER_LEADER) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration conf = node.getOptions().getInitialConf();
|
||||
final PeerId leader = PeerId.parsePeer(args.get(JRaftConstants.COMMAND_VALUE));
|
||||
Status status = cliService.transferLeader(groupId, conf, leader);
|
||||
if (status.isOk()) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
},
|
||||
|
||||
RESET_RAFT_CLUSTER(JRaftConstants.RESET_RAFT_CLUSTER) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration conf = node.getOptions().getInitialConf();
|
||||
final String peerIds = args.get(JRaftConstants.COMMAND_VALUE);
|
||||
Configuration newConf = JRaftUtils.getConfiguration(peerIds);
|
||||
Status status = cliService.changePeers(groupId, conf, newConf);
|
||||
if (status.isOk()) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
},
|
||||
|
||||
DO_SNAPSHOT(JRaftConstants.DO_SNAPSHOT) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration conf = node.getOptions().getInitialConf();
|
||||
final PeerId peerId = PeerId.parsePeer(args.get(JRaftConstants.COMMAND_VALUE));
|
||||
Status status = cliService.snapshot(groupId, peerId);
|
||||
if (status.isOk()) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
},
|
||||
|
||||
REMOVE_PEER(JRaftConstants.REMOVE_PEER) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration conf = node.getOptions().getInitialConf();
|
||||
|
||||
List<PeerId> peerIds = cliService.getPeers(groupId, conf);
|
||||
|
||||
final PeerId waitRemove = PeerId.parsePeer(args.get(JRaftConstants.COMMAND_VALUE));
|
||||
|
||||
if (!peerIds.contains(waitRemove)) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
|
||||
Status status = cliService.removePeer(groupId, conf, waitRemove);
|
||||
if (status.isOk()) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
},
|
||||
|
||||
REMOVE_PEERS(JRaftConstants.REMOVE_PEERS) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration conf = node.getOptions().getInitialConf();
|
||||
final String peers = args.get(JRaftConstants.COMMAND_VALUE);
|
||||
for (String s : peers.split(",")) {
|
||||
|
||||
List<PeerId> peerIds = cliService.getPeers(groupId, conf);
|
||||
final PeerId waitRemove = PeerId.parsePeer(s);
|
||||
|
||||
if (!peerIds.contains(waitRemove)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Status status = cliService.removePeer(groupId, conf, waitRemove);
|
||||
if (!status.isOk()) {
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
}
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
},
|
||||
|
||||
CHANGE_PEERS(JRaftConstants.CHANGE_PEERS) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration conf = node.getOptions().getInitialConf();
|
||||
final Configuration newConf = new Configuration();
|
||||
String peers = args.get(JRaftConstants.COMMAND_VALUE);
|
||||
for (String peer : peers.split(",")) {
|
||||
newConf.addPeer(PeerId.parsePeer(peer.trim()));
|
||||
}
|
||||
|
||||
if (Objects.equals(conf, newConf)) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
|
||||
Status status = cliService.changePeers(groupId, conf, newConf);
|
||||
if (status.isOk()) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* resetPeers.
|
||||
* <p>
|
||||
* Use only in very urgent situations where availability is more important!
|
||||
* https://www.sofastack.tech/projects/sofa-jraft/jraft-user-guide/#7.3
|
||||
* </p>
|
||||
*/
|
||||
RESET_PEERS(JRaftConstants.RESET_PEERS) {
|
||||
@Override
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
final Configuration newConf = new Configuration();
|
||||
String peers = args.get(JRaftConstants.COMMAND_VALUE);
|
||||
for (String peer : peers.split(",")) {
|
||||
newConf.addPeer(PeerId.parsePeer(peer.trim()));
|
||||
}
|
||||
|
||||
final PeerId nodePeerId = node.getNodeId().getPeerId();
|
||||
Status status = cliService.resetPeer(groupId, nodePeerId, newConf);
|
||||
if (status.isOk()) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
return RestResultUtils.failed(status.getErrorMsg());
|
||||
}
|
||||
};
|
||||
|
||||
private String name;
|
||||
|
||||
JRaftOps(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static JRaftOps sourceOf(String command) {
|
||||
for (JRaftOps enums : JRaftOps.values()) {
|
||||
if (Objects.equals(command, enums.name)) {
|
||||
return enums;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public RestResult<String> execute(CliService cliService, String groupId, Node node, Map<String, String> args) {
|
||||
return RestResultUtils.success();
|
||||
}
|
||||
}
|
||||
@@ -1,152 +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.core.distributed.raft.utils;
|
||||
|
||||
import com.alibaba.nacos.common.utils.ThreadUtils;
|
||||
import com.alibaba.nacos.consistency.SerializeFactory;
|
||||
import com.alibaba.nacos.consistency.entity.GetRequest;
|
||||
import com.alibaba.nacos.consistency.entity.Log;
|
||||
import com.alibaba.nacos.consistency.entity.ReadRequest;
|
||||
import com.alibaba.nacos.consistency.entity.Response;
|
||||
import com.alibaba.nacos.consistency.entity.WriteRequest;
|
||||
import com.alibaba.nacos.core.cluster.ServerMemberManager;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alibaba.nacos.core.distributed.raft.processor.NacosGetRequestProcessor;
|
||||
import com.alibaba.nacos.core.distributed.raft.processor.NacosLogProcessor;
|
||||
import com.alibaba.nacos.core.distributed.raft.processor.NacosReadRequestProcessor;
|
||||
import com.alibaba.nacos.core.distributed.raft.processor.NacosWriteRequestProcessor;
|
||||
import com.alibaba.nacos.sys.utils.ApplicationUtils;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import com.alipay.sofa.jraft.CliService;
|
||||
import com.alipay.sofa.jraft.RouteTable;
|
||||
import com.alipay.sofa.jraft.Status;
|
||||
import com.alipay.sofa.jraft.conf.Configuration;
|
||||
import com.alipay.sofa.jraft.entity.PeerId;
|
||||
import com.alipay.sofa.jraft.option.NodeOptions;
|
||||
import com.alipay.sofa.jraft.rpc.RaftRpcServerFactory;
|
||||
import com.alipay.sofa.jraft.rpc.RpcServer;
|
||||
import com.alipay.sofa.jraft.rpc.impl.GrpcRaftRpcFactory;
|
||||
import com.alipay.sofa.jraft.rpc.impl.MarshallerRegistry;
|
||||
import com.alipay.sofa.jraft.util.RpcFactoryHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JRaft utils.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class JRaftUtils {
|
||||
|
||||
public static RpcServer initRpcServer(JRaftServer server, PeerId peerId) {
|
||||
GrpcRaftRpcFactory raftRpcFactory = (GrpcRaftRpcFactory) RpcFactoryHelper.rpcFactory();
|
||||
raftRpcFactory.registerProtobufSerializer(Log.class.getName(), Log.getDefaultInstance());
|
||||
raftRpcFactory.registerProtobufSerializer(GetRequest.class.getName(), GetRequest.getDefaultInstance());
|
||||
raftRpcFactory.registerProtobufSerializer(WriteRequest.class.getName(), WriteRequest.getDefaultInstance());
|
||||
raftRpcFactory.registerProtobufSerializer(ReadRequest.class.getName(), ReadRequest.getDefaultInstance());
|
||||
raftRpcFactory.registerProtobufSerializer(Response.class.getName(), Response.getDefaultInstance());
|
||||
|
||||
MarshallerRegistry registry = raftRpcFactory.getMarshallerRegistry();
|
||||
registry.registerResponseInstance(Log.class.getName(), Response.getDefaultInstance());
|
||||
registry.registerResponseInstance(GetRequest.class.getName(), Response.getDefaultInstance());
|
||||
|
||||
registry.registerResponseInstance(WriteRequest.class.getName(), Response.getDefaultInstance());
|
||||
registry.registerResponseInstance(ReadRequest.class.getName(), Response.getDefaultInstance());
|
||||
|
||||
final RpcServer rpcServer = raftRpcFactory.createRpcServer(peerId.getEndpoint());
|
||||
RaftRpcServerFactory.addRaftRequestProcessors(rpcServer, RaftExecutor.getRaftCoreExecutor(),
|
||||
RaftExecutor.getRaftCliServiceExecutor());
|
||||
|
||||
// Deprecated
|
||||
rpcServer.registerProcessor(new NacosLogProcessor(server, SerializeFactory.getDefault()));
|
||||
// Deprecated
|
||||
rpcServer.registerProcessor(new NacosGetRequestProcessor(server, SerializeFactory.getDefault()));
|
||||
|
||||
rpcServer.registerProcessor(new NacosWriteRequestProcessor(server, SerializeFactory.getDefault()));
|
||||
rpcServer.registerProcessor(new NacosReadRequestProcessor(server, SerializeFactory.getDefault()));
|
||||
|
||||
return rpcServer;
|
||||
}
|
||||
|
||||
public static final void initDirectory(String parentPath, String groupName, NodeOptions copy) {
|
||||
final String logUri = Paths.get(parentPath, groupName, "log").toString();
|
||||
final String snapshotUri = Paths.get(parentPath, groupName, "snapshot").toString();
|
||||
final String metaDataUri = Paths.get(parentPath, groupName, "meta-data").toString();
|
||||
|
||||
// Initialize the raft file storage path for different services
|
||||
try {
|
||||
DiskUtils.forceMkdir(new File(logUri));
|
||||
DiskUtils.forceMkdir(new File(snapshotUri));
|
||||
DiskUtils.forceMkdir(new File(metaDataUri));
|
||||
} catch (Exception e) {
|
||||
Loggers.RAFT.error("Init Raft-File dir have some error, cause: ", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
copy.setLogUri(logUri);
|
||||
copy.setRaftMetaUri(metaDataUri);
|
||||
copy.setSnapshotUri(snapshotUri);
|
||||
}
|
||||
|
||||
public static List<String> toStrings(List<PeerId> peerIds) {
|
||||
return peerIds.stream().map(peerId -> peerId.getEndpoint().toString()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static void joinCluster(CliService cliService, Collection<String> members, Configuration conf, String group,
|
||||
PeerId self) {
|
||||
ServerMemberManager memberManager = ApplicationUtils.getBean(ServerMemberManager.class);
|
||||
if (!memberManager.isFirstIp()) {
|
||||
return;
|
||||
}
|
||||
Set<PeerId> peerIds = new HashSet<>();
|
||||
for (String s : members) {
|
||||
peerIds.add(PeerId.parsePeer(s));
|
||||
}
|
||||
peerIds.remove(self);
|
||||
for (; ; ) {
|
||||
if (peerIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
conf = RouteTable.getInstance().getConfiguration(group);
|
||||
Iterator<PeerId> iterator = peerIds.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final PeerId peerId = iterator.next();
|
||||
|
||||
if (conf.contains(peerId)) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
Status status = cliService.addPeer(group, conf, peerId);
|
||||
if (status.isOk()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
ThreadUtils.sleep(1000L);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,110 +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.core.distributed.raft.utils;
|
||||
|
||||
import com.alibaba.nacos.common.executor.ExecutorFactory;
|
||||
import com.alibaba.nacos.common.executor.NameThreadFactory;
|
||||
import com.alibaba.nacos.core.distributed.raft.JRaftServer;
|
||||
import com.alibaba.nacos.core.distributed.raft.RaftConfig;
|
||||
import com.alibaba.nacos.core.distributed.raft.RaftSysConstants;
|
||||
import com.alibaba.nacos.core.utils.ClassUtils;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* raft executor.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public final class RaftExecutor {
|
||||
|
||||
private static ExecutorService raftCoreExecutor;
|
||||
|
||||
private static ExecutorService raftCliServiceExecutor;
|
||||
|
||||
private static ScheduledExecutorService raftCommonExecutor;
|
||||
|
||||
private static ExecutorService raftSnapshotExecutor;
|
||||
|
||||
private static final String OWNER = ClassUtils.getCanonicalName(JRaftServer.class);
|
||||
|
||||
private RaftExecutor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* init raft executor by {@link RaftConfig}.
|
||||
*
|
||||
* @param config {@link RaftConfig}
|
||||
*/
|
||||
public static void init(RaftConfig config) {
|
||||
|
||||
int raftCoreThreadNum = Integer.parseInt(config.getValOfDefault(RaftSysConstants.RAFT_CORE_THREAD_NUM, "8"));
|
||||
int raftCliServiceThreadNum = Integer
|
||||
.parseInt(config.getValOfDefault(RaftSysConstants.RAFT_CLI_SERVICE_THREAD_NUM, "4"));
|
||||
|
||||
raftCoreExecutor = ExecutorFactory.Managed.newFixedExecutorService(OWNER, raftCoreThreadNum,
|
||||
new NameThreadFactory("com.alibaba.nacos.core.raft-core"));
|
||||
|
||||
raftCliServiceExecutor = ExecutorFactory.Managed.newFixedExecutorService(OWNER, raftCliServiceThreadNum,
|
||||
new NameThreadFactory("com.alibaba.nacos.core.raft-cli-service"));
|
||||
|
||||
raftCommonExecutor = ExecutorFactory.Managed.newScheduledExecutorService(OWNER, 8,
|
||||
new NameThreadFactory("com.alibaba.nacos.core.protocol.raft-common"));
|
||||
|
||||
int snapshotNum = raftCoreThreadNum / 2;
|
||||
snapshotNum = snapshotNum == 0 ? raftCoreThreadNum : snapshotNum;
|
||||
|
||||
raftSnapshotExecutor = ExecutorFactory.Managed.newFixedExecutorService(OWNER, snapshotNum,
|
||||
new NameThreadFactory("com.alibaba.nacos.core.raft-snapshot"));
|
||||
|
||||
}
|
||||
|
||||
public static void scheduleRaftMemberRefreshJob(Runnable runnable, long initialDelay, long period, TimeUnit unit) {
|
||||
raftCommonExecutor.scheduleAtFixedRate(runnable, initialDelay, period, unit);
|
||||
}
|
||||
|
||||
public static ExecutorService getRaftCoreExecutor() {
|
||||
return raftCoreExecutor;
|
||||
}
|
||||
|
||||
public static ExecutorService getRaftCliServiceExecutor() {
|
||||
return raftCliServiceExecutor;
|
||||
}
|
||||
|
||||
public static void executeByCommon(Runnable r) {
|
||||
raftCommonExecutor.execute(r);
|
||||
}
|
||||
|
||||
public static void scheduleByCommon(Runnable r, long delayMs) {
|
||||
raftCommonExecutor.schedule(r, delayMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public static void scheduleAtFixedRateByCommon(Runnable command, long initialDelayMs, long periodMs) {
|
||||
raftCommonExecutor.scheduleAtFixedRate(command, initialDelayMs, periodMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public static ScheduledExecutorService getRaftCommonExecutor() {
|
||||
return raftCommonExecutor;
|
||||
}
|
||||
|
||||
public static void doSnapshot(Runnable runnable) {
|
||||
raftSnapshotExecutor.execute(runnable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,125 +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.core.distributed.raft.utils;
|
||||
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
import com.alibaba.nacos.core.distributed.raft.RaftConfig;
|
||||
import com.alibaba.nacos.core.distributed.raft.RaftSysConstants;
|
||||
import com.alipay.sofa.jraft.option.RaftOptions;
|
||||
import com.alipay.sofa.jraft.option.ReadOnlyOption;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.APPLY_BATCH;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_APPLY_BATCH;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_DISRUPTOR_BUFFER_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_ELECTION_HEARTBEAT_FACTOR;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_ENABLE_LOG_ENTRY_CHECKSUM;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_MAX_APPEND_BUFFER_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_MAX_BODY_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_MAX_BYTE_COUNT_PER_RPC;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_MAX_ELECTION_DELAY_MS;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_MAX_ENTRIES_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_MAX_REPLICATOR_INFLIGHT_MSGS;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_REPLICATOR_PIPELINE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_SYNC;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DEFAULT_SYNC_META;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.DISRUPTOR_BUFFER_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.ELECTION_HEARTBEAT_FACTOR;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.ENABLE_LOG_ENTRY_CHECKSUM;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.MAX_APPEND_BUFFER_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.MAX_BODY_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.MAX_BYTE_COUNT_PER_RPC;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.MAX_ELECTION_DELAY_MS;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.MAX_ENTRIES_SIZE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.MAX_REPLICATOR_INFLIGHT_MSGS;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.REPLICATOR_PIPELINE;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.SYNC;
|
||||
import static com.alibaba.nacos.core.distributed.raft.RaftSysConstants.SYNC_META;
|
||||
|
||||
/**
|
||||
* build {@link RaftOptions}.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class RaftOptionsBuilder {
|
||||
|
||||
/**
|
||||
* By {@link RaftConfig} creating a {@link RaftOptions}.
|
||||
*
|
||||
* @param config {@link RaftConfig}
|
||||
* @return {@link RaftOptions}
|
||||
*/
|
||||
public static RaftOptions initRaftOptions(RaftConfig config) {
|
||||
RaftOptions raftOptions = new RaftOptions();
|
||||
raftOptions.setReadOnlyOptions(raftReadIndexType(config));
|
||||
|
||||
raftOptions.setMaxByteCountPerRpc(
|
||||
ConvertUtils.toInt(config.getVal(MAX_BYTE_COUNT_PER_RPC), DEFAULT_MAX_BYTE_COUNT_PER_RPC));
|
||||
|
||||
raftOptions.setMaxEntriesSize(ConvertUtils.toInt(config.getVal(MAX_ENTRIES_SIZE), DEFAULT_MAX_ENTRIES_SIZE));
|
||||
|
||||
raftOptions.setMaxBodySize(ConvertUtils.toInt(config.getVal(MAX_BODY_SIZE), DEFAULT_MAX_BODY_SIZE));
|
||||
|
||||
raftOptions.setMaxAppendBufferSize(
|
||||
ConvertUtils.toInt(config.getVal(MAX_APPEND_BUFFER_SIZE), DEFAULT_MAX_APPEND_BUFFER_SIZE));
|
||||
|
||||
raftOptions.setMaxElectionDelayMs(
|
||||
ConvertUtils.toInt(config.getVal(MAX_ELECTION_DELAY_MS), DEFAULT_MAX_ELECTION_DELAY_MS));
|
||||
|
||||
raftOptions.setElectionHeartbeatFactor(
|
||||
ConvertUtils.toInt(config.getVal(ELECTION_HEARTBEAT_FACTOR), DEFAULT_ELECTION_HEARTBEAT_FACTOR));
|
||||
|
||||
raftOptions.setApplyBatch(ConvertUtils.toInt(config.getVal(APPLY_BATCH), DEFAULT_APPLY_BATCH));
|
||||
|
||||
raftOptions.setSync(ConvertUtils.toBoolean(config.getVal(SYNC), DEFAULT_SYNC));
|
||||
|
||||
raftOptions.setSyncMeta(ConvertUtils.toBoolean(config.getVal(SYNC_META), DEFAULT_SYNC_META));
|
||||
|
||||
raftOptions.setDisruptorBufferSize(
|
||||
ConvertUtils.toInt(config.getVal(DISRUPTOR_BUFFER_SIZE), DEFAULT_DISRUPTOR_BUFFER_SIZE));
|
||||
|
||||
raftOptions.setReplicatorPipeline(
|
||||
ConvertUtils.toBoolean(config.getVal(REPLICATOR_PIPELINE), DEFAULT_REPLICATOR_PIPELINE));
|
||||
|
||||
raftOptions.setMaxReplicatorInflightMsgs(
|
||||
ConvertUtils.toInt(config.getVal(MAX_REPLICATOR_INFLIGHT_MSGS), DEFAULT_MAX_REPLICATOR_INFLIGHT_MSGS));
|
||||
|
||||
raftOptions.setEnableLogEntryChecksum(
|
||||
ConvertUtils.toBoolean(config.getVal(ENABLE_LOG_ENTRY_CHECKSUM), DEFAULT_ENABLE_LOG_ENTRY_CHECKSUM));
|
||||
|
||||
return raftOptions;
|
||||
}
|
||||
|
||||
private static ReadOnlyOption raftReadIndexType(RaftConfig config) {
|
||||
String readOnySafe = "ReadOnlySafe";
|
||||
String readOnlyLeaseBased = "ReadOnlyLeaseBased";
|
||||
|
||||
String val = config.getVal(RaftSysConstants.RAFT_READ_INDEX_TYPE);
|
||||
|
||||
if (StringUtils.isBlank(val) || StringUtils.equals(readOnySafe, val)) {
|
||||
return ReadOnlyOption.ReadOnlySafe;
|
||||
}
|
||||
|
||||
if (StringUtils.equals(readOnlyLeaseBased, val)) {
|
||||
return ReadOnlyOption.ReadOnlyLeaseBased;
|
||||
}
|
||||
throw new IllegalArgumentException("Illegal Raft system parameters => ReadOnlyOption" + " : [" + val
|
||||
+ "], should be 'ReadOnlySafe' or 'ReadOnlyLeaseBased'");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +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.core.distributed.raft.utils;
|
||||
|
||||
/**
|
||||
* Retry function.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RetryRunner {
|
||||
|
||||
/**
|
||||
* Tasks that require retry.
|
||||
*/
|
||||
void run();
|
||||
|
||||
}
|
||||
@@ -1,106 +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.core.exception;
|
||||
|
||||
/**
|
||||
* Core module code starts with 40001.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public enum ErrorCode {
|
||||
|
||||
/**
|
||||
* unknow error.
|
||||
*/
|
||||
UnKnowError(40001),
|
||||
|
||||
// kv error
|
||||
|
||||
/**
|
||||
* KVStorage write error.
|
||||
*/
|
||||
KVStorageWriteError(40100),
|
||||
|
||||
/**
|
||||
* KVStorage read error.
|
||||
*/
|
||||
KVStorageReadError(40101),
|
||||
|
||||
/**
|
||||
* KVStorage delete error.
|
||||
*/
|
||||
KVStorageDeleteError(40102),
|
||||
|
||||
/**
|
||||
* KVStorage snapshot save error.
|
||||
*/
|
||||
KVStorageSnapshotSaveError(40103),
|
||||
|
||||
/**
|
||||
* KVStorage snapshot load error.
|
||||
*/
|
||||
KVStorageSnapshotLoadError(40104),
|
||||
|
||||
/**
|
||||
* KVStorage reset error.
|
||||
*/
|
||||
KVStorageResetError(40105),
|
||||
|
||||
/**
|
||||
* KVStorage create error.
|
||||
*/
|
||||
KVStorageCreateError(40106),
|
||||
|
||||
/**
|
||||
* KVStorage write error.
|
||||
*/
|
||||
KVStorageBatchWriteError(40107),
|
||||
|
||||
// disk error
|
||||
|
||||
/**
|
||||
* mkdir error.
|
||||
*/
|
||||
IOMakeDirError(40201),
|
||||
|
||||
/**
|
||||
* copy directory has error.
|
||||
*/
|
||||
IOCopyDirError(40202),
|
||||
|
||||
// consistency protocol error
|
||||
|
||||
/**
|
||||
* protocol write error.
|
||||
*/
|
||||
ProtoSubmitError(40301),
|
||||
|
||||
/**
|
||||
* protocol read error.
|
||||
*/
|
||||
ProtoReadError(40302);
|
||||
|
||||
private final int code;
|
||||
|
||||
ErrorCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +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.core.exception;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
/**
|
||||
* RocksDB Exception.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class KvStorageException extends NacosException {
|
||||
|
||||
public KvStorageException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public KvStorageException(ErrorCode code, String errMsg) {
|
||||
super(code.getCode(), errMsg);
|
||||
}
|
||||
|
||||
public KvStorageException(ErrorCode errCode, Throwable throwable) {
|
||||
super(errCode.getCode(), throwable);
|
||||
}
|
||||
|
||||
public KvStorageException(ErrorCode errCode, String errMsg, Throwable throwable) {
|
||||
super(errCode.getCode(), errMsg, throwable);
|
||||
}
|
||||
|
||||
public KvStorageException(int errCode, String errMsg) {
|
||||
super(errCode, errMsg);
|
||||
}
|
||||
|
||||
public KvStorageException(int errCode, Throwable throwable) {
|
||||
super(errCode, throwable);
|
||||
}
|
||||
|
||||
public KvStorageException(int errCode, String errMsg, Throwable throwable) {
|
||||
super(errCode, errMsg, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getErrCode() {
|
||||
return super.getErrCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrMsg() {
|
||||
return super.getErrMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrCode(int errCode) {
|
||||
super.setErrCode(errCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrMsg(String errMsg) {
|
||||
super.setErrMsg(errMsg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCauseThrowable(Throwable throwable) {
|
||||
super.setCauseThrowable(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,46 +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.core.exception;
|
||||
|
||||
/**
|
||||
* SnakflowerException.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class SnakflowerException extends RuntimeException {
|
||||
|
||||
public SnakflowerException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SnakflowerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SnakflowerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SnakflowerException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected SnakflowerException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +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.core.listener;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.springframework.boot.context.logging.LoggingApplicationListener.CONFIG_PROPERTY;
|
||||
import static org.springframework.core.io.ResourceLoader.CLASSPATH_URL_PREFIX;
|
||||
|
||||
/**
|
||||
* For init logging configuration.
|
||||
*
|
||||
* @author horizonzy
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class LoggingApplicationListener implements NacosApplicationListener {
|
||||
|
||||
private static final String DEFAULT_NACOS_LOGBACK_LOCATION = CLASSPATH_URL_PREFIX + "META-INF/logback/nacos.xml";
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingApplicationListener.class);
|
||||
|
||||
@Override
|
||||
public void starting() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void environmentPrepared(ConfigurableEnvironment environment) {
|
||||
if (!environment.containsProperty(CONFIG_PROPERTY)) {
|
||||
System.setProperty(CONFIG_PROPERTY, DEFAULT_NACOS_LOGBACK_LOCATION);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("There is no property named \"{}\" in Spring Boot Environment, "
|
||||
+ "and whose value is {} will be set into System's Properties", CONFIG_PROPERTY,
|
||||
DEFAULT_NACOS_LOGBACK_LOCATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextPrepared(ConfigurableApplicationContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextLoaded(ConfigurableApplicationContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started(ConfigurableApplicationContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void running(ConfigurableApplicationContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(ConfigurableApplicationContext context, Throwable exception) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,78 +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.core.listener;
|
||||
|
||||
import com.alibaba.nacos.core.code.SpringApplicationRunListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
* Nacos Application Listener, execute init process.
|
||||
*
|
||||
* @author horizonzy
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public interface NacosApplicationListener {
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#starting}.
|
||||
*/
|
||||
void starting();
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#environmentPrepared}.
|
||||
*
|
||||
* @param environment environment
|
||||
*/
|
||||
void environmentPrepared(ConfigurableEnvironment environment);
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#contextLoaded}.
|
||||
*
|
||||
* @param context context
|
||||
*/
|
||||
void contextPrepared(ConfigurableApplicationContext context);
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#contextLoaded}.
|
||||
*
|
||||
* @param context context
|
||||
*/
|
||||
void contextLoaded(ConfigurableApplicationContext context);
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#started}.
|
||||
*
|
||||
* @param context context
|
||||
*/
|
||||
void started(ConfigurableApplicationContext context);
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#running}.
|
||||
*
|
||||
* @param context context
|
||||
*/
|
||||
void running(ConfigurableApplicationContext context);
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunListener#failed}.
|
||||
*
|
||||
* @param context context
|
||||
* @param exception exception
|
||||
*/
|
||||
void failed(ConfigurableApplicationContext context, Throwable exception);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user