mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
支持预发布、灰度发布
This commit is contained in:
@@ -4,9 +4,9 @@ import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tanghc
|
* @author tanghc
|
||||||
@@ -18,17 +18,13 @@ public class DefaultEnvGrayManager implements EnvGrayManager {
|
|||||||
*/
|
*/
|
||||||
private Map<String, ServiceGrayConfig> serviceUserKeyMap = Maps.newConcurrentMap();
|
private Map<String, ServiceGrayConfig> serviceUserKeyMap = Maps.newConcurrentMap();
|
||||||
|
|
||||||
private Map<String, List<String>> serviceInstanceIdMap = Maps.newConcurrentMap();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addServiceInstance(String serviceId, String instanceId) {
|
|
||||||
List<String> instanceIdList = serviceInstanceIdMap.computeIfAbsent(serviceId, key -> new ArrayList<>());
|
|
||||||
instanceIdList.add(instanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> listGrayInstanceId(String serviceId) {
|
public List<String> listGrayInstanceId(String serviceId) {
|
||||||
return serviceInstanceIdMap.get(serviceId);
|
return serviceUserKeyMap
|
||||||
|
.values()
|
||||||
|
.stream()
|
||||||
|
.map(ServiceGrayConfig::getInstanceId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,6 +47,7 @@ public class DefaultEnvGrayManager implements EnvGrayManager {
|
|||||||
public ServiceGrayConfig getServiceGrayConfig(String instanceId) {
|
public ServiceGrayConfig getServiceGrayConfig(String instanceId) {
|
||||||
return serviceUserKeyMap.computeIfAbsent(instanceId, key -> {
|
return serviceUserKeyMap.computeIfAbsent(instanceId, key -> {
|
||||||
ServiceGrayConfig serviceGrayConfig = new ServiceGrayConfig();
|
ServiceGrayConfig serviceGrayConfig = new ServiceGrayConfig();
|
||||||
|
serviceGrayConfig.setInstanceId(instanceId);
|
||||||
serviceGrayConfig.setUserKeys(Sets.newConcurrentHashSet());
|
serviceGrayConfig.setUserKeys(Sets.newConcurrentHashSet());
|
||||||
serviceGrayConfig.setGrayNameVersion(Maps.newConcurrentMap());
|
serviceGrayConfig.setGrayNameVersion(Maps.newConcurrentMap());
|
||||||
return serviceGrayConfig;
|
return serviceGrayConfig;
|
||||||
|
@@ -10,8 +10,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface EnvGrayManager extends BeanInitializer {
|
public interface EnvGrayManager extends BeanInitializer {
|
||||||
|
|
||||||
void addServiceInstance(String serviceId, String instanceId);
|
|
||||||
|
|
||||||
List<String> listGrayInstanceId(String serviceId);
|
List<String> listGrayInstanceId(String serviceId);
|
||||||
|
|
||||||
boolean containsKey(String instanceId, Object userKey);
|
boolean containsKey(String instanceId, Object userKey);
|
||||||
|
@@ -11,6 +11,7 @@ import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter;
|
|||||||
import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter;
|
import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter;
|
||||||
import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter;
|
import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter;
|
||||||
import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter;
|
import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter;
|
||||||
|
import com.gitee.sop.gatewaycommon.zuul.filter.PreVersionDecisionFilter;
|
||||||
import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt;
|
import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt;
|
||||||
import com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator;
|
import com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator;
|
||||||
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteRepository;
|
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteRepository;
|
||||||
@@ -111,6 +112,14 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
|
|||||||
return new PreLimitFilter();
|
return new PreLimitFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 决定版本号
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
PreVersionDecisionFilter preVersionDecisionFilter() {
|
||||||
|
return new PreVersionDecisionFilter();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 错误处理扩展
|
* 错误处理扩展
|
||||||
*/
|
*/
|
||||||
@@ -127,6 +136,7 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
|
|||||||
return new PostResultFilter();
|
return new PostResultFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一错误处理
|
* 统一错误处理
|
||||||
*/
|
*/
|
||||||
|
@@ -40,14 +40,16 @@ public class PreVersionDecisionFilter extends BaseZuulFilter {
|
|||||||
}
|
}
|
||||||
String serviceId = targetRoute.getServiceRouteInfo().getServiceId();
|
String serviceId = targetRoute.getServiceRouteInfo().getServiceId();
|
||||||
List<String> instanceIdList = envGrayManager.listGrayInstanceId(serviceId);
|
List<String> instanceIdList = envGrayManager.listGrayInstanceId(serviceId);
|
||||||
|
String appKey = apiParam.fetchAppKey();
|
||||||
for (String instanceId : instanceIdList) {
|
for (String instanceId : instanceIdList) {
|
||||||
|
if (envGrayManager.containsKey(instanceId, appKey)) {
|
||||||
String version = envGrayManager.getVersion(instanceId, nameVersion);
|
String version = envGrayManager.getVersion(instanceId, nameVersion);
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, version);
|
requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, version);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,22 +19,6 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class BaseServerChooser extends ZoneAvoidanceRule {
|
public abstract class BaseServerChooser extends ZoneAvoidanceRule {
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否匹配对应的服务器,可在此判断是否是预发布,灰度环境
|
|
||||||
*
|
|
||||||
* @param server 指定服务器
|
|
||||||
* @return 返回true:是
|
|
||||||
*/
|
|
||||||
protected abstract boolean match(Server server);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 客户端能否够访问服务器
|
|
||||||
*
|
|
||||||
* @param server 服务器实例
|
|
||||||
* @param request request
|
|
||||||
* @return 返回true:能访问
|
|
||||||
*/
|
|
||||||
protected abstract boolean canVisit(Server server, HttpServletRequest request);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是预发布服务器
|
* 是否是预发布服务器
|
||||||
@@ -97,7 +81,8 @@ public abstract class BaseServerChooser extends ZoneAvoidanceRule {
|
|||||||
|
|
||||||
List<Server> grayServers = allServers.stream()
|
List<Server> grayServers = allServers.stream()
|
||||||
.filter(this::isGrayServer)
|
.filter(this::isGrayServer)
|
||||||
.filter(server -> canVisitGray(server, request))
|
// 这句暂时不需要,放到了PreVersionDecisionFilter中判断
|
||||||
|
//.filter(server -> canVisitGray(server, request))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (!grayServers.isEmpty()) {
|
if (!grayServers.isEmpty()) {
|
||||||
return doChoose(grayServers, key);
|
return doChoose(grayServers, key);
|
||||||
|
@@ -10,6 +10,11 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class ServiceGrayConfig {
|
public class ServiceGrayConfig {
|
||||||
|
|
||||||
|
private String serviceId;
|
||||||
|
|
||||||
|
private String instanceId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户id
|
* 用户id
|
||||||
*/
|
*/
|
||||||
|
@@ -8,7 +8,6 @@ import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
|
|||||||
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser;
|
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser;
|
||||||
import com.netflix.loadbalancer.Server;
|
import com.netflix.loadbalancer.Server;
|
||||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -23,6 +22,7 @@ public class EnvironmentServerChooser extends BaseServerChooser {
|
|||||||
private static final String MEDATA_KEY_ENV = "env";
|
private static final String MEDATA_KEY_ENV = "env";
|
||||||
private static final String ENV_PRE_VALUE = "pre";
|
private static final String ENV_PRE_VALUE = "pre";
|
||||||
private static final String ENV_GRAY_VALUE = "gray";
|
private static final String ENV_GRAY_VALUE = "gray";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预发布机器域名
|
* 预发布机器域名
|
||||||
*/
|
*/
|
||||||
@@ -46,39 +46,6 @@ public class EnvironmentServerChooser extends BaseServerChooser {
|
|||||||
return metadata.get(MEDATA_KEY_ENV);
|
return metadata.get(MEDATA_KEY_ENV);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean match(Server server) {
|
|
||||||
// eureka存储的metadata
|
|
||||||
Map<String, String> metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();
|
|
||||||
String env = metadata.get(MEDATA_KEY_ENV);
|
|
||||||
return StringUtils.isNotBlank(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 这里判断客户端能否访问,可以根据ip地址,域名,header内容来决定是否可以访问预发布环境
|
|
||||||
*
|
|
||||||
* @param server 服务器实例
|
|
||||||
* @param request request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected boolean canVisit(Server server, HttpServletRequest request) {
|
|
||||||
// eureka存储的metadata
|
|
||||||
Map<String, String> metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();
|
|
||||||
String env = metadata.get(MEDATA_KEY_ENV);
|
|
||||||
boolean canVisit;
|
|
||||||
switch (env) {
|
|
||||||
case ENV_PRE_VALUE:
|
|
||||||
canVisit = canVisitPre(server, request);
|
|
||||||
break;
|
|
||||||
case ENV_GRAY_VALUE:
|
|
||||||
canVisit = canVisitGray(server, request);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
canVisit = false;
|
|
||||||
}
|
|
||||||
return canVisit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过判断hostname来确定是否是预发布请求,可修改此方法实现自己想要的
|
* 通过判断hostname来确定是否是预发布请求,可修改此方法实现自己想要的
|
||||||
|
@@ -46,7 +46,6 @@ public class DbEnvGrayManager extends DefaultEnvGrayManager {
|
|||||||
List<ConfigGrayUserkey> list = configGrayUserkeyMapper.list(query);
|
List<ConfigGrayUserkey> list = configGrayUserkeyMapper.list(query);
|
||||||
for (ConfigGrayUserkey configGrayUserkey : list) {
|
for (ConfigGrayUserkey configGrayUserkey : list) {
|
||||||
this.setServiceGrayConfig(configGrayUserkey);
|
this.setServiceGrayConfig(configGrayUserkey);
|
||||||
this.addServiceInstance(configGrayUserkey.getServiceId(), configGrayUserkey.getInstanceId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +68,7 @@ public class DbEnvGrayManager extends DefaultEnvGrayManager {
|
|||||||
|
|
||||||
List<String> list = Stream.of(userKeys).collect(Collectors.toList());
|
List<String> list = Stream.of(userKeys).collect(Collectors.toList());
|
||||||
ServiceGrayConfig serviceGrayConfig = getServiceGrayConfig(instanceId);
|
ServiceGrayConfig serviceGrayConfig = getServiceGrayConfig(instanceId);
|
||||||
|
serviceGrayConfig.setServiceId(configGrayUserkey.getServiceId());
|
||||||
serviceGrayConfig.getUserKeys().addAll(list);
|
serviceGrayConfig.getUserKeys().addAll(list);
|
||||||
|
|
||||||
Map<String, String> grayNameVersion = serviceGrayConfig.getGrayNameVersion();
|
Map<String, String> grayNameVersion = serviceGrayConfig.getGrayNameVersion();
|
||||||
|
Reference in New Issue
Block a user