支持预发布、灰度发布

This commit is contained in:
tanghc
2019-08-07 15:11:52 +08:00
parent 17602e6efe
commit f03be910c4
37 changed files with 278 additions and 227 deletions

View File

@@ -11,35 +11,29 @@ import java.util.Date;
/**
* 表名config_gray_userkey
* 备注灰度发布用户key
* 表名config_gray
* 备注服务灰度配置
*
* @author tanghc
*/
@Table(name = "config_gray_userkey")
@Table(name = "config_gray")
@Data
public class ConfigGrayUserkey {
public class ConfigGray {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** serviceId, 数据库字段service_id */
/** 数据库字段service_id */
private String serviceId;
/** instanceId, 数据库字段instance_id */
private String instanceId;
/** 用户key多个用引文逗号隔开, 数据库字段user_key_content */
private String userKeyContent;
/** 需要灰度的接口goods.get=1.2,order.list=1.2, 数据库字段name_version_content */
/** 需要灰度的接口goods.get1.0=1.2,多个用英文逗号隔开, 数据库字段name_version_content */
private String nameVersionContent;
/** 0禁用1启用, 数据库字段status */
private Byte status;
/** 数据库字段gmt_create */
private Date gmtCreate;

View File

@@ -0,0 +1,41 @@
package com.gitee.sop.gateway.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名config_gray_instance
*
* @author tanghc
*/
@Table(name = "config_gray_instance")
@Data
public class ConfigGrayInstance {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** instance_id, 数据库字段instance_id */
private String instanceId;
/** service_id, 数据库字段service_id */
private String serviceId;
/** 0禁用1启用, 数据库字段status */
private Byte status;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -2,12 +2,11 @@ package com.gitee.sop.gateway.loadbalancer;
import com.gitee.sop.gateway.manager.DbEnvGrayManager;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.Param;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser;
import com.netflix.loadbalancer.Server;
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
import org.springframework.core.env.Environment;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@@ -56,22 +55,10 @@ public class EnvironmentServerChooser extends BaseServerChooser {
@Override
protected boolean canVisitPre(Server server, HttpServletRequest request) {
String serverName = request.getServerName();
return PRE_DOMAIN.equals(serverName);
String domain = SpringContext.getBean(Environment.class).getProperty("pre.domain", PRE_DOMAIN);
return domain.equals(serverName);
}
/**
* 能否进入灰度环境
*
* @param request request
* @return 返回true可以进入到预发环境
*/
protected boolean canVisitGray(Server server, HttpServletRequest request) {
ApiParam apiParam = ZuulContext.getApiParam();
DbEnvGrayManager userKeyManager = SpringContext.getBean(DbEnvGrayManager.class);
return this.isGrayUser(apiParam, userKeyManager, server, request);
}
/**
* 是否是灰度用户,可修改此方法实现自己想要的
*

View File

@@ -2,13 +2,16 @@ package com.gitee.sop.gateway.manager;
import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.gateway.entity.ConfigGrayUserkey;
import com.gitee.sop.gateway.mapper.ConfigGrayUserkeyMapper;
import com.gitee.sop.gateway.entity.ConfigGray;
import com.gitee.sop.gateway.entity.ConfigGrayInstance;
import com.gitee.sop.gateway.mapper.ConfigGrayInstanceMapper;
import com.gitee.sop.gateway.mapper.ConfigGrayMapper;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.UserKeyDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceGrayDefinition;
import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,6 +22,8 @@ import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -33,82 +38,86 @@ public class DbEnvGrayManager extends DefaultEnvGrayManager {
private static final int STATUS_ENABLE = 1;
private static final Function<String[], String> FUNCTION_KEY = arr -> arr[0];
private static final Function<String[], String> FUNCTION_VALUE = arr -> arr[1];
@Autowired
private Environment environment;
@Autowired
private ConfigGrayUserkeyMapper configGrayUserkeyMapper;
private ConfigGrayMapper configGrayMapper;
@Autowired
private ConfigGrayInstanceMapper configGrayInstanceMapper;
@Override
public void load() {
List<ConfigGray> list = configGrayMapper.list(new Query());
for (ConfigGray configGray : list) {
this.setServiceGrayConfig(configGray);
}
Query query = new Query();
query.eq("status", STATUS_ENABLE);
List<ConfigGrayUserkey> list = configGrayUserkeyMapper.list(query);
for (ConfigGrayUserkey configGrayUserkey : list) {
this.setServiceGrayConfig(configGrayUserkey);
List<ConfigGrayInstance> grayInstanceList = configGrayInstanceMapper.list(query);
for (ConfigGrayInstance configGrayInstance : grayInstanceList) {
this.openGray(configGrayInstance.getInstanceId(), configGrayInstance.getServiceId());
}
}
/**
* 设置用户key
*
* @param configGrayUserkey 灰度配置
* @param configGray 灰度配置
*/
public void setServiceGrayConfig(ConfigGrayUserkey configGrayUserkey) {
if (configGrayUserkey == null) {
public void setServiceGrayConfig(ConfigGray configGray) {
if (configGray == null) {
return;
}
String instanceId = configGrayUserkey.getInstanceId();
this.clear(instanceId);
String userKeyData = configGrayUserkey.getUserKeyContent();
String nameVersionContent = configGrayUserkey.getNameVersionContent();
String userKeyData = configGray.getUserKeyContent();
String nameVersionContent = configGray.getNameVersionContent();
String[] userKeys = StringUtils.split(userKeyData, ',');
String[] nameVersionList = StringUtils.split(nameVersionContent, ',');
log.info("添加userKeyuserKeys.length:{}, nameVersionList:{}", userKeys.length, Arrays.toString(nameVersionList));
log.info("灰度配置userKeys.length:{}, nameVersionList:{}", userKeys.length, Arrays.toString(nameVersionList));
List<String> list = Stream.of(userKeys).collect(Collectors.toList());
ServiceGrayConfig serviceGrayConfig = getServiceGrayConfig(instanceId);
serviceGrayConfig.setServiceId(configGrayUserkey.getServiceId());
serviceGrayConfig.getUserKeys().addAll(list);
Set<String> userKeySet = Stream.of(userKeys)
.collect(Collectors.toCollection(Sets::newConcurrentHashSet));
Map<String, String> grayNameVersion = serviceGrayConfig.getGrayNameVersion();
for (String nameVersion : nameVersionList) {
String[] nameVersionInfo = StringUtils.split(nameVersion, '=');
String name = nameVersionInfo[0];
String version = nameVersionInfo[1];
grayNameVersion.put(name, version);
}
Map<String, String> grayNameVersionMap = Stream.of(nameVersionList)
.map(nameVersion -> StringUtils.split(nameVersion, '='))
.collect(Collectors.toConcurrentMap(FUNCTION_KEY, FUNCTION_VALUE));
}
/**
* 清空用户key
*/
public void clear(String instanceId) {
getServiceGrayConfig(instanceId).clear();
ServiceGrayConfig serviceGrayConfig = new ServiceGrayConfig();
serviceGrayConfig.setServiceId(configGray.getServiceId());
serviceGrayConfig.setUserKeys(userKeySet);
serviceGrayConfig.setGrayNameVersion(grayNameVersionMap);
this.saveServiceGrayConfig(serviceGrayConfig);
}
@PostConstruct
protected void after() throws Exception {
ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getUserKeyChannelPath();
String isvChannelPath = ZookeeperContext.getServiceGrayChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
String data = channelMsg.getData();
UserKeyDefinition userKeyDefinition = JSON.parseObject(data, UserKeyDefinition.class);
String instanceId = userKeyDefinition.getInstanceId();
ServiceGrayDefinition userKeyDefinition = JSON.parseObject(data, ServiceGrayDefinition.class);
String serviceId = userKeyDefinition.getServiceId();
switch (channelMsg.getOperation()) {
case "set":
ConfigGrayUserkey configGrayUserkey = configGrayUserkeyMapper.getByColumn("instance_id", instanceId);
this.setServiceGrayConfig(configGrayUserkey);
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
this.setServiceGrayConfig(configGray);
break;
case "clear":
clear(instanceId);
case "open":
openGray(userKeyDefinition.getInstanceId(), serviceId);
break;
case "close":
closeGray(userKeyDefinition.getInstanceId());
break;
default:
log.error("userKey消息错误的消息指令nodeData{}", nodeData);
}
});

View File

@@ -56,7 +56,6 @@ public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
remove(ip);
break;
default:
log.error("IP黑名单错误的消息指令nodeData{}", nodeData);
}
});
}

View File

@@ -61,7 +61,6 @@ public class DbIsvManager extends CacheIsvManager {
remove(isvDefinition.getAppKey());
break;
default:
log.error("ISV信息错误的消息指令nodeData{}", nodeData);
}
});

