rabbitMQ 的安装和使用

1、ubuntu24.04 安装 rabbitMQ

sudo apt update

sudo apt install erlang

sudo apt install rabbitmq-server

安装管理插件:sudo rabbitmq-plugins enable rabbitmq_management

启动服务 sudo systemctl start rabbitmq-server

设置开机自启 sudo systemctl enable rabbitmq-server

检查服务状态 sudo systemctl status rabbitmq-server

新建用户并授权:

创建新用户(将 your_username 和 your_password替换为你自己的)

sudo rabbitmqctl add_user your_username your_password

赋予管理员权限

sudo rabbitmqctl set_user_tags your_username administrator

授予所有权限

sudo rabbitmqctl set_permissions -p / your_username ".*" ".*" ".*"

登录管理页面:

浏览器打开 ​http://ip:15672/ ,使用新建的用户和密码登录

2、使用demo

pom.xml中引入:

复制代码
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.20.0</version>
</dependency>

**生产者:**确认消息发送成功的几种级别,可靠级别依次升高

1、消息写入到缓冲区,也就是以下代码中的实现(不可靠);

2、消息到达rabbitMQ服务器(较可靠)

channel.txSelect();

try {

channel.basicPublish("", "my_queue", null, message.getBytes());

channel.txCommit(); // 消息确认到达服务器

System.out.println("消息已到达服务器");

} catch (Exception e) {

channel.txRollback();

System.out.println("消息发送失败");

}

3、消息到达rabbitMQ服务器并持久化到磁盘 (高可靠)

// 持久化队列 + 持久化消息 + 发布者确认

channel.queueDeclare("my_queue", true, false, false, null);

channel.confirmSelect();

channel.basicPublish("", "my_queue",

MessageProperties.PERSISTENT_TEXT_PLAIN,

message.getBytes());

if (channel.waitForConfirms()) {

System.out.println("消息已持久化到磁盘");

}

4、到达队列并准备好消费(最可靠)

// 使用 mandatory 标志和 ReturnListener

channel.addReturnListener((replyCode, replyText, exchange, routingKey, properties, body) -> {

System.out.println("消息无法路由到队列: " + replyText);

});

channel.basicPublish("", "my_queue",

true, // mandatory = true, 如果无法路由到队列会返回

MessageProperties.PERSISTENT_TEXT_PLAIN,

message.getBytes());

生产者demo:

复制代码
public class Producer {
    public static void main(String[] args) throws Exception {
        // 1. 创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.187.133"); // RabbitMQ服务器地址
        factory.setPort(5672);        // 默认客户端端口
        factory.setUsername("rabbit"); // 用户名
        factory.setPassword("rabbit"); //认密码

        // 2. 创建连接和信道
        // 使用try-with-resources确保资源自动关闭
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            // 3. 声明一个队列。参数:队列名,是否持久化,是否独占,是否自动删除,其他参数
            channel.queueDeclare("hello", true, false, false, null);
            // 4. 准备消息
            String message = "nihao";
            // 5. 发送消息到默认交换机,路由键为队列名
            channel.basicPublish("", "hello", null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");
        }
        // 6. 连接和通道会自动关闭
    }
}

**消费者:**消费者中需要考虑消费失败、重试、死信队列等场景,收到消息之后如果失败,则将消息的header中添加失败的次数,然后再将消息放入到队列中,再次消费这个消息时判断header中的次数是否超过指定值,如果超过放入到死信队列

消费者demo:

