定制设计这是一个基于实现的微定制设计服务灰度路由,定制设计实现了以下功能:
- 动态修改ribbon负载策略
- 定制设计随机权重的灰度路由(流量切分)
- 指定Header定制设计匹配的灰度路由
- 指定Cookie匹配的灰度路由
- 指定请求参数的灰度路、
整体流程如下:
ribbon本质上是一个客户端负载工具,支持多种负载策略,并且支持自定义负载策略,因此我们就可以重写它的负载规则,并在运行时,动态修改规则,从指定位置(Header、Cookie等)获取参数,判断是否需要访问服务,达到灰度路由的目的。
public static void changeLbRule(String name, IRule rule) { ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) clientFactory.getLoadBalancer(name); rule.setLoadBalancer(loadBalancer); ((ZoneAwareLoadBalancer) clientFactory.getLoadBalancer(name)).setRule(rule); }
- 1
- 2
- 3
- 4
- 5
通过以上方法即可实时修改Ribbon的负责策略。SpringClientFactory是Ribbon的实例工厂,ribbon的配置、负载规则、实例的创建等都有用到它,我们通过它来获取到指定服务的loadbalabcer,然后再用自定义的负载策略替换原有的。
自定义负载规则如下:
/** * Loadbalancer rule for header */@Slf4jpublic class HeaderMatchRule extends AbstractMatcher { @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } @Override public Server choose(Object key) { ILoadBalancer lb = getLoadBalancer(); Server server; if (!this.isMatch()) { List<Server> notGrayServers = new ArrayList<>(lb.getReachableServers()); notGrayServers.removeAll(GrayRouteHelper.getGrayServer(lb)); server = choose(lb, key, notGrayServers); log.debug("Not hit gray service, current instance:{}", server); } else { server = choose(lb, key, GrayRouteHelper.getGrayServer(lb)); log.debug("Hit gray service,use rule: HeaderMatchRule, current instance:{}", server); } return server; } @Override @SuppressWarnings("Duplicates") public boolean isMatch() { Map<String, GatewayProperties.GrayRoute> all = GrayRouteHelper.getAll(); GatewayProperties.GrayRoute grayRoute = all.get(getName()); if (grayRoute == null || grayRoute.getServiceInstances().size() == 0) { return false; } RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); Enumeration<String> headerNames = request.getHeaderNames(); Map<String, Object> headers = grayRoute.getHeaders(); Set<String> headerSet = headers.keySet(); int count = 0; while (headerNames.hasMoreElements()) { String s = headerNames.nextElement(); if (headerSet.contains(s)) { if (StringUtils.equals(request.getHeader(s), String.valueOf(headers.get(s)))) { count++; } } } return count == headerSet.size(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
以上是一个基于Header匹配的灰度路由负载规则,其中isMatch()
用于判断当前路由是否是灰度路由,如果是,则从灰度服务实例里边选择一个实例,否则从非灰度服务实例中选择一个实例。
其中类关系如下:
完整代码: