rabbitmq

1.  RabbitMQ简介

l MQ全称为MessageQueue,消息队列是应用程序和应用程序之间的通信方法。

l RabbitMQ是一个开源的,在AMQP基础上完整的,可复用的企业消息系统。

l 支持主流的操作系统,Linux、Windows、MacOX等。

l 多种开发语言支持,Java、Python、Ruby、.NET、PHP、C/C++、node.js等

 

1.1. AMQP

1.2. Erlang

RabbitMQ是用Erlang语言开发的。

1.3. 其他MQ产品

 

2.  官网下载

 

下载:

 

教程:

3.  安装

具体参考《RabbitMQ-3.4.1安装手册.docx》。

 

3.1. 安装步骤

1.      安装环境Erlang

2.      安装RabbitMQ

 

 

3.2. 安装Erlang注意事项

1.      计算机名不能为中文

 

2.      用户名不能是中文

3.      安装路径不能有中文,推荐使用默认安装路径

4.      需要使用管理员账号进行安装

 

注意:

如果安装不成功,不要浪费太多时间在安装。

1.      找同学,开一个账号

2.      我在的时候,连接老师的RabbitMQ服务

3.      在最后一天,我们会使用Linux安装

 

3.3. 启用管理工具:

命令行工具目录:

在命令行输入:rabbitmq-plugins enable rabbitmq_management

 

安装成功:http://127.0.0.1:15672/

默认账号密码

guest

 

3.4. 安装成功

 

3.5. 功能介绍

 

 

程序和RabbitMQ交互使用的是:5672端口。

4.  创taotao用户

4.1. 创建用户

 

4.2. 创建 Virtual Hosts

 

4.3. 设置用户vhosts

 

4.4. 效果

 

5.  消息队列

 

学习是前5种。

 

5.1. 简单的消息队列

 

P:消息的生产者;

C:消息的消费者;

红色框:消息队列;

5.1.1.     创建连接

5.1.2.     生产者向队列中发送消息

5.1.3.     消费者

5.2. work模式

 

同一个消息只能被一个客户端所获取。

5.2.1.     生产者

发送100条消息到队列,并且每次发送消息后sleep i*10 毫秒;

 

5.2.2.     消费者1

从队列中获取消息,每次获取到消息后,休眠10毫秒,这个消费者消费消息比较快。

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 同一时刻服务器只会发一条消息给消费者

        //channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            //休眠

            Thread.sleep(10);

            // 返回确认状态

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

 

5.2.3.     消费者2

从队列中获取消息,每次获取到消息后,休眠1000毫秒,这个消费者消费消息比较慢。

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 同一时刻服务器只会发一条消息给消费者

//        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成状态

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            // 休眠1

            Thread.sleep(1000);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

5.2.4.     测试结果

结果:消费者1和消费者2获取到的消息是一样多,各50个。  这样是否合理?  --  不合理的。

 

5.3. 自动和手动反馈消息消费状态

自动:

从服务端获取到消息后,就认为该消息已经成功消费,无论客户端是否出异常。

 

手动:

从服务端获取消息后,服务端要标记为该不可用状态,等待客户端的反馈,如果客户端一直没有反馈,该消息一直被标记为不可用,同时认为该消费者在消费消息中

如果接收到客户端的反馈,服务端就将该消息删除。

 

 

如何选择手动和自动?  --  根据不同的业务需求做出不同选择。

 

5.4. work模式中的能者多劳

 

 

实际这种情况更加的合理。

 

测试结果:

消费者1:67条消息

消费者2:33条消息

 

5.5. 订阅模式

 

 

订阅:订阅微信公众号,微信公众号群发消息,所有的订阅者都能够收到消息

 

生产者可以绑定到交换机和队列

 

消费者只能绑定到队列

 

5.5.1.     队列绑定到交换机

 

5.5.2.     生产者

5.5.3.     消费者1

publicclass Recv {

 

    privatefinalstatic String QUEUE_NAME = "test_queue_ps_1";

 

    privatefinalstatic String EXCHANGE_NAME = "test_exchange_fanout";

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 绑定队列到交换机

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

 

        // 同一时刻服务器只会发一条消息给消费者

        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            Thread.sleep(10);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

}

5.5.4.     消费者2

publicclass Recv2 {

 

    privatefinalstatic String QUEUE_NAME = "test_queue_ps_2";

 

    privatefinalstatic String EXCHANGE_NAME = "test_exchange_fanout";

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 绑定队列到交换机

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

 

        // 同一时刻服务器只会发一条消息给消费者

        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            Thread.sleep(10);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

}

 

