百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

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

mhr18 2024-11-14 16:23 24 浏览 0 评论

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-idDapr sidecar 分配给 redis-publisher,同时我们使用 redis 端口 6379

我们还必须将 dapr/components(redis-pubsub.yaml) 文件夹挂载到 docker 容器中。

不要忘记声明 dapr-http-port。这是我们的 Dapr sidecarapi,允许我们调用各种 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

路由是发布 topicDapr 将调用的 API

scope 是订阅该 topic 的服务。

pubsubnameredis-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 配置文件中定义的 pubsubnameredis-pubsub)和 topicnest-redis-pub-topic)。

一旦发出 HTTP post 请求。我们的 NestJS 服务器应该在 /redis-publisher 收到一个 post 请求,这将导致以下日志:

我们可以看到它正在通过 Dapr 接收 Redis 发布。但是我们的 NestJS 服务器无法正确处理消息。

只有 {} 被发布,而不是我们发布的消息。

我们将在下一步中解决这个问题。

注意:我们通过 redis-dapr-sidecardapr-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(微软开源的分布式应用程序运行时)

相关推荐

说说Redis的单线程架构(redis的单线程模型)

一句话总结Redis采用单线程处理命令请求,避免了多线程的上下文切换和锁竞争,保证原子性操作。其基于内存的高效执行和I/O多路复用模型支撑了高并发性能。网络I/O和持久化操作(如RDB/AOF)由后台...

答记者问之 - Redis 的高效架构与应用模式解析

问:极客程序员你好,请帮我讲一讲redis答:redis主要涉及以下核心,我来一一揭幕Redis的高效架构与应用模式解析Redis是一个开源的内存数据存储系统,因其高性能、丰富的数据结构和易用性...

Redis的5种核心数据结构,及其最经典的“应用场景”

Redis凭什么稳坐缓存界头把交椅?全靠这五个“身怀绝技”的数据结构!在分布式系统的江湖里,Redis就像一位身怀绝技的武林高手,而它的五大核心数据结构正是克敌制胜的五套绝学。今天咱们就来拆解这些独门...

精准定位文件包含漏洞:代码审计中的实战思维

前言最近看到由有分析梦想cms的,然后也去搭建了一个环境看了一看,发现了一个文件包含漏洞的点,很有意思,下面是详细的复现和分析,以后代码审计又多了一中挖掘文件包含漏洞的新思路环境搭建下载https...

ARDM:一款国产跨平台的Redis管理工具

ARDM(AnotherRedisDesktopManager)是一款免费开源的Redis桌面管理客户端,支持Windows、Mac、Linux跨平台。功能特性ARDM提供的主要功能如...

SpringBoot的Web应用开发——Web缓存利器Redis的应用!

 Web缓存利器Redis的应用Redis是目前使用非常广泛的开源的内存数据库,是一个高性能的keyvalue数据库,它支持多种数据结构,常用做缓存、消息代理和配置中心。本节将简单介绍Redis的使...

Windows服务器部署CRMEB开源电商系统,详细教程来了!

安装PHP已经安装过PHP的可以跳过首先安装VC运行库下载地址https://docs.microsoft.com/zh-cn/cpp/windows/latest-supported-vc-redi...

Windows系统下Redis各个安装包介绍与选择指南

简介Redis作为高性能的键值数据库,广泛应用于缓存、消息队列等场景。在Windows系统中部署Redis时,用户可以选择多种安装包以满足不同的需求。本文将详细介绍以下Redis8.0.3版本的安装...

从面试题入手,深度剖析Redis Cluster原理

揭开RedisCluster的神秘面纱**在当今数字化浪潮中,数据量呈爆炸式增长,应用程序对数据存储和处理的要求也日益严苛。Redis作为一款高性能的内存数据库,凭借其出色的读写速度和丰富的数...

给大家推荐些好的c语言代码的网站

C语言,那就来推荐几个吧,部分含有C++:1、TheLinuxKernelArchives(kernel.org)Linux内核源码,仅限于C,但内核庞大,不太适合新手;2、redis(redi...

Redis String 类型的底层实现与性能优化

RedisString是Redis中最基础也是应用最广泛的数据类型,它能存储文本、数字、二进制数据等多种形式的信息。深入理解其底层实现对构建高性能分布式系统至关重要。Redis字符串的底层结...

阿里面试问:Redis 为什么把简单的字符串设计成 SDS?

分享了一道面阿里的redis题,我看了以后觉得挺有意思。题目大致是这样的面试官:了解redis的String数据结构底层实现嘛?铁子:当然知道,是基于SDS实现的面试官:redis是用C语言开发的,那...

编程语言那么多,为何C语言能成为最成功的语言?

编程语言那么多,为何C语言能成为最成功的语言?2025年嵌入式岗位暴增47%,新人却还在问"C语言过时了吗"。真相是连机器人关节驱动都得靠它写,不会指针连芯片手册都看不懂。见过用Pyt...

go-zero 使用 redis 作为 cache 的 2 种姿势

在go-zero框架内,如在rpc的应用service中,其内部已经预置了redis的应用,所以我们只需要在配置中加入相关字段即可,另外,在svcContext声明redisc...

Redis事务深度解析:ACID特性、执行机制与生产实践指南

一、Redis事务的本质与核心机制Redis事务通过MULTI、EXEC、WATCH等命令实现,其本质是将多个命令序列化后一次性执行,而非传统数据库的严格事务模型。核心特点如下:命令队列化:MULT...

取消回复欢迎 发表评论: