<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「微服務(wù)設(shè)計之禪」隔離模式

          共 2586字,需瀏覽 6分鐘

           ·

          2020-12-17 12:26

          前言

          微服務(wù)本質(zhì)上分布式架構(gòu),當(dāng)我們使用分布式系統(tǒng)時任何不可預(yù)知的問題都會發(fā)生(例如網(wǎng)絡(luò)可用性問題、服務(wù)可用性問題、中間件可用性問題)。一個系統(tǒng)的問題可能會直接影響另外一個系統(tǒng)的使用或性能。所以在系統(tǒng)設(shè)計過程既要保證自身運(yùn)行的彈性需求,也要避免對下游服務(wù)級聯(lián)故障。

          隔離模式

          9dad4a8f788e945c6b5ad18a04c55d21.webp

          如上圖,如果我們仔細(xì)觀察船的結(jié)構(gòu)時會發(fā)現(xiàn),使用了多個隔板將船分為了多個小的隔間。隔板用于密封船體的各個部分,避免由于某個部位泄漏導(dǎo)致整個船淹沒。當(dāng)我們進(jìn)行軟件設(shè)計時,應(yīng)該將整個應(yīng)用拆分為多個組件,并且一個組件的故障不會影響到全局,這就所謂的隔離模式。

          例如:假設(shè)有兩個服務(wù) A 和 B,服務(wù) A 只能同時處理 5 個并發(fā)請求。服務(wù) A 里面有兩個接口

          • /a/b 依賴于服務(wù) B (耗時比較多)

          • /a???? ?本地服務(wù)

          dee63e6581ace714cc03d7888901e71b.webp

          當(dāng)有 10 個并發(fā)請求 A 服務(wù)接口, 其中 5 個請求 /a/b接口 ,5 個請求 /a由于/a/b 需要調(diào)用服務(wù) B 耗時比較多,可能會造成 5 個線程阻塞應(yīng)用無法處理 /a 雖然只是本地處理。由于一個接口耗時占用了整個應(yīng)用的資源導(dǎo)致其他接口無法使用,導(dǎo)致用戶體驗很差。

          43cec0b9851b6efdc38ee378f4645186.webp

          通過隔離模式分配特定接口的資源限制,避免資源瓶頸。如上圖,將a/b 接口最大處理線程設(shè)置為 2,這樣應(yīng)用始終會有剩余線程處理其他接口請求。

          示例程序

          架構(gòu)圖

          bfe79e3060058bb82c5764e5a320776a.webp

          如上圖所示,簡單模擬電商下單邏輯

          • 用戶登錄瀏覽商品 (商品庫存模塊)
          • 扣減商品庫存 (商品庫存模塊)
          • 創(chuàng)建商品訂單 (訂單模塊)

          product-service 提供兩個接口


          1. /products 查詢?nèi)可唐氛故?/li>

          1. /order 調(diào)用 order 服務(wù)下單

          代碼實現(xiàn)

          ├──?bulkhead-demo
          ???├──?order-service????????#訂單服務(wù)??(8070)
          ???└──?product-service??????#商品庫存服務(wù)??(8050)
          • 依賴說明。由于 hystrix 年久失修,這里使用 resilience4j 斷路保護(hù)器做演示
          <dependency>
          ????<groupId>io.github.resilience4jgroupId>
          ????<artifactId>resilience4j-spring-boot2artifactId>
          ????<version>1.6.1version>
          dependency>
          • 消費(fèi)方定義隔離策略
          server:
          ??tomcat:
          ????threads:
          ??????max:?5?#限制應(yīng)用只能處理5?個并發(fā),方便測試

          resilience4j.bulkhead:
          ??instances:
          ????createOrder:??#?限制此接口只能使用兩個
          ??????maxConcurrentCalls:?2
          • 消費(fèi)方接口。product-service 8050
          ??/**
          ???*?用戶點(diǎn)擊購買
          ???*/

          ??@SneakyThrows
          ??@GetMapping("/order")
          ??public?String?buy()?{
          ??????//?模擬調(diào)用?訂單服務(wù)下單
          ??????orderService.createOrder().get();
          ??????return?"success";
          ??}

          ??/***
          ???*?獲取全部商品接口
          ???*/

          ??@SneakyThrows
          ??@GetMapping("/products")
          ??public?String?products()?{
          ??????//?模擬查詢DB?耗時
          ??????Thread.sleep(100);
          ??????return?"products";
          ??}
          • 定義遠(yuǎn)程調(diào)用類使用 Bulkhead 包裝
          /**
          ?*?創(chuàng)建訂單
          ?*?name:?指定接口隔離配置名稱
          ?*?fallbackMethod:?超出隔離限制降級方法
          ?*/
          @Bulkhead(name?=?"createOrder",?fallbackMethod?=?"getError")
          public?CompletableFuture?createOrder()?{
          ????return?CompletableFuture.supplyAsync(()?->?restTemplate.getForEntity("http://localhost:8070/createOrder"
          ????????????,?String.class).getBody());
          }

          public?CompletableFuture?getError(Throwable?error)?{
          ????log.warn("創(chuàng)建訂單失敗了?{}",?error.getMessage());
          ????return?CompletableFuture.completedFuture("");
          }
          • 服務(wù)提供方。order-service 8070
          @RestController
          public?class?PayController?{
          ????@SneakyThrows
          ????@GetMapping("/pay")
          ????public?String?pay(){
          ????????//?模擬調(diào)用支付渠道耗時?10s
          ????????Thread.sleep(10000);
          ????????return?"支付成功";
          ????}
          }

          測試

          • Jmeter 10 個線程請求 /order 接口, 10 個線程請求 /products ,30S 請求服務(wù)性能如下

          測試使用資源隔離

          資源隔離下,30S 共計執(zhí)行樣本 1750 次,通過率 43.5/每秒

          f8dc5efd1e3f410e7c20f704eab1c67f.webp1607306553

          測試不使用資源隔離(去掉@Bulkhead 邏輯)

          由于未做資源隔離,30S 共計執(zhí)行樣本 50 次,通過率 49.8/每分鐘

          2c9e5a959d95709b850f1bf29789af0b.webp

          總結(jié)

          在應(yīng)用資源緊張的前提下,通過設(shè)置資源隔離策略能大大提升整個應(yīng)用的性能。所謂資源緊張即請求并發(fā)大于容器的處理前最大值,如上邊壓測 tomcat 限制只能處理 5 個并發(fā),但是我們測試是 20 個并發(fā)。

          源碼:https://github.com/lltx/microservices-pattern

          參考資料和部分圖片來源 https://www.vinsguru.com

          往期推薦

          「微服務(wù)設(shè)計之禪」超時模式

          「微服務(wù)設(shè)計之禪」重試模式

          「2020封箱」Spring Boot 2.4.1 發(fā)布

          Spring Boot 2.4.0 正式發(fā)布,全面擁抱云原生




          瀏覽 80
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  影音先锋色资源网 | 青青草大香蕉伊人 | 韩国精品无码一区二区三区18 | 成人在线免费网站 | 国产精品成人99一区无码 |