什麼是繫結

處理外部事件或呼叫外部介面的功能就是繫結,繫結可以提供以下好處:

  • 避免連線到訊息系統 ( 如佇列和訊息匯流排 ) 並進行輪詢的複雜性
  • 聚焦於業務邏輯,而不是如何與系統互動
  • 使程式碼不受 SDK 或外部庫的強耦合
  • 處理重試和故障恢復

Dapr提供了很多支援的繫結,請見繫結。繫結分為輸入繫結輸出繫結,輸入繫結是監聽外部事件,觸發業務邏輯。輸出繫結是呼叫外部資源。

繫結可能與前面介紹的釋出訂閱類似。 儘管它們很相似,但也有不同之處。 釋出/訂閱側重於 Dapr services 之間的非同步通訊。 資源繫結具有更大的範圍。 它側重於軟體平臺之間的系統互操作性。 在不同的應用程式、資料儲存和微服務應用程式之外的服務之間交換資訊。

工作原理

Dapr 資源繫結需要通過yaml檔案定義繫結元件。 此 YAML 檔案描述要與其繫結的資源型別。 配置後,你的服務可以接收來自資源的事件或觸發事件。

輸入繫結

輸入繫結通過外部資源的傳入事件觸發程式碼。 下圖的示例中需要在app中保留/tweet介面,以供sidecar呼叫

  1. Dapr Sidecar讀取繫結配置檔案並訂閱為外部資源。
  2. 當外部資源觸發時,在 Dapr sidecar中執行的繫結元件會選取它並觸發一個事件。
  3. Dapr sidecar呼叫指定的介面。 在此示例中,服務在 /tweet 埠6000上偵聽終結點上的 HTTP POST。 由於它是 HTTP POST 操作,因此在請求正文中傳遞事件的 JSON 有效負載。
  4. 處理事件後,服務將返回 HTTP 狀態程式碼 200 OK 。

輸出繫結

輸出繫結使服務能夠觸發呼叫外部資源。 跟輸入繫結同樣,需要配置描述輸出繫結的繫結配置 YAML 檔案。該事件在應用程式的 Dapr Sidecar上呼叫bingdings API。

  1. Dapr sidecar讀取繫結配置檔案,其中包含有關如何連線到外部資源的資訊。
  2. 應用程式呼叫sidecar的 /v1.0/bindings/sms Dapr 終結點。 在這種情況下,它使用 HTTP POST 來呼叫 API。 還可以使用 gRPC。
  3. Dapr sidecar的繫結元件會呼叫外部訊息系統來發送訊息。 訊息將包含 POST 請求中傳遞的負載。

專案例項

此例子中我們使用rabbitmq作為外部資源。因為rabbitmq既支援輸入繫結又支援輸出繫結

首先,在預設元件目錄C:\Users\<username>\.dapr\components中新建rabbitbinding.yaml

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: RabbitBinding
spec:
type: bindings.rabbitmq
version: v1
metadata:
- name: queueName
value: queue1
- name: host
value: amqp://admin:[email protected]:5672
- name: durable
value: true
- name: deleteWhenUnused
value: false
- name: ttlInSeconds
value: 60
- name: prefetchCount
value: 0
- name: exclusive
value: false
- name: maxPriority
value: 5

每個繫結配置都在metadata 中包含常規元素 name 和 namespace 。 Dapr 將根據配置的 name 欄位確定要呼叫的服務的終結點 。 在上面的示例中,Dapr 將在事件發生是呼叫 /RabbitBinding 事件發生時呼叫方法。

我們在FrontEnd中定義RabbitBindingController

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using System.IO;
using System.Text; namespace FrontEnd.Controllers
{
[Route("[controller]")]
[ApiController]
public class RabbitBindingController : ControllerBase
{
private readonly ILogger<RabbitBindingController> _logger;
public RabbitBindingController(ILogger<RabbitBindingController> logger)
{
_logger = logger;
}
[HttpPost]
public ActionResult Post()
{
Stream stream = Request.Body;
byte[] buffer = new byte[Request.ContentLength.Value];
stream.Position = 0L;
stream.ReadAsync(buffer, 0, buffer.Length);
string content = Encoding.UTF8.GetString(buffer);
_logger.LogInformation(".............binding............." + content);
return Ok();
}
}
}

現在我們啟動Frontend程式

https://docs.dapr.io/zh-hans/reference/components-reference/supported-bindings/rabbitmq/

然後開啟RabbitMQ Management,檢視Queue,發現queue1已成功建立

我們先來驗證輸入繫結,在RabbitMQ Management中直接傳送訊息

現在去控制檯檢視日誌,發現輸入繫結成功觸發

== APP == info: FrontEnd.Controllers.RabbitBindingController[0]
== APP == .............binding.............1111111122222

現在我們來驗證輸出繫結,在RabbitBindingController中新建介面

        [HttpGet]
public async Task<ActionResult> GetAsync([FromServices]DaprClient daprClient)
{
await daprClient.InvokeBindingAsync("RabbitBinding", "create", "9999999");
return Ok();
}

為了防止新建的訊息被輸入繫結消費,先把Post方式註釋掉

        //[HttpPost]
//public ActionResult Post()
//{
// Stream stream = Request.Body;
// byte[] buffer = new byte[Request.ContentLength.Value];
// stream.Position = 0L;
// stream.ReadAsync(buffer, 0, buffer.Length);
// string content = Encoding.UTF8.GetString(buffer);
// _logger.LogInformation(".............binding............." + content);
// return Ok();
//}

現在呼叫, 檢視佇列queue1中的訊息,可看到剛才輸出的訊息

http://localhost:3501/v1.0/invoke/frontend/method/RabbitBinding

檢視結果