Reactive 模式優(yōu)勢(shì)與實(shí)戰(zhàn)

      網(wǎng)友投稿 608 2025-03-31

      Reactive 編程即反應(yīng)式編程,隨著這些年的發(fā)展已經(jīng)逐步的進(jìn)入了開(kāi)發(fā)者的視野當(dāng)中。早在 2014 年社區(qū)就有人發(fā)起響應(yīng)式宣言,推動(dòng)著 Reactive 的發(fā)展:

      響應(yīng)式宣言

      Published on September 16 2014. (v2.0) 來(lái)自不同領(lǐng)域的組織正在不約而同地發(fā)現(xiàn)一些看起來(lái)如出一轍的軟件構(gòu)建模式。它們的系統(tǒng)更加穩(wěn)健,更加有可回復(fù)性,更加靈活,并且以更好的定位來(lái)滿足現(xiàn)代的需求。這些變化之所以會(huì)發(fā)生,是因?yàn)榻鼛啄甑膽?yīng)用需求出現(xiàn)了戲劇性的變化。僅僅在幾年之前,大型應(yīng)用意味著數(shù)十臺(tái)服務(wù)器,數(shù)秒的響應(yīng)時(shí)間,數(shù)小時(shí)的離線維護(hù)時(shí)間以及若干 GB 的數(shù)據(jù)。而在今天,應(yīng)用被部署在一切場(chǎng)合,從移動(dòng)設(shè)備到基于云的集群,這些集群運(yùn)行在數(shù)以千計(jì)的多核心處 理器的之上。用戶期望毫秒級(jí)的響應(yīng)時(shí)間以及 100% 的正常運(yùn)行時(shí)間。數(shù)據(jù)則以 PB 為單位來(lái)衡 量。

      昨天的軟件架構(gòu)已經(jīng)完全無(wú)法地滿足今天的需求。我們相信,一種條理分明的系統(tǒng)架構(gòu)方法是必要的,而且我們相信關(guān)于這種方法的所有必要方面 已經(jīng)逐一地被人們認(rèn)識(shí)到:我們需要的系統(tǒng)是響應(yīng)式的,具有可回復(fù)性的,可伸縮的,以及以消息驅(qū)動(dòng)的。我們將這樣的系統(tǒng)稱之為響應(yīng)式系統(tǒng)。以響應(yīng)式系統(tǒng)方式構(gòu)建的系統(tǒng)更加靈活,松耦合和可擴(kuò)展。這使得它們更容易被開(kāi)發(fā),而且經(jīng)得起變化的考驗(yàn)。它們對(duì)于系統(tǒng)失敗表現(xiàn)出顯著的包容性,并且當(dāng)失敗真的發(fā)生時(shí),它們能用優(yōu)雅 的方式去應(yīng)對(duì),而不是放任災(zāi)難的發(fā)生。響應(yīng)式系統(tǒng)是高度靈敏的,能夠給用戶以有效的交互式的反饋。

      Reactive 構(gòu)建的程序代表的是異步非阻塞、函數(shù)式編程、事件驅(qū)動(dòng)的思想。

      異步非阻塞

      相比同步,異步的目的是提高硬件資源的利用率。同步模式下線程等待 I/O 時(shí)進(jìn)入阻塞狀態(tài) (Blocked) 相當(dāng)于閑置,異步則可以利用 CPU 同步等待 I/O 返回的時(shí)間以避免資源消耗,從而達(dá)到更大的并發(fā)量以及更低的響應(yīng)時(shí)延。

      在原生 JDK 中,juc 包提供 Future、Callable、FutureTask 等相關(guān)類讓我們完成最基本的異步編程。但其存在如下兩個(gè)典型問(wèn)題:

      獲得返回結(jié)果依然需要阻塞 get。

      大量應(yīng)用 Future 寫(xiě)出類似如下代碼,可讀性差且不優(yōu)雅。

      public?Future>>?getData();

      為了避免阻塞我們可以引入回調(diào) (Callback),從而達(dá)到真正的異步,解決上面提出的第一個(gè)問(wèn)題。但應(yīng)用回調(diào)的同時(shí)也容易產(chǎn)生回調(diào)地獄 (Callback Hell),層層嵌套的回調(diào)函數(shù)往往讓人產(chǎn)生困惑,極大的降低了代碼的可讀性和可維護(hù)性,仍然不完美。

      函數(shù)式編程:

      為了解決上文例子的第二個(gè)問(wèn)題——異步帶來(lái)的可讀性差,可以用函數(shù)式編程思想:把函數(shù)邏輯組織成事件流,通過(guò)對(duì)事件的編排和組合,可以用清晰的代碼接口來(lái)達(dá)到對(duì)事件返回的立即響應(yīng)和對(duì)失敗的立即響應(yīng) (Fail Fast),構(gòu)建起事件驅(qū)動(dòng) (Event Driven) 的程序。

      假設(shè)模擬一個(gè)訂單的場(chǎng)景,我們需要連續(xù)調(diào)用三個(gè)服務(wù)的接口:用戶服務(wù),訂單服務(wù),庫(kù)存服務(wù),并且每次調(diào)用都依賴于上次調(diào)用的返回結(jié)果。如果是傳統(tǒng)的同步阻塞代碼,我們需要連續(xù)等待每個(gè)接口的 I/O 調(diào)用返回。而應(yīng)用 Vert.x 等 Reactive 框架我們可以寫(xiě)出類似如下偽代碼:

      //?下訂單調(diào)用?public?Result?order(long?uid,?Product?product)?{ ????userServer.getUserInfo(uid)?//?用戶服務(wù),查詢用戶信息 ???????????.compose(user->asyncAddOrder(user,?product))?//?訂單服務(wù),生成訂單 ???????????.compose(order->asyncWmsOccupy(order))?//?庫(kù)存服務(wù),庫(kù)存占用 ???????????.setHandler(result->handle(result));?//?處理結(jié)果 ?}

      應(yīng)用 Reactive 模式,每個(gè) compose 方法異步調(diào)用,結(jié)束后都會(huì)自動(dòng)回調(diào)下一個(gè) compose,而任何錯(cuò)誤都會(huì)立即響應(yīng)到 setHandler 中同一處理,保證我們寫(xiě)出優(yōu)雅的異步代碼。

      Vert.x:

      隨著 Reactive 思想這些年來(lái)的發(fā)展,社區(qū)中逐漸涌現(xiàn)出一批優(yōu)秀的 Reactive 開(kāi)源框架:如RxJava(http:/reactivex.io/),Vert.x(https:/vertx.io/)等。

      2011 年,在 VMware 工作的 Tim Fox 開(kāi)始開(kāi)發(fā) Vert.x,后來(lái)貢獻(xiàn)給了 Eclipse 基金會(huì)。Vert.x 提供了一系列的異步、流式工具,它更像一個(gè)工具包,使用 Vert.x 可以輕松的構(gòu)建輕量級(jí)的 Reactive web 服務(wù)器。

      Vert.x 采用 Actor 的模型簡(jiǎn)化了多線程的編程。圖靈獎(jiǎng)得主、面向?qū)ο缶幊?/a>之父 Alan Kay 曾經(jīng)這樣描述面向?qū)ο螅?/p>

      我在描述“面向?qū)ο缶幊?/a>”時(shí)使用了“對(duì)象”這個(gè)概念。很抱歉這個(gè)概念讓許多人誤入歧途,他們將學(xué)習(xí)的重心放在了“對(duì)象”這個(gè)次要的方面。真正主要的方面是“消息”。

      幾十年前,Carl Hewitt 提出了 Actor 模型,將其作為在高性能網(wǎng)絡(luò)中處理并行任務(wù)的一種方法。如今隨著硬件條件的發(fā)展,產(chǎn)生了很多面向?qū)ο鬅o(wú)法解決的挑戰(zhàn),Actor 模型的思想重新進(jìn)入人們視野,并以一種新的思路解決了多線程多 cpu 環(huán)境下的并發(fā)問(wèn)題。

      Reactive 模式優(yōu)勢(shì)與實(shí)戰(zhàn)

      Vert.x 是一個(gè)事件驅(qū)動(dòng)的框架,底層使用 Netty 作為 I/O 庫(kù)保證性能 。Vert.x 采用了簡(jiǎn)單的并發(fā)模型,所有代碼都運(yùn)行在單線程中,避免多線程編程可能出現(xiàn)的并發(fā)問(wèn)題、狀態(tài)共享、以及各種鎖的處理,同時(shí)每個(gè) actor 模型獨(dú)立天然符合分布式的部署和支持高可用 (HA)。

      與 Node.js 的 Eventloop 類似,在 Vert.x 的線程模型中,同樣也有 Eventloop 的概念。但相比于單線程的 Node.js,Vert.x 設(shè)置了一個(gè) Eventloop 線程池,來(lái)發(fā)揮多核處理器的性能。通過(guò)在代碼中定義 Verticle——一種 actor 的實(shí)現(xiàn),使業(yè)務(wù)代碼和 Verticle 綁定,而每個(gè) Verticle 會(huì)綁定到一個(gè) Eventloop 線程上,只要不阻塞 Eventloop 線程,就可以源源不斷的處理新事件從而最大程度利用計(jì)算資源。當(dāng)遇到耗時(shí)的長(zhǎng)任務(wù)時(shí)則可以交給額外的 Worker 線程執(zhí)行,避免 Eventloop 線程阻塞。基于 Verticle 來(lái)編寫(xiě)的業(yè)務(wù)代碼始終運(yùn)行在單線程中,加上基于回調(diào)機(jī)制可以實(shí)現(xiàn)天然的異步無(wú)鎖。

      vert.x 的 actor 模型

      tomcat 的同步線程模型

      Java Chassis 的 Reactive 實(shí)踐

      Java Chassis 是?Apache Service Comb?的一個(gè)子項(xiàng)目,提供了開(kāi)箱即用的 Java 微服務(wù)開(kāi)發(fā)框架 SDK,并在通信部分采用了基于 Vert.x 的 Reactive 架構(gòu)。目前已經(jīng)在華為應(yīng)用市場(chǎng)業(yè)務(wù)中廣泛應(yīng)用,在生產(chǎn)實(shí)踐中為高達(dá) 60w tps 的業(yè)務(wù)并發(fā)保駕護(hù)航。通過(guò)性能對(duì)比測(cè)試,業(yè)務(wù)采用 Reactive 異步模式之后,TPS 提升 43% 左右、RT 時(shí)延降低 28% 左右,CPU 占用降低 56% 左右,性能收益很大。

      使用 Spring MVC 作為 web 框架的 Spring cloud,其底層實(shí)際上基于 Servlet 即采用 DipatcherServlet 來(lái)分發(fā)請(qǐng)求,需要運(yùn)行在 Tomcat 等 web 容器中。雖然 Servlet 3.1 以后的版本提供了對(duì)異步和 NIO 的支持,但也阻止不了最近幾年出現(xiàn)的一些新的 Reactive web 服務(wù)器試圖取代 Servlet 的地位,它們往往更加輕量級(jí)也更加靈活。Spring 也在去年推出了 Spring WebFlux 作為新一代的 Reactive web 框架可以做到代替 Spring MVC,但目前的主要應(yīng)用場(chǎng)景還是在網(wǎng)關(guān),與 Spring cloud 集成后的表現(xiàn)并沒(méi)有特別搶眼。

      Java Chassis 則采用基于 Vert.x 的 reactive 服務(wù)器,更加輕量級(jí)、線程模型更加友好,還提供了大量天然的異步 API、以及更多的協(xié)議支持,同時(shí)性能表現(xiàn)也更加出色。

      Java Chassis 原生支持純 Reactive 異步模型,在異步模式下同一個(gè) Enventloop 線程中完成 I/O 以及業(yè)務(wù)的處理。同時(shí),actor 的模型下代表著更少的線程數(shù)量可以做到更優(yōu)的性能:與 Tomcat 的默認(rèn) 200 個(gè)線程相比,Vert.x 默認(rèn)只開(kāi)啟兩倍 cpu 核數(shù)的 Eventloop 線程。從操作系統(tǒng)的計(jì)算成本角度上講,更少的線程數(shù)量意味著更少的上下文切換時(shí)間開(kāi)銷(xiāo)——在線程切換時(shí),操作系統(tǒng)從用戶態(tài)切換為內(nèi)核態(tài)再切回用戶態(tài)。同時(shí)更少的線程數(shù)讓內(nèi)存中的線程私有棧信息也更少。

      另外,Java Chassis 也為一些特殊需求的開(kāi)發(fā)者提供了對(duì) Tomcat 的兼容,通過(guò)簡(jiǎn)單配置即可部署到 Tomcat。

      筆者通過(guò)在 4 核 8g 的機(jī)器壓測(cè)對(duì)比測(cè)試,數(shù)據(jù)結(jié)果顯示:

      在調(diào)用鏈為單服務(wù) A->B 時(shí),對(duì)比 Tomcat 同步模式和切換到基于 Vert.x 的 Reactive 模式,平均時(shí)延和并發(fā)處理能力都有大幅度的提升。理論上在實(shí)際生產(chǎn)環(huán)境中如果服務(wù)調(diào)用鏈更長(zhǎng),服務(wù)中的同步操作越多,采用 Reactive 模式的優(yōu)勢(shì)會(huì)更大。詳細(xì)測(cè)試代碼以及數(shù)據(jù)已經(jīng)開(kāi)源,有興趣的讀者可以自行了解。

      結(jié)論

      Reactive 模式構(gòu)建的程序,不僅僅代表的是高 TPS 低 RT(時(shí)延),其帶來(lái)的更直接的受益就是同等條件下更低廉的硬件成本。Java Chassis 作為 Reactive 在微服務(wù)領(lǐng)域的先行者,已經(jīng)通過(guò)在生產(chǎn)環(huán)境中的應(yīng)用積累了大量經(jīng)驗(yàn)。

      但同時(shí)構(gòu)建 Reactive 模式的程序也為開(kāi)發(fā)者帶來(lái)更高的要求,面臨比同步更為復(fù)雜的編程模型,需要更好的處理好阻塞和寫(xiě)出更優(yōu)秀的異步代碼。

      容器 架構(gòu)設(shè)計(jì) 運(yùn)維 大數(shù)據(jù)

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:您應(yīng)該考慮的ERP軟件的重要功能
      下一篇:首行凍結(jié)方法(凍結(jié)首行的作用)
      相關(guān)文章
      亚洲乱码精品久久久久..| 亚洲精品免费网站| 亚洲精品美女久久久久| 亚洲高清国产拍精品青青草原| 亚洲a级在线观看| 亚洲国产精品乱码在线观看97| 亚洲综合成人网在线观看| 亚洲av无码国产精品色午夜字幕| 久久夜色精品国产亚洲av| 亚洲国产精品日韩专区AV| 亚洲一区二区高清| 亚洲日韩国产一区二区三区| 久久亚洲国产成人影院网站| 亚洲综合国产精品第一页| 国产av无码专区亚洲国产精品| 久久精品国产亚洲精品| 中文亚洲AV片不卡在线观看| 夜夜春亚洲嫩草影院| 亚洲国产精品嫩草影院在线观看| 久久精品国产精品亚洲精品| 亚洲精品免费视频| 亚洲视频国产视频| 亚洲AV综合色区无码二区爱AV| 亚洲精品中文字幕无乱码麻豆| 亚洲中文精品久久久久久不卡| 亚洲av无码日韩av无码网站冲| 亚洲 无码 在线 专区| 亚洲男人的天堂在线va拉文| 亚洲午夜未满十八勿入网站2| 亚洲AV无码专区国产乱码电影| 亚洲色图在线观看| 亚洲中字慕日产2021| 亚洲中文字幕无码爆乳app| 蜜臀亚洲AV无码精品国产午夜.| 亚洲精品亚洲人成在线观看下载| 亚洲综合伊人久久综合| 亚洲五月激情综合图片区| 亚洲剧场午夜在线观看| 亚洲av无码专区青青草原| 亚洲国产成人久久一区久久| 亚洲精品美女久久777777|