IceRPC之深入理解排程管道->快樂的RPC

xlgwr發表於2024-05-25

作者引言

很高興啊,我們來到了IceRPC之深入理解排程管道->快樂的RPC,為上篇的續篇,深入理解常見的排程型別, 基礎引導,有點小壓力,打好基礎,才能讓自已不在迷茫,快樂的暢遊世界。

傳入請求

瞭解如何處理傳入的請求

接收傳入的請求

排程器的排程方法接受傳入的請求。該傳入請求是由連線,在收到來自對等點的請求時建立的。

請求持有如下內容:

  • 目標服務的路徑
  • 服務上的操作名稱
  • 請求欄位
  • 請求的有效負載payload

傳入請求還包含功能features。這些功能用於該排程管道內的本地通訊;它們還用於管道中的排程與應用程式程式碼之間的通訊。

請求有效負載 payload

傳入請求的有效負載是表示操作引數的位元組流。IceRPC 而言,該流中的位元組數是未知的。

請求功能

排程管道中的排程員在排程期間相互傳輸資訊是很常見的。C# 中,這些排程獲取並設定請求的 IFeatureCollection 用於這些通訊。

還可以使用這些功能與服務程式碼進行通訊。例如,如果安裝排程資訊中介軟體,它會設定 IDispatchInformationFeature,並且可以在程式碼中檢索此功能:

// In Slice service implementation
public ValueTask OpAsync(string message, FeatureCollection features, CancellationToken cancellationToken)
{
    if (features.Get<IDispatchInformationFeature> is IDispatchInformationFeature dispatchInformation)
    {
        EndPoint from = dispatchInformation.ConnectionContext.TransportConnectionInformation.RemoteNetworkAddress;
        Console.WriteLine($"dispatching request from {from}");
    }
    Console.WriteLine(message);
    return default;
}

按照慣例,這些功能是使用介面型別進行鍵控的,例如上面示例中的 IDispatchInformationFeature

欄位用於"傳輸連線"進行通訊,而功能用於排程管道內的本地通訊。IceRPC同時提供請求欄位(由請求承載)和響應欄位(由響應承載),但只提供請求特性:由於它都是本地的,因此不需要響應特性。

傳出響應Outgoing response

瞭解如何建立傳出響應。

建立傳出響應

排程程式非同步返回傳出響應。

傳出響應攜帶如下內容:

  • 狀態程式碼
  • 錯誤訊息,僅在狀態程式碼非OK時設定
  • 響應欄位
  • 響應的有效負載payload

響應有效負載

響應的有效負載,是表示操作返回值的位元組流。呼叫者(傳送傳入請求的連線)讀取這些位元組,並邏輯地複製到網路連線,直到不再有位元組需要讀取。

C#中,傳出響應的有效負載,被分割為有效負載和有效負載延續,就像傳出請求的有效負載一樣。這種分割,使得響應有效負載的編碼,對於Slice生成的程式碼來說,更加方便和高效,但在其他方面,是不必要的。傳出響應有效負載,在概念上是一個連續的位元組流。

中介軟體Middleware

瞭解如何安裝和編寫中介軟體。

攔截傳入的請求

中介軟體是在傳入請求到達目標服務之前,攔截傳入請求的程式碼。相同的程式碼,還會在服務傳送回呼叫者之前,攔截服務提供的傳出響應。

在技術層面上,中介軟體是排程程式,它儲存另一個排程程式("下一個")並在下一個排程程式上呼叫排程,作為其自己的排程方法實現的一部分。下一個排程程式可以是另一箇中介軟體、服務、路由器或其他型別的排程程式;就中介軟體而言,它只是另一個排程程式。

中介軟體可以包括在,下一個排程程式呼叫排程之前(在處理請求之前)和在下一個排程程式呼叫排程之後(在收到響應之後)的邏輯。 中介軟體還可以透過返回快取響應或返回錯誤(具有 Ok 以外的狀態程式碼的響應)來短路排程管道。

例如,一個簡單的 C# 中介軟體可能如下所示:

public class SimpleMiddleware : IDispatcher
{
    private readonly IDispatcher _next;

    public SimpleMiddleware(IDispatcher next) => _next = next;

    public async ValueTask<OutgoingResponse> DispatchAsync(
        IncomingRequest request,
        CancellationToken cancellationToken)
    {
        Console.WriteLine("before _next.DispatchAsync");
        OutgoingResponse response = await _next.DispatchAsync(request, cancellationToken);
        Console.WriteLine($"after _next.DispatchAsync; the response status code is {response.StatusCode}");
        return response;
    }
}

安裝中介軟體

可以使用路由,建立排程管道,並在此排程管道中安裝一個或多箇中介軟體。

路由 Router

瞭解如何根據路徑路由傳入的請求。

基於路徑的路由

路由是根據請求的路徑,將傳入的請求,路由到其他排程器的排程器。它還可以沿著這條路線執行中介軟體。

--- title: Path-based request routing --- flowchart LR subgraph Router direction LR m1["middleware #1"] --> m2["middleware #2"] -- /greeter --> s1[" greeter service mapped at /greeter"] m2 -- /user/joe --> s2["account service mounted at /user"] m2 -- /user/bob --> s2 end connection --> m1

這些其他排程程式使用mapmount方法在路由器上註冊。

  • map 將排程程式與路由器中的路徑相關聯。

    例如,可以將路徑/greeter對映到chatbot服務,這是一場完全匹配的。具有路徑/greeter2/greeter/foo 的請求是不匹配。

    C#中,會像如下程式碼一樣:

    var router = new Router();
    router.Map("/greeter", chatbot);
    
  • mount 將排程程式與路由器中的路徑字首相關聯。

    例如,您可以將路徑字首/user掛載到account服務。具有路徑/user
    /user/foo 的請求是匹配的。而具有路徑 /, /user2的請求是不匹配。

    C#中, 程式碼如下:

    var router = new Router();
    router.Mount("/user", account);
    

對映子葉排程程式(例如服務和安裝子路由器)很常見,但這並不是一個硬性規則。

以對映並安裝完全相同的路徑(例如/greeter)。路由器將帶有路徑/greeter的請求,引導到對映的排程器,並將帶有路徑/greeter/foo的請求,引導到安裝的排程器。

如果路由器沒有找到,傳入請求路徑的對映或安裝排程程式,則它會返回具有狀態程式碼 NotFound 的響應。

子路由

子路由器是在另一個"父"路由器註冊的路由器。它有一個與其安裝點相對應的字首;當它查詢透過mapmount註冊的排程員時,它會刪除該字首。

--- title: Path-based request routing with a sub-router --- flowchart LR subgraph Router direction LR m1["middleware #1"] --> m2["middleware #2"] -- /greeter --> s1["service #1"] end subgraph Sub-router m3["middleware #3"] -- /superAdmin --> s2["service #2"] end m2 -- /admin/superAdmin --> m3 connection --> m1

C# 中, 可以建立一個子路由, 並使用 Route 擴充套件方法單步安裝:

var router = new Router();

// create a sub-router and mount it at /admin
router.Route("/admin", subRouter => subRouter.UseDispatchInformation().Map("/superAdmin", root));

此示例的根服務的完整路徑是/admin/superAdmin。管理子路由器在嘗試將此路徑與其對映和掛載字典中的條目匹配之前,會從請求的路徑中刪除/admin

在路由中安裝中介軟體

路由可以在將請求,移交給對映或安裝的排程程式之前,執行一個或多箇中介軟體。

在 C# 中,這些中介軟體透過類路由上的 Use{Name} 擴充套件方法註冊。例如:

Router router = new Router().UseLogger(loggerFactory).UseCompressor();
router.Map("/greeter", new Chatbot());

安裝這些中介軟體的順序通常很重要。安裝的第一個中介軟體,是第一個要執行的中介軟體。透過上面的示例,記錄器中介軟體首先執行,然後在壓縮器中介軟體上呼叫 DispatchAsync,最後壓縮器中介軟體在/greeter 對映的 Chatbot 服務上呼叫 DispatchAsync

路由總是將傳入的請求傳送到其註冊的中介軟體,即使它最終返回帶有狀態程式碼 NotFound 的響應。

收尾

基礎概念難啊,不好寫,怕寫的不好,誤導大家,大家看看,不用太深入,以官方為主。

作者結語

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

相關文章