rabbitmq入门、工作模式

作用:

消息中间件

使用场景:

主要用于程序的解耦、异步处理、消息缓存作用。

eg1:打开快递柜取出快递时,设备相关模块会调用短信模块的发送短信接口,此时可以使用rabbitmq实现“异步处理”(如果采用同步处理,可能出现阻塞的问题)

eg2:消息缓存、异步处理以解决大并发的请求

例如:

举一些我们平常生活中的消费场景,例如:火车票、机票、门票等,通常来说这些服务在下单之后,后续的出票结果都是异步通知的,如果服务本身只支持每秒1000访问量,由于外部服务的原因突然访问量增加到每秒2000并发,这个时候服务接收者因为流量的剧增,超过了自己系统本身所能处理的最大峰值,如果没有对消息做限流措施,系统在这段时间内就会造成不可用,在生产环境这是一个很严重的问题,实际应用场景不止于这些
例如之前做的报表系统,由于单个报表包括很多请求,然后用户会同时打开多个报表,所以在报表使用高峰期时,即使使用集群部署+redis集群做缓存,但是还是可能导致服务会挂掉。此时使用rabbitmq来实现消息缓存

 

 

 

 

 

简单模式:

工作队列:

发布订阅模式:

路由模式:

主题模式:

rabbitmq控制台:

//todo

概念:

概念:

Brocker:消息队列服务器实体。

exchange:消息交换机,指定消息按照什么规则路由到那个队列

queue:消息队列,存储用户发送的消息(数据)

binding:把exchange和queue按照路由规则binding起来

routing key:路由关键字,exchange根据这个关键字进行消息投递到不同的队列

channel:消息通道,生产者和消费者的通信是通过channel

        //定义通道对象
        Channel channel = connection.createChannel();

        //定义队列
        channel.queueDeclare("queue_work", false, false, false, null);

producer、consumer

rabbitmq的工作模式:

简单模式:

工作的流程:
一个消费者和一个生产者模式,生产者生成消息,消费者监听消息。若是消费者监听到它所需要的消息,就会消费该消息,这种消息是次性的,被消费了就没有了。

工作队列:

流程:一个队列是可以多个生产者,也可以有多个消费者来竞争消费消息

应用场景:抢红包机制、秒杀业务

流程:生产者只能把消息发送给一个exchange ;

Exchange作用:接收从生产者发送过来的消息;把接收到的数据推送给队列

有4种类型的交换器:

Direct

Topic   主题模式

Redirect 路由模式

Fanout  发布订阅模式

发布订阅fanout

这样的消息属于广播型,两个不同名的队列的都能收到该消息,只需它们都将自己绑定到同一个交换机,

该消息是持久的,只要交换机还在,消费者啥时候上线都能消费它所绑定的交换机,

而且只会一个消费者只会消费一次。

应用场景:群发、微信公众号订阅

//生产者:

        //定义通道对象
        Channel channel = connection.createChannel();
        
        //定义队列
        channel.queueDeclare("queue_work", false, false, false, null);
        
        //定义广播的消息
        String msg = "我是工作模式";
        
        //发送消息
        channel.basicPublish("", "queue_work", null, msg.getBytes());
 
//消费者
	//定义消费者
	@Test
	public void consumer1() throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException{
		//定义通道
		Channel channel = connection.createChannel();
		
		//定义队列
		channel.queueDeclare("queue_work", false, false, false, null);
		
	//定义消费数  每次只能消费一条记录.当消息执行后需要返回ack确认消息 才能执行下一条
		//当由于网络原因,出现返回延时的现象,允许最多3次没有返回ack确认消息
		//当达到3次时,则不允许再次获取消息
		channel.basicQos(1); //
		
		//定义消费者
		QueueingConsumer consumer = new QueueingConsumer(channel);
		
		//将队列和消费者绑定  false表示手动返回ack
		channel.basicConsume("queue_work", false, consumer);
		
		while(true){
			QueueingConsumer.Delivery delivery = consumer.nextDelivery();
			String msg = new String(delivery.getBody());
			System.out.println("队列A获取消息:"+msg);
			//deliveryTag 队列下标位置
			//multiple是否批量返回
			channel.basicAck(delivery.getEnvelope().getDeliveryTag(), true);
		}
	}

 

路由模式: 根据不同的路由key发往不同的队列


生产者发送消息时需要配置交换机名称、路由key和发送消息
     //定义发布订阅模式    fanout    direct 路由模式    topic 主题模式
    channel.exchangeDeclare(exchange_name, "direct");
    /**exchange:交换机名称  routingKey:路由key  props:参数  body:发送消息*/
    channel.basicPublish(exchange_name, rontKey, null, msg.getBytes());
消费者需要定义队列名称  并且与交换机绑定(绑定路由key)
      channel.queueBind(queue, exchange, routingKey)

