什麼是反應式程式設計?

涅槃~小白發表於2024-04-03

反應式程式設計是一種基於非同步資料流和基於事件的實時處理的程式設計正規化。這意味著操作並不會等待彼此同步完成。它支援非阻塞操作,並允許透過觀察事件實時非同步執行其他操作。反應式程式設計透過在執行時監控其他程序的執行情況來實現現實事件和非同步執行。

現如今許多應用程式都需要能處理大量併發/同步請求。因此,傳統方法不足以處理這些操作。所以我們向著以最有效果的方式使用硬體來開發軟體的原則邁進.伺服器端響應式程式設計是一種提高web應用程式或提高伺服器端應用程式的效能和可擴充套件性的方法。這種結構使伺服器端應用程式能夠處理多個請求,提高效能的同時處理高使用者流量。

如今,微服務、雲原生應用程式和分散式系統相當普遍,更有效的使用資源和低延遲非常重要。響應式程式設計透過允許非阻塞操作和基於事件的實時執行為這些問題提供瞭解決方案。

非同步:執行一項任務而不等待其結果並同時繼續執行其他任務的能力。
資料流:隨時間順序發生的一系列事件。流為我們提供值、錯誤和完成等訊號。
背壓: 用於確保資料流速度和處理能力之間相容性的概念。

反應式程式設計透過觀察和監聽事件並對它們做出反應來進行,這可以透過觀察者設計模式來實現。

背壓是什麼意思?
背壓是指控制系統中資料處理速率的能力。當系統接收到的資料超出其處理能力時,它可以向源發出訊號以減慢或調節資料流。這是維持系統穩定的重要特性,也是反應式程式設計的優點之一。

傳統程式設計
指令式程式設計,是一種程式設計正規化,其中程式設計師明確告訴計算機要採取哪些步驟來解決問題。在這些方法中,透過為執行緒池中的每個請求分配單獨的執行緒來處理請求。但是執行緒池的容量限制了可以同時處理請求的數量。這種方式會導致每個執行緒遇到I/O操作時被阻塞,導致等待並增加資源佔用。斷路器可以緩解其中的一些問題,但是還是遠遠不夠。

當請求數量增大時,同步的阻塞結構也會影響效能。此外,這種方法並沒有最佳化系統資源佔用,因為可能需要新的例項來處理高流量,這可能會帶來高昂的成本。指令式程式設計還缺乏對背壓機制的支援該機制可以防止負載突然增加時出現系統故障。

傳統指令式程式設計應用程式的一般特徵:

  • 同步和阻塞 →請求被同步和阻塞處理。當發出請求時,會為其分配一個執行緒,並在返回響應之前等待任何 I/O 操作完成。該執行緒對於其他任務保持阻塞狀態,並且可以在操作完成後返回響應。
  • 每個請求一個執行緒 →為每個請求分配一個執行緒也會限制傳入請求的數量。系統只能處理與執行緒池大小一樣多的請求。此外,大量請求也會影響效能。
  • 系統資源利用率低 →在同步和阻塞模式下,為了在大流量下處理一定數量的請求,需要建立新的例項。就資源使用而言,這是一項成本高昂的操作。
  • 缺乏對反壓機制的支援 →如果請求突然增加,可能會出現伺服器或客戶端中斷的情況。此後,使用者將無法訪問該應用程式。我們將更詳細地討論背壓,但它可以被描述為一種防止系統在負載突然增加時中斷的機制。

每個執行緒都會消耗一定量的記憶體。為了在高流量下的應用程式中獲得良好的效能,需要高記憶體大小。水平擴充套件可以透過像 Kubernetes 這樣的結構來完成。這種方法目前是很好的解決方案之一,將來會繼續使用,但是,每次流量增加時建立新例項也會在成本和複雜性方面產生其他問題。

考慮到成本和擴充套件問題,每個例項都有成本,作為工程師,我們傾向於事半功倍。為了解決這些型別的問題併產生更好的結果,我們可以透過更少的記憶體使用和更少的例項來實現更有效的可擴充套件性。

深入探討響應式程式設計
響應式程式設計並不是一種新的程式設計正規化,而是新近流行的程式設計正規化。

  • 它專門為了改進非同步和非阻塞操作而定製。它透過事件/訊息驅動的流建立資料流。
  • 響應式程式設計與 (!=) 函數語言程式設計不同。您可以透過結合反應式程式設計和函數語言程式設計來創造偉大的事物。
  • 資料流中提供背壓支援。
  • 由於其非同步和非阻塞結構,它提供了可預測的響應時間。
  • 它可以更好地利用系統資源。執行緒不會被阻塞,應用程式將能夠以更少的執行緒有效地服務更多的使用者。

響應式程式設計是如何工作的?
在反應式程式設計中,關鍵是使用基於事件的流來管理資料。事件、訊息、呼叫,甚至錯誤都是透過資料流傳輸的。透過反應式程式設計,這些流程會被不斷觀察並直接響應值的變化,執行下一個操作。

在編寫應用程式時,應該從任何事務建立資料流:使用者操作、HTTP請求、收到的訊息、要傳送的訊息、通知、變數變更、快取事件、資料庫操作;你可以說是任何事件的改變或發生的事情。

反應式程式設計中,為了從資料來源獲得每個結果建立一個事件或訊息。資料來源可以是外部服務、資料庫或檔案。如果資料來源完成或收到錯誤,則會建立事件或訊息。因此,在這兩種情況下,我們都存在一個事件。

當對資料庫進行查詢時,服務立即返回,並且一旦準備好,資料就會透過流推送。為每個資料元素建立一個事件。資料流透過OnComplete完成。

發生錯誤時會發生什麼?
流中發生的每個事件或訊息都對應一個事件或訊息。因此,發生錯誤也作為事件發生。

獲取專案時,如果遇到錯誤,則會將其作為事件傳遞給onError。我們還可以在onError部分解決如何處理異常。

當我們查詢資料庫沒有結果時,onComplete事件仍然發生。

對於註冊,我們傳送註冊請求,如果呼叫快速響應併成功完成,我們可以透過 onComplete 事件來了解這一點。

  • onNext,我們可以在流式傳輸時繼續下一個專案。
  • onComplete表示成功完成
  • onError表示錯誤情況。

背壓支援
例如,我們有一個從另一個服務接收資料的客戶端應用程式。服務可以以100x的速率傳送事件,而客戶端應用程式只能以20x的速率處理事件。在這種情況下客戶端應用程式可能會因負載過大而出現效能損失甚至中斷。藉助背壓,客戶端應用程式可以通知伺服器它只能以20倍的速率處理資料,並且服務只能以20倍的速率傳送資料。這樣,客戶端就可以繼續以其能夠處理的負載量高效工作。

流程的管理方式與流API中的lambda操作類似。因此函數語言程式設計與反應式程式設計配合的很好。

相關文章