5.5.5.     测试

结果:消费者1和消费者2同时都能获取到消息。

 

注意:订阅模式和work模式的区别。

1、  work模式将消息发送到队列

2、  订阅模式将消息发送到交换机

3、  work模式是1个队列2个消费者,订阅模式是2个队列2个消费者

 

5.6. 路由模式

 

路由模式:

可以在队列绑定到交换机时指定一个规则,根据不同的消息中规则,选择是否接受该消息。

 

5.6.1.     生产者

5.6.2.     消费者1

publicclass Recv {

 

    privatefinalstatic String QUEUE_NAME = "test_queue_rirect_1";

 

    privatefinalstatic String EXCHANGE_NAME = "test_exchange_direct";

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 绑定队列到交换机

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key");

 

        // 同一时刻服务器只会发一条消息给消费者

        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            Thread.sleep(10);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

}

5.6.3.     消费者2

publicclass Recv2 {

 

    privatefinalstatic String QUEUE_NAME = "test_queue_rirect_2";

 

    privatefinalstatic String EXCHANGE_NAME = "test_exchange_direct";

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 绑定队列到交换机

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key2");

 

        // 同一时刻服务器只会发一条消息给消费者

        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            Thread.sleep(10);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

}

5.7. 通配符匹配模式

 

 

5.7.1.     生产者

5.7.2.     消费者1

publicclass Recv {

 

    privatefinalstatic String QUEUE_NAME = "test_queue_topic_1";

 

    privatefinalstatic String EXCHANGE_NAME = "test_exchange_topic";

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 绑定队列到交换机

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "item.UPDATE");

 

        // 同一时刻服务器只会发一条消息给消费者

        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            Thread.sleep(10);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

}

 

5.7.3.     消费者2

publicclass Recv2 {

 

    privatefinalstatic String QUEUE_NAME = "test_queue_topic_2";

 

    privatefinalstatic String EXCHANGE_NAME = "test_exchange_topic";

 

    publicstaticvoid main(String[] argv) throws Exception {

 

        // 获取到连接以及mq通道

        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

 

        // 声明队列

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

 

        // 绑定队列到交换机

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "item.#");

 

        // 同一时刻服务器只会发一条消息给消费者

        channel.basicQos(1);

 

        // 定义队列的消费者

        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 监听队列,手动返回完成

        channel.basicConsume(QUEUE_NAME, false, consumer);

 

        // 获取消息

        while (true) {

            QueueingConsumer.Delivery delivery = consumer.nextDelivery();

            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");

            Thread.sleep(10);

 

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

        }

    }

}

 

 

5.7.4.     测试

消费者根据绑定关系中的key规则来接受不同的消息。

 

5.8. 在界面中完成队列和交换机的绑定

6.  Spring-AMQP

 

 

 

6.1. 使用

6.1.1.     导入依赖

 

依赖关系:

6.1.2.     定义连接工厂

6.1.3.     定义队列

6.1.4.     定义交换机

定义交换机并且完成队列和交换机的绑定。

 

6.1.5.     定义模板

6.1.6.     在Spring容器中获取模板发送消息

 

注意:消息是发送到交换机。

6.1.7.     定义监听

6.1.8.     Foo消费者

6.2. MQ的管理

 

管理包括:队列声明、交换机申明等。

6.3. 队列的持久化

RabbitMQ的队列有2种,一种是内存队列,一种是持久化队列

1、  内存队列

a)        优点:速度快,效率高

b)        缺点:宕机,消息丢失

2、  持久化队列

a)        优点:消息可以持久化保存,宕机或断电后消息不丢失

b)        缺点:比内存存储速度慢,性能差

 

 

 

