原理分析之预发布灰度发布

SOP网关采用自定义负载均衡策略来实现对预发布/灰度发布服务器实例的选择。

spring cloud gateway默认的负载均衡实现类在:org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.java

这个类主要做了几件事情:

  1. 解析出请求路径中的scheme
  2. 如果scheme不是以lb协议开头直接跳过
  3. 如果scheme以lb协议开头,则说明需要进行负载均衡,选出一台微服务实例
  4. lb协议解析成http://ip:port,继续向下请求

其中第4步是由org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient来完成的,我们只要分别继承LoadBalancerClientFilterRibbonLoadBalancerClient,然后重写其中的方法就能完成自定义负载均衡。

SOP中的重写类是:SopLoadBalancerClientFilterSopLoadBalancerClient,核心代码委托给了LoadBalanceServerChooser处理,核心代码如下:

  1. /**
  2. * 选择服务器
  3. *
  4. * @param serviceId serviceId,仅gateway网关有作用
  5. * @param exchange 请求上下文
  6. * @param loadBalancer loadBalancer
  7. * @param superChooser 父类默认的选择
  8. * @param serverChooserFunction 执行选择操作
  9. * @return 返回服务器实例,没有选到则返回null
  10. */
  11. public R choose(
  12. String serviceId
  13. , T exchange
  14. , ILoadBalancer loadBalancer
  15. , Supplier<R> superChooser
  16. , Function<List<Server>, R> serverChooserFunction) {
  17. // 获取所有服务实例
  18. List<Server> servers = loadBalancer.getReachableServers();
  19. // 存放预发服务器
  20. List<Server> preServers = new ArrayList<>(4);
  21. // 存放灰度发布服务器
  22. List<Server> grayServers = new ArrayList<>(4);
  23. // 存放非预发服务器
  24. List<Server> notPreServers = new ArrayList<>(4);
  25. for (Server server : servers) {
  26. // 获取实例metadata
  27. Map<String, String> metadata = getMetadata(serviceId, server);
  28. // 是否开启了预发模式
  29. if (this.isPreServer(metadata)) {
  30. preServers.add(server);
  31. } else if (this.isGrayServer(metadata)) {
  32. grayServers.add(server);
  33. } else {
  34. notPreServers.add(server);
  35. }
  36. }
  37. notPreServers.addAll(grayServers);
  38. // 如果没有开启预发布服务和灰度发布,直接用默认的方式
  39. if (preServers.isEmpty() && grayServers.isEmpty()) {
  40. return superChooser.get();
  41. }
  42. // 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器
  43. if (this.isRequestFromPreDomain(exchange)) {
  44. return serverChooserFunction.apply(preServers);
  45. }
  46. // 如果是灰度请求,则认为是灰度用户,选出灰度服务器
  47. if (this.isRequestGrayServer(exchange)) {
  48. return serverChooserFunction.apply(grayServers);
  49. }
  50. // 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器
  51. // 注意:这里允许走灰度服务器,如果不允许走,注释notPreServers.addAll(grayServers);这行
  52. return serverChooserFunction.apply(notPreServers);
  53. }

其业务逻辑如下:

  1. 选出serviceId对应的所有服务器实例
  2. 将服务器实例进行分类,分别放进预发布List灰度List非预发布List
  3. 如果预发布List灰度List都为空,表示没有开启任何预发/灰度服务,直接使用父类的负载均衡策略
  4. 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器
  5. 如果是灰度请求,则认为是灰度用户,选出灰度服务器
  6. 最后剩下的是正常用户,正常用户不能走预发环境

参考类

  • com.gitee.sop.gatewaycommon.gateway.filter.SopLoadBalancerClientFilter
  • com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient
  • com.gitee.sop.gatewaycommon.gateway.loadbalancer.GatewayLoadBalanceServerChooser