异步服务_微服务全链路异步化实践
1. 背景
隨著公司業(yè)務(wù)的發(fā)展,核心服務(wù)流量越來(lái)越大,使用到的資源也越來(lái)越多。在微服務(wù)架構(gòu)體系中,大部分的業(yè)務(wù)是基于Java 語(yǔ)言實(shí)現(xiàn)的,受限于Java 的線程實(shí)現(xiàn),一個(gè)Java 線程映射到一個(gè)kernel 線程,造成了高并發(fā)場(chǎng)景下線程資源的極大浪費(fèi),線程成為提高系統(tǒng)并發(fā)和吞吐量的瓶頸。
在微服務(wù)架構(gòu)下,使用同步編程模式時(shí)不僅造成了資源的極大浪費(fèi),并且在流量發(fā)生激增波動(dòng)的時(shí)候,受制于系統(tǒng)資源而無(wú)法快速的擴(kuò)容。本文將探索服務(wù)異步化在并發(fā)、吞吐量方面對(duì)系統(tǒng)帶來(lái)的提升。
2. 如何快速提高服務(wù)吞吐量
首先,以微服務(wù)架構(gòu)中的RPC 服務(wù)調(diào)用舉例,測(cè)試和探索在微服務(wù)架構(gòu)中,異步架構(gòu)如何提高服務(wù)的吞吐量和并發(fā)。ESA Stack 是OPPO 自研的基礎(chǔ)框架技術(shù)棧,ESA RPC 是自研的RPC 框架。本節(jié)測(cè)試服務(wù)我們使用ESA RPC 搭建。
關(guān)于ESA RPC的詳情,可以參考我們之前發(fā)布的文章《Dubbo協(xié)議解析及ESA RPC實(shí)踐》。
2.1 服務(wù)架構(gòu)
下圖所示為測(cè)試環(huán)境架構(gòu)。其中Service A 既是服務(wù)端也是客戶端,它模擬了生產(chǎn)環(huán)境中大部分服務(wù)的角色。我們對(duì)Service A 分別采用同步模型和純異步模型進(jìn)行壓測(cè),其中純異步模型包含了客戶端、服務(wù)端邏輯的異步處理。Service B 模擬一個(gè)耗時(shí)為N ms 的下游服務(wù),為Service A 的調(diào)用提供固定的延時(shí)響應(yīng)。
測(cè)試服務(wù)器的配置為8 核16G,千兆網(wǎng)卡。
2.2 同步異步模型對(duì)比
測(cè)試場(chǎng)景1:
并發(fā)壓測(cè)客戶端200~8000,服務(wù)耗時(shí)50ms,分別對(duì)同步和異步架構(gòu)進(jìn)行壓測(cè),對(duì)比TPS、服務(wù)耗時(shí)、CPU 上下文切換;同步模式下,線程數(shù)和并發(fā)客戶端相同;異步模式下,使用框架默認(rèn)的200 線程。測(cè)試數(shù)據(jù)如下。
測(cè)試場(chǎng)景2:
并發(fā)壓測(cè)客戶端8000,服務(wù)耗時(shí)50~500ms,分別對(duì)同步和異步模式進(jìn)行壓測(cè),對(duì)比TPS、服務(wù)耗時(shí)、CPU 上下文切換;同步模式下服務(wù)端8000 線程;異步模式下,使用框架默認(rèn)的200 線程。
2.3 服務(wù)擴(kuò)展性對(duì)比
并發(fā)指服務(wù)瞬時(shí)同時(shí)處理的任務(wù)數(shù)(包含處于IO 等待狀態(tài)的任務(wù))。服務(wù)端設(shè)置業(yè)務(wù)處理線程200,那么同步模式下能提供的并發(fā)為200;純異步模式下服務(wù)并發(fā)不受線程限制,IO密集型服務(wù)尤其收益。在系統(tǒng)流量突增的情景下,異步模式具有更強(qiáng)的可擴(kuò)展性(Scalability)。
2.4 結(jié)論
根據(jù)上面的測(cè)試數(shù)據(jù)可以做出以下對(duì)比:
同步模式,線程數(shù)與并發(fā)成正比,并發(fā)越高對(duì)線程的消耗越多
異步模式,提高并發(fā)不需要線程增加
同步模式,系統(tǒng)Context Switch 次數(shù)隨并發(fā)提高而快速增加
異步模式,系統(tǒng)Context Switch 次數(shù)明顯小于同步模式
同步模式,并發(fā)超過(guò)某個(gè)臨界點(diǎn)后,服務(wù)耗時(shí)快速上升,系統(tǒng)吞吐量急劇下降
異步模式,吞吐量隨著并發(fā)增加,服務(wù)耗時(shí)上升速度明顯低于同步模式
從而得出以下結(jié)論:
可以通過(guò)異步化微服務(wù)架構(gòu),提高相同資源配置下的服務(wù)吞吐量
隨著下游平均耗時(shí)的增加,異步化帶來(lái)的吞吐和耗時(shí)的提升作用減小
線程資源有限(內(nèi)核、內(nèi)存),不能無(wú)限增加來(lái)提高并發(fā)能力,異步化能極大提高系統(tǒng)瞬時(shí)并發(fā)能力(Scalability)
結(jié)論分析:
高并發(fā)下同步模型大量線程在內(nèi)核態(tài)度/用戶態(tài)、不同CPU 核之間進(jìn)行切換,Context Switch 增加,系統(tǒng)性能下降
下游平均耗時(shí)增加時(shí),系統(tǒng)CPU 繁忙程度降低,Context Switch 對(duì)性能系統(tǒng)影響下降
3. 異步模型探索
3.1 阻塞與非阻塞
在操作系統(tǒng)中,線程是CPU 調(diào)度的基本單位;阻塞調(diào)用是指發(fā)起調(diào)用后,線程進(jìn)入阻塞狀態(tài)(讓出CPU),直到獲得結(jié)果或異常返回;非阻塞調(diào)用是指不等待結(jié)果,調(diào)用不阻塞線程直接返回。
3.2 同步與異步
同步和異步關(guān)注的是消息通信機(jī)制;同步就是在發(fā)起調(diào)用后就得到返回結(jié)果(未必是完整結(jié)果),也就是由調(diào)用者主動(dòng)等待結(jié)果;異步則是調(diào)用在發(fā)出之后直接返回,通過(guò)信號(hào)通知、回調(diào)函數(shù)處理來(lái)通知結(jié)果。
3.3 四種IO 模型
非IO 系統(tǒng)調(diào)用層面, 阻塞/非阻塞和同步/異步基本是同義詞;在IO 系統(tǒng)調(diào)用層面,同步/異步和阻塞/非阻塞有以下組合:
同步阻塞調(diào)用,線程同步等待阻塞調(diào)用結(jié)果
同步非阻塞調(diào)用,線程通過(guò)輪訓(xùn)獲取非阻塞調(diào)用結(jié)果
異步阻塞調(diào)用,IO 事件阻塞,IO 操作不阻塞
異步非阻塞調(diào)用,調(diào)用立即返回,信號(hào)/回調(diào)處理結(jié)果
我們通過(guò)一個(gè)簡(jiǎn)單的客戶端來(lái)介紹四種IO 模型的代碼寫法:
同步阻塞IO
非同步阻塞IO
多路復(fù)用IO
Asynchnorous IO
對(duì)四中IO 模型,有以下的對(duì)比:
同步阻塞式IO 模型,編程簡(jiǎn)單但線程阻塞,資源利用率低;
同步非阻塞式IO 模型,需要輪訓(xùn)CPU,浪費(fèi)資源;
異步非阻塞AIO 模型,不阻塞線程,使用回調(diào)方式處理數(shù)據(jù),但是編程難度高;
多路復(fù)用IO 模型,能夠?qū)崿F(xiàn)異步非阻塞IO,且編程簡(jiǎn)單,方便實(shí)現(xiàn)同步和異步調(diào)用,因此成為RPC 框架的首選。
4. 全鏈路異步編程指南
4.1 全鏈路組成及現(xiàn)狀
微服務(wù)架構(gòu)下的全鏈路包含了網(wǎng)關(guān)層、WEB 服務(wù)、RPC 服務(wù)、數(shù)據(jù)層等。目前公司的網(wǎng)關(guān)層已經(jīng)實(shí)現(xiàn)了純異步架構(gòu),Web 框架和RPC 框架支持純異步編程,數(shù)據(jù)存儲(chǔ)層目前異步方案還不成熟。
4.2 網(wǎng)關(guān)異步化
網(wǎng)關(guān)層由于其特殊性,不需要訪問(wèn)業(yè)務(wù)數(shù)據(jù)庫(kù)只做協(xié)議轉(zhuǎn)換和流量轉(zhuǎn)發(fā),目前已經(jīng)使用了純異步的架構(gòu);其IO 密集型的特點(diǎn),特別適合純異步的架構(gòu),可以極大的節(jié)省資源。
4.3 Web 服務(wù)異步化
Web 服務(wù)作為微服務(wù)體系內(nèi)的重要組成,服務(wù)節(jié)點(diǎn)眾多,傳統(tǒng)的Web 服務(wù)框架SpringMVC 不支持純異步化編程,OPPO 自研Web 框架Restlight 支持純異步編程,且性能遠(yuǎn)超SpringMVC。下面是性能對(duì)比及Restlight 異步實(shí)踐。
Restlight 框架異步編程實(shí)踐:通過(guò)Controller 方法返回值區(qū)分同步和異步調(diào)用,且支持三種異步調(diào)用方式,CompletableFuture、ListenableFuture(Guava)、Future(Netty)。
4.4 RPC 調(diào)用異步化
RPC 調(diào)用等待下游response 返回時(shí),線程不應(yīng)處于block 狀態(tài);作為微服務(wù)架構(gòu)中數(shù)據(jù)流量最大的一部分,RPC 調(diào)用異步化的收益巨大;目前ESA RPC 已經(jīng)具備了純異步化的能力,提供RPC 調(diào)用的服務(wù)一般既是客戶端也是服務(wù)端,因此包含了客戶端異步調(diào)用能力和服務(wù)端異步處理能力;為了兼容存量接口,ESA RPC 既支持CompletableFuture 也支持普通返回值的接口。
客戶端異步化實(shí)踐:底層使用異步非阻塞IO 收發(fā)網(wǎng)路數(shù)據(jù)包,使用CompletableFUture傳遞IO 事件以實(shí)現(xiàn)響應(yīng)式編程,客戶端不被RPC 調(diào)用阻塞,可繼續(xù)調(diào)用其他服務(wù)。
接口返回CompletableFuture 來(lái)實(shí)現(xiàn)異步調(diào)用:
普通接口使用ESARpcContext::asyncCall 實(shí)現(xiàn)異步調(diào)用:
服務(wù)端異步化實(shí)踐:通過(guò)服務(wù)端異步功能返回CompletableFuture 給框架以釋放Biz 線程,自定義線程池或者IO 線程池收到下游response 后,完成返回給框架的Future。
接口定義返回CompletableFuture 來(lái)實(shí)現(xiàn)異步調(diào)用:
普通接口通過(guò)ESARpcContext::startAsync 開(kāi)啟服務(wù)端異步:
4.5 存儲(chǔ)層異步化
數(shù)據(jù)操作是每個(gè)請(qǐng)求調(diào)用鏈的終點(diǎn),純異步的架構(gòu)必須使用異步存儲(chǔ)層客戶端,目前OPPO 沒(méi)有自研的存儲(chǔ)層異步客戶端,但業(yè)界開(kāi)源方案欣欣向榮:
數(shù)據(jù)庫(kù):Vert.x JDBC 客戶端
Redis:Redisson、Lettuce
Queue:基本都支持異步調(diào)用
4.6 純異步與偽異步
異步調(diào)用目的在于防止當(dāng)前業(yè)務(wù)線程被阻塞。偽異步將任務(wù)包裝為Runnable 放入另一個(gè)線程執(zhí)行并等待,當(dāng)前Biz 線程不阻塞;純異步為響應(yīng)式編程模型,通過(guò)IO 實(shí)踐驅(qū)動(dòng)任務(wù)完成。他們的區(qū)別不在于是否將請(qǐng)求放入另一個(gè)線程池執(zhí)行,而在于是否有線程阻塞等待Response。
5. 異步化未來(lái)發(fā)展
5.1 異步化帶來(lái)的問(wèn)題
相比于同步模型,異步模型存在以下問(wèn)題:
代碼可讀性和可維護(hù)性較差,可能出現(xiàn)Callback Hell
框架SDK 變得復(fù)雜,使用門檻增加
業(yè)務(wù)可能不清楚代碼邏輯執(zhí)行線程
大量的ThreadLocal 需要手動(dòng)export/import
簡(jiǎn)單來(lái)說(shuō),異步編程就是以編程的簡(jiǎn)單性(simplity)來(lái)交換性能(performance)。
5.2 使用協(xié)程實(shí)現(xiàn)異步非阻塞
目前在其他語(yǔ)言中,Erlang、Go、Kotlin 等都支持了協(xié)程,使用協(xié)程的好處是在語(yǔ)言層面支持了異步調(diào)用,業(yè)務(wù)代碼可以使用同步的寫法達(dá)到異步的效果,線程不被阻塞,避免大量的CPU 上下文切換,提升系統(tǒng)的性能。
目前Java 對(duì)協(xié)程的支持也在進(jìn)行中, Project Loom 就是Java 的協(xié)程項(xiàng)目:http://openjdk.java.net/projects/loom/。
主要有以下幾個(gè)概念:
Fiber,輕量級(jí)線程(用戶態(tài)線程),基于Continuation 實(shí)現(xiàn)
Continuation,指令執(zhí)行單元, 阻塞時(shí)調(diào)用Continuation::yield , 恢復(fù)時(shí)調(diào)用Continuation::run
Scheduler,用戶態(tài)Fiber 調(diào)度器(ForkJoinPool),使用有限Workers 線程執(zhí)行任意數(shù)量Fibers
開(kāi)發(fā)者可以使用 Fiber 來(lái)執(zhí)行業(yè)務(wù)代碼塊,當(dāng)遇到LockSupport::park、socket io 等阻塞調(diào)用時(shí),Fiber 中的代碼單元執(zhí)行會(huì)被阻塞,但是底層的線程并不會(huì)被阻塞。由此達(dá)到了開(kāi)發(fā)同步模式代碼,運(yùn)行時(shí)達(dá)到異步執(zhí)行的目的。
未來(lái),ESAStack服務(wù)框架會(huì)支持協(xié)程。目前 Restlight框架已經(jīng)支持協(xié)程并在內(nèi)部開(kāi)始試用,ESARPC也有支持協(xié)程的計(jì)劃。框架提供的服務(wù)線程使用 Fiber 執(zhí)行業(yè)務(wù)邏輯,業(yè)務(wù)實(shí)現(xiàn)中數(shù)據(jù)庫(kù)請(qǐng)求、下游服務(wù)調(diào)用均在 Fiber 之中執(zhí)行, 其包含的 IO 等阻塞調(diào)用只掛起 Fiber 而不阻塞所在線程,從而避免了過(guò)多的上下文切換提升 了吞吐量,達(dá)到了和異步模式一樣的效果。
☆?END?☆
招聘信息OPPO互聯(lián)網(wǎng)基礎(chǔ)技術(shù)團(tuán)隊(duì)招聘一大波崗位,涵蓋C++、Go、OpenJDK、Java、DevOps、Android、ElasticSearch等多個(gè)方向,請(qǐng)點(diǎn)擊這里查看詳細(xì)信息及JD。
你可能還喜歡OPPO自研ESA DataFlow架構(gòu)與實(shí)踐
Dubbo協(xié)議解析與ESA RPC實(shí)踐
自研代碼審查系統(tǒng)火眼Code Review實(shí)踐
OPPO異地多活實(shí)踐——緩存篇
更多技術(shù)干貨
掃碼關(guān)注
OPPO互聯(lián)網(wǎng)技術(shù)
?我就知道你“在看” 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的异步服务_微服务全链路异步化实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: lighttpd安装配置支持php
- 下一篇: 手把手教你使用腾讯的热修复框架-Tink