内容概要:本文详细探讨了基于MATLAB/SIMULINK的多载波无线通信系统仿真及性能分析,重点研究了以OFDM为代表的多载波技术。文章首先介绍了OFDM的基本原理和系统组成,随后通过仿真平台分析了不同调制方式的抗干扰性能、信道估计算法对系统性能的影响以及同步技术的实现与分析。文中提供了详细的MATLAB代码实现,涵盖OFDM系统的基本仿真、信道估计算法比较、同步算法实现和不同调制方式的性能比较。此外,还讨论了信道特征、OFDM关键技术、信道估计、同步技术和系统级仿真架构,并提出了未来的改进方向,如深度学习增强、混合波形设计和硬件加速方案。; 适合人群:具备无线通信基础知识,尤其是对OFDM技术有一定了解的研究人员和技术人员;从事无线通信系统设计与开发的工程师;高校通信工程专业的高年级本科生和研究生。; 使用场景及目标:①理解OFDM系统的工作原理及其在多径信道环境下的性能表现;②掌握MATLAB/SIMULINK在无线通信系统仿真中的应用;③评估不同调制方式、信道估计算法和同步算法的优劣;④为实际OFDM系统的设计和优化提供理论依据和技术支持。; 其他说明:本文不仅提供了详细的理论分析,还附带了大量的MATLAB代码示例,便于读者动手实践。建议读者在学习过程中结合代码进行调试和实验,以加深对OFDM技术的理解。此外,文中还涉及了一些最新的研究方向和技术趋势,如AI增强和毫米波通信,为读者提供了更广阔的视野。
### RabbitMQ 使用指南和教程 #### 安装 RabbitMQ RabbitMQ 是一种基于 AMQP 协议的消息中间件,用于实现分布式系统的可靠消息传递。以下是安装 RabbitMQ 的基本流程: 1. **安装 Erlang** RabbitMQ 基于 Erlang 编程语言开发,因此需要先安装 Erlang 运行环境。可以通过包管理器或者下载官方二进制文件完成安装。 2. **安装 RabbitMQ Server** 下载并安装 RabbitMQ Server 软件包。对于 Linux 用户,可以使用以下命令: ```bash sudo apt-get install rabbitmq-server ``` 3. **启动服务** 启动 RabbitMQ 服务后,默认监听端口为 `5672`(AMQP 协议),Web 管理界面默认运行在 `15672` 端口上。 ```bash sudo systemctl start rabbitmq-server ``` 4. **启用 Web 管理插件** 可通过以下命令启用 RabbitMQ 提供的 Web 管理工具: ```bash sudo rabbitmq-plugins enable rabbitmq_management ``` --- #### 配置用户与权限 为了安全访问 RabbitMQ 实例,通常需要创建自定义用户并分配相应权限。 - 创建新用户: ```bash rabbitmqctl add_user rabbitmq 211314 ``` 此操作会新增名为 `rabbitmq` 的用户,并将其密码设为 `211314`[^1]。 - 设置用户角色: ```bash rabbitmqctl set_user_tags rabbitmq administrator ``` 将该用户的标签设定为管理员角色,使其拥有完全控制权[^1]。 - 授予用户权限: ```bash rabbitmqctl set_permissions -p "/" rabbitmq ".*" ".*" ".*" ``` 上述命令授予用户对根虚拟主机 `/` 中所有资源的操作权限[^1]。 - 查看现有用户及其角色: ```bash rabbitmqctl list_users ``` --- #### 集群配置 RabbitMQ 支持多种集群模式来提升可用性和性能。主要分为两类:普通模式和镜像模式。 - **普通模式** 在这种模式下,各节点独立存储队列中的数据和其他元信息(如交换机)。当客户端尝试消费某个不在当前连接节点上的消息时,目标节点会被请求转发所需的数据[^2]。 - **镜像模式** 对比之下,在镜像模式中,指定队列的内容将在多个节点间保持一致副本。即使部分成员失效,剩余存活节点仍能继续提供完整的服务功能[^2]。 > 注意事项:尽管镜像模式提高了可靠性,但也带来了额外开销——网络流量增加以及写入延迟上升等问题需被充分考虑进去。 --- #### 应用集成示例 假设要在一个 Java 或 Python 应用程序里利用 RabbitMQ 来发送/接收消息,则可能涉及以下几个步骤: 1. **声明交换器 (Exchange)** 和绑定关系: ```java channel.exchangeDeclare(exchangeName, "direct", true); channel.queueDeclare(queueName, true, false, false, null); channel.queueBind(queueName, exchangeName, routingKey); ``` 如此一来便完成了持久化队列及路由键关联工作[^3]。 2. 发布一条测试消息至上述已建立好的通道路径之中; 3. 订阅对应主题下的事件流以便实时捕获最新动态更新情况; --- #### 总结 以上涵盖了从基础安装到高级特性使用的整个过程概述。希望这些指导能够帮助您快速掌握如何部署与维护属于自己的 RabbitMQ 平台实例! 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值