parent
043b760e03
commit
6125625b87
@ -0,0 +1,37 @@ |
||||
package com.gitee.sop.adminserver.bean; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public enum MetadataEnum { |
||||
/** |
||||
* 预发布环境 |
||||
*/ |
||||
ENV_PRE("env", "pre"), |
||||
|
||||
/** |
||||
* 上线环境 |
||||
*/ |
||||
ENV_ONLINE("env", ""), |
||||
|
||||
/** |
||||
* 灰度环境 |
||||
*/ |
||||
ENV_GRAY("env", "gray"), |
||||
; |
||||
private String key,value; |
||||
|
||||
MetadataEnum(String key, String value) { |
||||
this.key = key; |
||||
this.value = value; |
||||
} |
||||
|
||||
public String getKey() { |
||||
return key; |
||||
} |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,72 @@ |
||||
package com.gitee.sop.gatewaycommon.zuul.loadbalancer; |
||||
|
||||
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.springframework.util.CollectionUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 服务实例选择器 |
||||
* |
||||
* @author tanghc |
||||
*/ |
||||
@Slf4j |
||||
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); |
||||
|
||||
@Override |
||||
public Server choose(Object key) { |
||||
ILoadBalancer lb = getLoadBalancer(); |
||||
// 获取服务实例列表
|
||||
List<Server> allServers = new ArrayList<>(lb.getAllServers()); |
||||
int index = -1; |
||||
for (int i = 0; i < allServers.size(); i++) { |
||||
Server server = allServers.get(i); |
||||
if (match(server)) { |
||||
index = i; |
||||
if (canVisit(server, RequestContext.getCurrentContext().getRequest())) { |
||||
return server; |
||||
} |
||||
} |
||||
} |
||||
// 调用默认的算法
|
||||
// 如果选出了特殊环境服务器,需要移除命中的服务器
|
||||
if (index > -1) { |
||||
allServers.remove(index); |
||||
} |
||||
if (CollectionUtils.isEmpty(allServers)) { |
||||
log.error("无可用服务实例,key:", key); |
||||
return null; |
||||
} |
||||
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(allServers, key); |
||||
if (server.isPresent()) { |
||||
return server.get(); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@ |
||||
# 错误配置 |
||||
|
||||
isp.error_isp.unknow-error=Service is temporarily unavailable |
||||
isp.error_isp.unknown-error=Service is temporarily unavailable |
||||
isp.error_isv.invalid-parameter=Invalid parameter |
@ -1,5 +1,5 @@ |
||||
# 错误配置 |
||||
|
||||
isp.error_isp.unknow-error=\u670d\u52a1\u6682\u4e0d\u53ef\u7528 |
||||
isp.error_isp.unknown-error=\u670d\u52a1\u6682\u4e0d\u53ef\u7528 |
||||
# 参数无效 |
||||
isp.error_isv.invalid-parameter=\u53c2\u6570\u65e0\u6548 |
||||
|
@ -0,0 +1,55 @@ |
||||
package com.gitee.sop.gateway.loadbalancer; |
||||
|
||||
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser; |
||||
import com.netflix.loadbalancer.Server; |
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
/** |
||||
* 预发布环境选择,参考自:https://segmentfault.com/a/1190000017412946
|
||||
* |
||||
* @author tanghc |
||||
*/ |
||||
public class PreEnvironmentServerChooser extends BaseServerChooser { |
||||
|
||||
private static final String MEDATA_KEY_ENV = "env"; |
||||
private static final String ENV_PRE_VALUE = "pre"; |
||||
|
||||
private static final String HOST_NAME = "localhost"; |
||||
|
||||
@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); |
||||
return Objects.equals(ENV_PRE_VALUE, env) && canClientVisit(request); |
||||
} |
||||
|
||||
/** |
||||
* 通过判断hostname来确定是否是预发布请求,如果需要通过其它条件判断,修改此方法 |
||||
* @param request request |
||||
* @return 返回true:可以进入到预发环境 |
||||
*/ |
||||
protected boolean canClientVisit(HttpServletRequest request) { |
||||
String serverName = request.getServerName(); |
||||
return HOST_NAME.equals(serverName); |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
package com.gitee.sop.gateway.loadbalancer; |
||||
|
||||
import com.netflix.loadbalancer.IRule; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.cloud.netflix.ribbon.PropertiesFactory; |
||||
import org.springframework.core.env.Environment; |
||||
|
||||
/** |
||||
* 自定义PropertiesFactory,用来动态添加LoadBalance规则 |
||||
* @author tanghc |
||||
*/ |
||||
public class SopPropertiesFactory extends PropertiesFactory { |
||||
|
||||
/** |
||||
* 可在配置文件中设置<code>zuul.custom-rule-classname=com.xx.ClassName</code>指定负载均衡规则类 |
||||
* 默认使用com.gitee.sop.gateway.loadbalancer.PreEnvironmentServerChooser |
||||
*/ |
||||
private static final String PROPERTIES_KEY = "zuul.custom-rule-classname"; |
||||
|
||||
private static final String CUSTOM_RULE_CLASSNAME = PreEnvironmentServerChooser.class.getName(); |
||||
|
||||
@Autowired |
||||
private Environment environment; |
||||
|
||||
/** |
||||
* 配置文件配置:<serviceId>.ribbon.NFLoadBalancerRuleClassName=com.gitee.sop.gateway.loadbalancer.PreEnvironmentServerChooser |
||||
* @param clazz |
||||
* @param name serviceId |
||||
* @return 返回class全限定名 |
||||
*/ |
||||
@Override |
||||
public String getClassName(Class clazz, String name) { |
||||
if (clazz == IRule.class) { |
||||
return this.environment.getProperty(PROPERTIES_KEY, CUSTOM_RULE_CLASSNAME); |
||||
} else { |
||||
return super.getClassName(clazz, name); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue