spring cloud zuul

一 spring cloud Zuul底層架構(gòu)

spring cloud zuul融合的是netflix 的zuul 1.x版本

1.1 netflix 的1.x的線程模型

zuul1.x線程模型.png

zuul1.x采用的是線程阻塞模型穗熬,也就是我們常說的BIO,每來一個請求就會從線程池中分配一個線程去處理阔涉。這里導(dǎo)致的問題就是如果每一次請求的耗時很長,i/o操作時間很長犁享,就會導(dǎo)致大量線程被掛起,利用率不僅低,很容易耗盡容器線程池內(nèi)的線程建邓,造成容器無法接受新的請求。所以對于這種io密集型睁枕,大請求來說官边,是不合適的。他適合那種小請求外遇,cpu密集型注簿,如果每一次請求只需要0.0幾秒,一個線程1s鐘也可以處理上百次請求跳仿,再加上簡單诡渴,所以對于流量不是特別大,請求時間很短的場景是很實用的菲语。
應(yīng)用場景

  • cpu密集型任務(wù)
  • 簡單操作的需求
  • 開發(fā)簡單的需求
  • 實時請求高的

1.2 zuul 2.x 的線程模型

image.png

可以簡單理解為有一個隊列專門負(fù)責(zé)處理用戶請求(如果連接量大妄辩,可以開個線程組來處理),后端有個隊列專門負(fù)責(zé)處理后臺服務(wù)調(diào)用(如果連接量大谨究,可以開個線程組來處理)恩袱,中間有個事件環(huán)線程(Event Loop Thread),它同時監(jiān)聽前后兩個隊列上的事件胶哲,有事件就觸發(fā)回調(diào)函數(shù)處理事件畔塔。這種模式下需要的線程比較少,基本上每個CPU核上只需要一個事件環(huán)處理線程鸯屿,前端的連接數(shù)可以很多澈吨,連接來了只需要進隊列,不需要啟動線程寄摆,事件環(huán)線程由事件觸發(fā)谅辣,沒有多線程阻塞問題。但是zuul2.x帶來的問題就是開發(fā)成本大婶恼,對于小請求來說他的性能提升不明顯桑阶。
應(yīng)用場景

  • io密集的任務(wù)
  • 大請求或者大文件
  • 隊列的流式數(shù)據(jù)
  • 超大量的連接

1.3 Zulu 1.x 的架構(gòu)

image.png

每一次請求都會通過servlet柏副,然后進入各種過濾器,最后再返回給客戶端蚣录。而各個filters之間不會直接進行通信的割择。zuul 1.x使用RequestContext來實現(xiàn)各個filters之間共享數(shù)據(jù),而RequestContext采用ConcurrentHashMap和ThreadLocal實現(xiàn)線程安全萎河。

1.4 Zuul 1.x requestLifeCycle

image.png

一次請求的生命周期就如上圖所示荔泳。可見最重要的一環(huán)就是各種過濾器虐杯。

過濾器類型

  • PRE:這種過濾器在請求被路由之前調(diào)用玛歌。我們可利用這種過濾器實現(xiàn)身份驗證、在集群中選擇請求的微服務(wù)擎椰、記錄調(diào)試信息等支子。

  • ROUTING:這種過濾器將請求路由到微服務(wù)。這種過濾器用于構(gòu)建發(fā)送給微服務(wù)的請求确憨,并使用Apache HttpClient或Netfilx Ribbon請求微服務(wù)译荞。

  • POST:這種過濾器在路由到微服務(wù)以后執(zhí)行。這種過濾器可用來為響應(yīng)添加標(biāo)準(zhǔn)的HTTP Header休弃、收集統(tǒng)計信息和指標(biāo)吞歼、將響應(yīng)從微服務(wù)發(fā)送給客戶端等你虹。

  • ERROR:在其他階段發(fā)生錯誤時執(zhí)行該過濾器

    對于我們的業(yè)務(wù)來說嚼酝,我們可以結(jié)合我們的業(yè)務(wù)來定制適合自己的過濾器。

    定制自己的過濾器其實也很簡單咕幻,只繼成ZuulFilter丈甸,實現(xiàn)

    • String filterType();

    • int filterOrder();

    • boolean shouldFilter();

    • Object run();

      其中
      filterType:返回過濾器的類型糯俗。有pre、route睦擂、post得湘、error等幾種取值,分別對應(yīng)上文的幾種過濾器
      filterOrder:返回一個int值來指定過濾器的執(zhí)行順序顿仇,不同的過濾器允許返回相同的數(shù)字淘正。
      shouldFilter:返回一個boolean值來判斷該過濾器是否要執(zhí)行,true表示執(zhí)行臼闻,false表示不執(zhí)行鸿吆。可以在此添加一些條件
      run:過濾器的具體邏輯述呐。

      一個對token進行check過濾器的例子

         * @author zhaokai008@ke.com
         * @date 2019-05-11 21:45
         */
        public class TokenFilters {
         private static Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);
        ?
         @Override
         public String filterType() {
         return PRE_TYPE;
         }
        ?
         @Override
         public int filterOrder() {
         return 0;
         }
        ?
         @Override
         public boolean shouldFilter() {
         //todo 什么時候需要驗證token

         return true;
         }
        ?
         @Override
         public Object run() {
        ?
         RequestContext ctx = RequestContext.getCurrentContext();
         HttpServletRequest request = ctx.getRequest();
         String url = request.getRequestURI();
         String token = request.getHeader("token");
         checkToken(url,token);
         return null;
        ?
         }
        ?
         private boolean checkToken(String url, String token) {

         //todo dosomething
         return true;
         }
        ?
        }

