# dapr 结合 rabbitMq

## 部署好rabbitmq

启动rabbitmq :

```
docker run -d --hostname my-rabbit --name some-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management
```

重启rabbitmq  :

```
docker restart some-rabbit
```

## 准备配置文件

### 编写配置文件：

1. talents-database-rabbitmq-pubsub.yaml

```
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: talents-database-rabbitmq-pubsub
  namespace: default
spec:
  type: pubsub.rabbitmq
  version: v1
  metadata:

    - name: host
      value: "amqp://admin:admin@localhost:5672"

    # 是否使用durable队列， 默认值为 "false" 
    - name: durable
      value: "true"

    # 是否应将队列配置为自动删除默认值为“true”
    - name: deletedWhenUnused
      value: "false"

    # 队列的消费者是否应该auto-ack消息 默认值为 "false" 
    - name: autoAck
      value: "false"

    # 发布消息时的持久化模式， 默认值为 "0". 值为"2"时RabbitMQ会进行持久化，其他值反之
    - name: deliveryMode
      value: "0"

    # 在发送否定应答失败的情况下，是否进行重排， 默认值为 "false" 
    - name: requeueInFailure
      value: "false"

    # prefecth的消息数量， 生产环境中需要考虑设置一个非零值。 生产环境中需要考虑设置一个非零值。 该值默认为"0"，这意味着所有可用消息都将被预先提取
    - name: prefetchCount
      value: "0"

    # 如果发生连接失败，在重新连接之前需要等待多长时间（秒）
    - name: reconnectWait
      value: "0"

    # 默认值是parallel，表示允许并行处理多个消息（如果配置了app-max-concurrency，最大并行数会受到该值限制）, 设置为single可禁用并行处理， 大多数情况下没必要去这么做 设置为single可禁用并行处理， 大多数情况下没必要去这么做
    - name: concurrencyMode
      value: parallel

    # 策略（指数型）
    - name: backOffPolicy
      value: "exponential"

    # 持续时间
    - name: backOffDuration
      value: "5s"

    # 初始间隔值
    - name: backOffInitialInterval
      value: "100"

    # 最大间隔值
    - name: backOffMaxInterval
      value: "16"

    # 最大重试次数
    - name: backOffMaxRetries
      value: "16"

    # 随机因子
    - name: backOffRandomizationFactor
      value: "0.5"

    # 倍数
    - name: backOffMultiplier
      value: "1.5"
    
    # 最大流逝时间
    - name: backOffMaxElapsedTime
      value: "15m"

  # 限制特定topic访问
  # - name: allowedTopics
  #   value: "A,B"
  # - name: publishingScopes
  #   value: "app1=A"
  # - name: subscriptionScopes
  #   value: "app1=;app2=A"
```

2. talents-database-rabbitmq-subscription.yaml

```
apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:
  name: talents-database-rabbitmq-subscription
spec:
  # topic名称
  topic: deathStarStatus
  # 端点
  route: /dsstatus
  # 发布名称
  pubsubname: talents-database-rabbitmq-pubsub
#  metadata:
#    rawPayload: "true"
```

### 编写消费者代码（python）

```
import flask
from flask import request, jsonify
from flask_cors import CORS
import json
import sys

app = flask.Flask(__name__)
CORS(app)

// 指定接受消息的路由地址和接收方式
@app.route('/dsstatus', methods=['POST'])
def ds_subscriber():
    print(request.json, flush=True)
    return json.dumps('你好啊！'), 200, {'ContentType':'application/json'}

app.run(port=5001)
```



## 声明式订阅

文件目录结构：

![](E:\JavaLearn\test\zhouyang\测试文档\企业微信截图_16364411239716.png)

```
# 启动生产者
dapr run --app-id testpubsub --components-path ./talents-component --dapr-http-port 3500

# 订阅
# 注意：components-path的路径是配置文件所在的路径
dapr --app-id app1 --app-port 5001 --components-path ./talents-component run python3 app1.py
# JAVA消费端
dapr run --app-id service1 --app-port 9101 --components-path ./talents-component -- java -jar ./java/service/dapr-java-service-exec.jar com.dapr.service.ServiceC -p 9101
```

