diff --git a/mq-demo/ReadMe.md b/mq-demo/ReadMe.md index 5f631d3..2eae681 100644 --- a/mq-demo/ReadMe.md +++ b/mq-demo/ReadMe.md @@ -615,6 +615,8 @@ void buildExchangeOverflowTest() { > > - 最大延迟时间:**2天(48小时)** > - 必须匹配RabbitMQ版本 +> +> **插件版本必须与RabbitMQ严格匹配(如3.13.x需使用v3.13.x插件)。** #### 1、确认docker数据卷 @@ -746,8 +748,8 @@ try { --- -### **2. 生产环境推荐方案** -#### **(1)Confirm 模式(轻量级确认)** +### 生产环境推荐方案 +#### (1)Confirm 模式(轻量级确认) - **原理**:异步确认消息是否成功到达 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 administrator sudo rabbitmqctl set_permissions -p / ".*" ".*" ".*" ``` 例如: -``` +```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) diff --git a/mq-demo/images/image-20250520105109623.png b/mq-demo/images/image-20250520105109623.png new file mode 100644 index 0000000..e2bb3d3 Binary files /dev/null and b/mq-demo/images/image-20250520105109623.png differ diff --git a/mq-demo/images/image-20250520105125396.png b/mq-demo/images/image-20250520105125396.png new file mode 100644 index 0000000..9405ef5 Binary files /dev/null and b/mq-demo/images/image-20250520105125396.png differ diff --git a/mq-demo/images/image-20250520105149567.png b/mq-demo/images/image-20250520105149567.png new file mode 100644 index 0000000..aa65af3 Binary files /dev/null and b/mq-demo/images/image-20250520105149567.png differ diff --git a/mq-demo/src/main/java/cn/bunny/mq/mqdemo/controller/IndexController.java b/mq-demo/src/main/java/cn/bunny/mq/mqdemo/controller/IndexController.java new file mode 100644 index 0000000..7586e0e --- /dev/null +++ b/mq-demo/src/main/java/cn/bunny/mq/mqdemo/controller/IndexController.java @@ -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"; + } +} diff --git a/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/ClusterEnvironmentListener.java b/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/ClusterEnvironmentListener.java new file mode 100644 index 0000000..035ac40 --- /dev/null +++ b/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/ClusterEnvironmentListener.java @@ -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("<<集群环境下消息>>----{}", dataString); + } +} diff --git a/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/MessageListenerOrder.java b/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/MessageListenerOrder.java index 8738c7b..f61fcac 100644 --- a/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/MessageListenerOrder.java +++ b/mq-demo/src/main/java/cn/bunny/mq/mqdemo/mq/listener/MessageListenerOrder.java @@ -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("<<优先级队列>>----{}", 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("<<优先级队列>>----{}", dataString); + // } } diff --git a/mq-demo/src/main/resources/application-dev.yml b/mq-demo/src/main/resources/application-dev.yml index 22c3674..4513150 100644 --- a/mq-demo/src/main/resources/application-dev.yml +++ b/mq-demo/src/main/resources/application-dev.yml @@ -4,7 +4,9 @@ server: bunny: rabbitmq: host: 192.168.3.144 - port: 5672 + # port: 5672 + # 集群环境的端口号 + port: 22222 virtual-host: / username: admin password: admin diff --git a/mq-demo/src/main/resources/templates/dialog.html b/mq-demo/src/main/resources/templates/dialog.html new file mode 100644 index 0000000..5a501ed --- /dev/null +++ b/mq-demo/src/main/resources/templates/dialog.html @@ -0,0 +1,480 @@ + + + + + + 优雅的Bootstrap弹窗表单 + + + + + +
+
+
+

优雅的Bootstrap弹窗示例

+

点击下方按钮查看带有表单验证的现代化弹窗

+ +
+
+
+ + +
+
+
+
+
+ 用户注册 +
+ +
+
+
+
+ + +
请输入有效的用户名(4-20个字符)
+
用户名可用
+
+ +
+ + +
请输入有效的电子邮箱地址
+
邮箱格式正确
+
+ +
+ + +
密码至少需要8个字符
+
+
+
+
+ +
+ + +
密码不匹配
+
+ +
+
+ + +
必须同意条款才能继续
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/mq-demo/src/test/java/cn/bunny/mq/mqdemo/ClusterEnvironmentTest.java b/mq-demo/src/test/java/cn/bunny/mq/mqdemo/ClusterEnvironmentTest.java new file mode 100644 index 0000000..1ef34e5 --- /dev/null +++ b/mq-demo/src/test/java/cn/bunny/mq/mqdemo/ClusterEnvironmentTest.java @@ -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); + } + } +}