支持预发布、灰度发布

This commit is contained in:
tanghc
2019-08-05 14:48:41 +08:00
parent 202267b686
commit 2e9e3c7ca7
45 changed files with 383 additions and 137 deletions

View File

@@ -1,6 +1,5 @@
package com.gitee.sop.gateway.config;
import com.gitee.sop.gateway.manager.ManagerInitializer;
import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration;
@@ -20,9 +19,6 @@ import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfigurat
//@Configuration
public class GatewayConfig extends AlipayGatewayConfiguration {
static {
new ManagerInitializer();
}
}
/**

View File

@@ -7,7 +7,6 @@ package com.gitee.sop.gateway.config;
*/
import com.gitee.sop.gateway.loadbalancer.SopPropertiesFactory;
import com.gitee.sop.gateway.manager.ManagerInitializer;
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration;
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
import org.springframework.context.annotation.Bean;
@@ -20,10 +19,6 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class ZuulConfig extends AlipayZuulConfiguration {
static {
new ManagerInitializer();
}
@Bean
PropertiesFactory propertiesFactory() {
return new SopPropertiesFactory();

View File

@@ -34,6 +34,9 @@ public class ConfigGrayUserkey {
/** 需要灰度的接口goods.get=1.2,order.list=1.2, 数据库字段name_version_content */
private String nameVersionContent;
/** 0禁用1启用, 数据库字段status */
private Byte status;
/** 数据库字段gmt_create */
private Date gmtCreate;

View File

@@ -1,6 +1,6 @@
package com.gitee.sop.gateway.loadbalancer;
import com.gitee.sop.gateway.manager.UserKeyManager;
import com.gitee.sop.gateway.manager.DbUserKeyManager;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.Param;
@@ -83,14 +83,15 @@ public class EnvironmentServerChooser extends BaseServerChooser {
*/
protected boolean canVisitGray(Server server, HttpServletRequest request) {
ApiParam apiParam = ZuulContext.getApiParam();
UserKeyManager userKeyManager = SpringContext.getBean(UserKeyManager.class);
DbUserKeyManager userKeyManager = SpringContext.getBean(DbUserKeyManager.class);
boolean canVisit = false;
if (this.isGrayUser(apiParam, userKeyManager, server, request)) {
// 指定灰度版本号
String instanceId = server.getId();
String instanceId = server.getMetaInfo().getInstanceId();
String newVersion = userKeyManager.getVersion(instanceId, apiParam.fetchNameVersion());
if (newVersion != null) {
RequestContext.getCurrentContext().getZuulRequestHeaders().put(ParamNames.HEADER_VERSION_NAME, newVersion);
// 在header中设置新的版本号然后微服务端先获取这个新版本号
RequestContext.getCurrentContext().addZuulRequestHeader(ParamNames.GRAY_HEADER_VERSION_NAME, newVersion);
canVisit = true;
}
}
@@ -107,8 +108,8 @@ public class EnvironmentServerChooser extends BaseServerChooser {
* @param request request
* @return true
*/
protected boolean isGrayUser(Param param, UserKeyManager userKeyManager, Server server, HttpServletRequest request) {
String instanceId = server.getId();
protected boolean isGrayUser(Param param, DbUserKeyManager userKeyManager, Server server, HttpServletRequest request) {
String instanceId = server.getMetaInfo().getInstanceId();
// 这里的灰度用户为appKey包含此appKey则为灰度用户允许访问
String appKey = param.fetchAppKey();
return userKeyManager.containsKey(instanceId, appKey);

View File

@@ -1,33 +0,0 @@
package com.gitee.sop.gateway.loadbalancer;
import lombok.Data;
import java.util.Map;
import java.util.Set;
/**
* @author tanghc
*/
@Data
public class ServiceGrayConfig {
/**
* 用户id
*/
private Set<String> userKeys;
/** 存放接口隐射关系key:nameversionvalue:newVersion */
private Map<String, String> grayNameVersion;
public boolean containsKey(Object userKey) {
return userKeys.contains(String.valueOf(userKey));
}
public String getVersion(String name) {
return grayNameVersion.get(name);
}
public void clear() {
this.userKeys.clear();
this.grayNameVersion.clear();
}
}

View File

@@ -9,6 +9,7 @@ import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
@@ -19,6 +20,7 @@ import java.util.List;
* @author tanghc
*/
@Slf4j
@Service
public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
@Autowired

View File

@@ -3,6 +3,7 @@ package com.gitee.sop.gateway.manager;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.gateway.entity.IsvDetailDTO;
import com.gitee.sop.gateway.mapper.IsvInfoMapper;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.IsvDefinition;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
@@ -11,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
@@ -19,6 +21,7 @@ import java.util.List;
* @author tanghc
*/
@Slf4j
@Service
public class DbIsvManager extends CacheIsvManager {
@Autowired
@@ -41,6 +44,7 @@ public class DbIsvManager extends CacheIsvManager {
@PostConstruct
protected void after() throws Exception {
ApiConfig.getInstance().setIsvManager(this);
ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getIsvInfoChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {

View File

@@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
@@ -35,6 +36,7 @@ import static java.util.stream.Collectors.toList;
* @author tanghc
*/
@Slf4j
@Service
public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManager {
@Autowired

View File

@@ -11,6 +11,7 @@ import com.gitee.sop.gatewaycommon.util.MyBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@@ -19,6 +20,7 @@ import javax.annotation.PostConstruct;
* @author tanghc
*/
@Slf4j
@Service
public class DbLimitConfigManager extends DefaultLimitConfigManager {
@Autowired

View File

@@ -14,6 +14,7 @@ import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Collection;
@@ -22,6 +23,7 @@ import java.util.Collection;
* @author tanghc
*/
@Slf4j
@Service
public class DbRouteConfigManager extends DefaultRouteConfigManager {
@Autowired

View File

@@ -1,14 +1,14 @@
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.loadbalancer.ServiceGrayConfig;
import com.gitee.sop.gateway.mapper.ConfigGrayUserkeyMapper;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.UserKeyDefinition;
import com.gitee.sop.gatewaycommon.manager.DefaultUserKeyManager;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -27,14 +27,11 @@ import java.util.stream.Stream;
*
* @author tanghc
*/
@Service
@Slf4j
public class UserKeyManager {
@Service
public class DbUserKeyManager extends DefaultUserKeyManager {
/**
* KEY:instanceId
*/
private Map<String, ServiceGrayConfig> serviceUserKeyMap = Maps.newConcurrentMap();
private static final int STATUS_ENABLE = 1;
@Autowired
private Environment environment;
@@ -42,18 +39,14 @@ public class UserKeyManager {
@Autowired
private ConfigGrayUserkeyMapper configGrayUserkeyMapper;
public boolean containsKey(String serviceId, Object userKey) {
if (serviceId == null || userKey == null) {
return false;
@Override
public void load() {
Query query = new Query();
query.eq("status", STATUS_ENABLE);
List<ConfigGrayUserkey> list = configGrayUserkeyMapper.list(query);
for (ConfigGrayUserkey configGrayUserkey : list) {
this.setServiceGrayConfig(configGrayUserkey);
}
return this.getServiceGrayConfig(serviceId).containsKey(userKey);
}
public String getVersion(String serviceId, String nameVersion) {
if (serviceId == null || nameVersion == null) {
return null;
}
return this.getServiceGrayConfig(serviceId).getVersion(nameVersion);
}
/**
@@ -61,11 +54,12 @@ public class UserKeyManager {
*
* @param configGrayUserkey 灰度配置
*/
public void setServiceGrayConfig(String serviceId, ConfigGrayUserkey configGrayUserkey) {
public void setServiceGrayConfig(ConfigGrayUserkey configGrayUserkey) {
if (configGrayUserkey == null) {
return;
}
this.clear(serviceId);
String instanceId = configGrayUserkey.getInstanceId();
this.clear(instanceId);
String userKeyData = configGrayUserkey.getUserKeyContent();
String nameVersionContent = configGrayUserkey.getNameVersionContent();
String[] userKeys = StringUtils.split(userKeyData, ',');
@@ -73,7 +67,7 @@ public class UserKeyManager {
log.info("添加userKeyuserKeys.length:{}, nameVersionList:{}", userKeys.length, Arrays.toString(nameVersionList));
List<String> list = Stream.of(userKeys).collect(Collectors.toList());
ServiceGrayConfig serviceGrayConfig = getServiceGrayConfig(serviceId);
ServiceGrayConfig serviceGrayConfig = getServiceGrayConfig(instanceId);
serviceGrayConfig.getUserKeys().addAll(list);
Map<String, String> grayNameVersion = serviceGrayConfig.getGrayNameVersion();
@@ -89,20 +83,10 @@ public class UserKeyManager {
/**
* 清空用户key
*/
public void clear(String serviceId) {
getServiceGrayConfig(serviceId).clear();
public void clear(String instanceId) {
getServiceGrayConfig(instanceId).clear();
}
public ServiceGrayConfig getServiceGrayConfig(String serviceId) {
ServiceGrayConfig serviceGrayConfig = serviceUserKeyMap.get(serviceId);
if (serviceGrayConfig == null) {
serviceGrayConfig = new ServiceGrayConfig();
serviceGrayConfig.setUserKeys(Sets.newConcurrentHashSet());
serviceGrayConfig.setGrayNameVersion(Maps.newConcurrentMap());
serviceUserKeyMap.put(serviceId, serviceGrayConfig);
}
return serviceGrayConfig;
}
@PostConstruct
protected void after() throws Exception {
@@ -113,14 +97,14 @@ public class UserKeyManager {
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
String data = channelMsg.getData();
UserKeyDefinition userKeyDefinition = JSON.parseObject(data, UserKeyDefinition.class);
String serviceId = userKeyDefinition.getServiceId();
String instanceId = userKeyDefinition.getInstanceId();
switch (channelMsg.getOperation()) {
case "set":
ConfigGrayUserkey configGrayUserkey = configGrayUserkeyMapper.getByColumn("service_id", serviceId);
this.setServiceGrayConfig(serviceId, configGrayUserkey);
ConfigGrayUserkey configGrayUserkey = configGrayUserkeyMapper.getByColumn("instance_id", instanceId);
this.setServiceGrayConfig(configGrayUserkey);
break;
case "clear":
clear(serviceId);
clear(instanceId);
break;
default:
log.error("userKey消息错误的消息指令nodeData{}", nodeData);

View File

@@ -14,5 +14,6 @@ public class ManagerInitializer {
apiConfig.setRouteConfigManager(new DbRouteConfigManager());
apiConfig.setLimitConfigManager(new DbLimitConfigManager());
apiConfig.setIpBlacklistManager(new DbIPBlacklistManager());
apiConfig.setUserKeyManager(new DbUserKeyManager());
}
}