## 解析默认配置

如果只有一个生产者和一个消费者（app.py）是单发单订阅；

一个生产者和多个消费者是单发多订阅（一个消费者有对应的一个队列维护）

在起消费者后，就会在rabbitmq里生产对应的队列：命名规则为：appName-topicName

![](E:\JavaLearn\test\zhouyang\测试文档\图片1.png)

## 发布消息

1、Dapr CLI :

dapr publish --publish-app-id testpubsub --pubsub talents-database-rabbitmq-pubsub --topic deathStarStatus --data '{"status": "completed","data":"list"}'

2、HTTP API(BASH)

Curl -X POST http://localhost:3500/v1.0/publish/talents-database-rabbitmq-pubsub/deathStarStatus -H "Content-Type: application/json" -d '{ "status": "completed"}'

![image-20211109150502012](E:\JavaLearn\test\zhouyang\测试文档\image-20211109150502012.png)

消费者可接收到消息

## 限定 Pub/Sub 主题访问权限

### 设置只允许指定消费者消费消息：

在 talents-database-rabbitmq-subscription.yaml 里

```
apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:
  name: talents-database-rabbitmq-subscription
spec:
  # topic名称
  topic: deathStarStatus
  # 端点
  route: /dsstatus
  # 发布名称
  pubsubname: talents-database-rabbitmq-pubsub
#  metadata:
#    rawPayload: "true"
# 指定app允许访问
scopes:
- app1
```

以上配置后，及时有多个消费端开启服务，也只有appName 为 app1的服务能接收到消息

### 限制主题访问权限

在 talents-database-rabbitmq-pubsub.yaml 里

```
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
  namespace: default
spec:
  type: pubsub.redis
  version: v1
  metadata:
   - name: host
      value: "amqp://admin:admin@localhost:5672"
  # 显示哪些应用程序允许在主题中发布
  - name: publishingScopes
    value: "app1=topic1;app2=topic2"
  # 显示哪些应用程序可以订阅主题  
  - name: subscriptionScopes
    value: "app2=;app3=topic1"
    
    
  # 限制特定topic访问
  # - name: allowedTopics
  #   value: "A,B" 
```

![](E:\JavaLearn\test\zhouyang\测试文档\企业微信截图_16364431561909.png)



![](E:\JavaLearn\test\zhouyang\测试文档\企业微信截图_16364433384722.png)



![](E:\JavaLearn\test\cyx\笔记\多对多.png)

## 数据不丢失的重要配置

```
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: talents-database-rabbitmq-pubsub
  namespace: default
spec:
  type: pubsub.rabbitmq
  version: v1
  metadata:

    - name: host
      value: "amqp://admin:admin@localhost:5672"

    # 是否使用durable队列， 默认值为 "false" 
    - name: durable
      value: "true"

    # 是否应将队列配置为自动删除默认值为“true”
    - name: deletedWhenUnused
      value: "false"

    # 队列的消费者是否应该auto-ack消息 默认值为 "false" 
    - name: autoAck
      value: "false"
```

压力测试

 

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3878.tmp.jpg)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3879.tmp.jpg)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps388A.tmp.jpg)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps388B.tmp.jpg) 

 

混沌测试（50个线程，30秒，循环10次）：

1、mq中断（发布立刻尝试重新连接，订阅出现错误提示），重启mq,发布连接成功，订阅正常接收。

 

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps388C.tmp.jpg) 

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps388D.tmp.jpg) 

 

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps388E.tmp.jpg)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps388F.tmp.jpg) 

 

2、 发布中断（订阅停止接收发布消息，发布者重新启动，订阅可继续接收）

 

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3890.tmp.jpg) 

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3891.tmp.jpg) 

 

3、 订阅中断（订阅重启可继续接收）

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3892.tmp.jpg)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3893.tmp.jpg)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3894.tmp.jpg) 

 

容易出现下图卡死情况

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps38A5.tmp.jpg)



资料：https://docs.dapr.io/zh-hans/developing-applications/building-blocks/pubsub/

