# 消息队列

## RabbitMQ 

版本：3.8.8

### 1.简介

####  1.消息队列 

MQ(messagequeue)，从字面意思上看，本质是个队列，FIFO先入先出，只不过队列中存放的内容是message而已，还是一种跨进程的通信机制，用于上下游传递消息。在互联网架构中，MQ是一种非常常见的上下游“逻辑解耦+物理解耦”的消息通信服务。使用了MQ之后，消息发送上游只需要依赖MQ，不用依赖其他服务。

对消息队列进行技术选型时，需要通过以下指标衡量你所选择的消息队列，是否可以满足你的需求：

- **消息顺序**：发送到队列的消息，消费时是否可以保证消费的顺序，比如A先下单，B后下单，应该是A先去扣库存，B再去扣，顺序不能反。
- **消息路由**：根据路由规则，只订阅匹配路由规则的消息，比如有A/B两者规则的消息，消费者可以只订阅A消息，B消息不会消费。
- 消息可靠性：是否会存在丢消息的情况，比如有A/B两个消息，最后只有B消息能消费，A消息丢失。
- **消息时序**：主要包括“消息存活时间”和“延迟/预定的消息”，“消息存活时间”表示生产者可以对消息设置TTL，如果超过该TTL，消息会自动消失；“延迟/预定的消息”指的是可以延迟或者预订消费消息，比如延时5分钟，那么消息会5分钟后才能让消费者消费，时间未到的话，是不能消费的。
- **消息留存**：消息消费成功后，是否还会继续保留在消息队列。
- **容错性**：当一条消息消费失败后，是否有一些机制，保证这条消息是一种能成功，比如异步第三方退款消息，需要保证这条消息消费掉，才能确定给用户退款成功，所以必须保证这条消息消费成功的准确性。
- **伸缩**：当消息队列性能有问题，比如消费太慢，是否可以快速支持库容；当消费队列过多，浪费系统资源，是否可以支持缩容。
- **吞吐量**：支持的最高并发数。







###  2.功能 



####  2.1.流量削峰 

在高流量的情况下，消息队列可以作为一个缓冲的中间件，将高峰的流量消息存入消息队列中，直接返回结果，然后慢慢处理消息队列里面的数据。这样可以防止短时间内有大量的请求访问服务器，极大的缓解了服务器的压力，达到了流量削峰的效果。

####  2.2.耦合 

指的是当你实现某个功能的时候（例如A发消息给B，或者A有任务要调用B去执行），直接调用需要的接口。而消息队列则是将相应的消息或任务存入消息队列中，即使其中一个接口出现问题，也不会影响另一方的功能使用。