应用场景:根据功能模块的业务不同,发往不同的队列中

	//定义生产者
	@Test
	public void  proverder() throws IOException{
		Channel channel = connection.createChannel();
		
		//定义交换机名称
		String exchange_name = "redirect";
		
		
		//定义发布订阅模式    fanout    direct 路由模式    topic 主题模式
		channel.exchangeDeclare(exchange_name, "direct");
		
		for(int i=0;i<10; i++){
			String msg = "生产者发送消息"+i;
			String rontKey = "1707B";
			
			/**
			 * exchange:交换机名称
			 * routingKey:路由key
			 * props:参数
			 * body:发送消息
			 */
			channel.basicPublish(exchange_name, rontKey, null, msg.getBytes());
		}
		
		channel.close();
		connection.close();
	}
	
	/**
	 * 消费者需要定义队列名称  并且与交换机绑定
	 * @throws IOException
	 * @throws InterruptedException 
	 * @throws ConsumerCancelledException 
	 * @throws ShutdownSignalException 
	 */
	@Test
	public void consumer1() throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException{
		
		//定义通道
		Channel channel = connection.createChannel();
		
		//定义交换机名称
		String exchange_name = "redirect";
		
		//定义队列名称
		String queue_name = "c_r_1";
		
		//定义交换机模式
		channel.exchangeDeclare(exchange_name, "direct");
		
		//定义队列
		channel.queueDeclare(queue_name, false, false, false, null);
		
		//将队列和交换机绑定
		/**
		 * 参数介绍:
		 * 	queue:队列名称
		 *  exchange:交换机名称
		 *  routingKey:路由key
		 */
		//channel.queueBind(queue, exchange, routingKey)
		channel.queueBind(queue_name, exchange_name, "1707A");
		
		//定义消费个数
		channel.basicQos(1);
		
		//定义消费者
		QueueingConsumer consumer = new QueueingConsumer(channel);
		
		//绑定消息与消费者
		channel.basicConsume(queue_name, false, consumer);
		
		while(true){
			QueueingConsumer.Delivery delivery = consumer.nextDelivery();
			String msg = "路由模式-消费者1"+new String(delivery.getBody());
			System.out.println(msg);
			
			//手动回复 一个一个回复
			channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
		}

	}

主题模式topic:

说明:主题模式是路由模式的升级版,只要是满足条件的路由key,消息队列都可以接收消息.

通配符的格式:
*号:匹配一个或一组字符(以.分割)
#号.能够匹配任意的字符.
例子:
    Item.update.aabb       item.#  可以匹配
    Item.update               item.# item.* 都可以匹配

 

消费者:

        //将交换机和队列进行绑定   
        //参数1.队列名称     参数2交换机名称   参数3 路由key  #号匹配多个字符
        channel.queueBind(queue_name, exchange_name, "item.#");

	//定义生产者
	@Test
	public void proverder() throws Exception{
		//获取通道
		Channel channel = connection.createChannel();
		
		//定义交换机的名称
		String exchange_name = "TOP";
		
		//创建交换机队列   
		//exchange  交换机名称
		//type 定义类型 fanout 发布订阅模式   direct-路由模式    topic-主题模式
		channel.exchangeDeclare(exchange_name, "topic");  //主题模式
		
		for (int i = 0; i < 100; i++) {
			
			String msg = "主题模式"+i;
			
			/**
			 * 参数说明:
			 * 	exchange:交换机名称
			 *  routingKey:路由key
			 *  props:参数
			 *  body:数据字节码
			 */
			//channel.basicPublish(exchange, routingKey, props, body);
			channel.basicPublish(exchange_name,"item.update.abc", null, msg.getBytes());
		}
		channel.close();
		connection.close();
	}
	@Test
	public  void consumer1() throws Exception{
		
		//定义通道
		Channel channel = connection.createChannel();
		
		//定义交换机名称
		String exchange_name = "TOP";
		
		//定义队列名称
		String queue_name = "TOP1";
		
		//声明交换机名称以及主题模式
		channel.exchangeDeclare(exchange_name, "topic");
		
		//定义队列
		channel.queueDeclare(queue_name, false, false, false, null);
		
		//将交换机和队列进行绑定   
		//参数1.队列名称     参数2交换机名称   参数3 路由key  #号匹配多个字符
		channel.queueBind(queue_name, exchange_name, "item.#");
		
		channel.basicQos(1);  //定义消费数量  1
		
		//定义消费者
		QueueingConsumer consumer = new QueueingConsumer(channel);
		
		//将队列和消费者绑定
		channel.basicConsume(queue_name, false, consumer);  //定义手动回复
		
		while(true){
			QueueingConsumer.Delivery delivery = consumer.nextDelivery();
			//获取消息队列中的数据
			String msg = new String(delivery.getBody());
			System.out.println("item.#消费者1:"+msg);
			
			//手动回复
			channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);	
		}
	}

 

 

参考

https://mp.weixin.qq.com/s?src=11&timestamp=1603877323&ver=2672&signature=iYEV3AW5N6yHJcLV0asvn0JYC-oN6o5RLxr2bcgDgl0uT8OGYxpigDQ*Ww*bGrFCTd1rLvfZdHrrrggBkbuEVSBqRdsWYq*afPodLt6kL-PNp1iTx8YPzw02iyF*3Xfz&new=1

https://zhuanlan.zhihu.com/p/33974998

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值