IceRPC之呼叫管道Invocation pipeline與傳出請求Outgoing request->快樂的RPC

xlgwr發表於2024-05-15

作者引言 .Net 8.0 下的新RPC

很高興啊,我們來到了IceRPC之呼叫管道 Invocation pipeline與傳出請求 Outgoing request->快樂的RPC, 基礎引導,讓自已不在迷茫,快樂的暢遊世界。

呼叫管道 Invocation pipeline

瞭解如何傳送請求requests和接收響應responses

定義

傳送請求並接收相應響應的過程稱為呼叫。

通常會透過客戶端連線進行呼叫。然而,由於客戶端和伺服器連線具有相同的功能,因此也可以反過來呼叫,從連線的伺服器端到此連線的客戶端。

呼叫抽象

IceRPC總是透過呼叫呼叫器invoker來進行呼叫。呼叫器是一個簡單的抽象,它接受傳出的請求並返回傳入的響應。

C# 中, 這個抽象是 IInvoker 介面:

namespace IceRpc;

public interface IInvoker
{
    Task<IncomingResponse> InvokeAsync(OutgoingRequest request, CancellationToken cancellationToken = default);
}

ClientConnectionConnectionCache 都實現此介面。 這允許透過建立客戶端連線或連線快取,然後在生成的例項上呼叫 InvokeAsync 來進行呼叫:

await using var clientConnection = new ClientConnection(new Uri("icerpc://hello.zeroc.com"));
using var request = new OutgoingRequest(...);

// Make an invocation by calling the IInvoker.InvokeAsync method implemented by ClientConnection.
IncomingResponse response = await clientConnection.InvokeAsync(request);

處理呼叫

在將其提供給連線之前,通常會對呼叫執行附加處理。例如,可能需要壓縮請求的有效負載、為每個請求新增遙測欄位、新增截止時間或簡單地新增日誌記錄等。

呼叫器實現可以呼叫另一個呼叫器,它本身呼叫另一個呼叫器,等等;用於進行呼叫的呼叫器可以是呼叫器鏈或樹的頭,稱為"呼叫管道"invocation pipeline.

3種常見的呼叫者型別:

  • Leaf invoker
    這是呼叫管道中的一片葉子。該呼叫器通常是連線。

  • Interceptor
    攔截器攔截呼叫,並將其轉發到"下一個"next攔截器。IceRPC提供了幾個內建的攔截器,用於記錄,壓縮等。

  • Pipeline
    管道在向呼叫器發出請求之前,透過在該管道中註冊的攔截器來執行請求。

--- title: A typical invocation pipeline --- flowchart LR app([application code]) -- request --> i1["interceptor #1"] -- request --> i2["interceptor #2"] i2 -- request --> ti["ClientConnection\n or ConnectionCache"] -- request --> connection connection -- response --> ti -- response --> i2 -- response --> i1 -- response --> app

傳出請求 Outgoing request

瞭解如何建立傳出請求

建立傳出請求 Outgoing request

為了建立 RPC,構造一個傳出請求,然後將此請求作為引數傳遞給呼叫者invoke的呼叫方法。

傳出請求攜帶呼叫者傳送請求所需的所有資訊:

  • 目標服務的服務地址service address
  • 呼叫此服務的操作名稱
  • 請求欄位
  • 請求的有效負載

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

請求欄位

請求欄位表示由"傳輸連線"的請求承載的帶外資訊". 這些欄位通常由攔截器和中介軟體讀取和寫入,以協調客戶端和伺服器中相同請求的處理。

欄位是位元組序列的字典 RequestFieldKey 中的條目,其中 RequestFieldKeySlice 中定義的列舉:

unchecked enum RequestFieldKey : varuint62 {
    Context = 0
    TraceContext = 1
    CompressionFormat = 2
    Deadline = 3
    Idempotent = 4
}

例如,當壓縮攔截器壓縮傳出請求的有效負載時,它設定請求欄位CompressionFormat。這告訴連線另一側的壓縮中介軟體"該有效負載是用 brotli 壓縮的";然後壓縮中介軟體可以解壓縮該(傳入)請求有效負載。

請求有效負載和繼續有效負載Payload

請求的有效負載是表示操作引數的位元組流。 當連線傳送請求時,它會讀取這些位元組並將其邏輯複製到網路連線,直到不再有位元組需要讀取。

另一方面,連線從網路讀取這些位元組,建立傳入請求並將此請求提供給排程器 dispatcher

傳出請求的有效負載實際上分為兩部分:連線在等待響應之前傳送的第一部分,以及連線在等待、接收和返回響應時在後臺傳送的第二部分("繼續")。

sequenceDiagram Local-)Remote: request header + payload par Remote--)Local: response header + payload and Local-)Remote: request payload continuation end

另一方面,排程器僅看到單個連續的傳入請求有效負載。

請求功能

呼叫管道中的呼叫者在呼叫期間相互傳輸資訊是很常見的。 例如,重試攔截器需要與連線快取通訊,以確保連線快取不會繼續使用相同的伺服器地址重試。C# 中,這些呼叫者獲取並設定請求的 IFeatureCollection 以相互通訊。

還可以使用這些功能與呼叫管道進行通訊。例如,您可以設定功能 ICompressFeature 以要求壓縮機攔截器(如果已安裝)壓縮請求的有效負載:

using var request = new OutgoingRequest(serviceAddress)
{
    Payload = largePayload,
    Features = new FeatureCollection().With<ICompressFeature>(CompressFeature.Compress)
};

// Hopefully invoker is an invocation pipeline with a compressor interceptor.
IncomingResponse response = await invoker.InvokeAsync(request);

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

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

作者結語

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

相關文章