#745 Support multiple server modes

This commit is contained in:
nkorange 2019-02-11 14:59:12 +08:00
parent 4fe7c3d3b8
commit 194387b583
40 changed files with 233 additions and 189 deletions

View File

@ -29,4 +29,6 @@ public class CommonParams {
public static final String NAMESPACE_ID = "namespaceId";
public static final String GROUP_NAME = "groupName";
}

View File

@ -23,7 +23,7 @@ import com.alibaba.nacos.api.exception.NacosException;
/**
* Naming Factory
*
* @author dungu.zpf
* @author nkorange
*/
public class NamingFactory {

View File

@ -27,7 +27,7 @@ import java.util.List;
/**
* Naming Service
*
* @author dungu.zpf
* @author nkorange
*/
public interface NamingService {

View File

@ -18,7 +18,7 @@ package com.alibaba.nacos.api.naming.listener;
/**
* Event Interface
*
* @author dungu.zpf
* @author nkorange
*/
public interface Event {
}

View File

@ -22,7 +22,7 @@ import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* Naming Event
*
* @author dungu.zpf
* @author nkorange
*/
public class NamingEvent implements Event {

View File

@ -21,7 +21,7 @@ import java.util.Map;
/**
* Cluster
*
* @author dungu.zpf
* @author nkorange
*/
public class Cluster {

View File

@ -22,7 +22,7 @@ import java.util.List;
/**
* ListView
*
* @author dungu.zpf
* @author nkorange
*/
public class ListView<T> {

View File

@ -19,9 +19,14 @@ import java.util.HashMap;
import java.util.Map;
/**
* Service
* Service of Nacos
* <p>
* We introduce a 'service --> cluster --> instance' model, in which service stores a list of clusters,
* which contains a list of instances.
* <p>
* Typically we put some unique properties between instances to service level.
*
* @author dungu.zpf
* @author nkorange
*/
public class Service {
@ -43,7 +48,7 @@ public class Service {
private String app;
/**
* Service group which is meant to classify services into different sets.
* Service group to classify services into different sets.
*/
private String group;

View File

@ -26,7 +26,7 @@ import java.util.List;
/**
* ServiceInfo
*
* @author dungu.zpf
* @author nkorange
*/
public class ServiceInfo {

View File

@ -16,7 +16,6 @@
package com.alibaba.nacos.naming.boot;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

View File

@ -0,0 +1,48 @@
/*
* 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.naming.cluster;
/**
* Server running mode
* <p>
* We use CAP theory to set the server mode, users can select their preferred mode in running time.
* <p>
* CP mode provides strong consistency, data persistence but network partition tolerance.
* <p>
* AP mode provides eventual consistency and network partition tolerance but data persistence.
* <p>
* Mixed mode provides CP for some data and AP for some other data.
* <p>
* Service level information and cluster level information are always operated via CP protocol, so
* in AP mode they cannot be edited.
*
* @author nkorange
* @since 1.0.0
*/
public enum ServerMode {
/**
* AP mode
*/
AP,
/**
* CP mode
*/
CP,
/**
* Mixed mode
*/
MIXED
}

View File

@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* Detect and control the working status of local server
@ -33,7 +34,7 @@ import javax.annotation.PostConstruct;
@Service
public class ServerStatusManager {
@Autowired
@Resource(name = "consistencyDelegate")
private ConsistencyService consistencyService;
@Autowired
@ -41,8 +42,6 @@ public class ServerStatusManager {
private ServerStatus serverStatus = ServerStatus.STARTING;
private boolean serverStatusLocked = false;
@PostConstruct
public void init() {
GlobalExecutor.registerServerStatusUpdater(new ServerStatusUpdater());

View File

@ -18,7 +18,10 @@ package com.alibaba.nacos.naming.consistency.ephemeral.partition;
import com.alibaba.nacos.naming.consistency.Datum;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**

View File

@ -49,14 +49,9 @@ public class RaftStore {
private Properties meta = new Properties();
private String metaFileName;
private String metaFileName = UtilsAndCommons.DATA_BASE_DIR + File.separator + "meta.properties";
private String cacheDir;
public RaftStore() {
metaFileName = UtilsAndCommons.DATA_BASE_DIR + File.separator + "meta.properties";
cacheDir = UtilsAndCommons.DATA_BASE_DIR + File.separator + "data";
}
private String cacheDir = UtilsAndCommons.DATA_BASE_DIR + File.separator + "data";
public synchronized ConcurrentHashMap<String, Datum<?>> loadDatums(RaftCore.Notifier notifier) throws Exception {
@ -116,7 +111,7 @@ public class RaftStore {
return null;
}
public synchronized static Datum readDatum(File file, String namespaceId) throws IOException {
public synchronized Datum readDatum(File file, String namespaceId) throws IOException {
ByteBuffer buffer;
FileChannel fc = null;

View File

@ -26,11 +26,7 @@ import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.naming.exception.NacosException;
import com.alibaba.nacos.naming.healthcheck.HealthCheckTask;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.pojo.ClusterInfo;
import com.alibaba.nacos.naming.pojo.IpAddressInfo;
import com.alibaba.nacos.naming.pojo.ServiceDetailInfo;
import com.alibaba.nacos.naming.pojo.ServiceDetailView;
import com.alibaba.nacos.naming.pojo.ServiceView;
import com.alibaba.nacos.naming.pojo.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;

View File

@ -21,8 +21,8 @@ import com.alibaba.nacos.api.naming.CommonParams;
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.naming.exception.NacosException;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;

View File

@ -21,6 +21,7 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.naming.CommonParams;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.boot.RunningConfig;
import com.alibaba.nacos.naming.cluster.ServerMode;
import com.alibaba.nacos.naming.core.DistroMapper;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
@ -90,7 +91,7 @@ public class InstanceController {
@RequestMapping(value = "/instance", method = RequestMethod.POST)
public String register(HttpServletRequest request) throws Exception {
return regService(request);
return registerInstance(request);
}
@RequestMapping(value = "/instance", method = RequestMethod.DELETE)
@ -112,7 +113,7 @@ public class InstanceController {
@RequestMapping(value = {"/instance/update", "instance"}, method = RequestMethod.PUT)
public String update(HttpServletRequest request) throws Exception {
return regService(request);
return registerInstance(request);
}
@RequestMapping(value = {"/instances", "/instance/list"}, method = RequestMethod.GET)
@ -184,6 +185,16 @@ public class InstanceController {
@RequestMapping(value = "/instance/beat", method = RequestMethod.PUT)
public JSONObject beat(HttpServletRequest request) throws Exception {
JSONObject result = new JSONObject();
result.put("clientBeatInterval", switchDomain.getClientBeatInterval());
// ignore client beat in CP mode:
if (ServerMode.CP.name().equals(switchDomain.getServerMode())) {
return result;
}
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,
UtilsAndCommons.DEFAULT_NAMESPACE_ID);
String beat = WebUtils.required(request, "beat");
@ -218,7 +229,13 @@ public class InstanceController {
instance.setClusterName(clusterName);
instance.setServiceName(serviceName);
instance.setInstanceId(instance.generateInstanceId());
instance.setEphemeral(clientBeat.isEphemeral());
if (ServerMode.AP.name().equals(switchDomain.getServerMode())) {
serviceManager.registerInstance(namespaceId, serviceName, clusterName, instance);
} else {
serviceManager.addInstance(namespaceId, serviceName, clusterName, true, instance);
}
}
Service service = serviceManager.getService(namespaceId, serviceName);
@ -252,10 +269,6 @@ public class InstanceController {
service.processClientBeat(clientBeat);
}
JSONObject result = new JSONObject();
result.put("clientBeatInterval", switchDomain.getClientBeatInterval());
return result;
}
@ -295,7 +308,7 @@ public class InstanceController {
return result;
}
private String regService(HttpServletRequest request) throws Exception {
private String registerInstance(HttpServletRequest request) throws Exception {
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
String clusterName = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME);
@ -325,7 +338,9 @@ public class InstanceController {
String weight = WebUtils.optional(request, "weight", "1");
String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME);
boolean enabled = BooleanUtils.toBoolean(WebUtils.optional(request, "enable", "true"));
boolean ephemeral = BooleanUtils.toBoolean(WebUtils.optional(request, "ephemeral", "true"));
// If server running in CP mode, we set this flag to false:
boolean ephemeral = BooleanUtils.toBoolean(WebUtils.optional(request, "ephemeral",
String.valueOf(!ServerMode.CP.name().equals(switchDomain.getServerMode()))));
Instance instance = new Instance();
instance.setPort(Integer.parseInt(port));

View File

@ -16,14 +16,11 @@
package com.alibaba.nacos.naming.controllers;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.common.util.IoUtils;
import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.cluster.transport.Serializer;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.ephemeral.partition.PartitionConsistencyServiceImpl;
import com.alibaba.nacos.naming.cluster.transport.Serializer;
import com.alibaba.nacos.naming.core.Instances;
import com.alibaba.nacos.naming.exception.NacosException;
import com.alibaba.nacos.naming.misc.Loggers;
@ -37,7 +34,6 @@ import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**

View File

@ -24,7 +24,9 @@ import com.alibaba.nacos.core.utils.WebUtils;
import com.alibaba.nacos.naming.consistency.DataListener;
import com.alibaba.nacos.naming.consistency.Datum;
import com.alibaba.nacos.naming.consistency.KeyBuilder;
import com.alibaba.nacos.naming.consistency.persistent.raft.*;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftConsistencyServiceImpl;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeer;
import com.alibaba.nacos.naming.core.Instances;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;

View File

@ -25,7 +25,6 @@ import com.alibaba.nacos.naming.cluster.ServerListManager;
import com.alibaba.nacos.naming.core.*;
import com.alibaba.nacos.naming.exception.NacosException;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.selector.LabelSelector;
import com.alibaba.nacos.naming.selector.NoneSelector;
@ -53,9 +52,6 @@ public class ServiceController {
@Autowired
protected ServiceManager serviceManager;
@Autowired
private SwitchDomain switchDomain;
@Autowired
private DistroMapper distroMapper;

View File

@ -16,7 +16,6 @@
package com.alibaba.nacos.naming.core;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
import com.alibaba.nacos.naming.healthcheck.HealthCheckReactor;
import com.alibaba.nacos.naming.healthcheck.HealthCheckStatus;
import com.alibaba.nacos.naming.healthcheck.HealthCheckTask;

View File

@ -40,12 +40,12 @@ import java.security.MessageDigest;
import java.util.*;
/**
* Service of Nacos
* Service of Nacos server side
* <p>
* We introduce a 'service --> cluster --> instance' model, in which service stores a list of clusters,
* which contains a list of instances.
* <p>
* Typically we put some common properties between instances to service level.
* This class inherits from Service in API module and stores some fields that do not expose to client.
*
* @author nkorange
*/

View File

@ -21,7 +21,6 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.naming.cluster.ServerListManager;
import com.alibaba.nacos.naming.cluster.servers.Server;
import com.alibaba.nacos.naming.cluster.transport.Serializer;
import com.alibaba.nacos.naming.consistency.ConsistencyService;
import com.alibaba.nacos.naming.consistency.DataListener;
import com.alibaba.nacos.naming.consistency.Datum;
@ -37,12 +36,15 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Core manager storing all services in Nacos
*
* @author nkorange
*/
@Component
@ -54,21 +56,12 @@ public class ServiceManager implements DataListener<Service> {
*/
private Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
private LinkedBlockingDeque<ServiceKey> toBeUpdatedDomsQueue = new LinkedBlockingDeque<>(1024 * 1024);
private LinkedBlockingDeque<ServiceKey> toBeUpdatedServicesQueue = new LinkedBlockingDeque<>(1024 * 1024);
private Synchronizer synchronizer = new DomainStatusSynchronizer();
/**
* thread pool core size
*/
private final static int DOMAIN_UPDATE_EXECUTOR_NUM = 2;
private final Lock lock = new ReentrantLock();
private Map<String, Condition> service2ConditionMap = new ConcurrentHashMap<>();
private Map<String, Lock> service2LockMap = new ConcurrentHashMap<>();
@Resource(name = "consistencyDelegate")
private ConsistencyService consistencyService;
@ -84,29 +77,12 @@ public class ServiceManager implements DataListener<Service> {
@Autowired
private PushService pushService;
@Autowired
private Serializer serializer;
/**
* thread pool that processes getting service detail from other server asynchronously
*/
private ExecutorService serviceUpdateExecutor
= Executors.newFixedThreadPool(DOMAIN_UPDATE_EXECUTOR_NUM, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.naming.service.update.http.handler");
t.setDaemon(true);
return t;
}
});
@PostConstruct
public void init() {
UtilsAndCommons.DOMAIN_SYNCHRONIZATION_EXECUTOR.schedule(new ServiceReporter(), 60000, TimeUnit.MILLISECONDS);
UtilsAndCommons.DOMAIN_UPDATE_EXECUTOR.submit(new UpdatedDomainProcessor());
UtilsAndCommons.DOMAIN_UPDATE_EXECUTOR.submit(new UpdatedServiceProcessor());
try {
Loggers.SRV_LOG.info("listen for service meta change");
@ -123,10 +99,10 @@ public class ServiceManager implements DataListener<Service> {
public void addUpdatedService2Queue(String namespaceId, String serviceName, String serverIP, String checksum) {
lock.lock();
try {
toBeUpdatedDomsQueue.offer(new ServiceKey(namespaceId, serviceName, serverIP, checksum), 5, TimeUnit.MILLISECONDS);
toBeUpdatedServicesQueue.offer(new ServiceKey(namespaceId, serviceName, serverIP, checksum), 5, TimeUnit.MILLISECONDS);
} catch (Exception e) {
toBeUpdatedDomsQueue.poll();
toBeUpdatedDomsQueue.add(new ServiceKey(namespaceId, serviceName, serverIP, checksum));
toBeUpdatedServicesQueue.poll();
toBeUpdatedServicesQueue.add(new ServiceKey(namespaceId, serviceName, serverIP, checksum));
Loggers.SRV_LOG.error("[DOMAIN-STATUS] Failed to add service to be updatd to queue.", e);
} finally {
lock.unlock();
@ -162,16 +138,12 @@ public class ServiceManager implements DataListener<Service> {
if (oldDom != null) {
oldDom.update(service);
} else {
addLockIfAbsent(UtilsAndCommons.assembleFullServiceName(service.getNamespaceId(), service.getName()));
putService(service);
service.init();
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJSON());
}
wakeUp(UtilsAndCommons.assembleFullServiceName(service.getNamespaceId(), service.getName()));
} catch (Throwable e) {
Loggers.SRV_LOG.error("[NACOS-SERVICE] error while processing service update", e);
}
@ -189,23 +161,20 @@ public class ServiceManager implements DataListener<Service> {
consistencyService.remove(KeyBuilder.buildInstanceListKey(namespace, name, true));
consistencyService.remove(KeyBuilder.buildInstanceListKey(namespace, name, false));
consistencyService.unlisten(KeyBuilder.buildServiceMetaKey(namespace, name), service);
Loggers.SRV_LOG.info("[DEAD-DOM] {}", service.toJSON());
Loggers.SRV_LOG.info("[DEAD-SERVICE] {}", service.toJSON());
}
}
private class UpdatedDomainProcessor implements Runnable {
private class UpdatedServiceProcessor implements Runnable {
//get changed service from other server asynchronously
@Override
public void run() {
String serviceName = null;
String serverIP = null;
try {
while (true) {
ServiceKey serviceKey = null;
try {
serviceKey = toBeUpdatedDomsQueue.take();
while (true) {
try {
serviceKey = toBeUpdatedServicesQueue.take();
} catch (Exception e) {
Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while taking item from LinkedBlockingDeque.");
}
@ -213,14 +182,10 @@ public class ServiceManager implements DataListener<Service> {
if (serviceKey == null) {
continue;
}
serviceName = serviceKey.getServiceName();
serverIP = serviceKey.getServerIP();
serviceUpdateExecutor.execute(new ServiceUpdater(serviceKey.getNamespaceId(), serviceName, serverIP));
GlobalExecutor.sumbitServiceUpdate(new ServiceUpdater(serviceKey));
}
} catch (Exception e) {
Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while update service: {} from {}, error: {}", serviceName, serverIP, e);
Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while update service: {}", serviceKey, e);
}
}
}
@ -231,10 +196,10 @@ public class ServiceManager implements DataListener<Service> {
String serviceName;
String serverIP;
public ServiceUpdater(String namespaceId, String serviceName, String serverIP) {
this.namespaceId = namespaceId;
this.serviceName = serviceName;
this.serverIP = serverIP;
public ServiceUpdater(ServiceKey serviceKey) {
this.namespaceId = serviceKey.getNamespaceId();
this.serviceName = serviceKey.getServiceName();
this.serverIP = serviceKey.getServerIP();
}
@Override
@ -357,7 +322,7 @@ public class ServiceManager implements DataListener<Service> {
}
/**
* Register an instance to a service.
* Register an instance to a service in AP mode.
* <p>
* This method creates service or cluster silently if they don't exist.
*
@ -400,28 +365,9 @@ public class ServiceManager implements DataListener<Service> {
serviceUpdated = true;
}
// only local memory is updated:
if (serviceUpdated) {
Lock lock = addLockIfAbsent(UtilsAndCommons.assembleFullServiceName(namespaceId, serviceName));
Condition condition = addCondtion(UtilsAndCommons.assembleFullServiceName(namespaceId, serviceName));
final Service finalService = service;
GlobalExecutor.submit(new Runnable() {
@Override
public void run() {
try {
addOrReplaceService(finalService);
} catch (Exception e) {
Loggers.SRV_LOG.error("register or update service failed, service: {}", finalService, e);
}
}
});
try {
lock.lock();
condition.await(5000, TimeUnit.MILLISECONDS);
} finally {
lock.unlock();
}
putService(service);
}
if (service.allIPs().contains(instance)) {
@ -437,6 +383,11 @@ public class ServiceManager implements DataListener<Service> {
Service service = getService(namespaceId, serviceName);
if (service == null) {
throw new NacosException(NacosException.INVALID_PARAM,
"service not found, namespace: " + namespaceId + ", service: " + serviceName);
}
Map<String, Instance> instanceMap = addIpAddresses(service, ephemeral, ips);
Instances instances = new Instances();
@ -564,7 +515,6 @@ public class ServiceManager implements DataListener<Service> {
serviceMap.get(service.getNamespaceId()).put(service.getName(), service);
}
public List<Service> searchServices(String namespaceId, String regex) {
List<Service> result = new ArrayList<>();
for (Map.Entry<String, Service> entry : chooseServiceMap(namespaceId).entrySet()) {
@ -716,40 +666,11 @@ public class ServiceManager implements DataListener<Service> {
}
}
public void wakeUp(String key) {
Lock lock = service2LockMap.get(key);
Condition condition = service2ConditionMap.get(key);
try {
lock.lock();
condition.signalAll();
} catch (Exception ignore) {
} finally {
lock.unlock();
}
}
public Lock addLockIfAbsent(String key) {
if (service2LockMap.containsKey(key)) {
return service2LockMap.get(key);
}
Lock lock = new ReentrantLock();
service2LockMap.put(key, lock);
return lock;
}
public Condition addCondtion(String key) {
Condition condition = service2LockMap.get(key).newCondition();
service2ConditionMap.put(key, condition);
return condition;
}
private static class ServiceKey {
private String namespaceId;
private String serviceName;
private String serverIP;
private String checksum;
public String getChecksum() {
return checksum;
@ -767,13 +688,16 @@ public class ServiceManager implements DataListener<Service> {
return namespaceId;
}
private String checksum;
public ServiceKey(String namespaceId, String serviceName, String serverIP, String checksum) {
this.namespaceId = namespaceId;
this.serviceName = serviceName;
this.serverIP = serverIP;
this.checksum = checksum;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
}

View File

@ -18,7 +18,9 @@ package com.alibaba.nacos.naming.healthcheck;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.nacos.naming.boot.SpringContext;
import com.alibaba.nacos.naming.core.*;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import com.alibaba.nacos.naming.push.PushService;

View File

@ -18,7 +18,6 @@ package com.alibaba.nacos.naming.healthcheck;
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
import com.ning.http.client.AsyncCompletionHandler;

View File

@ -18,7 +18,6 @@ package com.alibaba.nacos.naming.healthcheck;
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.monitor.MetricsMonitor;

View File

@ -36,6 +36,7 @@ public class RsInfo {
private String ak;
private String cluster;
private double weight;
private boolean ephemeral = true;
private Map<String, String> metadata;
public String getServiceName() {
@ -126,6 +127,14 @@ public class RsInfo {
this.weight = weight;
}
public boolean isEphemeral() {
return ephemeral;
}
public void setEphemeral(boolean ephemeral) {
this.ephemeral = ephemeral;
}
public Map<String, String> getMetadata() {
return metadata;
}

View File

@ -19,8 +19,8 @@ import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.monitor.MetricsMonitor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@ -15,10 +15,7 @@
*/
package com.alibaba.nacos.naming.misc;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
/**
* @author nacos
@ -103,6 +100,20 @@ public class GlobalExecutor {
}
});
/**
* thread pool that processes getting service detail from other server asynchronously
*/
private static ExecutorService serviceUpdateExecutor
= Executors.newFixedThreadPool(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.naming.service.update.http.handler");
t.setDaemon(true);
return t;
}
});
public static void submitDataSync(Runnable runnable) {
dataSyncExecutor.submit(runnable);
}
@ -147,4 +158,8 @@ public class GlobalExecutor {
public static void submit(Runnable runnable) {
executorService.submit(runnable);
}
public static void sumbitServiceUpdate(Runnable runnable) {
serviceUpdateExecutor.execute(runnable);
}
}

View File

@ -28,7 +28,6 @@ import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;

View File

@ -93,7 +93,9 @@ public class SwitchDomain implements DataListener<SwitchDomain> {
public boolean enableAuthentication = false;
public String overriddenServerStatus = null;
private String overriddenServerStatus = null;
private String serverMode = "MIXED";
public boolean isEnableAuthentication() {
return enableAuthentication;
@ -361,6 +363,14 @@ public class SwitchDomain implements DataListener<SwitchDomain> {
this.overriddenServerStatus = overriddenServerStatus;
}
public String getServerMode() {
return serverMode;
}
public void setServerMode(String serverMode) {
this.serverMode = serverMode;
}
public void replace(SwitchDomain newSwitchDomain) {
// TODO
}

View File

@ -66,4 +66,5 @@ public class SwitchEntry {
public static final String READ_ENABLED = "readEnabled";
public static final String OVERRIDDEN_SERVER_STATUS = "overriddenServerStatus";
public static final String SERVER_MODE = "serverMode";
}

View File

@ -17,6 +17,7 @@ package com.alibaba.nacos.naming.misc;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.naming.cluster.ServerMode;
import com.alibaba.nacos.naming.consistency.ConsistencyService;
import com.alibaba.nacos.naming.consistency.Datum;
import org.apache.commons.lang3.StringUtils;
@ -356,6 +357,17 @@ public class SwitchManager {
return;
}
if (entry.equals(SwitchEntry.SERVER_MODE)) {
String mode = value;
switchDomain.setServerMode(ServerMode.valueOf(mode).name());
if (!debug) {
consistencyService.put(UtilsAndCommons.getSwitchDomainKey(), JSON.toJSONString(switchDomain));
}
return;
}
throw new IllegalArgumentException("update entry not found: " + entry);
} finally {
lock.unlock();

View File

@ -34,7 +34,6 @@ import java.util.Map;
import java.util.concurrent.*;
import static com.alibaba.nacos.common.util.SystemUtils.NACOS_HOME;
import static com.alibaba.nacos.common.util.SystemUtils.NACOS_HOME_KEY;
/**
* @author nacos
@ -119,6 +118,8 @@ public class UtilsAndCommons {
public static final String DEFAULT_NAMESPACE_ID = "public";
public static final String DEFAULT_GROUP_NAME = "DEFAULT_GROUP";
public static final String DATA_BASE_DIR = NACOS_HOME + File.separator + "data" + File.separator + "naming";
public static final ScheduledExecutorService DOMAIN_SYNCHRONIZATION_EXECUTOR;

View File

@ -22,8 +22,8 @@ import com.alibaba.nacos.naming.misc.Loggers;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.push.PushService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;

View File

@ -100,35 +100,35 @@ public class AuthFilter implements Filter {
private Class<?> mapClass(String path) throws NacosException {
if (path.contains(UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT)) {
return InstanceController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_SERVICE_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_SERVICE_CONTEXT)) {
return ServiceController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_CLUSTER_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_CLUSTER_CONTEXT)) {
return ClusterController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_OPERATOR_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_OPERATOR_CONTEXT)) {
return OperatorController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_CATALOG_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_CATALOG_CONTEXT)) {
return CatalogController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_HEALTH_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_HEALTH_CONTEXT)) {
return HealthController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_RAFT_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_RAFT_CONTEXT)) {
return RaftController.class;
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_PARTITION_CONTEXT)) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_PARTITION_CONTEXT)) {
return PartitionController.class;
}

View File

@ -19,8 +19,6 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
/**
* @author nkorange
*/

View File

@ -16,8 +16,10 @@
package com.alibaba.nacos.naming.web;
import com.alibaba.nacos.common.util.HttpMethod;
import com.alibaba.nacos.naming.cluster.ServerMode;
import com.alibaba.nacos.naming.cluster.ServerStatus;
import com.alibaba.nacos.naming.cluster.ServerStatusManager;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -26,6 +28,8 @@ import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Filter incoming traffic to refuse or revise unexpected requests
@ -38,12 +42,33 @@ public class TrafficReviseFilter implements Filter {
@Autowired
private ServerStatusManager serverStatusManager;
@Autowired
private SwitchDomain switchDomain;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// in AP mode, service and cluster cannot be edited:
try {
String path = new URI(req.getRequestURI()).getPath();
if (ServerMode.AP.name().equals(switchDomain.getServerMode()) && !HttpMethod.GET.equals(req.getMethod())) {
if (path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_SERVICE_CONTEXT)
|| path.startsWith(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_CLUSTER_CONTEXT)) {
resp.getWriter().write("server in AP mode, request: " + req.getMethod() + " " + path + " not permitted");
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
} catch (URISyntaxException e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Server parse url failed," + UtilsAndCommons.getAllExceptionMsg(e));
return;
}
// if server is UP:
if (serverStatusManager.getServerStatus() == ServerStatus.UP) {
filterChain.doFilter(req, resp);

View File

@ -15,9 +15,9 @@
*/
package com.alibaba.nacos.naming;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeerSet;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeer;
import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeerSet;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.naming.misc.NetUtils;
import org.junit.Before;

View File

@ -43,7 +43,6 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author nkorange
@ -87,10 +86,6 @@ public class InstanceControllerTest extends BaseTest {
Mockito.when(domainsManager.getService(UtilsAndCommons.DEFAULT_NAMESPACE_ID, "nacos.test.1")).thenReturn(domain);
Mockito.when(domainsManager.addLockIfAbsent(
UtilsAndCommons.assembleFullServiceName(UtilsAndCommons.DEFAULT_NAMESPACE_ID, "nacos.test.1")))
.thenReturn(new ReentrantLock());
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.put("/naming/instance")
.param("serviceName", "nacos.test.1")