View File

@@ -152,6 +152,8 @@ public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManage
log.info("删除ISV路由权限信息isvRoutePermission:{}", isvRoutePermission);
remove(isvRoutePermission.getAppKey());
break;
default:
}
});
}

View File

@@ -63,7 +63,6 @@ public class DbLimitConfigManager extends DefaultLimitConfigManager {
update(configLimitDto);
break;
default:
log.error("限流配置信息错误的消息指令nodeData{}", nodeData);
}
});
}

View File

@@ -87,7 +87,6 @@ public class DbRouteConfigManager extends DefaultRouteConfigManager {
update(routeConfig);
break;
default:
log.error("路由配置信息错误的消息指令nodeData{}", nodeData);
}
});
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.ConfigGrayInstance;
/**
* @author tanghc
*/
public interface ConfigGrayInstanceMapper extends CrudMapper<ConfigGrayInstance, Long> {
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.ConfigGray;
/**
* @author tanghc
*/
public interface ConfigGrayMapper extends CrudMapper<ConfigGray, Long> {
}

View File

@@ -1,11 +0,0 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.ConfigGrayUserkey;
/**
* @author tanghc
*/
public interface ConfigGrayUserkeyMapper extends CrudMapper<ConfigGrayUserkey, Long> {
}

View File

@@ -12,6 +12,9 @@ eureka.url=http://localhost:1111/eureka/
zookeeper.url=localhost:2181
# zipkin服务监控地址没有开启不用改
zipkin.url=http://127.0.0.1:9411/
# 预发布网关域名
pre.domain=localhost
# ------- 需要改的配置end -------
# 入口地址,不用改,默认是/zuul