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了

 

完畢

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM