【第二戰】又談網關Zuul

Zuul 很有意思,作爲網關服務,它將充當內部服務的代理,負責與外部通信。但僅僅是與外部服務通信需要它嘛?不對,從設計上來講,它能將具有相同訪問特徵的系列服務歸類處理。

zuul 架構

不僅僅是外部訪問,服務簇之間的通信也可以依賴代理 zuul。但這樣多增加一跳,就會增加相應的網絡開銷。

客戶端不可能直接訪問內部服務總代理,如果直接訪問,這個代理沒法實現集羣,所以,一般會從 Nginx ,再到 zuul,這樣 zuul 部署爲集羣就可以實現高可用了。

本文會簡單談談幾個思考的點,你會發現這些組件真的很有趣,沒有想象那麼複雜;

  1. 增加 zuul,究竟能帶來什麼?
  2. 負載均衡有多重要?
  3. 使用 zuul 的一些注意事項
    • routes 的 path 配置的順序問題
    • httpclient 的指定
    • 大文件上傳問題
    • 管理 zuul 應用程序的端點
    • 超時問題

增加 zuul,究竟能帶來什麼?

想想如何管理服務的 CORS認證。看起來,每個服務都需要去做這件事,如果更好的話,可能會打成相應的 jar 包,然後依賴。這看起來也可行,CORS 和 認證通過 web 容器的攔截器很方便就能做到。CORS 在 spring mvc 中可以通過如下配置做到:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/path-1/**")
                    .allowedOrigins("https://allowed-origin.com")
                    .allowedMethods("GET", "POST");
        }
    };
}

zuul 還提供路由,如果服務自己實現路由,那就沒有意義,這更多的是想在一個更高的層次去做統一路徑訪問管理。

增加 zuul 這一層次,能夠統一解決這些每個服務都不得不面對的問題,對於部署爲集羣的服務還支持負載均衡,這很重要!如果不部署這一層,對外接口的服務將直接利用 nginx 來實現負載均衡,,僅僅維護這些服務路徑就是很難忍受的。並且在代碼層面能做的事比較少,一些共性不得不氾濫在每個服務裏。我們常常所說的面向對象,對於共性,都是可抽取的,重複是不能容忍的!


負載均衡有多重要?

爲什麼需要負載均衡?因爲部署爲集羣,服務提供者提供了多個可訪問地址,調用者需要通過負載均衡調用。部署爲集羣是爲實現高可用,增加服務的冗餘性,避免單點故障!

所以,你會發現,在微服務架構中,如果按層次來看,下一層要實現高可用,那麼上一層就需要支持負載均衡,這是避免不了的,哪怕是最簡單的順序訪問,它也算!

微服務強調高可用,集羣是實現高可用的最佳方式,而訪問集羣又需要調用者實現負載均衡,所以,它所處的地位自然重要,但很多情況下,客戶端僅僅只使用了簡單的順序訪問(輪詢),並未實現常用的負載均衡策略。

常用的負載均衡策略是不是也可以抽象出來呢?spring cloud 就抽象了負載均衡客戶端(LoadBalancerClient)。所以,我想負載均衡策略也是可以的,但由於負載均衡策略本身不算太複雜,可能也就沒花那麼多時間去思考如何抽象它。

微服務主鍵中涉及負載均衡的是組件是 ribbon,spring cloud 微服務生態中,需要負載均衡組的件也大多依賴它,那它自然可以看做負載均衡抽象的實現。那談到負載均衡策略的抽象呢?ribbon 的負載均衡策略最終是執行 http 請求,真正的抽象應該獨立於這個之外,dubbo 的負載均衡策略又是基於 rpc 的。如果我們有這樣一個負載均衡策略的抽象,那麼,dubbo 以及 ribbon 都能很好的使用它!

感覺這會是一個很有趣的想法,但談論總是很簡單,展示代碼纔是最重要的!先暫時記於此。


使用 zuul 的一些注意事項

這一節更多的是對閱讀官網文檔的一個總結;

  • routes 的 path 配置的順序問題

    在路由器配置中,需要注意順序,如果在上一個路徑規則中匹配到,則不會繼續往後匹配,所以會選擇將兜底的匹配放在最後。這與 Java 的 catch 異常差不多,兜底的會放在最後,匹配肯定能正常結束。還需要注意的是需要使用 yaml 文件作爲配置文件,properties 文件獲取路由配置是無序的。

  • httpclient 的指定

    現在默認使用的 http client 是 Apache HTTP Client,替代了已不推薦使用的 Ribbon RestClient。但想要使用 RestClient 或者 okhttp3.OkHttpClient ,可以設置:

    ribbon.restclient.enable=true 或者 ribbon.okhttp.enable=true

    如果想要自定義,提供 CloseableHttpClient 或者 OkHttpClient 類型的 bean 即可。

  • 大文件上傳問題

    小文件上傳可以走代理路徑,但對於大文件,官網推薦使用 “/zuul/*” 來做,這會跳過 zuul 中的 DispatcherServlet ,直接由 ZuulServlet 處理。

    “/zuul/*” 可以由 zuul.servletPath 修改掉;

  • 管理 zuul 應用程序的端點

    zuul 有 /routes/filters 端點,一個用於獲取路由,一個用於獲取過濾器;zuul 會爲從服務註冊中心獲取到的服務添加默認路由(這可以通過配置修改這種行爲),@EnableZuulProxy 會啓用一些默認的 filter,這些信息都可以從上面這兩個端點獲取到。

    @EnableZuulServer 使用的默認 filters 和 @EnableZuulProxy 註解不同,這些端點需要通過 management.endpoints.web.exposure.include 暴露。

  • 超時問題

    Zuul 的超時配置在 ZuulPropertiesHost 內部類中,maxTotalConnectionsmaxPerRouteConnections 等這些容易理解的配置就不做特殊說明。這裏主要困惑的是 socketTimeoutMillisconnectTimeoutMills 這兩個配置,因爲 ribbonhystrix

    也有對應的配置,那我們應該如何處理這些配置值呢?

    分析

    zuul 中,這兩個值是用於 httpclient 的:

    • connectTimeoutMills 連接建立時間;
    • socketTimeoutMillis 等待數據的時間;

    ribbon 當中也是一樣,hystrix 有所不同,它是用在 HystrixCommand 上,所以整個包裝層次應該是 hystrix 》ribbon,不提及 zuul,是因爲 zuul 使用了 ribbon 之後,它的超時配置並不會使用,所以整個超時配置時間配置應該確保上層大於下層,並且需要考慮重試,也就是說:

    ​ hystrix 超時時間 > ribbon 重試次數 * (ribbon 連接超時 + ribbon socket超時)


總結:

前端時間學習了 zuul 的使用,這次結合整個環境,思考了之前忽略的一些問題,但還是不能脫離俗套,這可能與個人的知識點積累的太淺有關!少年加油,不負年華。

這篇文章是 【第一戰】微服務何不康康我 spring cloud 一文的後續,上篇博文中提到的源碼 JWeb 依然在更新,新增對外開放的文件服務。

下一篇準備寫寫 ribbon,記錄下一些思考,考慮從源碼以及它所處的層次去分析,做一次思想上的昇華!


我與風來


認認真真學習,做思想的產出者,而不是文字的搬運工
錯誤之處,還望指出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章