<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    本文由去哪兒網技術團隊田文琦分享,本文有修訂和改動。

    1、引言

    本文針對去哪兒網酒店業務網關的吞吐率下降、響應時間上升等問題,進行全流程異步化、服務編排方案等措施,進行了高性能網關的技術優化實踐。

    技術交流:

    - 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM

    - 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK備用地址點此

    (本文已同步發布于:http://www.52im.net/thread-4618-1-1.html

    2、作者介紹

    田文琦:2021年9月加入去哪兒網機票目的地事業群,擔任軟件研發工程師,現負責國內酒店主站技術團隊。主要關注高并發、高性能、高可用相關技術和系統架構。主導的酒店業務網關優化項目,榮獲22年去哪兒網技術中心TC項目三等獎。

    3、專題目錄

    本文是專題系列文章的第9篇,總目錄如下:

    1. 長連接網關技術專題(一):京東京麥的生產級TCP網關技術實踐總結
    2. 長連接網關技術專題(二):知乎千萬級并發的高性能長連接網關技術實踐
    3. 長連接網關技術專題(三):手淘億級移動端接入層網關的技術演進之路
    4. 長連接網關技術專題(四):愛奇藝WebSocket實時推送網關技術實踐
    5. 長連接網關技術專題(五):喜馬拉雅自研億級API網關技術實踐
    6. 長連接網關技術專題(六):石墨文檔單機50萬WebSocket長連接架構實踐
    7. 長連接網關技術專題(七):小米小愛單機120萬長連接接入層的架構演進
    8. 長連接網關技術專題(八):B站基于微服務的API網關從0到1的演進之路
    9. 長連接網關技術專題(九):去哪兒網酒店高性能業務網關技術實踐》(* 本文

    4、技術背景

    近來,Qunar 酒店的整體技術架構在基于 DDD 指導思想下,一直在進行調整。其中最主要的一個調整就是包含核心領域的團隊交出各自的“應用層”,統一交給下游網關團隊,組成統一的應用層。

    這種由多個網關合并成大前臺(酒店業務網關)的融合,帶來的好處是核心系統邊界清晰了,但是對酒店業務網關來說,也帶來了不小的困擾。

    系統面臨的壓力主要來自兩方面:

    • 1)首先,一次性新增了幾十萬行大量硬編碼、臨時兼容、聚合業務規則的復雜代碼且代碼風格迥異,有些甚至是跨語言的代碼遷移;
    • 2)其次,后續的復雜多變的應用層業務需求,之前分散在各個子網關中,現在在源源不斷地匯總疊加到酒店業務網關。

    這就導致了一系列的問題:

    • 1)業務網關吞吐性能變差:應對流量尖峰時期的單機最大吞吐量與合并之前相比,下降了20%
    • 2)內部業務邏輯處理速度變差:主流程業務邏輯的處理時間與合并之前相比,上漲了10%。
    • 3)代碼難以維護、開發效率低:主站內部各個模塊之間嚴重耦合,邊界不清,修改擴散問題非常明顯,給后續的迭代增加了維護成本,開發新需求的效率也不高。

    酒店業務網關作為直接面對用戶的系統,出現任何問題都會被放大百倍,上述這些問題亟待解決。

    5、吞吐量下降問題分析

    現有系統雖然業務處理部分是異步化的,但是并不是全鏈路異步化(如下圖所示)。

    同步 servlet 容器,servlet 線程與業務邏輯線程是同一個,高峰期流量上漲或者尤其是遇到流量尖峰的時候,servlet 容器線程被阻塞的時候,我們服務的吞吐量就會明顯下降。

    業務處理雖然使用了線程池確實能實現異步調用的效果,也能壓縮同步等待的時間,但是也有一些缺陷。

    比如:

    • 1)CPU 資源大量浪費在阻塞等待上,導致 CPU 資源利用率低;
    • 2)為了增加并發度,會引入更多額外的線程池,隨著 CPU 調度線程數的增加,會導致更嚴重的資源爭用,上下文切換占用 CPU 資源;
    • 3)線程池中的線程都是阻塞的,硬件資源無法充分利用,系統吞吐量容易達到瓶頸。

    6、響應時間上漲問題分析

    前期為了快速落地酒店 DDD 架構,合并大前臺的重構中,并沒有做到一步到位的設計。

    為了保證項目質量,將整個過程切分為了遷移+重構兩個步驟。遷移之后,整個酒店業務網關的內部代碼結構是割裂、混亂的。

    總結如下:

    我們最核心的一個接口會調用70多個上游接口,上述問題:邊界不清、不內聚、各種重復調用、依賴阻塞等問題導致了核心接口的響應時間有明顯上漲。

    7、 解決方案Part1:全流程異步化提升吞吐量

    全流程異步化方案,我們主要采用的是 Spring WebFlux。

    7.1選擇的理由

    1)響應式編程模型:Spring WebFlux 基于響應式編程模型,使用異步非阻塞式 I/O,可以更高效地處理并發請求,提高應用程序的吞吐量和響應速度。同時,響應式編程模型能夠更好地處理高負載情況下的請求,降低系統的資源消耗。

    2)高性能:Spring WebFlux 使用 Reactor 庫實現響應式編程模型,可以處理大量的并發請求,具有出色的性能表現。與傳統的 Spring MVC 框架相比,Spring WebFlux 可以更好地利用多核 CPU 和內存資源,以實現更高的性能和吞吐量。

    3)可擴展性:Spring WebFlux 不僅可以使用 Tomcat、Jetty 等常規 Web 服務器,還可以使用 Netty 或 Undertow 等基于 NIO 的 Web 服務器實現,與其它非阻塞式 I/O 的框架結合使用,可以更容易地構建可擴展的應用程序。

    4)支持函數式編程:Spring WebFlux 支持函數式編程,使用函數式編程可以更好地處理復雜的業務邏輯,并提高代碼的可讀性和可維護性。

    5)50與 Spring 生態系統無縫集成:Spring WebFlux 可以與 Spring Boot、Spring Security、Spring Data 等 Spring 生態系統的組件無縫集成,提供了完整的 Web 應用程序開發體驗。

    7.2實現原理和異步化過程

    上圖中從下到上每個組件的作用:

    • 1)Web Server:適配各種 Web 服務, 監聽客戶端請求,并將其轉發到 HttpHandler 處理;
    • 2)HttpHandler:以非阻塞的方式處理響應式 http 請求的最底層處理器,不同的處理器處理的請求都會歸一到 httpHandler 來處理,并返回響應;
    • 3)DispatcherHandler:調度程序處理程序用于異步處理 HTTP 請求和響應,封裝了HandlerMapping、HandlerAdapter、HandlerResultHandler 的調用,實際實現了HttpHandler的處理邏輯;
    • 4)HandlerMapping:根據路由處理函數 (RouterFunction) 將 http 請求路由到相應的handler。WebFlux 中可以有多個 handler,每個 handler 都有自己的路由;
    • 5)HandlerAdapter:使用給定的 handler 處理 http 請求,必要時還包括使用異常處理handler 處理異常;
    • 6)HandlerResultHandler:處理返回結果,將 response 寫到輸出流中;
    • 7)Reactive Streams:Reactive Streams 是一個規范,用于處理異步數據流。Spring WebFlux 實現了 Reactor 庫,該庫基于響應式流規范,處理異步數據流。

    在整個過程中 Spring WebFlux 實現了響應式編程模型,構建了高吞吐量、高并發的 Web 應用程序,同時也具有響應快速、可擴展性好、資源利用率高等優點。

    下面我們來看下 webFlux 是如何將 Servlet 請求異步化的:

    1)ServletHttpHandlerAdapter 展示了使用 Servlet 異步支持和 Servlet 3.1非阻塞I/O,將 HttpHandler 適配為 HttpServlet。

    2)第10行:request.startAsync()開啟異步模式,然后將原始 request 和 response 封裝成 ServletServerHttpRequest 和 ServletServerHttpResponse。

    3)第36行:httpHandler.handle(httpRequest, httpResponse) 返回一個 Mono 對象(即Publisher),對 Request 和 Response 的所有具體處理都在 Mono 對象中定義。

    所有的操作只有在 subscribe 訂閱的那一刻才開始進行,HandlerResultSubscriber 是 Reactive Streams 規范中標準的 subscriber,在它的 onComplete 事件觸發時,會結束 servlet 的異步模式。

    對 Servlet 返回結果的異步寫入,以 DispatcherHandler 為例說明:

    1)第2行:exchange 是對 ServletServerHttpRequest 和 ServletServerHttpResponse 的封裝。

    2)第10-15行:在系統預加載的 handlerMappings 中根據 exchange 找到對應的 handler,然后利用 handler 處理 exchange 執行相關業務邏輯,最終結果由 result 將 ServletServerHttpResponse 寫入到輸出流中。

    最后:除了 Servlet 的異步化,作為業務網關,要實現全鏈路異步化還需要在遠程調用方面要支持異步化。在 RPC 調用方式下,我們采用的異步 Dubbo,在 HTTP 調用方式下,我們采用的是 WebClient。

    WebClient 默認使用的是 Netty 的 IO 線程進行發送請求,調用線程通過訂閱一些事件例如:doOnRequest、doOnResponse 等進行回調處理。異步化的客戶端,避免了業務線程池的阻塞,提高了系統的吞吐量。

    在使用 WebClient 這種異步 http 客戶端的時候,我們也遇到了一些問題:

    1)首先:為了避免默認的 NettyIO 線程池可能會執行比較耗時的 IO 操作導致 Channel 阻塞,建議替換成其他線程池,替換方法是 Mono.publishOn(reactor.core.scheduler.Schedulers.newParallel("biz_scheduler", 300))。

    2)其次:因為線程發生了切換,無法兼容 Qtracer (Qunar內部的分布式全鏈路跟蹤系統),所以在初始化 WebClient 客戶端的時候,需要在 filter 里插入對 Request 的修改,記錄前一個線程保存的 Qtracer 的上下文。WebClient.Builder wcb = WebClient.builder().filter(new QTraceRequestFilter())。

    8、解決方案Part2:服務編排降低響應時間

    Spring WebFlux 并不是銀彈,它并不能保證一定能降低接口響應時間,除了全流程異步化,我們還利用 Spring WebFlux 提供的響應式編程模型,對業務流程進行服務編排,降低依賴之間的阻塞。

    8.1服務編排解決方案

    在介紹服務編排之前,我們先來了解一下 Spring WebFlux 提供的響應式編程模型 Reactor。

    它有最重要的兩個響應式類 Flux 和 Mono:

    • 1)一個 Flux 對象表明一個包含0..N 個元素的響應式序列;
    • 2)一個 Mono 對象表明一個包含零或者一個(0..1)元素的結果。

    不管是 Flux 還是 Mono,它的處理過程分三步:

    • 1)首先聲明整個執行過程(operator);
    • 2)然后連通主過程,觸發執行;
    • 3)最后執行主過程,觸發并執行子過程、生成結果。

    每個執行過程連通輸入流和輸出流,子過程之間可以是并行的,也可以是串行的這個取決于實際的業務邏輯。我們的服務編排就是完成輸入和輸出流的編排,即在第一步聲明執行過程(包括子過程),第二步和第三步完全交給 Reactor。

    下面是我們服務編排的總體設計:

    如上圖所示:

    1)service:是最小的業務編排單元,對 invoker 和 handler 進行了封裝,并將結果寫回到上下文中。主流程中,一般是由多個 service 進行并行/串行地編排。

    2)Invoker:是對第三方的異步非阻塞調用,對返回結果作 format,不包含業務邏輯。相當于子過程,一個 service 內部根據實際業務場景可以編排0個或多個 Invoker。

    3)handler:純內存計算,封裝共用和內聚的業務邏輯。在實際的業務開發過程中,對上下文中的任一變量,只有一個 handler 有寫權限,避免了修改擴散問題。也相當于子過程,根據實際需要編排進 service 中。

    4)上下文:為每個接口都設計了獨立的請求/處理/響應上下文,方便監控定位每個模塊的處理正確性。

    上下文設計舉例:

    在復雜的 service 中我們會根據實際業務需求組裝 invoker 和 handler,例如:日歷房售賣信息展示 service 組裝了酒店報價、輔營權益等第三方調用 invoker,優惠明細計算、過濾報價規則等共用的邏輯處理 handler。

    在實際優化過程中我們抽象了100多個 service,180多個 invoker,120多個 handler。他們都是小而獨立的類,一般都不會超過200行,減輕了開發同學尤其是新同學對代碼的認知負擔。邊界清晰,邏輯內聚,代碼的不可知問題也得到了解決。

    每個 service 都是由一個或多個 Invoker、handler 組裝編排的業務單元,內部處理都是全異步并行處理的。

    如下圖所示:ListPreAsyncReqService 中編排了多個 invoker,在基類 MonoGroupInvokeService 中,會通過 Mono.zip(list, s -> this.getClass() + " succ")將多個流合并成為一個流輸出。

    在 controller 層就負責處理一件事,即對 service 進行編排(如下圖所示)。

    我們利用 flatMap 方法可以方便地將多個 service 按照業務邏輯要求,進行多次地并行/串行編排。

    1)并行編排示例:第12、14行是兩個并行處理的輸入流 afterAdapterValidMono、preRankSecMono ,二者并行執行各自 service 的處理。

    2)并行處理后的流合并:第16行,搜索結果流 rankMono 和不依賴搜索的其他結果流preRankAsyncMono,使用 Mono.zip 操作將兩者合并為一個輸出流 afterRankMergeMono。

    3)串行編排舉例:第16、20、22行,afterRankMergeMono 結果流作為輸入流執行 service14 后轉換成 resultAdaptMono,又串行執行 service15 后,輸出流 cacheResolveMono。

    以上是酒店業務網關的整體服務編排設計。

    8.2編排示例

    下面來介紹一下,我們是如何進行流程編排,發揮網關優勢,在系統內和系統間達到響應時間全局最優的。

    8.2.1)系統內:

    上圖示例中的左側方案總耗時是300ms。

    這300ms 來自最長路徑 Service1的200ms 加上 Service3 的100ms:

    • 1)Service1 包含2個并行 invoker 分別耗時100ms、200ms,最長路徑200ms;
    • 2)Service3 包含2個并行invoker 分別耗時50ms、100ms,最長路徑100ms。

    而右圖是將 Service1 的200ms 的 invoker 遷移至與 Service1 并行的 Service0 里。

    此時,整個處理的最長路徑就變成了200ms:

    • 1)Service0 的最長路徑是200ms;
    • 2)Service1+service3 的最長路徑是100ms+100ms=200ms。

    通過系統內 invoker 的最優編排,整體接口的響應時間就會從300ms 降低到200ms。

    8.2.2)系統間:

    舉例來說:優化前業務網關會并行調用 UGC 點評(接口耗時100ms)和 HCS 住客秀(接口耗時50ms)兩個接口,在 UGC 點評系統內部還會串行重復調用 HCS 住客秀接口(接口耗時50ms)。

    發揮業務網關優勢,UGC 無需再串行調用 HCS 接口,所需業務聚合處理(這里的業務聚合處理是純內存操作,耗時可以忽略)移至業務網關中操作,這樣 UGC 接口的耗時就會降下來。對全局來說,整體接口的耗時就會從原來的100ms 降為50ms。

    還有一種情況:假設業務網關是串行調用 UGC 點評接口和 HCS 住客秀接口的話,那么也可以在業務網關調用 HCS 住客秀接口后,將結果通過入參在調用 UGC 點評接口的時候傳遞過去,也可以省去 UGC 點評調用 HCS 住客秀接口的耗時。

    基于對整個酒店主流程業務調用鏈路充分且清晰的了解基礎之上,我們才能找到系統間的最優解決方案。

    9、優化后的效果

    9.1頁面打開速度明顯加快

    優化后最直接的效果就是在用戶體感上,頁面的打開速度明顯加快了。

    以詳情頁為例:

     

    9.2接口響應時間下降50%

    列表、詳情、訂單等主流程各個核心接口的P50響應時間都有明顯的降幅,平均下降了50%。

    以詳情頁的 A、B 兩個接口為例,A接口在優化前的 P50 為366ms:

    A 接口優化后的 P50 為36ms:

    B 接口的 P50 響應時間,從660ms 降到了410ms:

    9.3單機吞吐量性能上限提升100%,資源成本下降一半

    單機可支持 QPS 上限從100提升至200,吞吐量性能上限提升100%,平穩應對七節兩月等常規流量高峰。

    在考試、演出、臨時政策變化、競對故障等異常突發事件情況下,會產生瞬時的流量尖峰。在某次實戰的情況下,瞬時流量高峰達到過二十萬 QPS 以上,酒店業務網關系統經受住了考驗,能夠輕松應對。

    單機性能的提升,我們的機器資源成本也下降了一半。

    9.4圈復雜度降低38%,研發效率提升30%

    具體就是:

    • 1)優化后酒店業務網關的有效代碼行數減少了6萬行;
    • 2)代碼圈復雜度從19518減少至12084,降低了38%;
    • 3)網關優化后,業務模塊更加內聚、邊界清晰,日常需求的開發、聯調時間均有明顯減少,研發效率也提升了30%。

    10、本文小結與下一步規劃

    1)通過采用 Spring WebFlux 架構和系統內/系統間的服務編排,本次酒店業務網關的優化取得了不錯的效果,單機吞吐量提升了100%,整體接口的響應時間下降了50%,為同類型業務網關提供一套行之有效的優化方案。

    2)在此基礎上,為了保持優化后的效果,我們除了建立監控日常做好預警外,還開發了接口響應時長變化的歸因工具,自動分析變化的原因,可以高效排查問題作好持續優化。

    3)當前我們在服務編排的時候,只能根據上游接口在穩定期的響應時間,來做到最優編排。當某些上游接口響應時間存在波動較大的情況時,目前的編排功能還無法做到動態自動最優,這部分是我們未來需要優化的方向。

    11、相關文章

    [1] 從C10K到C10M高性能網絡應用的理論探索

    [2] 一文讀懂高性能網絡編程中的I/O模型

    [3] 一文讀懂高性能網絡編程中的線程模型

    [4] 以網游服務端的網絡接入層設計為例,理解實時通信的技術挑戰

    [5] 手淘億級移動端接入層網關的技術演進之路

    [6] 喜馬拉雅自研億級API網關技術實踐

    [7] B站基于微服務的API網關從0到1的演進之路

    [8] 深入操作系統,徹底理解I/O多路復用

    [9] 深入操作系統,徹底理解同步與異步

    [10] 通俗易懂,高性能服務器到底是如何實現的

    [11] 百度統一socket長連接組件從0到1的技術實踐

    [12] 淘寶移動端統一網絡庫的架構演進和弱網優化技術實踐

    [13] 百度基于金融場景構建高實時、高可用的分布式數據傳輸系統的技術實踐


    (本文已同步發布于:http://www.52im.net/thread-4618-1-1.html



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: aa毛片免费全部播放完整| 在线观看成人免费视频不卡| 国产精品99爱免费视频| 三年在线观看免费观看完整版中文| 美女被免费网站在线视频免费 | 成全影视免费观看大全二| 免费高清av一区二区三区| 亚洲第一页综合图片自拍| 亚洲乱码国产一区三区| 亚洲精品国产专区91在线| 亚洲精品无码国产片| 免费日本一区二区| 国产免费观看黄AV片| 国产亚洲情侣一区二区无| 亚洲黄色在线观看| 一级毛片正片免费视频手机看| 拍拍拍无挡视频免费观看1000| 久久久久久国产a免费观看黄色大片 | 最新中文字幕免费视频| 免费va人成视频网站全| 在线观看亚洲天天一三视| 亚洲日本一线产区和二线| 性xxxxx大片免费视频| 免费a级毛片无码a∨性按摩| 无码乱人伦一区二区亚洲| 猫咪免费人成在线网站| 在线v片免费观看视频| 亚洲精品无码久久久| 国产成人精品日本亚洲专一区| 中文字幕视频在线免费观看| jjzz亚洲亚洲女人| 色综合久久精品亚洲国产| 一二三四免费观看在线电影| 亚洲黄色在线网站| 日本免费在线观看| 亚洲国产精品久久久久久| 久久久受www免费人成| 亚洲AV无码一区二区三区国产 | 国产精品亚洲精品爽爽| 免费阿v网站在线观看g| 久久久久精品国产亚洲AV无码|