复制代码
public class Consumer {
    public static void main(String[] args) throws Exception {
        // 1. 创建连接工厂(配置同生产者)
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.187.133");
        factory.setUsername("rabbit");
        factory.setPassword("rabbit");

        // 2. 建立连接和信道
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.basicQos(10); // 消费者端最多存在未提交数据的条数,默认1条
        // 3. 声明队列(必须与生产者声明的队列一致)
        channel.queueDeclare("hello", true, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        // 在消息头中记录重试次数
        Map<String, Object> headers = new HashMap<>();
        headers.put("retry-count", 0);

        // 4. 创建回调函数,定义如何处理消息
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            try {
                String message = new String(delivery.getBody(), "UTF-8");
                // 获取消息头中的重试次数
                Map<String, Object> headersData = delivery.getProperties().getHeaders();
                Integer retryCount = (Integer) headersData.getOrDefault("retry-count", 0);
                if (retryCount >= 3) {
                    // 超过最大重试次数,进入死信队列
                    channel.basicNack(delivery.getEnvelope().getDeliveryTag(), false, false);
                    System.out.println("消息重试超过3次,进入死信队列");
                    return;
                }
                // 处理消息
                System.out.println(" [x] Received '" + message + "'");
                // 手动确认消息
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

            } catch (Exception e) {
                // 增加重试次数并重新入队
                AMQP.BasicProperties props = delivery.getProperties();
                Map<String, Object> newHeaders = new HashMap<>(props.getHeaders());
                Integer currentRetry = (Integer) newHeaders.getOrDefault("retry-count", 0);
                newHeaders.put("retry-count", currentRetry + 1);

                AMQP.BasicProperties newProps = new AMQP.BasicProperties.Builder()
                        .headers(newHeaders)
                        .build();

                // 重新发布消息(带有更新后的重试次数)
                channel.basicPublish("", "hello", newProps, delivery.getBody());
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        };
    }
}

3、rabbitMQ的结构

从以上代码中可以看出,生产者、消费者连接rabbitMQ后生成一个connection,里面有一个channel,使用channel往一个队列中写、读数据,没有kafka中的topic、tag等;

当多个消费者消费某个队列的消息时,服务端使用轮询将消息推送到多个消费者,消费者是被动响应的,不需要向服务端发起拉消息的请求;

4、rabbitMQ 的集群模式

主备:也就是一主多从

镜像模式:多主多从,也是最常用的模式

factory.setHost("192.168.187.133"); 中可以设置多个ip,客户端顺序连接对应的服务端节点,连接成功为止,客户端和服务端都只会和其中一个ip建立连接,有一个特殊场景是队列主从副本数量少于节点数量,消费者连接的是没有队列数据的某个节点,会导致消费不到数据,所以在设置策略时要考虑到每个节点都有完成的副本数据;

当向队列中写数据时默认写数据的这个节点是主节点,其他的节点是镜像节点(从节点),消费者从队列获取数据时,如果连接的是某个队列的从节点,会自动路由到主节点获取数据;从节点只是用于备份数据和选举产生主节点,所有的客户端的读写操作都在主节点队列上;

当主节点挂了,从节点选举的优先级是 和主节点数据是否完全同步、节点加入集群的先后顺序;

5、延时消息

rabbitMQ可以通过死信交换机实现延时 消息,代码不做说明,知道有这个事就行;

6、心跳机制:

生产者和消费者和服务端通过心跳确认节点状态,当生成者、消费者发送心跳后一段时间没有收到返回 会认为连接的节点宕机,重新换一个节点连接;当服务端没有收到消费者节点的心跳,认为这个消费者不可用触发重平衡,不再向这个消费者推送消息;

7、应用特点

概念上的轻量化:没有kafka和rocketMQ 中的topic、tag,topic下面有多个分区或队列,结构简单;

灵活路由:需要给某个业务发消息直接将数据写入到对应队列即可,强调在队列上的灵活读写

相关推荐
福旺旺17 小时前
Linux——解压缩各类文件
linux
MasterLi802319 小时前
我的读书清单
android·linux·学习
ha204289419419 小时前
Linux操作系统学习之---初识网络
linux·网络·学习
飞凌嵌入式19 小时前
【玩转多核异构】T153核心板RISC-V核的实时性应用解析
linux·嵌入式硬件·嵌入式·risc-v
陌路2019 小时前
Linux 34TCP服务器多进程并发
linux·服务器·网络
玉树临风江流儿19 小时前
Linux驱动开发实战指南-中
linux·驱动开发
q***728719 小时前
SpringBoot中整合RabbitMQ(测试+部署上线 最完整)
spring boot·rabbitmq·java-rabbitmq
m0_5276539020 小时前
NVIDIA Orin NX使用Jetpack安装CUDA、cuDNN、TensorRT、VPI时的error及解决方法
linux·人工智能·jetpack·nvidia orin nx
adnyting21 小时前
【Linux日新月异(五)】CentOS 7防火墙深度解析:firewalld全面指南
linux·运维·centos
Code Warrior1 天前
【Linux】Socket编程UDP
linux·udp