RabbitMQ学习(一)——MQ入门

1.背景

消息队列产生背景:
在网络通讯中,Http请求默认采用同步请求方式,基于请求响应模式,在客户端与服务端通讯时,客户端调用服务端接口后,必须等待服务端返回才能接着执行(这是同步方式)。如果服务器发生网络延迟、不可达情况,可能客户端也会受到影响
消息队列应用场景:
是分布式系统重要组件,主要解决——应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性框架
**

2.主要概念

**

(1)RabbitMQ Server: 也叫broker server,它是一种传输服务。 他的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输
(2)Producer: 消息生产者,如图A、B、C,数据的发送方。消息生产者连接RabbitMQ服务器然后将消息投递到Exchange
(3)Consumer:消息消费者,如图1、2、3,数据的接收方。消息消费者订阅队列,RabbitMQ将Queue中的消息发送到消息消费者。
(4)Exchange:生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。Exchange并不存储消息。RabbitMQ中的Exchange有
direct、fanout、topic、headers四种类型,每种类型对应不同的路由规则。
(5)Queue:(队)是RabbitMQ的内部对象,用于存储消息。消息消费者就是通过订阅队列来获取消息的,RabbitMQ中的消息都只能存储在Queue中,生产者生产消息并最终投递到Queue中,消费者可以从Queue中获取消息并消费。多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者
都收到所有的消息并处理。
(6)RoutingKey:生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过
指定routing key来决定消息流向哪里。RabbitMQ为routing key设定的长度限制为255bytes。
(7)Connection: (连接):Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。
(8)Channels: (信道):它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。
(9)VirtualHost:权限控制的基本单位,一个VirtualHost里面有若干Exchange和MessageQueue,以及指定被哪些user或者团队使用
在这里插入图片描述
在这里插入图片描述

3.简洁代码演示整个流程

(1)创建连接
在这里插入图片描述

public class MQConnectionUtils {

	// 创建新的MQ连接
	public static Connection newConnection() throws IOException, TimeoutException {
		// 1.创建连接工厂
		ConnectionFactory factory = new ConnectionFactory();
		// 2.设置连接地址
		factory.setHost("127.0.0.1");
		// 3.设置用户名称
		factory.setUsername("admin_yushengjun");
		// 4.设置用户密码
		factory.setPassword("123456");
		// 5.设置amqp协议端口号
		factory.setPort(5672);
		// 6.设置VirtualHost地址
		factory.setVirtualHost("/admin_host");
		//最后可以创建连接了
		Connection connection = factory.newConnection();
		return connection;
	}

}

(2)创建生产者

// 简单队列生产者
public class Producer {
	// 队列名称
	private static final String QUEUE_NAME = "xrCheng";
	public static void main(String[] args) throws IOException, TimeoutException {
		// 1.创建一个新的连接
		Connection connection = MQConnectionUtils.newConnection();
		// 2.创建通道
		Channel channel = connection.createChannel();
		// 3.创建一个队列
		channel.queueDeclare(QUEUE_NAME, false, false, false, null);
		channel.basicQos(1);
		for (int i = 1; i <= 50; i++) {
			// 4.创建msg
			String msg = xrCheng_msg_" + i;
			// System.out.println("生产者投递消息内容:" + msg);
			// 5.生产者发送消息者
			channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
		}
		// 关闭通道和连接
		channel.close();
		connection.close();
	}
}

然后到RabbitMQ客户端网页Queues一栏可以查看到新增加了xrCheng队列信息
(3)创建消费者

public class Consumer {
	// 队列名称
	private static final String QUEUE_NAME = "xrCheng";
	public static void main(String[] args) throws IOException, TimeoutException {
		System.out.println("消费者启动....01");
		// 1.创建一个新的连接
		Connection connection = MQConnectionUtils.newConnection();
		// 2.创建通道
		final Channel channel = connection.createChannel();
		// 3.消费者关联队列
		channel.queueDeclare(QUEUE_NAME, false, false, false, null);
		channel.basicQos(1);
		DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
			// 监听获取消息
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) throws IOException {
				String msg = new String(body, "UTF-8");
				System.out.println("消费者获取生产者消息:" + msg);
				try {
					Thread.sleep(1000);
				} catch (Exception e) {
					// TODO: handle exception
				} finally {
					// 手动应答 模式 告诉给队列服务器 已经处理成功
					// channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
		};
		// 4.设置应答模式 如果为true情况下 表示为自动应答模式 false 表示为手动应答
		channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
	}
}

