首頁  >  文章  >  Java  >  為什麼我們從程式碼中放棄反應式系統架構?

為什麼我們從程式碼中放棄反應式系統架構?

王林
王林原創
2024-08-30 06:00:35975瀏覽

本文探討了我們在軟體專案中放棄反應式架構的決定。我們將深入研究反應式系統的核心原則、非阻塞 I/O 的好處以及反應式方法所面臨的挑戰。

理解響應式架構風格

Reactive 包含一系列旨在建立響應式分散式系統和應用程式的原則和指南,其特點是:

  1. 回應能力:即使在重負載下也能夠快速處理請求。
  2. 彈性:能夠以最短的停機時間從故障中恢復。
  3. 彈性:可以透過相應地擴展資源來適應不斷變化的工作負載。
  4. 訊息驅動:利用非同步訊息傳遞來增強容錯能力並解耦元件。

反應式系統的一個主要好處是它們使用非阻塞 I/O。這種方法避免了 I/O 操作期間阻塞線程,允許單一線程同時處理多個請求。與傳統的阻塞 I/O 相比,這可以顯著提高系統效率。
在傳統的多執行緒中,阻塞操作對最佳化系統提出了重大挑戰(圖 1)。消耗過多記憶體的貪婪應用程式效率低下,並且會懲罰其他應用程序,通常需要請求額外的資源,如記憶體、CPU 或更大的虛擬機。

Why we discarded Reactive systems architecture from our code?

圖 1 – 傳統多執行緒


I/O 操作是現代系統不可或缺的一部分,有效管理它們對於防止貪婪行為至關重要。反應式系統採用非阻塞 I/O,使少量的作業系統執行緒能夠處理大量並發 I/O 操作。

反應式執行模型

雖然非阻塞 I/O 提供了巨大的好處,但它引入了一種不同於傳統框架的新穎的執行模型。響應式程式設計的出現就是為了解決這個問題,因為它可以緩解阻塞操作期間平台執行緒空閒的低效率問題(圖 2)。

Why we discarded Reactive systems architecture from our code?

圖 2 – 響應式事件循環


Quarkus 和 Reactive

Quarkus 利用 Eclipse Vert.x 和 Netty 提供支援的反應式引擎,促進非阻塞 I/O 互動。 Mutiny 是使用 Quarkus 編寫反應式程式碼的首選方法,它採用事件驅動範例,其中反應由接收到的事件觸發。

Mutiny 提供兩種事件驅動和惰性類型:

  1. Uni: 發出單一事件(一項或失敗),適合表示具有零個或一個結果的非同步操作。
  2. Multi: 發出多個事件(n 個項目、一個失敗或一個完成),表示專案流,可能是無限的。

響應式的挑戰

雖然反應式系統提供了好處,但我們在開發過程中遇到了一些挑戰:

  • 範式轉變: 響應式程式設計需要開發人員思維方式的根本轉變,這可能具有挑戰性,特別是對於習慣命令式程式設計的開發人員來說。與 Streams API 等輔助工具不同,反應式方法需要徹底改變思考方式。
  • 程式碼可讀性和理解: 反應式程式碼給新開發人員帶來了理解困難,導致破解和理解程式碼的時間增加。反應式範式帶來的複雜性加劇了這個問題。

「事實上,閱讀與寫作所花費的時間之比遠遠超過10 比1。我們不斷地閱讀舊程式碼,作為編寫新程式碼的一部分。...[因此,]使其易於閱讀使得寫起來更容易。 ―
Robert C. Martin,《整潔程式碼:敏捷軟體製程手冊》

  • 偵錯挑戰:由於 lambda 封裝了大多數程式碼,使用標準 IDE 偵錯器偵錯反應式程式碼幾乎是不可能的。此外,異常期間有意義的堆疊追蹤的遺失進一步阻礙了調試工作。 增加開發和測試工作:由於編寫、修改和測試所需的時間,反應式程式碼固有的複雜性可能會導致更長的開發週期。
這是一個使用 Mutiny 的反應式程式碼範例來說明其複雜性:


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 軸 則描述了這些開發變化所需的時間。

Why we discarded Reactive systems architecture from our code?

以上是為什麼我們從程式碼中放棄反應式系統架構?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn