為什麼我們從程式碼中放棄反應式系統架構?
本文探討了我們在軟體專案中放棄反應式架構的決定。我們將深入研究反應式系統的核心原則、非阻塞 I/O 的好處以及反應式方法所面臨的挑戰。
理解響應式架構風格
Reactive 包含一系列旨在建立響應式分散式系統和應用程式的原則和指南,其特點是:
- 回應能力:即使在重負載下也能夠快速處理請求。
- 彈性:能夠以最短的停機時間從故障中恢復。
- 彈性:可以透過相應地擴展資源來適應不斷變化的工作負載。
- 訊息驅動:利用非同步訊息傳遞來增強容錯能力並解耦元件。
反應式系統的一個主要好處是它們使用非阻塞 I/O。這種方法避免了 I/O 操作期間阻塞線程,允許單一線程同時處理多個請求。與傳統的阻塞 I/O 相比,這可以顯著提高系統效率。
在傳統的多執行緒中,阻塞操作對最佳化系統提出了重大挑戰(圖 1)。消耗過多記憶體的貪婪應用程式效率低下,並且會懲罰其他應用程序,通常需要請求額外的資源,如記憶體、CPU 或更大的虛擬機。
圖 1 – 傳統多執行緒
I/O 操作是現代系統不可或缺的一部分,有效管理它們對於防止貪婪行為至關重要。反應式系統採用非阻塞 I/O,使少量的作業系統執行緒能夠處理大量並發 I/O 操作。
反應式執行模型
雖然非阻塞 I/O 提供了巨大的好處,但它引入了一種不同於傳統框架的新穎的執行模型。響應式程式設計的出現就是為了解決這個問題,因為它可以緩解阻塞操作期間平台執行緒空閒的低效率問題(圖 2)。
圖 2 – 響應式事件循環
Quarkus 和 Reactive
Quarkus 利用 Eclipse Vert.x 和 Netty 提供支援的反應式引擎,促進非阻塞 I/O 互動。 Mutiny 是使用 Quarkus 編寫反應式程式碼的首選方法,它採用事件驅動範例,其中反應由接收到的事件觸發。
Mutiny 提供兩種事件驅動和惰性類型:
- Uni: 發出單一事件(一項或失敗),適合表示具有零個或一個結果的非同步操作。
- Multi: 發出多個事件(n 個項目、一個失敗或一個完成),表示專案流,可能是無限的。
響應式的挑戰
雖然反應式系統提供了好處,但我們在開發過程中遇到了一些挑戰:
- 範式轉變: 響應式程式設計需要開發人員思維方式的根本轉變,這可能具有挑戰性,特別是對於習慣命令式程式設計的開發人員來說。與 Streams API 等輔助工具不同,反應式方法需要徹底改變思考方式。
- 程式碼可讀性和理解: 反應式程式碼給新開發人員帶來了理解困難,導致破解和理解程式碼的時間增加。反應式範式帶來的複雜性加劇了這個問題。
「事實上,閱讀與寫作所花費的時間之比遠遠超過10 比1。我們不斷地閱讀舊程式碼,作為編寫新程式碼的一部分。...[因此,]使其易於閱讀使得寫起來更容易。 ―
Robert C. Martin,《整潔程式碼:敏捷軟體製程手冊》
- 偵錯挑戰:由於 lambda 封裝了大多數程式碼,使用標準 IDE 偵錯器偵錯反應式程式碼幾乎是不可能的。此外,異常期間有意義的堆疊追蹤的遺失進一步阻礙了調試工作。 增加開發和測試工作:由於編寫、修改和測試所需的時間,反應式程式碼固有的複雜性可能會導致更長的開發週期。
Multi.createFrom().ticks().every(Duration.ofSeconds(15)) .onItem().invoke(() - > Multi.createFrom().iterable(configs()) .onItem().transform(configuration - > { try { return Tuple2.of(openAPIConfiguration, RestClientBuilder.newBuilder() .baseUrl(new URL(configuration.url())) .build(MyReactiveRestClient.class) .getAPIResponse()); } catch (MalformedURLException e) { log.error("Unable to create url"); } return null; }).collect().asList().toMulti().onItem().transformToMultiAndConcatenate(tuples - > { AtomicInteger callbackCount = new AtomicInteger(); return Multi.createFrom().emitter(emitter - > Multi.createFrom().iterable(tuples) .subscribe().with(tuple - > tuple.getItem2().subscribe().with(response - > { emitter.emit(callbackCount.incrementAndGet()); if (callbackCount.get() == tuples.size()) { emitter.complete(); } }) )); }).subscribe().with(s - > {}, Throwable::printStackTrace, () - > doSomethingUponComplete())) .subscribe().with(aLong - > log.info("Tic Tac with iteration: " + aLong));
未來展望-Project Loom 及未來
Project Loom 是 Java 生態系統的最新開發項目,有望緩解與阻塞操作相關的問題。透過在不更改硬體的情況下創建數千個虛擬線程,Project Loom 可能在許多情況下消除對反應式方法的需求。
「Loom 專案將殺死響應式程式設計」
―布萊恩·戈茨
結論
總之,我們決定放棄反應式架構風格,採用務實的方法來實現專案的長期可維護性。雖然反應式系統提供了潛在的好處,但它們為我們團隊帶來的挑戰超過了我們特定環境中的這些優勢。
重要的是,這種轉變並沒有影響性能。這是一個積極的結果,因為它表明設計良好的非反應式(命令式)架構可以提供必要的效能,而不會帶來與我們案例中的反應式架構相關的複雜性。
展望未來,我們的重點仍然是建立一個程式碼庫,該程式碼庫不僅實用,而且易於所有經驗水平的開發人員理解和維護。這不僅減少了開發時間,也促進了團隊內更好的協作和知識共享。
在下圖中,X 軸 代表我們的程式碼庫在發展過程中不斷增加的複雜性,而 Y 軸 則描述了這些開發變化所需的時間。
以上是為什麼我們從程式碼中放棄反應式系統架構?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

在使用IntelliJIDEAUltimate版本啟動Spring...

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...

Redis緩存方案如何實現產品排行榜列表的需求?在開發過程中,我們常常需要處理排行榜的需求,例如展示一個�...
