微服务改变了我们设计和实施软件系统的方式。这些可独立部署的小型应用程序专注于解决特定问题,其解耦特性确保每个应用程序都能自主运行。但这种解耦带来了一个基本问题: 如果服务之间不知道对方的存在,它们该如何通信呢?这就是 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上可用。
注意:如果运行环境无法轻松访问网络浏览器,以下 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