update 重构 ruoyi-nacos 使用官方依赖整合 升级 2.1.2 版本

This commit is contained in:
疯狂的狮子li
2022-11-07 10:23:12 +08:00
parent d30a00557a
commit 1aa8075eeb
179 changed files with 350 additions and 18398 deletions

View File

@@ -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>

View File

@@ -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());

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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 portThis 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};
}

View File

@@ -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;
}
}

View File

@@ -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 changesAll 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);
}
}
}

View File

@@ -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,
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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
+ '}';
}
}
}

View File

@@ -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 + '\'' + '}';
}
}
}

View File

@@ -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();
}

View File

@@ -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 + "";
}
}

View File

@@ -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.");
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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.");
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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())));
}
}
}

View File

@@ -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 + '}';
}
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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 + '\'' + '}';
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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/electionHeartbeatFactorOne 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";
}

View File

@@ -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");
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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"));
}
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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'");
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}

View File

@@ -1,269 +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.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.common.executor.ExecutorFactory;
import com.alibaba.nacos.common.executor.NameThreadFactory;
import com.alibaba.nacos.common.executor.ThreadPoolManager;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.file.FileChangeEvent;
import com.alibaba.nacos.sys.file.FileWatcher;
import com.alibaba.nacos.sys.file.WatchFileCenter;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.alibaba.nacos.sys.utils.DiskUtils;
import com.alibaba.nacos.sys.utils.InetUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* init environment config.
*
* @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a>
* @since 0.5.0
*/
public class StartingApplicationListener implements NacosApplicationListener {
private static final Logger LOGGER = LoggerFactory.getLogger(StartingApplicationListener.class);
private static final String MODE_PROPERTY_KEY_STAND_MODE = "nacos.mode";
private static final String MODE_PROPERTY_KEY_FUNCTION_MODE = "nacos.function.mode";
private static final String LOCAL_IP_PROPERTY_KEY = "nacos.local.ip";
private static final String NACOS_APPLICATION_CONF = "nacos_application_conf";
private static final String NACOS_MODE_STAND_ALONE = "stand alone";
private static final String NACOS_MODE_CLUSTER = "cluster";
private static final String DEFAULT_FUNCTION_MODE = "All";
private static final String DEFAULT_DATABASE = "mysql";
private static final String DATASOURCE_PLATFORM_PROPERTY = "spring.datasource.platform";
private static final String DEFAULT_DATASOURCE_PLATFORM = "";
private static final String DATASOURCE_MODE_EXTERNAL = "external";
private static final String DATASOURCE_MODE_EMBEDDED = "embedded";
private static final Map<String, Object> SOURCES = new ConcurrentHashMap<>();
private ScheduledExecutorService scheduledExecutorService;
private volatile boolean starting;
@Override
public void starting() {
starting = true;
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
makeWorkDir();
injectEnvironment(environment);
loadPreProperties(environment);
initSystemProperty();
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
logClusterConf();
logStarting();
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void started(ConfigurableApplicationContext context) {
starting = false;
closeExecutor();
ApplicationUtils.setStarted(true);
judgeStorageMode(context.getEnvironment());
}
@Override
public void running(ConfigurableApplicationContext context) {
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
starting = false;
makeWorkDir();
LOGGER.error("Startup errors : ", exception);
ThreadPoolManager.shutdown();
WatchFileCenter.shutdown();
NotifyCenter.shutdown();
closeExecutor();
context.close();
LOGGER.error("Nacos failed to start, please see {} for more details.",
Paths.get(EnvUtil.getNacosHome(), "logs/nacos.log"));
}
private void injectEnvironment(ConfigurableEnvironment environment) {
EnvUtil.setEnvironment(environment);
}
private void loadPreProperties(ConfigurableEnvironment environment) {
try {
SOURCES.putAll(EnvUtil.loadProperties(EnvUtil.getApplicationConfFileResource()));
environment.getPropertySources()
.addLast(new OriginTrackedMapPropertySource(NACOS_APPLICATION_CONF, SOURCES));
registerWatcher();
} catch (Exception e) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, e);
}
}
private void registerWatcher() throws NacosException {
WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), new FileWatcher() {
@Override
public void onChange(FileChangeEvent event) {
try {
Map<String, ?> tmp = EnvUtil.loadProperties(EnvUtil.getApplicationConfFileResource());
SOURCES.putAll(tmp);
NotifyCenter.publishEvent(ServerConfigChangeEvent.newEvent());
} catch (IOException ignore) {
LOGGER.warn("Failed to monitor file ", ignore);
}
}
@Override
public boolean interest(String context) {
return StringUtils.contains(context, "application.properties");
}
});
}
private void initSystemProperty() {
if (EnvUtil.getStandaloneMode()) {
System.setProperty(MODE_PROPERTY_KEY_STAND_MODE, NACOS_MODE_STAND_ALONE);
} else {
System.setProperty(MODE_PROPERTY_KEY_STAND_MODE, NACOS_MODE_CLUSTER);
}
if (EnvUtil.getFunctionMode() == null) {
System.setProperty(MODE_PROPERTY_KEY_FUNCTION_MODE, DEFAULT_FUNCTION_MODE);
} else if (EnvUtil.FUNCTION_MODE_CONFIG.equals(EnvUtil.getFunctionMode())) {
System.setProperty(MODE_PROPERTY_KEY_FUNCTION_MODE, EnvUtil.FUNCTION_MODE_CONFIG);
} else if (EnvUtil.FUNCTION_MODE_NAMING.equals(EnvUtil.getFunctionMode())) {
System.setProperty(MODE_PROPERTY_KEY_FUNCTION_MODE, EnvUtil.FUNCTION_MODE_NAMING);
}
System.setProperty(LOCAL_IP_PROPERTY_KEY, InetUtils.getSelfIP());
}
private void logClusterConf() {
if (!EnvUtil.getStandaloneMode()) {
try {
List<String> clusterConf = EnvUtil.readClusterConf();
LOGGER.info("The server IP list of Nacos is {}", clusterConf);
} catch (IOException e) {
LOGGER.error("read cluster conf fail", e);
}
}
}
private void closeExecutor() {
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdownNow();
}
}
private void makeWorkDir() {
String[] dirNames = new String[] {"logs", "conf", "data"};
for (String dirName : dirNames) {
LOGGER.info("Nacos Log files: {}", Paths.get(EnvUtil.getNacosHome(), dirName));
try {
DiskUtils.forceMkdir(new File(Paths.get(EnvUtil.getNacosHome(), dirName).toUri()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private void logStarting() {
if (!EnvUtil.getStandaloneMode()) {
scheduledExecutorService = ExecutorFactory
.newSingleScheduledExecutorService(new NameThreadFactory("com.alibaba.nacos.core.nacos-starting"));
scheduledExecutorService.scheduleWithFixedDelay(() -> {
if (starting) {
LOGGER.info("Nacos is starting...");
}
}, 1, 1, TimeUnit.SECONDS);
}
}
private void judgeStorageMode(ConfigurableEnvironment env) {
// External data sources are used by default in cluster mode
boolean useExternalStorage = (DEFAULT_DATABASE.equalsIgnoreCase(env.getProperty(DATASOURCE_PLATFORM_PROPERTY, DEFAULT_DATASOURCE_PLATFORM)));
// must initialize after setUseExternalDB
// This value is true in stand-alone mode and false in cluster mode
// If this value is set to true in cluster mode, nacos's distributed storage engine is turned on
// default value is depend on ${nacos.standalone}
if (!useExternalStorage) {
boolean embeddedStorage = EnvUtil.getStandaloneMode() || Boolean.getBoolean("embeddedStorage");
// If the embedded data source storage is not turned on, it is automatically
// upgraded to the external data source storage, as before
if (!embeddedStorage) {
useExternalStorage = true;
}
}
LOGGER.info("Nacos started successfully in {} mode. use {} storage",
System.getProperty(MODE_PROPERTY_KEY_STAND_MODE), useExternalStorage ? DATASOURCE_MODE_EXTERNAL : DATASOURCE_MODE_EMBEDDED);
}
}

Some files were not shown because too many files have changed in this diff Show More