• Spring Cloud Zuul的一个坑


    Spring Cloud 版本:

    Dalston.SR5

    今天使用Zuul发现一个和动态刷新相关的问题,动态刷新使用的是 /bus/refresh,即我的Zuul连着一个Rabbitmq,我这里是使用的总线刷新的方式,普通的刷新/refresh应该也是可以再现这个坑的。

    我一共有两个服务,服务名分别为one和all,刷新之前的路由规则:

    zuul:
      ribbonIsolationStrategy: THREAD
      retryable: true
      add-host-header: true
      servlet-path: /zuul/*
      prefix: /test
      routes:
    #规则
        n1:
          path: /*
          serviceId: all

    改为:

    zuul:
      ribbonIsolationStrategy: THREAD
      retryable: true
      add-host-header: true
      servlet-path: /zuul/*
      prefix: /test
      routes:
    #规则
        n0:
          path: /one
          serviceId: one
        n1:
          path: /*
          serviceId: all

    加了个n0的规则,并且放在了n1前边,按说刷新之后,如果访问/test/one,那么应该会由服务【one】来处理,而非服务【all】,结果却是仍然会交由服务【all】来处理。

    很坑是不是,我觉得这是个BUG,目前我还没有研究源码,但是通过实验得出了几个结论,并且也有了一个不用修改源码的解决方案,详情如下:

    先说结论:

    通过动态刷新的配置,对于路由规则的变动,只能新增和修改,不能删除;并且新增的规则在匹配顺序上,位于老规则的后边,也就是说,一旦你老规则里配置了个/*,那么后边的新规则你怎么改都不能生效,仍然会路由到/*对应的服务上。

    再说解决办法:

    借助上边描述的规则,我们可以将配置规则换一种写法再刷新进去,新的写法如下:

    zuul:
      ribbonIsolationStrategy: THREAD
      retryable: true
      add-host-header: true
      servlet-path: /zuul/*
      prefix: /test
      routes:
    #规则
        n1:
          path: /one
          serviceId: one
        n2:
          path: /*
          serviceId: all

    这里修改了n1,然后新增了n2,巧妙的借助这个规则完成了,让/one路由到服务【one】上,其他规则还继续让服务【all】来处理。

    这中解决方式,感觉还是不完美,后续我们可以通过修改源码,或者关注社区的方式,纠正这个坑(BUG)。

    ————————————————————2018年5月15日 追加——————————————————————————

    经过调查发现:

    zuul获取路由规则的时候,会从所有路由规则中选择第一个能正则匹配的,用来处理当前的请求,接着,我们需要看看刷新之后配置的顺序是不是有问题。

    这里看到顺序是按照配置文件的顺序进行加载,应该是没有问题的,结果发现配置文件的顺序并不能保证。这里我们先不去管为什么顺序不能保证了,因为需要牵扯大量的refresh端点事件、配置中心相关代码。

    这里根据我们的需求直接决定改成优先精确匹配,精确匹配失败再正则匹配即可,修改后:

     

    修改非常简单,重在调查问题的过程。

     如果你想调查配置中心相关代码,这里给个思路,或许有所帮助:

    调用/bus/refresh时候走了这段。

    继续跟进代码。

     属性对比的完整截图,两个Map,一个是之前的配置内容,一个是修改后的配置内容,最终结果是对比得出的两者的不同点。

    广播了属性替换事件,具体广播的处理者在哪又得跟源码了,时间有限,就写到这里吧。欢迎指正和补充

    ----------------------------------------------------------2018年7月31日 ----------------------------------------------------------------

    今天又发现一个新的坑,也是和上文同一个原因所致。

    之前的结论:

    通过动态刷新的配置,对于路由规则的变动,只能新增和修改,不能删除;并且新增的规则在匹配顺序上,位于老规则的后边,也就是说,一旦你老规则里配置了个/*,那么后边的新规则你怎么改都不能生效,仍然会路由到/*对应的服务上。

    现在发现同一个路由规则的变动也是适用的,也就是说,如果你之前配了一个路由规则:

    zuul:
      routes:
        route1:
          path: /a/**
          url: http://URL/PATH/

    将所有/a/xxx的请求交给下边这个url处理,之后你通过配刷新的方式改为了:

    zuul:
      routes:
        route1:
          path: /a/**
          serviceId: service1

    是没有效果的,所有/a/xxx的请求还是会被之前那个url处理。

    正确的姿势是改为:

    zuul:
      routes:
        route1:
          path: /a/**
          serviceId: service1
          url: 

    再刷新配置。

    总结一下原因:

    1、配置刷新目前存在问题无法删除已有的路由规则,只能修改已有规则和新增规则。

    2、在路由的serviceId和url同时存在的时候,会以url为准,只有url为空的时候才会交给serviceId来处理。

    该问题在 

    Edgware.SR3

    版本中,仍然未得到解决。也许我该转向spring cloud gateway了

    完毕

  • 相关阅读:
    对于大流量的网站,您采用什么样的方法来解决访问量问题?
    div section article区分--20150227
    不懂的code整理学习
    常用又容易忘记的代码
    【转】机器学习中常用损失函数
    姿态估计的两个数据集COCO和MPII的认识
    用caffe训练openpose过程中,出现异常
    编译caffe的诸多注意事项
    Win7下Anaconda3+Tensorflow
    论文阅读(Zhe Cao——【CVPR2017】Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields )
  • 原文地址:https://www.cnblogs.com/flying607/p/9036915.html
Copyright © 2020-2023  润新知