经过昨天的营业
我们总结一下,现在营业的问题
首先,从始至终,我们的面包店只有一个顾客
这不行嘛,这不仅赚不到钱,还得亏钱
所以,我们要打广告,让更多的顾客进入~
但是顾客多了,就回到了我们昨天的那个问题了:
如果来了多个顾客,正好第一个顾客还是个土豪,一口气说要二百个,但是第二个也在等,是不是我先要保证第一个不走,第二个也不走呢?还得考虑到第一个顾客应该要拿多点(不然他应该会不爽,毕竟人家先来嘛)
机智的我怎么会被这种问题难倒呢?
首先我们来看,RabbitMQ中的Work模式:
即一个生产者,多个消费者
需要注意的是:
(1)我就算有很多面包,但是我一个面包也只能给到一个消费者嘛,即:生产者的消息是发送到一个队列里,所以即使有两个消费者,一个消息只能被一个消费者消费。
(2)Work模式中可以分为两种模式:
公平队列:两个消费者平均消费队列中的消息,即使它们的消费能力是不一样的;
能者多劳:消费能力强的消费者会获取更多的消息。
那我们先看看啥是公平队列
@RestController
public class Producer {
@Autowired
RabbitTemplate template;
@GetMapping("/makeLover")
public String makeLover(){
for (int i = 0; i < 50; i++) {
String msg = "send msg = " + i;
try {
//每发一条消息睡一会会
Thread.sleep(i * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
template.convertAndSend(AppConfig.EXCHANGE_NAME,AppConfig.ROUTING_KEY,msg);
}
return "OK";
}
}
@Component
public class Consumer {
// tag代表投递的标识符,唯一标识了当前信道上的投递,通过 deliveryTag ,消费者就可以告诉 RabbitMQ 确认收到了当前消息
@RabbitListener(queues = AppConfig.QUEUE_NAME)
public void getLover(String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) Long tag) {
try {
//这里代表顾客收到了一个面包,false等于是他要一个个对比是不是自己要的,ture的话他就直接全部打包了
Thread.sleep(10);
channel.basicAck(tag, false);
System.out.println(msg + "顾客1确认");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
@RabbitListener(queues = AppConfig.QUEUE_NAME)
public void getLover2(String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) Long tag) {
try {
//这里代表顾客收到了一个面包,false等于是他要一个个对比是不是自己要的,ture的话他就直接全部打包了
Thread.sleep(1000);
channel.basicAck(tag, false);
System.out.println(msg + "顾客2确认");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
</pre>
然后我们看看结果:
send msg = 0顾客1确认
send msg = 2顾客1确认
send msg = 4顾客1确认
send msg = 6顾客1确认
send msg = 8顾客1确认
send msg = 10顾客1确认
send msg = 12顾客1确认
send msg = 1顾客2确认
send msg = 14顾客1确认
send msg = 16顾客1确认
send msg = 18顾客1确认
send msg = 3顾客2确认
send msg = 20顾客1确认
send msg = 22顾客1确认
send msg = 5顾客2确认
send msg = 24顾客1确认
send msg = 26顾客1确认
send msg = 7顾客2确认
send msg = 28顾客1确认
send msg = 30顾客1确认
send msg = 9顾客2确认
send msg = 32顾客1确认
send msg = 34顾客1确认
send msg = 11顾客2确认
send msg = 36顾客1确认
send msg = 13顾客2确认
send msg = 38顾客1确认
send msg = 15顾客2确认
send msg = 40顾客1确认
send msg = 17顾客2确认
send msg = 42顾客1确认
send msg = 44顾客1确认
send msg = 19顾客2确认
send msg = 46顾客1确认
send msg = 21顾客2确认
send msg = 48顾客1确认
send msg = 23顾客2确认
send msg = 25顾客2确认
send msg = 27顾客2确认
send msg = 29顾客2确认
send msg = 31顾客2确认
send msg = 33顾客2确认
send msg = 35顾客2确认
send msg = 37顾客2确认
send msg = 39顾客2确认
send msg = 41顾客2确认
send msg = 43顾客2确认
send msg = 45顾客2确认
send msg = 47顾客2确认
send msg = 49顾客2确认</pre>
可以看到,顾客1永远拿了个奇数,顾客2永远拿了个偶数
拿明显不对嘛,顾客一明显钱更多
我这么好的人,怎么可能不会劫富济贫呢?
所以,我们的第二个模式就上线了!
能(jie)者(fu)多(ji)劳(pin)模式:
// tag代表投递的标识符,唯一标识了当前信道上的投递,通过 deliveryTag ,消费者就可以告诉 RabbitMQ 确认收到了当前消息
@RabbitListener(queues = AppConfig.QUEUE_NAME)
public void getLover(String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) Long tag) throws IOException {
//这里三个参数代表:
//prefetchSize: 单条消息的大小限制,消费端通常设置为0,表示不做限制
//prefetchCount: 一次最多能处理多少条消息,通常设置为1
//global: 是否将上面设置应用于channel,false代表consumer级别
//也就是说 我们保证每次这个顾客都只拿到一个
channel.basicQos(0,1,true);
try {
System.out.println(msg + "顾客1确认");
//这里代表顾客收到了一个面包,false等于是他要一个个对比是不是自己要的,ture的话他就直接全部打包了
channel.basicAck(tag, false);
Thread.sleep(10);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}</pre>
那么第一个顾客设置完了,我们把第二个也设置一样的
然后我们看看结果:
send msg = 0顾客1确认
send msg = 2顾客1确认
send msg = 4顾客1确认
send msg = 5顾客1确认
send msg = 6顾客1确认
send msg = 7顾客1确认
send msg = 8顾客1确认
send msg = 9顾客1确认
send msg = 10顾客1确认
send msg = 11顾客1确认
send msg = 12顾客1确认
send msg = 13顾客1确认
send msg = 14顾客1确认
send msg = 16顾客1确认
send msg = 17顾客1确认
send msg = 18顾客1确认
send msg = 19顾客1确认
send msg = 20顾客1确认
send msg = 22顾客1确认
send msg = 23顾客1确认
send msg = 24顾客1确认
send msg = 26顾客1确认
send msg = 27顾客1确认
send msg = 28顾客1确认
send msg = 30顾客1确认
send msg = 31顾客1确认
send msg = 32顾客1确认
send msg = 34顾客1确认
send msg = 36顾客1确认
send msg = 38顾客1确认
send msg = 39顾客1确认
send msg = 40顾客1确认
send msg = 42顾客1确认
send msg = 44顾客1确认
send msg = 46顾客1确认
send msg = 48顾客1确认
send msg = 29顾客2确认
send msg = 25顾客2确认
send msg = 15顾客2确认
send msg = 21顾客2确认
send msg = 1顾客2确认
send msg = 3顾客2确认
send msg = 33顾客2确认
send msg = 35顾客2确认
send msg = 41顾客2确认
send msg = 37顾客2确认
send msg = 47顾客2确认
send msg = 49顾客2确认
send msg = 45顾客2确认
send msg = 43顾客2确认</pre>
可以看到我确实能(jie)者(fu)多(ji)劳(pin)了
同样这个能(jie)者(fu)多(ji)劳(pin)可以做到限流的问题。
因为RabbitMQ的特性嘛,那如果我面包房现在有2w存货(没过期啊喂,我可不是黑心商家)
现在来了一个顾客,那这个特性就是一股脑全给他
那如果本身他只要拿一个,然后去挑挑选选,干他自己的事情
你全丢给他了
你猜他会不会疯了?
所以我们每次只接受一个,等他把自己的事情干完了,再来拿第二个
这样我们能保证他不崩溃,也能起到一个限流的作用。
要不今天就先关门吧?
我要去投诉一下快递~
明天再来解决一下面包的保质期(消息生存时间)以及我们的垃圾桶(死信队列)问题
那今天就拜拜咯~