本地使用 Docker Compose 与 Nestjs 快速构建基于 Dapr 的 Redis 发布/订阅分布式应用

Dapr(分布式应用程序运行时)介绍
Dapr 是一个可移植的、事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的、无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架。
Dapr 官网:https://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"
14. 源码
https://github.com/Hacker-Linner/dapr-nestjs-redis-pub-sub.git
更多
使用 Dapr JS SDK 让 Nest.js 集成 Dapr
本地使用 Docker Compose 与 Nestjs 快速构建基于 Dapr 的 Redis 发布/订阅分布式应用的更多相关文章
- 用前端姿势玩docker【五】快速构建中类Unix系统与Windows系统的差异化处理
目录 用前端姿势玩docker[一]Docker通俗理解常用功能汇总与操作埋坑 用前端姿势玩docker[二]dockerfile定制镜像初体验 用前端姿势玩docker[三]基于nvm的前端环境构建 ...
- 使用PowerApps快速构建基于主题的轻业务应用 —— 进阶篇
作者:陈希章 发表于 2017年12月14日 在上一篇 使用PowerApps快速构建基于主题的轻业务应用 -- 入门篇 中,我用了三个实际的例子演示了如何快速开始使用PowerApps构建轻业务应用 ...
- Docker Compose部署项目到容器-基于Tomcat和mysql的项目yml配置文件代码
场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...
- Docker Compose + Traefik v2 快速安装, 自动申请SSL证书 http转https 初次尝试
前言 昨晚闲得无聊睡不着觉,拿起服务器尝试部署了一下Docker + Traefik v2.1.6 ,以下是一些配置的总结,初次接触,大佬勿喷. 我的系统环境是 Ubuntu 18.04.3 LTS ...
- NodeJS 基于 Dapr 构建云原生微服务应用,从 0 到 1 快速上手指南
Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架.Dapr 确保开发人员专注 ...
- 使用PowerApps快速构建基于主题的轻业务应用 —— 入门篇
作者:陈希章 发表于 2017年12月12日 前言 在上一篇文章 基于Office 365的随需应变业务应用平台 中我提到,随着随需应变的业务需要,以及技术的发展,业务应用的开发的模式也有了深刻的变化 ...
- Docker Compose部署项目到容器-基于Tomcat和mysql的商城项目(附源码和sql下载)
场景 Docker-Compose简介与Ubuntu Server 上安装Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...
- 使用Spring Boot快速构建基于SQLite数据源的应用
为了提供一个单包易部署的服务器应用,考虑使用Spring Boot,因为其集成了Apache Tomcat,易于运行,免去绝大部分了服务器配置的步骤. 项目初始化 首先从mvn archetype:g ...
- ActiveMQ 快速入门教程系列 第二章 发布-订阅者模式实现
第二章我们会介绍怎样实现一个发布者对多个订阅者的消息传递 Topic和queue的最大区别在于topic是以广播的形式,通知所有在线监听的客户端有新的消息,没有监听的客户端将收不到消息:而queue则 ...
随机推荐
- .NET LoongArch64 正式合并进入.NET
国内自主的龙芯,在做龙芯技术生态就把 .NET 作为其中一部分考虑进去,这也将对接下来国内.NET应用场景充满了期待.通过dotnet/runtime 可以知道现在龙芯版本的 .NET 已经合并到.N ...
- FreeRTOS --(5)内存管理 heap4
FreeRTOS 中的 heap 4 内存管理,可以算是 heap 2 的增强版本,在 <FreeRTOS --(3)内存管理 heap2>中,我们可以看到,每次内存分配后都会产生一个内存 ...
- Hadoop(三)通过C#/python实现Hadoop MapReduce
MapReduce Hadoop中将数据切分成块存在HDFS不同的DataNode中,如果想汇总,按照常规想法就是,移动数据到统计程序:先把数据读取到一个程序中,再进行汇总. 但是HDFS存的数据量非 ...
- Linux 多网卡bonding
bonding 将多块网卡绑定同一IP地址对外提供服务,可以实现高可用或者负载均衡.直接给两块网卡设置同一IP 地址是不可以的.通过 bonding,虚拟一块网卡对外提供连接,物理网卡的被修改为相同的 ...
- kvm 虚拟化技术 1.1 安装
1.·VMware开启虚拟化设置 2.安装一些虚拟化的必备插件 yum install -y qemu-kvm qemu-kvm-tools libvirt virt-manager virt-ins ...
- git 1.2
1.git服务器的搭建 gitlab 常用命令: gitlab-rails console -e production 进入控制台指令 sudo gitlab-ctl start # 启动所有 gi ...
- 【数据库】MYSQL如何添加索引
1.使用ALTER TABLE语句创建索性 应用于表创建完毕之后再添加. 1.1语法 ALTER TABLE 表名 ADD 索引类型 (unique,primary key,fulltext,inde ...
- C#实现登录功能(连接SQLServer数据库)
本例使用C#实现一个简单的登录功能,分为用户和管理员两个角色登录. 效果图: 核心代码 login.cs private void button1_Click(object sender, Event ...
- Vue关闭语法检测
为什么?为了防止写到一半保存,报错.关闭默认的语法检测 新建vue.config.js 1.vue.config.js的作用是允许你修改脚手架中wekpack的默认参数. 2.vue.config.j ...
- 云开发中的战斗机 Laf,让你像写博客一样写代码
各位云原生搬砖师 and PPT 架构师,你们有没有想过像写文章一样方便地写代码呢? 怎样才能像写文章一样写代码? 理想的需求应该是可以在线编写.调试函数,不用重启服务,随时随地在 Web 上查看函数 ...