.Net 8.0 下的新RPC,IceRPC之"請求"生命線意義非凡

xlgwr發表於2024-05-02

作者引言

很高興啊,我們來到了IceRPC之"請求"生命線意義非凡,號稱“死亡時間”的追命線,顫抖吧!

"請求"生命線之意義非凡

本文將深入探討將截止時間納入RPCs的重要性, 以開發更強大的分散式應用程式。

概述

RPC(遠端過程呼叫)系統中傳送請求,通常會帶來不確定性:無法保證,何時會收到回覆,或請求需要多長時間,才能到達目的地。 由於各種原因,請求可能會被延遲:

  • 目標服務可能會不堪重負,無法及時響應
  • 網路擁堵可能會減慢流量
  • 或者技術問題可能根本無法阻止目標服務處理請求(同步阻塞、假死等)

這些場景強調了分散式應用程式設計,準備處理延遲呼叫,或無法完成的呼叫的重要性

我們將探討使用截止時間,是如何幫助構建更強大的分散式應用程式的。

但首先,讓我們先了解如果不使用截止時間,會產生什麼後果呢?

截止時間如何影響分散式系統

想象一下,前端服務依賴於一系列後端服務,來完成其任務的場景。假設這些基本後端服務之一,發生故障並且無法處理請求。我們的前端服務,繼續處理客戶的請求。並且每次都需要使用,有故障的後端服務來完成請求,請求都會被卡住,無限期地,等待從未到達的響應。

因此,滿足請求所需的資源仍然無限期地被佔用。在這種情況下,由於請求無法完成,前端的資源利用率將穩步提高。

最糟糕表現之一:是發生在同步進行遠端呼叫時,導致執行緒在等待響應時被阻止. 遲早,所有可用的執行緒都可能被卡住,等待永遠無法完成的請求. 幸運的是,IceRPC的設計,從源頭上是非同步的,可以防止落入這個陷阱。

然而,請求所需的其他資源(例如記憶體和檔案控制代碼)無法釋放,這進一步削弱了系統處理新請求的能力。

在其他場景中,應用程式可能需要快速返回響應。如果當前呼叫,不再需要,沒有釋放被佔用,會浪費重要的伺服器資源。

什麼是請求截止時間?

要了解請求截止時間,我們必須首先掌握超時的情況。超時是指呼叫者願意等待,呼叫完成多長時間的時間間隔。在 C# 中,該持續時間由 System.TimeSpan 型別表示。

截止時間可以被視為"絕對超時",由呼叫者認為可以接受,等待呼叫完成的時間點表示。在 C# 中,截止時間由 System.DateTime 型別表示。

截止時間提供了一種簡單的機制,有助於在呼叫者不再有興趣,等待其完成後取消呼叫和傳送。

使用超過超時的截止時間的優點是,它們可以使用請求欄位請求一起傳輸,使目標服務能夠在截止時間過去時取消排程,並在從排程完成的巢狀呼叫中使用截止時間。而在請求欄位中傳輸超時是無效的,因為目標服務無法確定呼叫的確切開始時間或超時何時到期。

在進行遠端程式時(RPC),加入截止時間至關重要。 一般通常會選擇超時,並根據該超時計算截止時間。為特定操作選擇最佳超時,可能需要一些反覆試驗。如果超時設定得太低,可能會遇到不必要的故障。相反,如果設定得太高,錯誤檢測可能會被延遲。所以,為正常情況下的操作,提供足夠的時間;併為不同負載條件下可能出現的小延遲,留出一些空間。

IceRPC(C#)中的截止時間

從 IceRPC 成立以來,很明顯,支援截止時間的機制至關重要。此外, IceRPC 決定利用標準中介軟體和攔截器在 IceRPC 核心之外實現此功能。

這種方法不僅允許使用者整合自己的實現,還可以證明 IceRPC 核心的靈活性。它展示了核心透過獨立攔截器和中介軟體容納此類機制的能力。

IceRpc.Deadline NuGet包,包括攔截器和中介軟體,可以在呼叫和排程管道中使用截止時間

在最簡單的場景中,可以在呼叫管道invocation pipeline中使用截止時間攔截器並設定預設呼叫超時,從中計算截止時間:


// Create an invocation pipeline with the deadline interceptor and a default timeout of 500 ms.
Pipeline pipeline = new Pipeline()
    .UseDeadline(defaultTimeout: TimeSpan.FromMilliseconds(500))
    .Into(connection);

處理請求時,截止時間攔截器執行以下幾個操作:

  • 如果請求沒有關聯的截止時間,它會使用預設超時生成一個截止時間
  • 它建立了一個取消令牌源,一旦到達截止時間,該源就會取消呼叫
  • 它在傳出請求欄位中新增了截止時間欄位
  • 如果由於截止時間過去而取消呼叫,則會丟擲超時異常TimeoutException
  • 對於單向請求,攔截器無法取消排程,因為單向請求通常在排程開始之前完成。

並非所有請求都需要相同的截止時間設定,IDeadlineFeature 允許自定義截止時間:


// Customize the invocation deadline for a specific request to ensure it isn't canceled prematurely.
var features = new FeatureCollection();
features.Set<IDeadlineFeature>(DeadlineFeature.FromTimeout(TimeSpan.FromSeconds(10)));

值得注意的是,截止時間代表了一個確切的時間時刻。因此,應該在進行呼叫之前設定它。

icerpc協議的一個顯著特點是,它支援透過線路取消請求,截止時間攔截器有效地利用了這一點。當到達截止時間並且截止時間攔截器取消呼叫取消令牌時,它會觸發底層RPC流的重置。此操作反過來取消傳送,過程執行與目標服務的排程管道,與是否包括截止時間中介軟體無關。

在接收端,排程管道可以採用截止時間中介軟體,將截止時間欄位解碼為相應的功能並獨立於客戶端強制執行截止時間。 這依賴於呼叫者透過某些外部機制(例如 NTP(網路時間協議))同步他們的系統時鐘。


// Add the deadline middleware to the dispatch pipeline.
Router router = new Router()
    .UseDeadline();
    .Map<...>(...);

如果由於截止時間過期,而在截止時間中介軟體之前取消傳送,則它會返回狀態程式碼status code等於StatusCode.DeadlineExceeded的傳出響應.

此外,截止時間中介軟體使用解碼截止時間初始化 'IDeadlineFeature' 。這允許從排程管道完成的巢狀呼叫,遵守相同的截止時間約束。


public async ValueTask<string> GreetAsync(
    string name,
    IFeatureCollection features,
    CancellationToken cancellationToken)
    {
        // By adding the deadline middleware features contains the deadline feature
        // created from the decoded deadline field.

結論

截止時間是開發更強大的分散式應用程式的重要機制,在進行遠端呼叫時,始終包含截止時間,因為這可以確保應用程式不會陷入,等待永遠不會到達的響應的困境,即使出了問題,也能夠及時響應。

作者結語

  • 一直做,不停做,才能提升速度
  • 翻譯的不好,請手下留情,謝謝
  • 如果對我有點小興趣,如可加我哦,一起探討人生,探討道的世界
  • 覺得還不錯的話,點個
    image

相關文章