DAPR:释放 Pub-Sub 模型在微服务通信中的威力

微服务改变了我们设计和实施软件系统的方式。这些可独立部署的小型应用程序专注于解决特定问题,其解耦特性确保每个应用程序都能自主运行。但这种解耦带来了一个基本问题: 如果服务之间不知道对方的存在,它们该如何通信呢?这就是 DAPR 发挥作用的地方。

DAPR 简介

分布式应用程序运行时(DAPR)是实现服务间基于事件通信的支柱。它将松散耦合的服务转变为同步系统,主要通过事件进行操作,是一种令人着迷的成分。

以下是 DAPR 带来的好处:

  • 弹性分布式应用程序: DAPR 专为微服务而设计,无论您是创建无状态应用程序还是有状态应用程序,都能更顺畅地开发应用程序。
  • 多功能性: 使用 DAPR 的应用程序可以在任何地方运行 – Kubernetes、云环境、虚拟机、边缘计算等。
  • 与语言无关: 使用 DAPR,开发人员不必局限于特定的编程语言。虽然某些语言有 SDK,但您可以使用 HTTP 或 gRPC 端点与 DAPR 接口。

DAPR 的主要功能

DAPR 是一个多功能平台,提供一系列功能:

  • 服务对服务调用: 促进服务之间的直接通信。
  • 状态管理: 有助于管理应用程序的状态。
  • 发布-订阅模型: 实现服务间的异步通信。
  • 资源绑定:将代码链接到外部资源。
  • 可观察性:监控和跟踪应用程序。
  • 秘密管理:安全存储和检索秘密。
  • 配置管理:对服务进行集中配置。

DAPR 中的 Pub-Sub 模型

当微服务在隔离状态下运行时,直接通信就成了一项挑战。DAPR 提供了一种以事件为媒介的解决方案。整个系统取决于一个神奇的组件: DAPR。它将松散耦合的服务转化为基于事件运行的连贯系统。

架构简单,但影响深远。发布者发布事件,订阅者监听这些事件。这种事件驱动方法可确保服务保持解耦,只关注其核心职责。实际的通信物流、事件存储和事件分发都被抽象出来,由 DAPR 进行有效管理。

DAPR 中的 Pub-Sub 模型实际应用:实用概述

设置 DAPR

开始使用 DAPR 时,我将它与 Redis 一起安装在 Kubernetes 集群上,Redis 是 DAPR 支持的各种状态存储之一。DAPR 组件在清单文件中定义,它们指导 DAPR 在何处存储状态或事件信息。在我的设置中,状态存储和事件发布都指向 Redis。

  • 确保在计算机上安装了 Helm 3
  • 添加 Helm repo 并更新。
helm repo add dapr <https://dapr.github.io/helm-charts/>
helm repo update
  • 在 Kubernetes 集群上创建 dapr-system 命名空间。
kubectl create namespace dapr-system
  • 在集群的 dapr-system 命名空间中安装 Dapr 图表。
helm  install  dapr  dapr/dapr  --namespace  dapr-system

设置 Redis 存储

Dapr 使用可插拔的消息总线来启用 pub-sub,本例中使用的是 Redis Streams(在 Redis 5 及以上版本中启用)。你将使用 Helm 将 Redis 安装到集群中,但请记住,只要版本大于 5,你可以使用任何你喜欢的 Redis 主机。

  • 将 Redis 安装到集群中
helm repo add bitnami <https://charts.bitnami.com/bitnami>
helm repo update
helm install redis bitnami/redis --set image.tag=6.2
  • 运行 kubectl get pods 查看集群中正在运行的 Redis 容器:
$ kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
redis-master-0   1/1     Running   0          69s
redis-replicas-0    1/1     Running   0          69s
redis-replicas-1    1/1     Running   0          22s

将 DAPR 与应用程序集成

您将建立一个发布者微服务,并辅以三个订阅者微服务,以展示发布-订阅模式的实际应用。发布者的主要功能是发布与指定主题相关的消息。相比之下,我们的订阅者将主动收听与特定主题产生共鸣的消息。底层逻辑简单明了,不会因编程语言的不同而有太大差异。有了 SDK,初始化新客户端和发布事件就变得轻而易举。

设置发布者微服务: 该服务将在预定义的主题上生成和广播消息。为此,我们将使用一个

  • React 前端消息生成器( kubectl apply -f react-form.yaml)
kind: Service
apiVersion: v1
metadata:
  name: react-form
  labels:
    app: react-form
spec:
  selector:
    app: react-form
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-form
  labels:
    app: react-form
spec:
  replicas: 1
  selector:
    matchLabels:
      app: react-form
  template:
    metadata:
      labels:
        app: react-form
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "react-form"
        dapr.io/app-port: "8080"
    spec:
      containers:
      - name: react-form
        image: ghcr.io/dapr/samples/pubsub-react-form:latest
        ports:
        - containerPort: 8080
        imagePullPolicy: Always

配置订阅者: 这些服务将监听特定主题的消息并进行相应处理。我们将设置:

  • Node.js 订阅器 ( kubectl apply -f node-subscriber.yaml )
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-subscriber
  labels:
    app: node-subscriber
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-subscriber
  template:
    metadata:
      labels:
        app: node-subscriber
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "node-subscriber"
        dapr.io/app-port: "3000"
    spec:
      containers:
      - name: node-subscriber
        image: ghcr.io/dapr/samples/pubsub-node-subscriber:latest
        ports:
        - containerPort: 3000
        imagePullPolicy: Always
  • Python 订阅者( kubectl apply -f python -subscriber.yaml )
apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-subscriber
  labels:
    app: python-subscriber
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-subscriber
  template:
    metadata:
      labels:
        app: python-subscriber
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "python-subscriber"
        dapr.io/app-port: "5001"
    spec:
      containers:
      - name: python-subscriber
        image: ghcr.io/dapr/samples/pubsub-python-subscriber:latest
        ports:
        - containerPort: 5001
        imagePullPolicy: Always
  • C# 订阅者 ( kubectl apply -f csharp-subscriber.yaml )
apiVersion: apps/v1
kind: Deployment
metadata:
  name: csharp-subscriber
  labels:
    app: csharp-subscriber
spec:
  replicas: 1
  selector:
    matchLabels:
      app: csharp-subscriber
  template:
    metadata:
      labels:
        app: csharp-subscriber
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "csharp-subscriber"
        dapr.io/app-port: "5009"
    spec:
      containers:
      - name: csharp-subscriber
        image: ghcr.io/dapr/samples/pubsub-csharp-subscriber:latest
        ports:
        - containerPort: 5009
        imagePullPolicy: Always

使用 DAPR

  • 访问网络表单

访问 Kubernetes 服务有几种不同的方式,具体取决于您使用的平台。端口转发是访问服务的一种一致方式。

kubectl port-forward service/react-form 8000:80

这将使服务在http://localhost:8000上可用。

DAPR:释放 Pub-Sub 模型在微服务通信中的威力

注意:如果运行环境无法轻松访问网络浏览器,以下 curl 命令将模拟浏览器向节点服务器发出的请求。

curl -s <http://localhost:8000/publish> -H Content-Type:application/json --data @message_a.json
curl -s <http://localhost:8000/publish> -H Content-Type:application/json --data @message_b.json
curl -s <http://localhost:8000/publish> -H Content-Type:application/json --data @message_c.json
  • 查看订阅者生成的日志
$ kubectl logs --selector app=node-subscriber -c node-subscriber
A:  Message on A
B:  Message on B
A:  Message A
B:  Message B
$ kubectl logs --selector app=python-subscriber -c python-subscriber
C: {'data': {'message': 'Message on C', 'messageType': 'C'}, 'datacontenttype': 'application/json', 'id': '8b5b5eff-34fe-456f-8512-b3b67fc327ea', 'pubsubname': 'pubsub', 'source': 'react-form', 'specversion': '1.0', 'time': '2023-10-29T00:21:50Z', 'topic': 'C', 'traceid': '00-00000000000000000000000000000000-0000000000000000-00', 'traceparent': '00-00000000000000000000000000000000-0000000000000000-00', 'tracestate': '', 'type': 'com.dapr.event.sent'}
Received message "Message on C" on topic "C"
127.0.0.1 - - [29/Oct/2023 00:21:50] "POST /C HTTP/1.1" 200 -
A: {'data': {'message': 'Message A\\n', 'messageType': 'A'}, 'datacontenttype': 'application/json', 'id': 'c328e069-9f9f-4638-a2cb-b48188f9b272', 'pubsubname': 'pubsub', 'source': 'react-form', 'specversion': '1.0', 'time': '2023-10-30T01:30:47Z', 'topic': 'A', 'traceid': '00-00000000000000000000000000000000-0000000000000000-00', 'traceparent': '00-00000000000000000000000000000000-0000000000000000-00', 'tracestate': '', 'type': 'com.dapr.event.sent'}
Received message "Message A
" on topic "A"
127.0.0.1 - - [30/Oct/2023 01:30:47] "POST /A HTTP/1.1" 200 -
C: {'data': {'message': 'Message C', 'messageType': 'C'}, 'datacontenttype': 'application/json', 'id': 'e70ad0ca-faad-43a4-9300-157a72dc30b1', 'pubsubname': 'pubsub', 'source': 'react-form', 'specversion': '1.0', 'time': '2023-10-30T01:31:00Z', 'topic': 'C', 'traceid': '00-00000000000000000000000000000000-0000000000000000-00', 'traceparent': '00-00000000000000000000000000000000-0000000000000000-00', 'tracestate': '', 'type': 'com.dapr.event.sent'}
Received message "Message C" on topic "C"
127.0.0.1 - - [30/Oct/2023 01:31:00] "POST /C HTTP/1.1" 200 -
$ kubectl logs --selector app=csharp-subscriber -c csharp-subscriber
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app
A: Message on A
B: Message on B
C: Message on C
A: Message A
B: Message B
C: Message C

幕后

部署这些服务时,DAPR 会自动向 pod 中注入一个额外的容器。这个容器承担了事件管理的重任。通过集群中的事件总线(如 Redis),可以发布和存储事件。任何服务都可以订阅和使用这些事件。

这里真正的神奇之处在于隔离。服务无法直接感知 DAPR 甚至 Redis。它们在一个气泡中运行,只知道自己的行动,相信 DAPR 会处理服务间的通信。

DAPR 脱颖而出的原因

像 DAPR 这样强大而直观的工具实属罕见。它的多功能性和广泛的集成性使其成为管理应用程序,尤其是解耦微服务的最佳选择。虽然生态系统中也有其他工具和平台(如服务网格)提供一些重叠的功能,但 DAPR 专注于简化微服务之间的通信,这使它脱颖而出。

DAPR 迅速巩固了其作为微服务领域游戏规则改变者的地位。它能够无缝融入任何环境,再加上简化服务之间通信的能力,使其成为不可或缺的工具。

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/36721.html

(0)

相关推荐

发表回复

登录后才能评论