RabbitMQ核心概念
1.生产者即这条消息的产生者
2.Connection是生产者建立连接到broker(rabbitmq的服务器)
3.channel是通道的意思,在你建立连接之后,还是不能与服务器交互需要通过一个个通道访问,channel是在connection里面的,是一个多对一关系
4.broker 是rabbitmq的服务器,里面有虚拟主机
5.vhost 是虚拟主机,里面有exchange bind queue等重要东西
6.exchange是交换机,作用是通知queue的,他有四种类型,fanout广播类型(全匹配),direct直连(精准匹配),topic扇形(模糊匹配),headers (参数匹配)
7.binding是一个虚拟连接,有个routingkey的东西,帮exchange与queue之间建立连接
8.queue是消息队列,用于保存消息给消费者,使用
RabbitMQ基本使用
package com.study.rabbitmq.a132.simple; import com.rabbitmq.client.*; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * 简单队列消费者 */ public class Consumer { public static void main(String[] args) { // 1、创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); // 2、设置连接属性 factory.setHost("192.168.100.242"); factory.setUsername("admin"); factory.setPassword("admin"); Connection connection = null; Channel channel = null; try { // 3、从连接工厂获取连接 connection = factory.newConnection("消费者"); // 4、从链接中创建通道 channel = connection.createChannel(); /** * 5、声明(创建)队列 * 如果队列不存在,才会创建 * RabbitMQ 不允许声明两个队列名相同,属性不同的队列,否则会报错 * * queueDeclare参数说明: * @param queue 队列名称 * @param durable 队列是否持久化 * @param exclusive 是否排他,即是否为私有的,如果为true,会对当前队列加锁,其它通道不能访问, * 并且在连接关闭时会自动删除,不受持久化和自动删除的属性控制。 * 一般在队列和交换器绑定时使用 * @param autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除 * @param arguments 队列参数,设置队列的有效期、消息最大长度、队列中所有消息的生命周期等等 */ channel.queueDeclare("queue1", false, false, false, null); // 6、定义收到消息后的回调 DeliverCallback callback = new DeliverCallback() { public void handle(String consumerTag, Delivery message) throws IOException { System.out.println("收到消息:" + new String(message.getBody(), "UTF-8")); } }; // 7、监听队列 channel.basicConsume("queue1", true, callback, new CancelCallback() { public void handle(String consumerTag) throws IOException { } }); System.out.println("开始接收消息"); System.in.read(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } finally { // 8、关闭通道 if (channel != null && channel.isOpen()) { try { channel.close(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } // 9、关闭连接 if (connection != null && connection.isOpen()) { try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
package com.rabbitmq.demo1; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * 普通模式 */ public class Producer { public static void main(String[] args) { //建立连接工厂 ConnectionFactory factory = new ConnectionFactory(); //设置连接参数 factory.setHost("121.199.11.93"); factory.setPort(5672); factory.setUsername("guest"); factory.setPassword("guest"); Connection connection = null; Channel channel = null; try { //获取连接 connection = factory.newConnection(); //获取通道 channel = connection.createChannel(); //创建队列 channel.queueDeclare("queue1",false,false,false,null); String message = "Hello Word"; //发送消息 channel.basicPublish("","queue1",null,message.getBytes()); System.out.println("消息已发送"); }catch (Exception e){ e.printStackTrace(); }finally { try { if(channel!=null && channel.isOpen()){ channel.close(); } if(connection!=null && connection.isOpen()){ connection.close(); } } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } } }
集群环境下
package com.study.rabbitmq.a133.cluster; import com.rabbitmq.client.*; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.TimeoutException; /** * 客户端连接集群示例 */ public class Consumer { public static void main(String[] args) { // 1、创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); // 2、设置连接属性 factory.setUsername("order-user"); factory.setPassword("order-user"); factory.setVirtualHost("v1"); Connection connection = null; Channel channel = null; // 3、设置每个节点的链接地址和端口 Address[] addresses = new Address[]{ new Address("121.5.52.195", 5672), new Address("121.199.11.93", 5672) }; try { // 开启/关闭连接自动恢复,默认是开启状态 factory.setAutomaticRecoveryEnabled(true); // 设置每100毫秒尝试恢复一次,默认是5秒:com.rabbitmq.client.ConnectionFactory.DEFAULT_NETWORK_RECOVERY_INTERVAL factory.setNetworkRecoveryInterval(100); // 4、从连接工厂获取连接 connection = factory.newConnection(addresses, "消费者"); // 添加重连监听器 ((Recoverable) connection).addRecoveryListener(new RecoveryListener() { /** * 重连成功后的回调 * @param recoverable */ public void handleRecovery(Recoverable recoverable) { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 已重新建立连接!"); } /** * 开始重连时的回调 * @param recoverable */ public void handleRecoveryStarted(Recoverable recoverable) { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 开始尝试重连!"); } }); // 5、从链接中创建通道 channel = connection.createChannel(); /** * 6、声明(创建)队列 * 如果队列不存在,才会创建 * RabbitMQ 不允许声明两个队列名相同,属性不同的队列,否则会报错 * * queueDeclare参数说明: * @param queue 队列名称 * @param durable 队列是否持久化 * @param exclusive 是否排他,即是否为私有的,如果为true,会对当前队列加锁,其它通道不能访问, * 并且在连接关闭时会自动删除,不受持久化和自动删除的属性控制。 * 一般在队列和交换器绑定时使用 * @param autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除 * @param arguments 队列参数,设置队列的有效期、消息最大长度、队列中所有消息的生命周期等等 */ channel.queueDeclare("queue1", true, false, false, null); // 7、定义收到消息后的回调 final Channel finalChannel = channel; DeliverCallback callback = new DeliverCallback() { public void handle(String consumerTag, Delivery message) throws IOException { System.out.println("收到消息:" + new String(message.getBody(), "UTF-8")); finalChannel.basicAck(message.getEnvelope().getDeliveryTag(), false); } }; // 8、监听队列 channel.basicConsume("queue1", false, callback, new CancelCallback() { public void handle(String consumerTag) throws IOException { } }); System.out.println("开始接收消息"); System.in.read(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } finally { // 9、关闭通道 if (channel != null && channel.isOpen()) { try { channel.close(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } // 10、关闭连接 if (connection != null && connection.isOpen()) { try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
package com.study.rabbitmq.a133.cluster; import com.rabbitmq.client.*; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * 客户端连接集群示例 */ public class Producer { public static void main(String[] args) { // 1、创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); // 2、设置连接属性 factory.setUsername("order-user"); factory.setPassword("order-user"); factory.setVirtualHost("v1"); Connection connection = null; Channel channel = null; // 3、设置每个节点的链接地址和端口 Address[] addresses = new Address[]{ new Address("121.5.52.195", 5672), new Address("121.199.11.93", 5672) }; try { // 开启/关闭连接自动恢复,默认是开启状态 factory.setAutomaticRecoveryEnabled(true); // 设置每100毫秒尝试恢复一次,默认是5秒:com.rabbitmq.client.ConnectionFactory.DEFAULT_NETWORK_RECOVERY_INTERVAL factory.setNetworkRecoveryInterval(100); factory.setTopologyRecoveryEnabled(false); // 4、使用连接集合里面的地址获取连接 connection = factory.newConnection(addresses, "生产者"); // 添加重连监听器 ((Recoverable) connection).addRecoveryListener(new RecoveryListener() { /** * 重连成功后的回调 * @param recoverable */ public void handleRecovery(Recoverable recoverable) { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 已重新建立连接!"); } /** * 开始重连时的回调 * @param recoverable */ public void handleRecoveryStarted(Recoverable recoverable) { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 开始尝试重连!"); } }); // 5、从链接中创建通道 channel = connection.createChannel(); /** * 6、声明(创建)队列 * 如果队列不存在,才会创建 * RabbitMQ 不允许声明两个队列名相同,属性不同的队列,否则会报错 * * queueDeclare参数说明: * @param queue 队列名称 * @param durable 队列是否持久化 * @param exclusive 是否排他,即是否为私有的,如果为true,会对当前队列加锁,其它通道不能访问,并且在连接关闭时会自动删除,不受持久化和自动删除的属性控制 * @param autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除 * @param arguments 队列参数,设置队列的有效期、消息最大长度、队列中所有消息的生命周期等等 */ channel.queueDeclare("queue1", true, false, false, null); for (int i = 0; i < 100; i++) { // 消息内容 String message = "Hello World " + i; try { // 7、发送消息 channel.basicPublish("", "queue1", null, message.getBytes()); } catch (AlreadyClosedException e) { // 可能连接已关闭,等待重连 System.out.println("消息 " + message + " 发送失败!"); i--; TimeUnit.SECONDS.sleep(2); continue; } System.out.println("消息 " + i + " 已发送!"); TimeUnit.SECONDS.sleep(2); } } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 8、关闭通道 if (channel != null && channel.isOpen()) { try { channel.close(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } // 9、关闭连接 if (connection != null && connection.isOpen()) { try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
package com.study.rabbitmq.a133.cluster; import com.rabbitmq.client.*; import com.rabbitmq.client.Consumer; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * vhost和权限应用示例 * <p> * 说明:先阅读文档中的使用示例,创建号用户名和vhost,分配好权限。 * http://code.study.com/MQ/rabbitmq/rabbitmq/blob/master/java/src/main/java/com/study/rabbitmq/a133/cluster/readme.md#vhost使用示例 * <p> * 另外需要自己在管理界面创建queue2队列和test交换器 */ public class VirtualHostsDemo { public static void main(String[] args) { // 1、创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); // 2、设置连接属性 factory.setUsername("order-user"); factory.setPassword("order-user"); factory.setVirtualHost("v1"); Connection connection = null; Channel prducerChannel = null; Channel consumerChannel = null; // 3、设置每个节点的链接地址和端口 Address[] addresses = new Address[]{ new Address("121.5.52.195", 5672), new Address("121.199.11.93", 5672) }; try { // 4、从连接工厂获取连接 connection = factory.newConnection(addresses, "消费者"); // 5、从链接中创建通道 prducerChannel = connection.createChannel(); prducerChannel.exchangeDeclare("test-exchange", "fanout"); prducerChannel.queueDeclare("queue1", false, false, false, null); prducerChannel.queueBind("queue1", "test-exchange", "xxoo"); // 消息内容 String message = "Hello A"; prducerChannel.basicPublish("test-exchange", "c1", null, message.getBytes()); consumerChannel = connection.createChannel(); // 创建一个消费者对象 Consumer consumer = new DefaultConsumer(consumerChannel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println("收到消息:" + new String(body, "UTF-8")); } }; consumerChannel.basicConsume("queue1", true, consumer); System.out.println("等待接收消息"); System.in.read(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } finally { // 9、关闭通道 if (prducerChannel != null && prducerChannel.isOpen()) { try { prducerChannel.close(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } // 10、关闭连接 if (connection != null && connection.isOpen()) { try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
RabbitMQ持久化,内存/硬盘管理
持久化机制: 是一个持久化消息他会存储在内存中,也会存储在磁盘中,非持久化消息,存储在内存中,在内存不够用的时候,存在磁盘中
队列持久化:使用通道创建队列,的时候第二个参数设置为true,设置成功之后,在管理界面会有个D的标志
// 定义一个持久化队列 channel.queueDeclare(queueName, true, false, false, null);
交换机持久化:使用通道创建队列,的时候第三个参数设置为true,设置成功之后,在管理界面会有个D的标志
// 定义一个持久化的,direct类型交换器 channel.exchangeDeclare("routing_test", "direct", true);
消息持久化:在发送消息的时候,第三个参数设置成MessageProperties.PERSISTENT_TEXT_PLAIN
// 发送持久化消息到routing_test交换器上 channel.basicPublish("routing_test", "c1", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
持久化保证了数据不丢失也会,带来新的问题,比如:RabbitMQ内存、磁盘不够用还会发生内存换页
设置内存阈值
rabbitmqctl set_vm_memory_high_watermark absolute 50MB
rabbitmqctl set_vm_memory_high_watermark 0.4
内存换页,比如在内存为1000MB的机器上面,我默认阈值是0.4,你内存换页的默认阈值是0.5 也就是说 1000*0.4*0.5=200MB就会发生换页
设置磁盘阈值
rabbitmqctl set_disk_free_limit 100GB