一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Springcloud如何实现服务多版本控制 Springcloud实现服务多版本控制示例代码

时间:2020-05-15 编辑:袖梨 来源:一聚教程网

Springcloud如何实现服务多版本控制?本篇文章小编给大家分享一下Springcloud实现服务多版本控制示例代码,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。

实现

首先需要说明的是选择的控制中心是consul,网关是zuul。

负载均衡策略被抽象为IRule接口,项目默认情况下使用的IRule的子类ZoneAvoidanceRule extends PredicateBasedRule,我们需要实现一个PredicateBasedRule的子类来替换ZoneAvoidanceRule。

PredicateBasedRule需要实现一个过滤的方法我们就在这个方法里实现版本控制,过滤后就是默认的负载均衡策略了,默认是轮询。

  /**
   * Method that provides an instance of {@link AbstractServerPredicate} to be used by this class.
   * 
   */
  public abstract AbstractServerPredicate getPredicate();

我们可以看到PredicateBasedRule的getPredicate()方法需要返回一个AbstractServerPredicate实例,这个实例具体定义了版本控制的业务逻辑。代码如下:

private static class VersionPredicate extends AbstractServerPredicate {

    private static final String VERSION_KEY = "version";

    @Override
    public boolean apply(@NullableDecl PredicateKey predicateKey) {
      if (predicateKey == null) {
        return true;
      }
      RequestContext ctx = RequestContext.getCurrentContext();
      HttpServletRequest request = ctx.getRequest();
      String version = request.getHeader(VERSION_KEY);
      if (version == null) {
        return true;
      }
      ConsulServer consulServer = (ConsulServer) predicateKey.getServer();
      if (!consulServer.getMetadata().containsKey(VERSION_KEY)) {
        return true;
      }
      return consulServer.getMetadata().get(VERSION_KEY).equals(version);
    }
  }

首先来了解下负载均衡的过程。一个请求到达网关后会解析出对应的服务名,然后会获取到该服务的所有可用实例,之后就会调用我们的过滤方法过滤出该请求可用的所有服务实例,最后进行轮询负载均衡。

PredicateKey类就是上层方法将可用实例Server和loadBalancerKey封装后的类。版本控制的业务逻辑如下:

判断predicateKey是否为null,是的话直接返回true,true代表该实例可用

通过RequestContext获取当前请求实例HttpServletRequest,再通过请求实例获取请求头里的版本号

判断前端请求是否带了版本号,没带的话就不进行版本控制直接返回true

获取服务实例并转换成ConsulServer类,这里是因为用的注册中心是consul,选择其他的可自行转换成对应的实现类

判断服务实例是否设置了版本号(例:spring.cloud.consul.discovery.tags="version=1.0.0"),可以看到我们是用consul的tags实现的版本控制,可以设置不同的tag实现很多功能

同样服务实例没有设置版本号的话也是直接返回true

最后进行版本匹配,返回匹配成功的服务实例

注意的点

最终实现如下:

/**
 * @author Yuicon
 */
@Slf4j
public class VersionRule extends PredicateBasedRule {

  private final CompositePredicate predicate;

  public VersionRule() {
    super();
    this.predicate = createCompositePredicate(new VersionPredicate(),
        new AvailabilityPredicate(this, null));
  }

  @Override
  public AbstractServerPredicate getPredicate() {
    return this.predicate;
  }

  private CompositePredicate createCompositePredicate(VersionPredicate versionPredicate,
                            AvailabilityPredicate availabilityPredicate) {
    return CompositePredicate.withPredicates(versionPredicate, availabilityPredicate)
        .build();
  }

  private static class VersionPredicate extends AbstractServerPredicate {

    private static final String VERSION_KEY = "version";

    @Override
    public boolean apply(@NullableDecl PredicateKey predicateKey) {
      if (predicateKey == null) {
        return true;
      }
      RequestContext ctx = RequestContext.getCurrentContext();
      HttpServletRequest request = ctx.getRequest();
      String version = request.getHeader(VERSION_KEY);
      if (version == null) {
        return true;
      }
      ConsulServer consulServer = (ConsulServer) predicateKey.getServer();
      if (!consulServer.getMetadata().containsKey(VERSION_KEY)) {
        return true;
      }
      log.info("id is {}, header is {}, metadata is {}, result is {}",
          consulServer.getMetaInfo().getInstanceId(),
          version, consulServer.getMetadata().get(VERSION_KEY),
          consulServer.getMetadata().get(VERSION_KEY).equals(version));
      return consulServer.getMetadata().get(VERSION_KEY).equals(version);
    }
  }
}

原本是加上@Component注解后在本地直接测试通过了。可是在更新到生产服务器后却出现大部分请求都找不到的服务实例的错误,赶紧回到原来的版本。

查询了很多资料后才找到一篇文章,发现需要一个Config类来声明替换原有的负载均衡策略类。代码如下:

@RibbonClients(defaultConfiguration = RibbonGatewayConfig.class)
@Configuration
public class RibbonGatewayConfig {

  @Bean
  public IRule versionRule() {
    return new VersionRule();
  }
}

到此为止版本控制算是实现成功了。

热门栏目