(4)docker下安装

docker run -di --name=project_rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 rabbitmq:management

4.RabbitMQ五种形式队列

(1)点对点(简单)的队列
在这里插入图片描述
自动应答:不在乎消费者对这个消息处理是否成功。都会告诉队列删除该消息。如果处理消息失败情况下,实现自动补偿

手动应答:消费者处理完完业务逻辑,手动返回ack(通知)告诉队列服务器是否删除该消息
(2)工作(公平性)队列模式
默认消费者集群——均摊消费,假设生产者向队列发送10个消费者,消息1和2都各自消费5个,保证消费唯一。
思考:均摊消费有什么弊端?
如果每个消费者处理消息时间不同,可能对消费者处理比较慢的服务不公平
公平队列原理:队列服务向消费者发送消息时,消费者采用手动应答模式。队列服务器必须要收到消费者发送ack结果通知,才会接着发送下一个消息,谁应答快就能多消费消息

(3)发布订阅模式
(4)路由模式Routing
(5)通配符模式Topics

3.三种模式(直接、分裂、主题模式)
(1)直接模式(Direct):我们需要将消息发给唯一一个节点时使用这种模式,这是最简单的一种形式。
在这里插入图片描述
任何发送到Direct Exchange的消息都会被转发到RouteKey中指定的Queue。
1.一般情况可以使用rabbitMQ自带的Exchange:”"(该Exchange的名字为空字符串,下 文称其为default Exchange)。
2.这种模式下不需要将Exchange进行任何绑定(binding)操作
3.消息传递时需要一个“RouteKey”,可以简单的理解为要发送到的队列名字。
4.如果vhost中不存在RouteKey中指定的队列名,则该消息会被抛弃。
(2)分列模式(Fanout):当我们需要将消息一次发给多个队列时,需要使用这种模式。如下图:
在这里插入图片描述
任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定(Binding)的所有
Queue上。
1.可以理解为路由表的模式
2.这种模式不需要RouteKey
3.这种模式需要提前将Exchange与Queue进行绑定,一个Exchange可以绑定多个
Queue,一个Queue可以同多个Exchange进行绑定。
4.如果接受到消息的Exchange没有与任何Queue绑定,则消息会被抛弃。
(3)主题模式(Topic):任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的Queue上
在这里插入图片描述
如上图所示
此类交换器使得来自不同的源头的消息可以到达一个对列,其实说的更明白一点就是模
糊匹配的意思,例如:上图中红色对列的routekey为usa.#,#代表匹配任意字符,但是
要想消息能到达此对列,usa.必须匹配后面的#好可以随意。图中usa.news
usa.weather,都能找到红色队列,符号# 匹配一个或多个词,符号* 匹配不多不少一个
词。因此usa.# 能够匹配到usa.news.XXX ,但是usa.* 只会匹配到usa.XXX 。
注:交换器说到底是一个名称与队列绑定的列表。当消息发布到交换器时,实际上是由你所连接的信道,将消息路由键同交换器上绑定的列表进行比较,最后路由消息。
任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的
Queue上。
1.这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一
个“标题”(RouteKey),Exchange会将消息转发到所有关注主题能与RouteKey模糊匹配的
队列。
2.这种模式需要RouteKey,也许要提前绑定Exchange与Queue。
3.在进行绑定时,要提供一个该队列关心的主题,如“#.log.#”表示该队列关心所有涉及
log的消息(一个RouteKey为”MQ.log.error”的消息会被转发到该队列)。
4.“#”表示0个或若干个关键字,“”表示一个关键字。如“log.”能与“log.warn”匹配,无法
与“log.warn.timeout”匹配;但是“log.#”能与上述两者匹配。
5.同样,如果Exchange没有发现能够与RouteKey匹配的Queue,则会抛弃此消息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值