优化灰度预发布

2.x
tanghc 5 years ago
parent 994b486163
commit c1849bcaf3
  1. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvGrayManager.java
  2. 1
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreEnvGrayFilter.java
  3. 73
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java

@ -8,6 +8,8 @@ import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
*/
public interface EnvGrayManager extends BeanInitializer {
String ENV_GRAY = "sop.env-gray";
/**
* 保存灰度配置
* @param serviceGrayConfig 灰度配置

@ -42,6 +42,7 @@ public class PreEnvGrayFilter extends BaseZuulFilter {
// 如果服务在灰度阶段,返回一个灰度版本号
String version = envGrayManager.getVersion(serviceId, nameVersion);
if (version != null && envGrayManager.containsKey(serviceId, apiParam.fetchAppKey())) {
requestContext.set(EnvGrayManager.ENV_GRAY, true);
requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, version);
}
return null;

@ -1,15 +1,20 @@
package com.gitee.sop.gatewaycommon.zuul.loadbalancer;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
import com.google.common.base.Optional;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 服务实例选择器
@ -47,26 +52,64 @@ public abstract class BaseServerChooser extends ZoneAvoidanceRule {
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
// 获取服务实例列表
List<Server> allServers = lb.getAllServers();
List<Server> servers = lb.getReachableServers();
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
// 存放预发服务器
List<Server> preServers = new ArrayList<>(4);
// 存放灰度发布服务器
List<Server> grayServers = new ArrayList<>(4);
// 存放非预发服务器
List<Server> notPreServers = new ArrayList<>(4);
List<Server> preServers = allServers.stream()
.filter(this::isPreServer)
.filter(server -> canVisitPre(server, request))
.collect(Collectors.toList());
if (!preServers.isEmpty()) {
return this.doChoose(preServers, key);
for (Server server : servers) {
// 是否开启了预发模式
if (this.isPreServer(server)) {
preServers.add(server);
} else if (this.isGrayServer(server)) {
grayServers.add(server);
} else {
notPreServers.add(server);
}
}
List<Server> grayServers = allServers.stream()
.filter(this::isGrayServer)
.collect(Collectors.toList());
if (!grayServers.isEmpty()) {
notPreServers.addAll(grayServers);
// 如果没有开启预发布服务和灰度发布,直接用默认的方式
if (preServers.isEmpty() && grayServers.isEmpty()) {
return super.choose(key);
}
// 如果是从预发布域名访问过来,则认为是预发布请求
if (this.isRequestFromPreDomain(request)) {
return doChoose(preServers, key);
}
// 如果是灰度请求
if (this.isRequestGrayServer(RequestContext.getCurrentContext())) {
return doChoose(grayServers, key);
}
return super.choose(key);
// 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器
return doChoose(notPreServers, key);
}
/**
* 通过判断hostname来确定是否是预发布请求
*
* @param t t
* @return 返回true可以进入到预发环境
*/
protected boolean isRequestFromPreDomain(HttpServletRequest t) {
String domain = SpringContext.getBean(Environment.class).getProperty("pre.domain");
if (StringUtils.isEmpty(domain)) {
return false;
}
String[] domains = domain.split("\\,");
return ArrayUtils.contains(domains, getHost(t));
}
protected boolean isRequestGrayServer(RequestContext t) {
return t.get(EnvGrayManager.ENV_GRAY) != null;
}
protected String getHost(HttpServletRequest t) {
return t.getServerName();
}
protected Server doChoose(List<Server> servers, Object key) {

Loading…
Cancel
Save