二 配置詳解

  zuul:
  SendErrorFilter:
    error:
      disable: true
  sensitive-headers:
  #ignored-services: '*'
  # 限流
  ratelimit:
    enabled: true
    fallback: true
    repository: in_memory
    # 全局限流
    default-policy-list:
      - limit: 10000 #optional - request number limit per refresh interval window
        quota: 300 #optional - request time limit per refresh interval window (in seconds)
        refresh-interval: 60 #default value (in seconds)
        type: #optional
          - url
    # 分route限流
    policy-list:
      test1:
        - limit: 1 #optional - request number limit per refresh interval window
          quota: 10 #optional - request time limit per refresh interval window (in seconds)
          refresh-interval: 1 #default value (in seconds)
          type: #optional
            - url
  routes:
    test1:
      path: /api/10/search/**
      serviceId: common
      stripPrefix: false
      token: 10
    test2:
      path: /api/10/search/**
      serviceId: on
      stripPrefix: false
      token: 10
    test3:
      path: /api/data/10/**
      serviceId: DAS
      stripPrefix: false
      token: d10
    test4:
      path: /api/data/**
      serviceId: no
      stripPrefix: false
      token: d10
    test5:
      path: /api/search/**
      serviceId: no
      stripPrefix: true
      token: d10
    test6:
      path: /api/search/**
      url: http://host/api/data/**
      stripPrefix: false
      token: d10
    test7:
      path: /*
      url: http://host/api/data/**
      stripPrefix: false
      token: d10

# hystrix
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000

  host:
    max-per-route-connections: 20 #默認(rèn)20
    max-total-connections: 200  #默認(rèn)200

ribbon:
  eager-load:
    enabled: true
  ConnectTimeout: 15 #默認(rèn)1000
  ReadTimeout: 15 #默認(rèn)2000

2.1 請求路由

zuul.ignored-services: 默認(rèn)情況下所有Eureka上的服務(wù)都會被Zuul自動創(chuàng)建映射關(guān)系進行路由惩淳,一般情況下需要 將其 置為 * ,表示不需要為所有服務(wù)自動創(chuàng)建路規(guī)則乓搬。這個默認(rèn)情況下是需要設(shè)置為 * 思犁,因為很多時候我們不想讓我們的服務(wù)都對外暴露

2.1.1 設(shè)置路由

有兩種方式代虾,URL和serviceId.都是通過匹配到網(wǎng)關(guān)的path然后映射到對應(yīng)的服務(wù)(url或者serviceId)上去。其中test5是url式抒倚,其余的都是serviceId式褐着。但是要注意的是url方式?jīng)]有 Hystrix、Ribbon 特性托呕。

2.1.2 存取路由順序

  • 所有的Route保存在一個map里面着降,而map的key是path,所有如果配置有兩個path一致的話就會有一個被覆蓋
  • 而對于yaml文件的來說拗军,存入的順序是按照先后順序存入的任洞。
    示例:
    比如上面的配置,首先存入的是test1发侵,但是后來發(fā)現(xiàn)最后test2的path和test1一致交掏,最終我們的routes里面包含的route就只有test2而沒有test1

2.1.3 讀取路由規(guī)則

1,使用路由規(guī)則匹配請求路徑的時候是通過線性遍歷的方式刃鳄,在請求路徑獲取到第一個匹配的路由規(guī)則之后就會返回并結(jié)束匹配過程盅弛。所以當(dāng)存在多個匹配的路由規(guī)則時,匹配結(jié)果完全取決于路由規(guī)則的保存順序叔锐。
2挪鹏, 在yaml存入是按照順序存入的,左邊第一個圖當(dāng)我們訪問/api/data/10的時候愉烙,因為第一個匹配到的是/api/data/10/**讨盒,所以會映射到test3的DAS,而不會映射到test4 的no服務(wù)

2.2 限流

  • 分為全局限流(default-policy-list)和分route(policy-list)限流:
  • Limit:單位時間內(nèi)允許訪問的次數(shù)
  • Quota:單位時間內(nèi)允許訪問的總時間(統(tǒng)計每次請求的時間綜合)
  • refresh-interval:單位時間設(shè)置,默認(rèn)60s
  • Type限流方式:ORIGIN, USER, URL
    policy-list.test1配置的意思是:在一個時間窗口 1s 內(nèi)步责,最多允許 12 次訪問返顺,或者總請求時間小于 120s

2.3 超時,熔斷

  • ribbon. ConnectTimeout,ribbon.ReadTimeout
  • zuul.host.connect-timeout-millis勺择, zuul.host.socket-timeout-millis
  • hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 6000
    單位:ms,區(qū)別在于创南,如果路由方式是serviceId的方式,那么ribbon的生效省核,如果是url的方式稿辙,則zuul.host開頭的生效,ribbon 和hystrix誰小,誰生效气忠。Hystrix是熔斷邻储,力度可基于全局配置和基于某個服務(wù)赋咽,但是不能基于route

2.4 線程池大小

  • max-per-route-connections:表示為每一個route分配的最大線程數(shù),只是限制了線程數(shù)而不是限流吨娜,和qps沒多大關(guān)系
  • max-total-connections:表示所有route的最大線程數(shù)

三 Zuul 使用的坑:

  • stripPrefix:默認(rèn)為true脓匿,需要注意
  • 過動態(tài)刷新的配置,對于路由規(guī)則的變動宦赠,只能新增和修改陪毡,不能刪除(所以動態(tài)刪除會刷新不生效的錯覺);
  • 新增的規(guī)則在匹配順序上勾扭,位于老規(guī)則的后(如上面的test7配置生效之后毡琉,因為/*已經(jīng)表示所有的路由,導(dǎo)致后面所有新加的所以路由都會打到test7之上妙色,以后想要再添加其他的路由桅滋,是相當(dāng)于不生效的。)
  • 一定要要將超時時間設(shè)置小一點身辨,負(fù)責(zé)如果一瞬間上來都是2s或者更長的請求丐谋,就會導(dǎo)致在這2s內(nèi)的這些線程得不到釋放,就不能處理更多的請求煌珊,服務(wù)器性能大幅度降低号俐。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市怪瓶,隨后出現(xiàn)的幾起案子萧落,更是在濱河造成了極大的恐慌,老刑警劉巖洗贰,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件找岖,死亡現(xiàn)場離奇詭異,居然都是意外死亡敛滋,警方通過查閱死者的電腦和手機许布,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绎晃,“玉大人蜜唾,你說我怎么就攤上這事∈” “怎么了袁余?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咱揍。 經(jīng)常有香客問我颖榜,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任掩完,我火速辦了婚禮噪漾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘且蓬。我一直安慰自己欣硼,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布恶阴。 她就那樣靜靜地躺著诈胜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冯事。 梳的紋絲不亂的頭發(fā)上耘斩,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音桅咆,去河邊找鬼。 笑死坞笙,一個胖子當(dāng)著我的面吹牛岩饼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薛夜,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼籍茧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梯澜?” 一聲冷哼從身側(cè)響起寞冯,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晚伙,沒想到半個月后吮龄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡咆疗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年漓帚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片午磁。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡尝抖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迅皇,到底是詐尸還是另有隱情昧辽,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布登颓,位于F島的核電站搅荞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜取具,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一脖隶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暇检,春花似錦产阱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至悔据,卻和暖如春庄敛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背科汗。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工藻烤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人头滔。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓怖亭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坤检。 傳聞我的和親對象是個殘疾皇子兴猩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容