![img](https://xiaosu.yuque.com/api/filetransfer/images?url=https%3A%2F%2Ffigure-bed-1304788733.cos.ap-guangzhou.myqcloud.com%2Ftypora%2F202204171546883.png&sign=f17ceb30bb716be61188f704114d2205b0a8c9357f1f948ea55fa2e453f33491)

###### 降低系统耦合性

举个例子，A公司做了某个系统，B公司觉得A公司的某个功能很好，于是B公司和A公司的系统进行了集成。这时C公司也觉得A公司的这个功能很好，于是，C公司也和A公司的系统进行了集成。以后还有D公司…。

介于这种情况，A公司的系统和其他公司的耦合度都很高，每集成一个公司的系统，A公司都需要修改自己的系统。如果采用消息队列，则变成了如下：

![图片](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202210121054018.png)

不管以后还有多少公司的应用程序想要用A公司的程序，都不需要和A公司进行集成，谁需要这个功能，谁就去消息队列里面获取。







#### 2.3 异步处理 

不同于传统的同步处理，不需要等消息处理完才返回处理结果，而是先返回处理结果，再由消息对应的处理接口从队列中拉取消息进行处理（消费）。

![img](https://xiaosu.yuque.com/api/filetransfer/images?url=https%3A%2F%2Ffigure-bed-1304788733.cos.ap-guangzhou.myqcloud.com%2Ftypora%2F202204171546990.png&sign=22ded5a259ecdeb1f8caaea646945e23bf16f98680a15ba808fbb9798a2b06a5)

###  3.MQ分类 



####  3.1 ActiveMQ 



●优点：单机吞吐量万级，时效性 ms 级，可用性高，基于主从架构实现高可用性，消息可靠性较 低的概率丢失数据

●缺点:官方社区现在对 ActiveMQ 5.x 维护越来越少，高吞吐量场景较少使用。



####  3.2 Kafka 



大数据的杀手锏，谈到大数据领域内的消息传输，则绕不开 Kafka，这款为大数据而生的消息中间件， 以其百万级 TPS 的吞吐量名声大噪，迅速成为大数据领域的宠儿，在数据采集、传输、存储的过程中发挥 着举足轻重的作用。目前已经被 LinkedIn，Uber, Twitter, Netflix 等大公司所采纳。



●优点：单机吞吐量十万级，可用性非常高，分布式架构,消息可以做到 0 丢失,MQ 功能较为完善，还是分布式的，扩展性好,支持 10 亿级别的消息堆积，不会因为堆积导致性能下降,源码是 java 我们可以自己阅读源码，定制自己公司的 MQ

●缺点：支持的客户端语言不多，目前是 java 及 c++，其中 c++不成熟；社区活跃度一般,没有在MQ 核心中去实现 JMS 等接口,有些系统要迁移需要修改大量代码



####  3.3 RabbitMQ 



2007 年发布，是一个在AMQP(高级消息队列协议)基础上完成的，可复用的企业消息系统，是当前最主流的消息中间件之一。



●优点：由于 erlang 语言的高并发特性，性能较好；吞吐量到万级，MQ 功能比较完备,健壮、稳定、易 用、跨平台、支持多种语言 如：Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP 等，支持 AJAX 文档齐全；开源提供的管理界面非常棒，用起来很好用,社区活跃度高；更新频率相当高

●缺点：商业版需要收费,学习成本较高



####  3.4 RocketMQ 



RocketMQ 出自阿里巴巴的开源产品，用 Java 语言实现，在设计时参考了 Kafka，并做出了自己的一些改进。被阿里巴巴广泛应用在订单，交易，充值，流计算，消息推送，日志流式处理，binglog 分发等场 景。



● 优点：单机吞吐量十万级,可用性非常高，分布式架构,消息可以做到 0 丢失,MQ 功能较为完善，还是分布式的，扩展性好,支持 10 亿级别的消息堆积，不会因为堆积导致性能下降,源码是 java 我们可以自己阅读源码，定制自己公司的 MQ 

● 缺点:支持的客户端语言不多，目前是 java 及 c++，其中 c++不成熟；社区活跃度一般,没有在 MQ 核心中去实现 JMS 等接口,有些系统要迁移需要修改大量代码 



###  4.RabbitMQ 的概念 



RabbitMQ 是一个消息中间件：它接受并转发消息。你可以把它当做一个快递站点，当你要发送一个包裹时，你把你的包裹放到快递站，快递员最终会把你的快递送到收件人那里，按照这种逻辑 RabbitMQ 是一个快递站，一个快递员帮你传递快件。RabbitMQ 与快递站的主要区别在于，它不处理快件而是接收，存储和转发消息数据。



####  4.1 四大核心概念 



● 生产者 产生数据发送消息的程序是生产者 

● 交换机 交换机是 RabbitMQ 非常重要的一个部件，一方面它接收来自生产者的消息，另一方面它将消息推送到队列中。交换机必须确切知道如何处理它接收到的消息，是将这些消息推送到特定队列还是推送到多个队列，亦或者是把消息丢弃，这个得有交换机类型决定 

● 队列 队列是 RabbitMQ 内部使用的一种数据结构，尽管消息流经 RabbitMQ 和应用程序，但它们只能存储在队列中。队列仅受主机的内存和磁盘限制的约束，本质上是一个大的消息缓冲区。许多生产者可以将消息发送到一个队列，许多消费者可以尝试从一个队列接收数据。这就是我们使用队列的方式 

● 消费者 消费与接收具有相似的含义。消费者大多时候是一个等待接收消息的程序。请注意生产者，消费者和消息中间件很多时候并不在同一机器上。同一个应用程序既可以是生产者又是可以是消费者。 



####  4.2 RabbitMQ 核心部分 

![img](https://xiaosu.yuque.com/api/filetransfer/images?url=https%3A%2F%2Ffigure-bed-1304788733.cos.ap-guangzhou.myqcloud.com%2Ftypora%2F202204171558954.png&sign=92c7f702c4910dab404d12c2842c79cb1f0d3fc02cd2abd20d8f071e0aa6ce0b)

####  4.3 各个名词介绍 

![img](https://xiaosu.yuque.com/api/filetransfer/images?url=https%3A%2F%2Ffigure-bed-1304788733.cos.ap-guangzhou.myqcloud.com%2Ftypora%2F202204171558675.png&sign=b339ecd8875ff05cd4216634471c895f08ef06f83143aa9b2090360ea57cd1ad)

AMQP 协议模型由三部分组成：生产者、消费者和服务端，执行流程如下：

1. 生产者是连接到 Server，建立一个连接，开启一个信道。
2. 生产者声明交换器和队列，设置相关属性，并通过路由键将交换器和队列进行绑定。
3. 消费者也需要进行建立连接，开启信道等操作，便于接收消息。
4. 生产者发送消息，发送到服务端中的虚拟主机。
5. 虚拟主机中的交换器根据路由键选择路由规则，发送到不同的消息队列中。
6. 订阅了消息队列的消费者就可以获取到消息，进行消费。





###  注意 

rabbitmq对主机名要求严格，因为rabbitmq的主题是绑定主机名的，千万不要乱改，设置好后就不要动，依赖erlang编程语言，所以需要erlang环境。

官网有提供yum仓库下载，可是没有centos7的，所以建议还是直接去官方找到旧版本链接下载需要的版本

●rabbitmq[官网](https://www.rabbitmq.com/)

●rabbitmq[所有版本下载](https://github.com/rabbitmq/rabbitmq-server/tags)

●rabbitmq环境依赖([erlang](https://github.com/rabbitmq/erlang-rpm/tags))

●erlang官网：https://www.erlang.org/



###  本地安装 

采用的是rabbitmq3.8.8和erlang23.3.4

####  1.解压安装 

上传rabbitmq与依赖到/opt/

```
[root@rb-mq1 opt]# yum -y install esl-erlang_23.3.4.5-1_centos_7_amd64.rpm
[root@rb-mq1 opt]# yum -y install rabbitmq-server-3.8.8-1.el7.noarch.rpm
```

####  2.启动rabbitmq 

```
[root@rb-mq1 opt]# systemctl start rabbitmq-server
[root@rb-mq1 opt]# systemctl status rabbitmq-server
```

报错：

[root@rabbitmq1 opt]# rabbitmq-plugins enable rabbitmq_management
{:query, :rabbit@rabbitmq1, {:badrpc, :timeout}}

没有填写/etc/hosts文件



```
# 因为有个插件还没开，所以少一个15672
[root@rabbitmq1 opt]# netstat -atpl |grep 15672				#管理页面端口
[root@rabbitmq1 opt]# netstat -atpl |grep 25672
tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      1401/beam.smp
[root@rabbitmq1 rabbitmq]# netstat -anpl|grep 4369			#rabbitmq默认端口
tcp        0      0 0.0.0.0:4369            0.0.0.0:*               LISTEN      1723/epmd 
```

####  3.启动插件 

官网插件文档：https://www.rabbitmq.com/plugins.html

```
[root@rb-mq1 opt]# rabbitmq-plugins list   # 查询插件开启状态，开启中括号里面有标识
Listing plugins with pattern ".*" ...
 Configured: E = explicitly enabled; e = implicitly enabled
 | Status: * = running on rabbit@rb-mq1
 |/
[  ] rabbitmq_amqp1_0                  3.8.8
[  ] rabbitmq_auth_backend_cache       3.8.8
[  ] rabbitmq_auth_backend_http        3.8.8
[  ] rabbitmq_auth_backend_ldap        3.8.8
[  ] rabbitmq_auth_backend_oauth2      3.8.8
[  ] rabbitmq_auth_mechanism_ssl       3.8.8
[  ] rabbitmq_consistent_hash_exchange 3.8.8
[  ] rabbitmq_event_exchange           3.8.8
[  ] rabbitmq_federation               3.8.8
[  ] rabbitmq_federation_management    3.8.8
[  ] rabbitmq_jms_topic_exchange       3.8.8
[  ] rabbitmq_management               3.8.8
[  ] rabbitmq_management_agent         3.8.8
[  ] rabbitmq_mqtt                     3.8.8
[  ] rabbitmq_peer_discovery_aws       3.8.8
[  ] rabbitmq_peer_discovery_common    3.8.8
[  ] rabbitmq_peer_discovery_consul    3.8.8
[  ] rabbitmq_peer_discovery_etcd      3.8.8
[  ] rabbitmq_peer_discovery_k8s       3.8.8
[  ] rabbitmq_prometheus               3.8.8
[  ] rabbitmq_random_exchange          3.8.8
[  ] rabbitmq_recent_history_exchange  3.8.8
[  ] rabbitmq_sharding                 3.8.8
[  ] rabbitmq_shovel                   3.8.8
[  ] rabbitmq_shovel_management        3.8.8
[  ] rabbitmq_stomp                    3.8.8
[  ] rabbitmq_top                      3.8.8
[  ] rabbitmq_tracing                  3.8.8
[  ] rabbitmq_trust_store              3.8.8
[  ] rabbitmq_web_dispatch             3.8.8
[  ] rabbitmq_web_mqtt                 3.8.8
[  ] rabbitmq_web_mqtt_examples        3.8.8
[  ] rabbitmq_web_stomp                3.8.8
[  ] rabbitmq_web_stomp_examples       3.8.8
```

```
[root@rb-mq1 opt]# rabbitmq-plugins enable rabbitmq_management   # 启动插件
Enabling plugins on node rabbit@rb-mq1:
rabbitmq_management
The following plugins have been configured:
  rabbitmq_management
  rabbitmq_management_agent
  rabbitmq_web_dispatch
Applying plugin configuration to rabbit@rb-mq1...
The following plugins have been enabled:
  rabbitmq_management
  rabbitmq_management_agent
  rabbitmq_web_dispatch

started 3 plugins.
```

```
# 此时再检查端口15672就出现了
[root@rb-mq1 opt]# netstat -aulntp | grep 15672
tcp        0      0 0.0.0.0:15672           0.0.0.0:*               LISTEN      10317/beam.smp
```

此时去浏览器输入ip:15672，如下图

![image-20220602141048650](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202206021410768.png)







默认账号密码是guest，但是没有权限远程登录，不安全，所以要创建用户



####  4.添加用户 

```
# 创建账号
[root@rb-mq1 opt]# rabbitmqctl add_user shy shy514,.   # rabbitmqctl add_user 账号 密码
Adding user "shy" ...
# 设置用户角色
[root@rb-mq1 opt]# rabbitmqctl set_user_tags shy administrator
Setting tags for user "shy" to [administrator] ...
```



####  5.登陆与赋权 

浏览器操作，如下图

![image-20220602142220013](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202206021422066.png)



![image-20220602142318079](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202206021423140.png)

![image-20220602142524617](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202206021425676.png)



命令行操作

```
# 设置用户权限： set_permissions [-p <vhostpath>] <user> <conf> <write> <read>（用户 user_admin 具有/vhost1 这个 virtual host 中所有资源的配置、写、读权限当前用户和角色）
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
# 当前用户和角色
rabbitmqctl list_users
```

```
# 添加一个新用户ssy，用命令行授权
[root@rb-mq1 opt]# rabbitmqctl add_user ssy ssy514,.
Adding user "ssy" ...
[root@rb-mq1 opt]# rabbitmqctl set_user_tags ssy administrator
Setting tags for user "ssy" to [administrator] ...
[root@rb-mq1 opt]# rabbitmqctl set_permissions -p "/" ssy ".*" ".*" ".*"
Setting permissions for user "ssy" in vhost "/" ...
[root@rb-mq1 opt]# rabbitmqctl list_users
Listing users ...
user	tags
shy	[administrator]
ssy	[administrator]
guest	[administrator]
```

###  集群搭建 

####  实验环境 

| 主机名 | ip              |
| ------ | --------------- |
| rb-mq1 | 192.168.245.175 |
| rb-mq2 | 192.168.245.176 |
| rb-mq3 | 192.168.245.177 |



####  1.修改hosts

```
[root@rb-mq1 opt]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.245.175 rb-mq1
192.168.245.176 rb-mq2
192.168.245.177 rb-mq3

[root@rb-mq1 opt]# scp /etc/hosts 192.168.245.176:/etc/hosts
[root@rb-mq1 opt]# scp /etc/hosts 192.168.245.177:/etc/hosts
```



####  2.在其余机子安装rabbitmq与依赖 

```
yum -y install esl-erlang_23.3.4.5-1_centos_7_amd64.rpm
yum -y install rabbitmq-server-3.8.8-1.el7.noarch.rpm
```



####  3.配置主机名解析 

在其中一台服务器同步.erlang.cookie至其他两台服务器

```
[root@rb-mq1 opt]# cd /var/lib/rabbitmq/
[root@rb-mq1 rabbitmq]# ls -a
.  ..  .erlang.cookie  mnesia
[root@rb-mq1 rabbitmq]# cat .erlang.cookie 
SRXJHYYWQTKEJJLWVOPZ
[root@rb-mq1 rabbitmq]# pwd
/var/lib/rabbitmq
[root@rb-mq1 rabbitmq]#
```

```
[root@rb-mq1 rabbitmq]# scp .erlang.cookie 192.168.245.176:/var/lib/rabbitmq/
root@192.168.245.176's password: 
.erlang.cookie                                        100%   20    16.3KB/s   00:00    
[root@rb-mq1 rabbitmq]# scp .erlang.cookie 192.168.245.177:/var/lib/rabbitmq/
root@192.168.245.177's password: 
.erlang.cookie                                        100%   20    29.4KB/s   00:00
```

```
# 如果其它机器有权限则无需操作			
[root@rb-mq2 rabbitmq]# chown rabbitmq.rabbitmq /var/lib/rabbitmq/.erlang.cookie

[root@rb-mq3 rabbitmq]# chown rabbitmq.rabbitmq /var/lib/rabbitmq/.erlang.cookie
```



####  4.启动 

```
# 所有机子都操作启动服务与插件
systemctl start rabbitmq-server
rabbitmq-plugins enable rabbitmq_management
```





####  5.确定谁是ram节点谁是磁盘节点

在RabbitMQ集群中的节点只有两种类型：内存节点/磁盘节点，单节点系统只运行磁盘类型的节点。而在集群中，可以选择配置部分节点为内存节点。


内存节点将所有的队列，交换器，绑定关系，用户，权限，和元数据信息保存在内存中。

磁盘节点将这些信息保存在磁盘中，但是内存节点的性能更高，为了保证集群的高可用性，必须保证集群中有两个以上的磁盘节点，来保证当有一个磁盘节点崩溃了，集群还能对外提供访问服务。在上面的操作中，可以通过如下的方式，设置新加入的节点为内存节点还是磁盘节点。


这里以rb-mq3为磁盘节点其他都为内存节点

```shell
# 在内存节点上停止app服务
[root@rb-mq1 rabbitmq]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rb-mq1 ...
# 磁盘不存东西，清空
[root@rb-mq1 rabbitmq]# rabbitmqctl reset
Resetting node rabbit@rb-mq1 ...
[root@rb-mq1 rabbitmq]# rabbitmqctl join_cluster rabbit@rb-mq3 --ram   # 添加ram角色
Clustering node rabbit@rb-mq1 with rabbit@rb-mq3
[root@rb-mq1 rabbitmq]# rabbitmqctl start_app
Starting node rabbit@rb-mq1 ...


# rb-mq2
[root@rb-mq2 rabbitmq]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@rb-mq2 ...
[root@rb-mq2 rabbitmq]# rabbitmqctl reset
Resetting node rabbit@rb-mq2 ...
[root@rb-mq2 rabbitmq]# rabbitmqctl join_cluster rabbit@rb-mq3 --ram
Clustering node rabbit@rb-mq2 with rabbit@rb-mq3
[root@rb-mq2 rabbitmq]# rabbitmqctl start_app
Starting node rabbit@rb-mq2 ...
```

```
# 查看集群状态
rabbitmqctl cluster_status
```



####  6.重新添加用户 

```
[root@rb-mq1 rabbitmq]# rabbitmqctl add_user shy shy514,.
Adding user "shy" ...
[root@rb-mq1 rabbitmq]# rabbitmqctl set_user_tags shy administrator
Setting tags for user "shy" to [administrator] ...
[root@rb-mq1 rabbitmq]# rabbitmqctl set_permissions -p "/" shy ".*" ".*" ".*"
Setting permissions for user "shy" in vhost "/" ...
[root@rb-mq1 rabbitmq]# rabbitmqctl list_users
Listing users ...
user	tags
shy	[administrator]
guest	[administrator]
```





####  7.浏览器查看 

![image-20220602150811092](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202206021508176.png)





####  8.开机自启 

```
systemctl enable rabbitmq-server
```

####  9.缺点 

ram节点会同步元数据给磁盘节点，原始数据没有同步。所以一般不采用默认模式，采取同步所有数据模式

```
rabbitmqctl set_policy ha-all "#" '{"ha-mode":"all"}'   # 将集群设置为镜像模式
```

##  10.压力测试 

https://blog.51cto.com/fengwan/5184502

### 1.电脑安装jdk 1.8 ( https://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html)

略！

### 2.电脑安装apache-ant ( https://dlcdn.apache.org//ant/binaries/apache-ant-1.9.16-bin.zip)

```
配置环境变量
window中设置ant环境变量：
ANT_HOME     C:\Users\lin\Desktop\apache-ant-1.9.16
path         C:\Users\lin\Desktop\apache-ant-1.9.16/bin
classpath    C:\Users\lin\Desktop\apache-ant-1.9.16/lib
```

![image-20221012204421358](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122044412.png)

```
验证ant
为了验证ant是否成功安装，可以进行如下操作：
依次选择：开始->运行->cmd，输入如下命令：ant
如果出现如下内容，说明安装成功：
```

![image-20221012204311505](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122043543.png)

### 3.下载 RabbitMQ客户端插件amqp-client-3.4.4.jar（ https://repo1.maven.org/maven2/com/rabbitmq/amqp-client/3.4.4/amqp-client-3.4.4.jar）到源码目录

### 4.下载编译 JMeter-Rabbit-AMQP插件https://github.com/jlavallee/JMeter-Rabbit-AMQP

修改配置文件

修改源码里的build.xml，http改成https

修改build.xml里面ivy.install.version，2.3.0改成2.5.0

![image-20221012205004685](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122050801.png)

![image-20221012204851409](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122048456.png)

直接在所在目录，执行ant命令即可

![image-20221012205020933](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122050997.png)

### 5.下载JMeter

\1. 进入官网[Apache JMeter - Download Apache JMeter](http://jmeter.apache.org/download_jmeter.cgi)

\2. 选择操作系统所对应的版本进行下载。

![image-20221012203614241](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122036354.png)

将下载成功的压缩包解压到指定目录当中，

复制插件到jmeter目录

（1）把上面下载的amqp-client-3.4.4.jar复制到jmeter-5.5安装目录的lib\ext目录下

（2）把源码目录下target\dist目录下的JMeterAMQP.jar也复制到lib\ext目录下

![image-20221012203721617](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122037658.png)

即安装成功。

### 6.启动jmeter

![image-20221012203755460](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122037498.png)

出现两个窗口（cmd窗口不能关闭！）

![image-20221012203816989](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122038060.png)

### 7.压力测试

创建压力测试文件rabbitmq.jmx

```yml
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="RPC Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="rabbitmq" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">stoptest</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">8</stringProp>
        <stringProp name="ThreadGroup.ramp_time">15</stringProp>
        <longProp name="ThreadGroup.start_time">1361373100000</longProp>
        <longProp name="ThreadGroup.end_time">1361373100000</longProp>
        <boolProp name="ThreadGroup.scheduler">true</boolProp>
        <stringProp name="ThreadGroup.duration">60</stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
      </ThreadGroup>
      <hashTree>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Reply-To Queue Name" enabled="true">
          <stringProp name="maximumValue">999999999</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="outputFormat">000000000</stringProp>
          <boolProp name="perThread">false</boolProp>
          <stringProp name="randomSeed"></stringProp>
          <stringProp name="variableName">replyToQueue</stringProp>
        </RandomVariableConfig>
        <hashTree/>
        <RandomVariableConfig guiclass="TestBeanGUI" testclass="RandomVariableConfig" testname="Unique ID" enabled="true">
          <stringProp name="variableName">uniqueId</stringProp>
          <stringProp name="outputFormat">0000000</stringProp>
          <stringProp name="minimumValue">1</stringProp>
          <stringProp name="maximumValue">9999999</stringProp>
          <stringProp name="randomSeed">3499272</stringProp>
          <boolProp name="perThread">false</boolProp>
        </RandomVariableConfig>
        <hashTree/>
        <TransactionController guiclass="TransactionControllerGui" testclass="TransactionController" testname="RPC Endpoint" enabled="true">
          <boolProp name="TransactionController.parent">true</boolProp>
          <boolProp name="TransactionController.includeTimers">false</boolProp>
        </TransactionController>
        <hashTree>
          <com.zeroclue.jmeter.protocol.amqp.AMQPPublisher guiclass="com.zeroclue.jmeter.protocol.amqp.gui.AMQPPublisherGui" testclass="com.zeroclue.jmeter.protocol.amqp.AMQPPublisher" testname="RPC Request" enabled="true">
            <stringProp name="AMQPSampler.Exchange">my_rpc_exchange</stringProp>
            <boolProp name="AMQPSampler.ExchangeDurable">false</boolProp>
            <boolProp name="AMQPSampler.ExchangeAutoDelete">false</boolProp>
            <boolProp name="AMQPSampler.ExchangeRedeclare">false</boolProp>
            <stringProp name="AMQPSampler.Queue">RPCRequestQueue</stringProp>
            <stringProp name="AMQPSampler.RoutingKey">RPCMessage.Request.v1_0</stringProp>
            <stringProp name="AMQPSampler.VirtualHost">/</stringProp>
            <stringProp name="AMQPSampler.MessageTTL"></stringProp>
            <stringProp name="AMQPSampler.MessageExpires"></stringProp>
            <stringProp name="AMQPSampler.ExchangeType">direct</stringProp>
            <stringProp name="AMQPSampler.QueueDurable">true</stringProp>
            <stringProp name="AMQPSampler.QueueExclusive">false</stringProp>
            <stringProp name="AMQPSampler.QueueAutoDelete">false</stringProp>
            <boolProp name="AMQPSampler.Redeclare">false</boolProp>
            <stringProp name="AMQPSampler.Timeout">1000</stringProp>
            <stringProp name="AMQPSampler.Iterations">1</stringProp>
            <stringProp name="AMQPSampler.Host">192.168.110.175</stringProp>
            <stringProp name="AMQPSampler.Port">5672</stringProp>
            <stringProp name="AMQPSampler.Username">yhl</stringProp>
            <stringProp name="AMQPSampler.Password">yhl123456</stringProp>
            <stringProp name="AMQPSampler.SSL">false</stringProp>
            <boolProp name="AMQPPublisher.Persistent">false</boolProp>
            <boolProp name="AMQPPublisher.UseTx">false</boolProp>
            <stringProp name="AMQPPublisher.MessageRoutingKey">RPCMessage.Request.v1_0</stringProp>
            <stringProp name="AMQPPublisher.Message">{
        &quot;RequestMessageText&quot;: &apos;${uniqueId}&apos;
}</stringProp>
            <stringProp name="AMQPPublisher.MessageType">RPCMessageRequest</stringProp>
            <stringProp name="AMQPPublisher.ReplyToQueue">jMeter_${__threadNum}_${replyToQueue}</stringProp>
            <stringProp name="AMQPPublisher.CorrelationId">${uniqueId}</stringProp>
            <stringProp name="AMQPPublisher.ContentType"></stringProp>
            <stringProp name="AMQPPublisher.MessageId"></stringProp>
            <elementProp name="AMQPPublisher.Headers" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
              <collectionProp name="Arguments.arguments"/>
            </elementProp>
          </com.zeroclue.jmeter.protocol.amqp.AMQPPublisher>
          <hashTree/>
          <com.zeroclue.jmeter.protocol.amqp.AMQPConsumer guiclass="com.zeroclue.jmeter.protocol.amqp.gui.AMQPConsumerGui" testclass="com.zeroclue.jmeter.protocol.amqp.AMQPConsumer" testname="RPC Response" enabled="true">
            <stringProp name="AMQPSampler.Exchange">my_rpc_exchange</stringProp>
            <boolProp name="AMQPSampler.ExchangeDurable">false</boolProp>
            <boolProp name="AMQPSampler.ExchangeAutoDelete">false</boolProp>
            <boolProp name="AMQPSampler.ExchangeRedeclare">false</boolProp>
            <stringProp name="AMQPSampler.Queue">jMeter_${__threadNum}_${replyToQueue}</stringProp>
            <stringProp name="AMQPSampler.RoutingKey">RPCMessage.Request.v1_0</stringProp>
            <stringProp name="AMQPSampler.VirtualHost">/</stringProp>
            <stringProp name="AMQPSampler.MessageTTL"></stringProp>
            <stringProp name="AMQPSampler.MessageExpires"></stringProp>
            <stringProp name="AMQPSampler.ExchangeType">direct</stringProp>
            <stringProp name="AMQPSampler.QueueDurable">false</stringProp>
            <stringProp name="AMQPSampler.QueueExclusive">true</stringProp>
            <stringProp name="AMQPSampler.QueueAutoDelete">true</stringProp>
            <boolProp name="AMQPSampler.Redeclare">false</boolProp>
            <stringProp name="AMQPSampler.Timeout">1000</stringProp>
            <stringProp name="AMQPSampler.Iterations">1</stringProp>
            <stringProp name="AMQPSampler.Host">10.254.219.27</stringProp>
            <stringProp name="AMQPSampler.Port">5672</stringProp>
            <stringProp name="AMQPSampler.Username">guest</stringProp>
            <stringProp name="AMQPSampler.Password">guest</stringProp>
            <stringProp name="AMQPSampler.SSL">false</stringProp>
            <boolProp name="AMQPConsumer.ReadResponse">false</boolProp>
            <stringProp name="AMQPConsumer.PrefetchCount">0</stringProp>
            <stringProp name="AMQPConsumer.ReceiveTimeout">10000</stringProp>
            <stringProp name="AMQPConsumer.PurgeQueue">false</stringProp>
            <stringProp name="AMQPConsumer.AutoAck">true</stringProp>
            <boolProp name="AMQPConsumer.UseTx">false</boolProp>
          </com.zeroclue.jmeter.protocol.amqp.AMQPConsumer>
          <hashTree/>
        </hashTree>
        <ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" enabled="true">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>false</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Respones" enabled="true">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>false</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>
```

选择"文件"/“打开”，在bin目录下，打开"AMQP Publisher.jmx"这个测试计划

![image-20221012204041074](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122040132.png)

进行生产者测试： 启用AMQP_publihser取样器，禁用AMQP_Consumer，按照下图，修改对应信息为实际信息

![image-20221012204106687](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122041757.png)

![image-20221012204122787](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122041854.png)

启动测试，可以在"察看结果树"中，看到接口的测试情况；可以在聚合报告中，看到压力测试峰值等信息

![image-20221012204143974](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122041035.png)



![image-20221012203420386](https://ye5201314-1312898079.cos.ap-guangzhou.myqcloud.com/202210122046435.png)

