目錄
- Dapr(分布式應用程序運行時)介紹
- 實戰 Dapr 的 Redis 發布/訂閱應用
- 1. 創建項目
- 2. 創建 Dapr Placement 服務
- 3. 創建 Redis Publish 服務
- 4. 創建 Dapr Pub-Sub 組件
- 5. 創建 Redis Dapr Sidecar
- 6. 創建 NestJS Server
- 7. 為 NestJS 訂閱服務器創建 Dockerfile
- 8. 將 NestJS 訂閱服務添加到 docker-compose 文件
- 9. 創建 Dapr 訂閱
- 10. 創建 NestJS 服務器 Dapr Sidecar
- 11. 測試它是否有效
- 12. 允許 NestJS 解析 application/cloudevents+json
- 13. 完整 docker-compose.yaml

Dapr(分布式應用程序運行時)介紹
Dapr 是一個可移植的、事件驅動的運行時,它使任何開發人員能夠輕松構建出彈性的、無狀態和有狀態的應用程序,并可運行在云平臺或邊緣計算中,它同時也支持多種編程語言和開發框架。
Dapr 官網:dapr.io/
實戰 Dapr 的 Redis 發布/訂閱應用
1. 創建項目
首先,我們將創建我們的項目根文件夾來托管我們將在后續步驟中創建的所有服務。
mkdir dapr-nestjs-redis-pub-sub
2. 創建 Dapr Placement 服務
由于我們將創建多個服務,我們將使用 docker-compose 來運行這些服務。
讓我們在項目的根文件夾中創建 docker-compose.yml 文件
cd dapr-nestjs-redis-pub-sub touch docker-compose.yml
version: "3.5"
services:
dapr-placement:
image: "daprio/dapr"
command: ["./placement", "-port", "50006"]
Dapr placement 服務將負責管理 Dapr actors(我們的服務)之間的所有通信。
簡單來說,它負責將所有通信路由到假設接收通信的相應 actor。它充當 message broker(消息代理)。
3. 創建 Redis Publish 服務
讓我們繼續通過添加我們的 Redis 服務來修改我們的 docker-compose.yml 文件。
將以下代碼添加到 docker-compose.yml 的服務部分:
redis-publisher:
image: redis
restart: always
depends_on:
- dapr-placement
4. 創建 Dapr Pub-Sub 組件
創建一個 dapr/components 文件夾。然后創建組件文件 redis-pubsub.yaml。
mkdir -p dapr/components cd dapr/components touch redis-pubsub.yaml
然后打開文件并插入我們的 Dapr pub/sub 組件的詳細信息
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: redis-pubsub
namespace: default
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: redis-publisher:6379
- name: redisPassword
value: ""
redisHost 是我們的 Redis 服務 redis-pub 的名稱,默認 Redis 端口為 6379。
5. 創建 Redis Dapr Sidecar
正如前面部分反復提到的,服務直接與 Dapr 通信,而不是直接與其他服務通信。Dapr 充當所有服務的中間人。
服務通過它們自己的 Dapr sidecar 直接與 Dapr 通信,Dapr sidecar 將通信傳遞給 Dapr placement,該 placement 再次將其傳遞給假設接收通信的服務的 Dapr sidecar。
將 redis-dapr-sidecar 服務添加到我們的 docker-compose.yml
redis-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id",
"redis-publisher",
"-app-port",
"6379",
"-dapr-http-port",
"5000",
"-components-path",
"/components",
"-placement-host-address",
"dapr-placement:50006"
]
volumes:
- "./dapr/components/:/components"
depends_on:
- redis-publisher
network_mode: "service:redis-publisher"
在這里,我們使用 app-id 將 Dapr sidecar 分配給 redis-publisher,同時我們使用 redis 端口 6379。
我們還必須將 dapr/components(redis-pubsub.yaml) 文件夾掛載到 docker 容器中。
不要忘記聲明 dapr-http-port。這是我們的 Dapr sidecar 的 api,允許我們調用各種 HTTP 方法。
定義您的 dapr-http-port 很重要,因為您將在此處調用各種 HTTP 調用/方法/請求。
最后,注意將 redis-dapr-sidecar 附加到 redis-publisher 網絡命名空間。
6. 創建 NestJS Server
我們將使用 NestJS 作為我們的 node server 作為我們的 Redis subscriber(訂閱者)。
進入到項目文件夾
cd dapr-nestjs-redis-pub-sub
然后執行以下命令設置一個 NestJS node server:
npm i -g @nestjs/cli nest new nest-subscriber
對于這個項目,我們將選擇 yarn 作為包管理器。
接下來,我們將設置一個 post API 端點。 Dapr 將調用這個端點,一旦它收到我們的 Redis 服務發布,它就被調用。
轉到 nest-subscriber/src/app.controller.ts
將此文件中的代碼替換為以下內容:
import { Controller, Post, Body } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post('/redis-publisher')
async postRedisPub(@Body() reqBody) {
console.log(`Redis 發布了 ${JSON.stringify(reqBody)} `);
return `NestJS 訂閱者收到的 ${reqBody} 發布`;
}
}
7. 為 NestJS 訂閱服務器創建 Dockerfile
我們將 NestJS 服務器作為 Docker 容器運行。需要創建一個 Dockerfile。
cd nest-subscriber touch Dockerfile
然后打開文件并粘貼以下代碼:
FROM node:16.13.0-alpine WORKDIR "/app" COPY ./nest-subscriber/package.json ./ RUN yarn install COPY ./nest-subscriber . RUN yarn run build EXPOSE 3000 CMD ["yarn","start:prod"]
構建鏡像:
docker build -f ./nest-subscriber/Dockerfile -t nest-subscriber:latest . --no-cache
8. 將 NestJS 訂閱服務添加到 docker-compose 文件
在創建了我們的 NestJS 服務器和 Dockerfile 之后,我們創建了 nest-subscriber docker 服務。
將以下內容添加到 docker-compose.yml:
nest-subscriber:
image: "nest-subscriber:latest"
depends_on:
- redis-publisher
- dapr-placement
restart: always
9. 創建 Dapr 訂閱
我們將為我們的 pub/sub 訂閱定義配置。
創建一個 dapr/subscriptions 文件夾。然后創建組件文件 redis-subscription.yaml
mkdir -p dapr/subscriptions cd dapr/subscriptions touch redis-subscription.yaml
然后打開文件并插入我們的 Dapr 訂閱組件的詳細信息
apiVersion: dapr.io/v1alpha1 kind: Subscription metadata: name: nest-redis-sub spec: topic: nest-redis-pub-topic route: /redis-publisher pubsubname: redis-pubsub scopes: - nest-subscriber
路由是發布 topic 時 Dapr 將調用的 API
scope 是訂閱該 topic 的服務。
pubsubname 是 redis-pubsub,它等于我們的 redis-pubsub.yaml 文件中定義的元數據名稱。
在這個項目中,如果發布了一個 topic nest-redis-pub-topic,Dapr 將在我們的 nest-subscriber 服務中調用 API /redis-publisher。
10. 創建 NestJS 服務器 Dapr Sidecar
我們需要為我們的 NestJS 服務創建一個 sidecar,就像 redis-publisher 服務一樣。
將 nest-subscriber-dapr-sidecar 服務添加到我們的 docker-compose.yml
nest-subscriber-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id",
"nest-subscriber",
"-app-port",
"3000",
"-components-path",
"/components",
"-placement-host-address",
"dapr-placement:50006",
]
volumes:
- "./dapr/components/:/components"
depends_on:
- nest-subscriber
network_mode: "service:nest-subscriber"
11. 測試它是否有效
通常 Dapr Docker 容器會在 Docker 網絡中進行通信。
但是為了我們做測試,我們將打開映射暴露端口 5000 到我們的本地機器 5001。
redis-publisher:
image: redis
depends_on:
- dapr-placement
restart: always
ports:
- 5001:5000
然后在您的終端中執行以下命令:
curl --location --request POST 'http://localhost:5001/v1.0/publish/redis-pubsub/nest-redis-pub-topic' \
--header 'Content-Type: application/json' \
--data-raw '{
"hello": "world"
}'
Dapr 的優點之一是它遵循特定的 URL 格式。這里我們只使用 Dapr sidecar HTTP 端口(5001),然后是版本號(v1.0),然后是 action(publish)。然后是我們 redis-pubsub.yaml 配置文件中定義的 pubsubname(redis-pubsub)和 topic(nest-redis-pub-topic)。
一旦發出 HTTP post 請求。我們的 NestJS 服務器應該在 /redis-publisher 收到一個 post 請求,這將導致以下日志:

