rpm -ivh erlang-23.1.5-1.el7.x86_64.rpm //安装erlang包,https://github.com/rabbitmq/erlang-rpm
rpm -ivh rabbitmq-server-3.8.9-1.el7.noarch.rpm //安装rabbitmq-server,https://www.rabbitmq.com/install-rpm.html#downloads
结果报错了
[root@localhost ~]# rpm -ivh rabbitmq-server-3.8.9-1.el7.noarch.rpm
warning: rabbitmq-server-3.8.9-1.el7.noarch.rpm: Header V4 RSA/SHA256 Signature, key ID 6026dfca: NOKEY
error: Failed dependencies:
socat is needed by rabbitmq-server-3.8.9-1.el7.noarch
少了一个socat的管理包,我们在线安装一个
yum install socat
再次安装rabbitmq-server,安装成功
systemctl status rabbitmq-server//查看rabbitmq的状态
systemctl start rabbitmq-server//启动rabbitmq服务
systemctl restart rabbitmq-server//重新启动rabbitmq服务
systemctl stop rabbitmq-server//停止rabbitmq服务
现在3.8.9版本在/etc/rabbitmq是没有配置文件的,而且安装包里面也没有自带配置文件模板,而如果想登录web管理界面,我们需要开启默认用户guest
vim /etc/rabbitmq/rabbitmq.conf
##粘贴以下内容,该配置文件是网上找的,保存后重新启动
loopback_users.guest = false
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_consul
cluster_formation.consul.host = consul
cluster_formation.node_cleanup.only_log_warning = false
cluster_formation.consul.svc_addr_auto = true
cluster_partition_handling = autoheal
vm_memory_high_watermark.relative = 0.8
开启管理界面
rabbitmq-plugins enable rabbitmq_management
记得关闭防火墙或者开启端口15672
然后就可以打开web界面了,输入账号密码guest进入管理界面
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。
在rabbitmq里面是有交换机的概念的,消息发送到交换机,队列绑定交换机,然后消费者绑定队列进行消费
其中的virtual是虚拟主机的意思,就是为了多个项目进行区分,每一个项目创建一个virtual自己使用
引入客户端依赖
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.10.0version>
dependency>
//工具类
public class RabbitMQUtils {
private static ConnectionFactory factory;
static {
//创建工厂
factory = new ConnectionFactory();
//设置主机
factory.setHost("192.168.137.100");
//设置端口号
factory.setPort(5672);
//设置连接的主机
factory.setVirtualHost("/mes");
//设置用户
factory.setUsername("guest");
//设置密码
factory.setPassword("guest");
}
//获取连接
public static Connection getConnection() {
try {
//获取连接
Connection connection = factory.newConnection();
return connection;
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return null;
}
//关闭连接
public static void close(Channel channel, Connection connection) {
try {
channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
//消息生产者
@Test
void helloProvider() throws IOException, TimeoutException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//通道绑定队列
//参数1:队列名称,不存在会自动创建
//参数2:队列是否持久化
//参数3:是否独占队列(是否允许其他连接可用) true独占 false不独占
//参数4:是否在消息消费完后自动删除
//参数5:附加参数
channel.queueDeclare("hello", false, false, false, null);
//发布消息
//参数1:交换机名称
//参数2:队列名称
//参数3:额外设置
//参数4:消息内容,必须为字节数组
channel.basicPublish("", "hello", null, "这是hello".getBytes());
RabbitMQUtils.close(channel,connection);
}
发现消息发布成功
//消息消费
public class HelloConsumer {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
channel.queueDeclare("hello",false,false,false,null);
//参数1:队列名称
//参数2:是否消息确认
//参数3:消费回调
channel.basicConsume("hello",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消息内容为:"+new String(body));
}
});
//RabbitMQUtils.close(channel,connection);//如果关掉连接的话,程序就直接结束了,不会再监听队列
}
}
hello模型是最简单的消息模型,是一对一的,一个生产者对应一个队列对应一个消费者
在第一种模型(helloworld)之上,如果每一个消息在消费的时候如果处理时间过程,队列中消息越来越多,会导致消息不及时消费,造成很多问题,所以有了work queue(任务)的消息模型,这种消息模型就是多个消费者消费同一个队列里面的消息,消息不会被多次消费
//生产者
public class Provider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//通道绑定队列
//参数1:队列名称,不存在会自动创建
//参数2:队列是否持久化
//参数3:是否独占队列(是否允许其他连接可用) true独占 false不独占
//参数4:是否在消息消费完后自动删除
//参数5:附加参数
channel.queueDeclare("work", false, false, false, null);
for (int i = 1; i <= 10; i++) {
//发布消息
//参数1:交换机名称
//参数2:队列名称
//参数3:额外设置
//参数4:消息内容,必须为字节数组
channel.basicPublish("", "work", null, ("这是work"+i+"").getBytes());
}
RabbitMQUtils.close(channel,connection);
}
}
//消费者2
public class WorkConsumer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
channel.queueDeclare("work",false,false,false,null);
//参数1:队列名称
//参数2:是否消息确认
//参数3:消费回调
channel.basicConsume("work",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("work模型消费者1:"+new String(body));
}
});
}
}
//消费者2
public class WorkConsumer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
channel.queueDeclare("work",false,false,false,null);
//参数1:队列名称
//参数2:是否消息确认
//参数3:消费回调
channel.basicConsume("work",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("work模型消费者2:"+new String(body));
}
});
}
}
这种默认是平均消费,也就是如果10条消息的话,也就是两个消费者都消费5条消息,这样肯定也有问题,要是有一个消费者卡顿了,处理一个消息需要5秒钟,这样的话总体消费消息的时间还是很久,不科学,如果每个消费者消费完了一条消息就去队列里面继续消费消息就好了,也就是能者多劳
能者多劳
生产者不变,消费者开启手动确认,每次消费一个
//消费者1
public class WorkConsumer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//每次消费多少个消息(1)
channel.basicQos(1);
channel.queueDeclare("work",false,false,false,null);
//参数1:队列名称
//参数2:是否自动消息确认(2)
//参数3:消费回调
channel.basicConsume("work",false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("work模型消费者1:"+new String(body));
//(3)
//手动确认
//确认标识
//是否开启多个消息自动确认
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}
//消费者2
public class WorkConsumer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//每次消费多少个消息(1)
channel.basicQos(1);
channel.queueDeclare("work",false,false,false,null);
//参数1:队列名称
//参数2:是否自动消息确认(2)
//参数3:消费回调
channel.basicConsume("work",false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("work模型消费者2:"+new String(body));
//(3)
//手动确认
//确认标识
//是否开启多个消息自动确认
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}
1:设置每次消费1个消息
2:开启手动确认消息
3,消费关闭手动确认
生产者把消息发送给交换机,在由交换机发送给各个订阅的队列(一个队列对应一个消费者),在由消费者消费,这种很消息模型还是比较常见的,比如说微信的订阅号,你订阅过后,就相当于队列订阅了交换机,然后生产者给交换机发送消息时,交换机就会给所有订阅他的队列发送消息
//生产者
public class FanoutProvider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//申明交换机
//参数1:交换机名称
//参数2:交换机类型
channel.exchangeDeclare("fanout","fanout");
//发送消息
//参数1:交换机名称
//参数2:路由key
//参数3:消息持久化
//参数4:消息内容
channel.basicPublish("fanout","",null,"这是fanout类型".getBytes());
RabbitMQUtils.close(channel,connection);
}
}
//消费者1
public class FanoutConsumer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("fanout","fanout");
//临时队列
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
channel.queueBind(queueName,"fanout","");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("fanout的消费者1,消息内容为:"+new String(body));
}
});
}
}
//消费者2
public class FanoutConsumer3 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("fanout","fanout");
//临时队列
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
channel.queueBind(queueName,"fanout","");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("fanout的消费者2,消息内容为:"+new String(body));
}
});
}
}
//消费者3
public class FanoutConsumer3 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("fanout","fanout");
//临时队列
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
channel.queueBind(queueName,"fanout","");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("fanout的消费者3,消息内容为:"+new String(body));
}
});
}
}
在fanout的消息模型中是没有用到路由key的,所有在发送消息时路由key为空
路由,就是可以按照路由key来匹配,确定要发送的队列,在有时候有些消息需要全部的消费者消费,有时候需要一部分消费者消费
//生产者
public class RoutingProvider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("direct","direct");
channel.basicPublish("direct","blue",null,"direct消息模型".getBytes());
RabbitMQUtils.close(channel,connection);
}
}
//消费者1
public class RoutingConsumer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("direct","direct");
String queue = channel.queueDeclare().getQueue();
channel.queueBind(queue,"direct","red");
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("这里只接受red,消息内容为:"+new String(body));
}
});
}
}
//消费2
public class RoutingConsumer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("direct","direct");
String queue = channel.queueDeclare().getQueue();
channel.queueBind(queue,"direct","blue");
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("这里只接受blue,消息内容为:"+new String(body));
}
});
}
}
//消费3
public class RoutingConsumer3 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("direct","direct");
String queue = channel.queueDeclare().getQueue();
channel.queueBind(queue,"direct","red");
channel.queueBind(queue,"direct","blue");
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("这里只接受red和blue,消息内容为:"+new String(body));
}
});
}
}
当生产者发送消息,路由key为:red时,消费者1和消费者3会消费,因为消费者2是绑定的blue的路由key
当生产者发送消息,路由key为:blue时,消费者2和消费者3会消费,因为消费者1是绑定的red的路由key
在路由的消息模型之上,允许key使用通配符,这样就可以更加的灵活
//生产者
public class TopicsProvider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("topics","topic");
channel.basicPublish("topics","green.blue.green",null,"topics消息模型".getBytes());
RabbitMQUtils.close(channel,connection);
}
}
//消费者1
public class TopicsConsumer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("topics","topic");
String queue = channel.queueDeclare().getQueue();
channel.queueBind(queue,"topics","red.*");
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费red开头的,不关心后续内容,消息内容为:"+new String(body) );
}
});
}
}
//消费者2
public class TopicsConsumer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("topics","topic");
String queue = channel.queueDeclare().getQueue();
channel.queueBind(queue,"topics","*.blue.*");
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费blue为中间的,不关心前后内容,消息内容为:"+new String(body) );
}
});
}
}
*:代表一个单词,可以为任何单词,但是不能为空,不然匹配不到
#:代表任何,可以有,可以没有,也就是代表0到多个单词