集群环境-负载均衡完成;

This commit is contained in:
bunny 2025-05-20 11:07:36 +08:00
parent f1e7394450
commit 6fcf7a4b75
10 changed files with 704 additions and 32 deletions

View File

@ -615,6 +615,8 @@ void buildExchangeOverflowTest() {
>
> - 最大延迟时间:**2天48小时**
> - 必须匹配RabbitMQ版本
>
> **插件版本必须与RabbitMQ严格匹配如3.13.x需使用v3.13.x插件。**
#### 1、确认docker数据卷
@ -746,8 +748,8 @@ try {
---
### **2. 生产环境推荐方案**
#### **1Confirm 模式(轻量级确认)**
### 生产环境推荐方案
#### 1Confirm 模式(轻量级确认)
- **原理**:异步确认消息是否成功到达 Broker。
- **配置方式**
```java
@ -763,14 +765,14 @@ try {
```
- **优点**:性能接近非事务模式,可靠性高。
#### **2消息补偿 + 幂等设计**
#### 2消息补偿 + 幂等设计
- **步骤**
1. 消息表记录发送状态(如 `status: sending/success/fail`)。
2. 定时任务补偿失败消息。
3. 消费者端做幂等处理(如唯一 ID + 去重表)。
- **适用场景**:订单支付、库存扣减等关键业务。
#### **3本地消息表最终一致性**
#### 3本地消息表最终一致性
```mermaid
sequenceDiagram
participant App
@ -852,6 +854,8 @@ channel.queueDeclare("myLazyQueue", true, false, false, args);
## 优先级队列
**优先级仅在消息堆积时生效(空队列时无意义)**
**优先级范围**
- 通过 `x-max-priority` 参数定义队列支持的最大优先级默认0=无优先级)
@ -949,6 +953,8 @@ public void processMessagePriority(String dataString, Channel channel, Message m
> [!IMPORTANT]
>
> 如果需要修改记得修改网关和IP地址。
>
> 节点间端口要求如4369/25672需互通避免防火墙问题.。
看自己是否有这个需求。
@ -1014,7 +1020,6 @@ sudo systemctl daemon-reload && sudo systemctl restart docker
> # 3. 重建目录并设置权限
> mkdir -p ~/docker/docker_data/rabbitmq/{rabbit1,rabbit2,rabbit3}/{data,conf,log}
> sudo chown -R 999:999 ~/docker/docker_data/rabbitmq
> sudo chmod -R 775 ~/docker/docker_data/rabbitmq
>
> # 4. 重新启动
> docker compose up -d
@ -1253,6 +1258,14 @@ sudo vim /etc/hosts
#### 3、设置Erlang Cookie
> [!IMPORTANT]
>
> 普通方式搭建集群时,`.erlang.cookie`的权限必须为`400`
>
> ```bash
> sudo chmod 400 /var/lib/rabbitmq/.erlang.cookie
> ```
RabbitMQ节点使用Erlang cookie进行认证所有节点必须使用相同的cookie。
如果是克隆的虚拟机,可以不检查(最好还是检查下),因为克隆的基本上是一样的。
@ -1270,8 +1283,8 @@ sudo systemctl stop rabbitmq-server
sudo nano /var/lib/rabbitmq/.erlang.cookie
# 粘贴主节点的cookie内容
# 然后设置正确的权限
sudo chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie
# 然后设置正确的权限
sudo chmod 400 /var/lib/rabbitmq/.erlang.cookie
# 重新启动RabbitMQ服务
@ -1353,6 +1366,14 @@ sudo rabbitmqctl status
- 如果需要Web管理界面
> [!IMPORTANT]
>
> 如果使用Web界面需要在每个集群上都执行一下否则情况会出现下面情况举个例子。
>
> 如果在主节点上执行那么主节点可以访问之后输入账户密码登录之后可以看到主节点的情况但是其余节点会出现【Node statistics not available】。
>
> 为了避免这种情况,要在每个节点上都执行一下下面的命令。
```bash
sudo rabbitmq-plugins enable rabbitmq_management
```
@ -1470,26 +1491,26 @@ sudo cat /var/lib/rabbitmq/.erlang.cookie
1. 停止 RabbitMQ
```
```bash
sudo systemctl stop rabbitmq-server
```
2. 修改 Cookie复制主节点的 Cookie 到其他节点):
```
```bash
echo "YOUR_MASTER_NODE_COOKIE" | sudo tee /var/lib/rabbitmq/.erlang.cookie
```
3. 设置权限:
```
```bash
sudo chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie
sudo chmod 400 /var/lib/rabbitmq/.erlang.cookie
```
4. 重启 RabbitMQ
```
```bash
sudo systemctl start rabbitmq-server
```
@ -1501,14 +1522,14 @@ sudo cat /var/lib/rabbitmq/.erlang.cookie
确保用户在所有节点都有 **管理员权限**
```
```bash
sudo rabbitmqctl set_user_tags <username> administrator
sudo rabbitmqctl set_permissions -p / <username> ".*" ".*" ".*"
```
例如:
```
```bash
sudo rabbitmqctl set_user_tags admin administrator
sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
```
@ -1516,3 +1537,111 @@ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
**情况五 管理界面缓存问题**
浏览器可能缓存了旧数据,导致显示异常。
### 集群环境-负载均衡
#### 1. 安装 HAProxy
```bash
sudo apt update
sudo apt install haproxy -y
```
#### 2. 配置 HAProxy
编辑 HAProxy 的配置文件 `/etc/haproxy/haproxy.cfg`
```bash
sudo vim /etc/haproxy/haproxy.cfg
```
添加以下内容(假设 RabbitMQ 节点为 `rabbit1:5672``rabbit2:5672`
> [!IMPORTANT]
>
> 绑定的端口号(`bind *:`)不能重复!!!
```ini
frontend rabbitmq_front
bind *:22222
mode tcp
default_backend rabbitmq_back
backend rabbitmq_back
mode tcp
balance roundrobin
# 在之前设置了hosts文件所以这里没有写端口号 == server rabbit1 192.168.3.144:5672 check
server rabbit1 rabbit1:5672 check
server rabbit2 rabbit2:5672 check
server rabbit3 rabbit3:5672 check
server rabbit4 rabbit4:5672 check
# 可选:启用 RabbitMQ 管理界面的负载均衡(默认端口 15672
frontend rabbitmq_admin
bind *:12222
mode http
default_backend rabbitmq_admin_back
backend rabbitmq_admin_back
mode http
balance roundrobin
# 在之前设置了hosts文件所以这里没有写端口号 == server rabbit1 192.168.3.144:15672 check
server rabbit1 rabbit1:15672 check
server rabbit2 rabbit2:15672 check
server rabbit3 rabbit3:15672 check
server rabbit4 rabbit4:15672 check
```
#### 3. 重启 HAProxy
> [!TIP]
>
> 重启报错可以看下报错内容: journalctl -xeu haproxy.service
>
> 如果使用一些远程软件修改时可能会出现多行配置变一行问题需要手动通过vim查看。
```bash
sudo systemctl restart haproxy
```
### 集群环境的连接
> [!NOTE]
>
> 如果是新建环境,需要将之前写的监听内容注释,否则启动容易报错。
使用Java程序进行连接。如果搭建了集群环境还配置了负载均衡就是用负载均衡的方式进行连接。
负载均衡配置的是端口是:`5672`对应上面的文件是`22222`。所以在连接时候是`22222`这个 端口参考【2. 配置 HAProxy】
#### Java配置
```yaml
# application.yaml
rabbitmq:
host: ${bunny.rabbitmq.host}
port: ${bunny.rabbitmq.port}
username: ${bunny.rabbitmq.username}
password: ${bunny.rabbitmq.password}
virtual-host: ${bunny.rabbitmq.virtual-host}
# application-dev.yaml
bunny:
rabbitmq:
host: 192.168.3.144
# port: 5672
# 集群环境的端口号
port: 22222
virtual-host: /
username: admin
password: admin
```
#### 创建环境
**交换机:**exchange.cluster.test
![image-20250520105125396](./images/image-20250520105125396.png)
**队列:**queue.cluster.test
![image-20250520105109623](./images/image-20250520105109623.png)
**路由键:**routing.key.cluster.test
![image-20250520105149567](./images/image-20250520105149567.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,20 @@
package cn.bunny.mq.mqdemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping
public class IndexController {
@GetMapping("")
public String index() {
return "index";
}
@GetMapping("dialog")
public String dialog() {
return "dialog";
}
}

View File

@ -0,0 +1,25 @@
package cn.bunny.mq.mqdemo.mq.listener;
import com.rabbitmq.client.Channel;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
@Slf4j
public class ClusterEnvironmentListener {
@Resource
private RabbitTemplate rabbitTemplate;
/* 测试优先级队列 */
@RabbitListener(queues = "queue.cluster.test")
public void processMessagePriority(String dataString, Channel channel, Message message) throws IOException, InterruptedException {
log.info("<<集群环境下消息>>----<cluster>{}", dataString);
}
}

View File

@ -1,15 +1,8 @@
package cn.bunny.mq.mqdemo.mq.listener;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
@Slf4j
public class MessageListenerOrder {
@ -81,17 +74,17 @@ public class MessageListenerOrder {
// channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
// }
/* 测试延迟消息 */
@RabbitListener(queues = "queue.test.delay")
public void processMessageDelay(String dataString, Channel channel, Message message) throws IOException, InterruptedException {
log.info("<延迟消息>----消息本身{}", dataString);
log.info("<延迟消息>----当前时间{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
/* 测试优先级队列 */
@RabbitListener(queues = "queue.test.priority")
public void processMessagePriority(String dataString, Channel channel, Message message) throws IOException, InterruptedException {
log.info("<<优先级队列>>----<priority>{}", dataString);
}
// /* 测试延迟消息 */
// @RabbitListener(queues = "queue.test.delay")
// public void processMessageDelay(String dataString, Channel channel, Message message) throws IOException, InterruptedException {
// log.info("<延迟消息>----消息本身{}", dataString);
// log.info("<延迟消息>----当前时间{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// }
//
// /* 测试优先级队列 */
// @RabbitListener(queues = "queue.test.priority")
// public void processMessagePriority(String dataString, Channel channel, Message message) throws IOException, InterruptedException {
// log.info("<<优先级队列>>----<priority>{}", dataString);
// }
}

View File

@ -4,7 +4,9 @@ server:
bunny:
rabbitmq:
host: 192.168.3.144
port: 5672
# port: 5672
# 集群环境的端口号
port: 22222
virtual-host: /
username: admin
password: admin

View File

@ -0,0 +1,480 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>优雅的Bootstrap弹窗表单</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
:root {
--primary-color: #4e73df;
--secondary-color: #2e59d9;
--success-color: #1cc88a;
--danger-color: #e74a3b;
--light-color: #f8f9fc;
--dark-color: #5a5c69;
}
body {
font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f8f9fc;
}
/* 自定义弹窗样式 */
.custom-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1050;
overflow-y: auto;
}
.custom-modal-dialog {
max-width: 500px;
margin: 1.75rem auto;
transition: transform 0.3s ease-out;
}
.custom-modal-content {
border: none;
border-radius: 0.5rem;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
overflow: hidden;
}
.custom-modal-header {
padding: 1.5rem;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
position: relative;
}
.custom-modal-title {
font-weight: 700;
font-size: 1.25rem;
}
.btn-close-custom {
position: absolute;
top: 1rem;
right: 1rem;
font-size: 1.5rem;
color: rgba(255, 255, 255, 0.8);
background: none;
border: none;
cursor: pointer;
transition: color 0.2s;
}
.btn-close-custom:hover {
color: white;
}
.custom-modal-body {
padding: 1.5rem;
background-color: white;
}
.custom-modal-footer {
padding: 1rem 1.5rem;
background-color: var(--light-color);
border-top: 1px solid #e3e6f0;
display: flex;
justify-content: flex-end;
}
/* 表单样式 */
.form-label {
font-weight: 600;
color: var(--dark-color);
margin-bottom: 0.5rem;
}
.form-control-custom {
border: 1px solid #d1d3e2;
border-radius: 0.35rem;
padding: 0.75rem 1rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.form-control-custom:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
}
/* 验证样式 */
.is-invalid {
border-color: var(--danger-color);
}
.is-valid {
border-color: var(--success-color);
}
.invalid-feedback {
color: var(--danger-color);
font-size: 0.875rem;
margin-top: 0.25rem;
}
.valid-feedback {
color: var(--success-color);
font-size: 0.875rem;
margin-top: 0.25rem;
}
/* 按钮样式 */
.btn-primary-custom {
background-color: var(--primary-color);
border-color: var(--primary-color);
padding: 0.5rem 1.25rem;
font-weight: 600;
transition: all 0.2s;
}
.btn-primary-custom:hover {
background-color: var(--secondary-color);
border-color: var(--secondary-color);
transform: translateY(-1px);
}
.btn-outline-secondary-custom {
border-color: #d1d3e2;
color: var(--dark-color);
padding: 0.5rem 1.25rem;
font-weight: 600;
transition: all 0.2s;
}
.btn-outline-secondary-custom:hover {
background-color: #f8f9fc;
border-color: #d1d3e2;
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideInDown {
from {
transform: translateY(-50px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.modal-show {
display: block;
animation: fadeIn 0.3s;
}
.modal-show .custom-modal-dialog {
animation: slideInDown 0.3s;
}
/* 浮动标签效果 */
.form-floating-custom {
position: relative;
margin-bottom: 1.5rem;
}
.form-floating-custom label {
position: absolute;
top: 0.75rem;
left: 1rem;
color: #6e707e;
transition: all 0.2s;
pointer-events: none;
}
.form-floating-custom input:focus ~ label,
.form-floating-custom input:not(:placeholder-shown) ~ label {
top: -0.75rem;
left: 0.75rem;
font-size: 0.75rem;
background-color: white;
padding: 0 0.25rem;
color: var(--primary-color);
}
/* 密码强度指示器 */
.password-strength {
height: 4px;
background-color: #e3e6f0;
margin-top: 0.5rem;
border-radius: 2px;
overflow: hidden;
}
.password-strength-bar {
height: 100%;
width: 0;
transition: width 0.3s ease, background-color 0.3s ease;
}
</style>
</head>
<body>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8 text-center">
<h1 class="display-4 mb-4">优雅的Bootstrap弹窗示例</h1>
<p class="lead mb-5">点击下方按钮查看带有表单验证的现代化弹窗</p>
<button class="btn btn-primary btn-lg px-4 py-2" id="openModalBtn">
<i class="bi bi-box-arrow-in-down-right me-2"></i>打开注册弹窗
</button>
</div>
</div>
</div>
<!-- 自定义弹窗 -->
<div class="custom-modal" id="customModal">
<div class="custom-modal-dialog">
<div class="custom-modal-content">
<div class="custom-modal-header">
<h5 class="custom-modal-title">
<i class="bi bi-person-plus-fill me-2"></i>用户注册
</h5>
<button class="btn-close-custom" id="closeModalBtn" type="button">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="custom-modal-body">
<form id="registrationForm" novalidate>
<div class="form-floating-custom mb-4">
<input class="form-control form-control-custom" id="username" placeholder="用户名" required
type="text">
<label for="username">用户名</label>
<div class="invalid-feedback">请输入有效的用户名4-20个字符</div>
<div class="valid-feedback">用户名可用</div>
</div>
<div class="form-floating-custom mb-4">
<input class="form-control form-control-custom" id="email" placeholder="电子邮箱" required
type="email">
<label for="email">电子邮箱</label>
<div class="invalid-feedback">请输入有效的电子邮箱地址</div>
<div class="valid-feedback">邮箱格式正确</div>
</div>
<div class="form-floating-custom mb-4">
<input class="form-control form-control-custom" id="password" minlength="8" placeholder="密码"
required type="password">
<label for="password">密码</label>
<div class="invalid-feedback">密码至少需要8个字符</div>
<div class="password-strength">
<div class="password-strength-bar"></div>
</div>
</div>
<div class="form-floating-custom mb-4">
<input class="form-control form-control-custom" id="confirmPassword" placeholder="确认密码"
required type="password">
<label for="confirmPassword">确认密码</label>
<div class="invalid-feedback">密码不匹配</div>
</div>
<div class="mb-4">
<div class="form-check">
<input class="form-check-input" id="terms" required type="checkbox">
<label class="form-check-label" for="terms">
我已阅读并同意 <a class="text-primary" href="#">服务条款</a><a class="text-primary"
href="#">隐私政策</a>
</label>
<div class="invalid-feedback">必须同意条款才能继续</div>
</div>
</div>
</form>
</div>
<div class="custom-modal-footer">
<button class="btn btn-outline-secondary-custom me-2" id="cancelBtn" type="button">
取消
</button>
<button class="btn btn-primary-custom" id="submitBtn" type="button">
<i class="bi bi-check-lg me-1"></i> 提交注册
</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 弹窗控制
const modal = document.getElementById('customModal');
const openModalBtn = document.getElementById('openModalBtn');
const closeModalBtn = document.getElementById('closeModalBtn');
const cancelBtn = document.getElementById('cancelBtn');
const submitBtn = document.getElementById('submitBtn');
const form = document.getElementById('registrationForm');
// 打开弹窗
openModalBtn.addEventListener('click', () => {
modal.classList.add('modal-show');
document.body.style.overflow = 'hidden';
});
// 关闭弹窗
function closeModal() {
modal.classList.remove('modal-show');
document.body.style.overflow = 'auto';
form.reset();
resetValidation();
}
closeModalBtn.addEventListener('click', closeModal);
cancelBtn.addEventListener('click', closeModal);
// 点击弹窗外部关闭
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closeModal();
}
});
// 表单验证
function resetValidation() {
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
input.classList.remove('is-invalid', 'is-valid');
});
}
// 实时验证
form.addEventListener('input', (e) => {
const input = e.target;
validateInput(input);
// 密码强度检测
if (input.id === 'password') {
updatePasswordStrength(input.value);
}
// 确认密码验证
if (input.id === 'confirmPassword' || input.id === 'password') {
const password = document.getElementById('password').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (confirmPassword && password !== confirmPassword) {
document.getElementById('confirmPassword').classList.add('is-invalid');
document.getElementById('confirmPassword').classList.remove('is-valid');
} else if (confirmPassword) {
document.getElementById('confirmPassword').classList.add('is-valid');
document.getElementById('confirmPassword').classList.remove('is-invalid');
}
}
});
function validateInput(input) {
if (input.id === 'username') {
const isValid = input.value.length >= 4 && input.value.length <= 20;
updateValidationState(input, isValid);
} else if (input.id === 'email') {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const isValid = emailRegex.test(input.value);
updateValidationState(input, isValid);
} else if (input.id === 'password') {
const isValid = input.value.length >= 8;
updateValidationState(input, isValid);
} else if (input.id === 'terms') {
updateValidationState(input, input.checked);
}
}
function updateValidationState(input, isValid) {
if (input.value === '' && input.required) {
input.classList.remove('is-invalid', 'is-valid');
return;
}
if (isValid) {
input.classList.add('is-valid');
input.classList.remove('is-invalid');
} else {
input.classList.add('is-invalid');
input.classList.remove('is-valid');
}
}
// 密码强度检测
function updatePasswordStrength(password) {
const strengthBar = document.querySelector('.password-strength-bar');
let strength = 0;
// 长度检测
if (password.length >= 8) strength += 20;
if (password.length >= 12) strength += 20;
// 复杂度检测
if (/[A-Z]/.test(password)) strength += 20;
if (/[0-9]/.test(password)) strength += 20;
if (/[^A-Za-z0-9]/.test(password)) strength += 20;
// 更新UI
strengthBar.style.width = `${strength}%`;
if (strength < 40) {
strengthBar.style.backgroundColor = '#e74a3b'; // 红色
} else if (strength < 80) {
strengthBar.style.backgroundColor = '#f6c23e'; // 黄色
} else {
strengthBar.style.backgroundColor = '#1cc88a'; // 绿色
}
}
// 提交表单
submitBtn.addEventListener('click', () => {
let isValid = true;
const inputs = form.querySelectorAll('input[required]');
inputs.forEach(input => {
validateInput(input);
if (input.classList.contains('is-invalid')) {
isValid = false;
}
});
// 检查密码匹配
const password = document.getElementById('password').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (password !== confirmPassword) {
document.getElementById('confirmPassword').classList.add('is-invalid');
isValid = false;
}
if (isValid) {
// 模拟提交
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span> 提交中...';
submitBtn.disabled = true;
setTimeout(() => {
alert('注册成功!');
closeModal();
submitBtn.innerHTML = '<i class="bi bi-check-lg me-1"></i> 提交注册';
submitBtn.disabled = false;
}, 1500);
} else {
// 滚动到第一个错误
const firstInvalid = form.querySelector('.is-invalid');
if (firstInvalid) {
firstInvalid.scrollIntoView({behavior: 'smooth', block: 'center'});
}
}
});
</script>
</body>
</html>

View File

@ -0,0 +1,23 @@
package cn.bunny.mq.mqdemo;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ClusterEnvironmentTest {
@Autowired
private RabbitTemplate rabbitTemplate;
/* 集群环境下消息 */
@Test
void clusterTest() {
for (int i = 0; i <= 10; i++) {
rabbitTemplate.convertAndSend("exchange.cluster.test",
"routing.key.cluster.test",
"集群环境下消息-" + i);
}
}
}