我們可以看到它正在通過 Dapr 接收 Redis 發布。但是我們的 NestJS 服務器無法正確處理消息。
只有 {} 被發布,而不是我們發布的消息。
我們將在下一步中解決這個問題。
注意:我們通過 redis-dapr-sidecar 的 dapr-http-port 調用發布服務。通常會有一個單獨的 Docker 服務(例如另一個服務器),它有自己的 Dapr sidecar,它將調用 redis 發布服務。 在這種情況下,我們將使用該 Docker 服務的 Dapr sidecar http-port。該請求將由 sidecar 發送到 Dapr placement 服務,然后該服務將確定將請求轉發到的正確 Dapr sidecar。
12. 允許 NestJS 解析 application/cloudevents+json
我們的 nest-subscriber-dapr-sidecar 向我們的 nest-subscriber 服務器發出的 post 請求的 Content-Type 將是 application/cloudevents+json 而不是 application/json
目前我們的 NestJS 服務器無法解析 application/cloudevents+json。
為了解決這個問題,我們首先需要安裝 body-parser:
cd nest-subscriber yarn add body-parser
接下來我們需要修改我們的 NestJS 服務器 main.ts:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as bodyParser from 'body-parser';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(bodyParser.json({ type: 'application/cloudevents+json' }));
app.use(bodyParser.json());
await app.listen(3000);
}
bootstrap();
當我們再次發送 post 請求時,我們的 NestJS 服務器將能夠處理請求正文并顯示以下日志:
好了,我們現在有一個基于 Dapr 工作的 Redis Pub/Sub 分布式應用。
13. 完整 docker-compose.yaml
version: "3.5"
services:
dapr-placement:
image: "daprio/dapr"
command: ["./placement", "-port", "50006"]
redis-publisher:
image: redis
depends_on:
- dapr-placement
restart: always
ports:
- 5001:5000
redis-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id",
"redis-publisher",
"-app-port",
"6379",
"-dapr-http-port",
"5000",
"-components-path",
"/components",
"-placement-host-address",
"dapr-placement:50006"
]
volumes:
- "./dapr/components/:/components"
depends_on:
- redis-publisher
network_mode: "service:redis-publisher"
nest-subscriber:
image: "nest-subscriber:latest"
depends_on:
- redis-publisher
- dapr-placement
restart: always
nest-subscriber-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id",
"nest-subscriber",
"-app-port",
"3000",
"-components-path",
"/components",
"-placement-host-address",
"dapr-placement:50006",
]
volumes:
- "./dapr/components/:/components"
depends_on:
- nest-subscriber
network_mode: "service:nest-subscriber"
源碼 github.com/Hacker-Linn…
以上就是Docker Compose+Nestjs構建Dapr Redis發布訂閱分布式應用的詳細內容,更多關于Docker Nestjs構建Redis分布式的資料請關注其它相關文章!






