生产者的核心配置:
一致性的保证:
生产者的核心配置。
2.投递到broker失败重新发送。
3.最大消息的大小。
4.主题下队列的数量。
5.是否自动创建,生产环境要设置为false。
7.consumer订阅topic可以配置为组,生产环境建议关闭。
10.Broker的服务地址。
12.每天执行过期文件删除是什么时候。
14.broker的监听端口。
15.消息的存储地址。
16.queue的消息条数。consumequeue每个默认是30W条。
17.单个commitLog默认是1G的。
这个可以拉大在电脑内存不足的时候。
---------------------------01-----------------------
ASYNC_MASTER:同步双写。
SYNC-MASTER:异步复制。
一个同步刷盘错误 两个同步双写错误。
第二个式同步双写。第三个是同步双写没找到子节点。
消息在堆同步到内存同步到磁盘。
第二点:
演示:
--------------------------------------------------------------------------------------------------
同步双写,异步刷盘
第三种:主从模式下配置为同步双写。没有找到子节点。一般第三种式比较常见的错误。
第一步:主节点改为同步复制。
第二步:代码不改。杀掉从节点SLAVE。
---------------------------------------------------------------------------------
测试:把主broker改为异步复制,重复上诉的步骤
异步的话不用给从节点直接返回成功。
------------------02-------------------
很重要的:
一条消息无论重试多少次,其MessageID和key都是不变的。
broker挂了,生产者是不能及时感知的。
消费者虽然消费消息了,但是只能给broker以ACK确认才可以在队列删除消息。
第一个知识点,我们如何设置生产者的重试的次数呢?
代码:02-06/02
代码
// 生产者的重试次数
producer.setRetryTimesWhenSendFailed(3);
生产者的重试的话,如何保证消息不重复生产呢?
这里有key,加入我们把订单号作为key。
@RequestMapping("/api/v1/pay_cb")
public Object callback(String text) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
Message message = new Message(JmsConfig.TOPIC,"taga", "业务订单的key,防止重复消费",("hello fdy rocketmq = "+text).getBytes() );
SendResult sendResult = payProducer.getProducer().send(message);
System.out.println(sendResult);
return new HashMap<>();
}
生产者不要过多的关注。
代码:
第二个知识点消费者的消息重试:
广播模式不支持消息重试的。
一般3-4次。
模拟:第一步:看下这个包装类。这个是Message的包装类。这个我本地没有写代码直接看截图。
基本的原理就是消费端没有给broker返回CONSUMER_SUCCESS,就一直重试。
第二步:改造代码
第三步:模拟异常,就不返回成功给broker了。
第三步:我们如何做异常的处理呢?在catch里面。并返回success。
返回CONSUMER_SUCCESS就删除队列的消息
返回RECONSUME_LATER就根据重试次数重试
在catch里面返回SUCCESS,自己处理错误。
----------------------------------------------------------------------------------------
第三个知识点:广播不重试
第一步:
第二步:
改为集群模式:
广播模式不支持重试的!!!!!!!!!!!!!!!!!!!!
--------------03--------------
我们之前都是同步的发送消息,现在我们异步的发送消息。
异步发送消息在发送端是不支持重试的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
代码:02
参考网址:https://rocketmq.apache.org/docs/simple-example/
发送异步的消息。
异步消息是不会重试的。
@RestController
public class PayController {
@Autowired
private PayProducer payProducer;
@RequestMapping("/api/v1/pay_cb")
public Object callback(String text) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
Message message = new Message(JmsConfig.TOPIC,"taga", "6666key",("hello fdy rocketmq = "+text).getBytes() );
// 如何异步的发送消息?
payProducer.getProducer().send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.printf("发送结果 %s,body=%s",sendResult.getSendStatus(),sendResult);
}
@Override
public void onException(Throwable e) {
e.printStackTrace();
// 补偿机制 根据业务场景看是不是重试机制的
}
});
return new HashMap<>();
}
}
快速响应不关心结果用的是异步的。
------------------04------------------
发送消息的多种场景对比:
异步:比如我们注册用户,注册成功了就返回,在onSuccess回调函数里面去发放和优惠券。
oneWay:例如日志搜集。
// 如何oneWay的发送消息
payProducer.getProducer().sendOneway(message);
看下源码:
应用场景:我们点击的淘宝的点击动作回传回服务器。点击淘宝的操作链路,用户的完整行为。
---------------------------05------------------------
延时消息:
我们看下源码:消息被消费的延迟级别。
注意:延时消息是在消息发送时候做的。
// 如何同步的发送消息
// SendResult sendResult = payProducer.getProducer().send(message);
// System.out.println(sendResult);
message.setDelayTimeLevel(2);
应用场景:
1.生日推送。2.订单延时。
--------------------06-----------------
指定队列发送消息。
MessageQueueSelector实战。
为什么这么用?假设有三类订单,要是手机的订单所在的队列满了就会影响家居和运动的订单的消费,所以指定队列。
这个是同步的发送消息。
// 如何指定队列发送消息
// 记住一个知识点,最后一个参数是通过传给arg的
SendResult sendResult = payProducer.getProducer().send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
int queneNumber = Integer.parseInt(arg.toString());
return mqs.get(queneNumber);
}
},1);
System.out.printf("发送结果 %s,body=%s",sendResult.getSendStatus(),sendResult);
修下面演示异步发送的。
// 如何指定队列发送消息异步发送
payProducer.getProducer().send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
int queneNumber = Integer.parseInt(arg.toString());
return mqs.get(queneNumber);
}
}, 3, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.printf("发送结果 %s,body=%s",sendResult.getSendStatus(),sendResult);
}
@Override
public void onException(Throwable e) {
}
});
第一个可以用lambda表达式,第二个有两个函数不能用lambda表达式的。
异步发送改为lambda表达式的写法。
什么是异步的发送:就是在回调函数返回结果,程序往下进行。
payProducer.getProducer().send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
int queneNumber = Integer.parseInt(arg.toString());
return mqs.get(queneNumber);
}
}, 3, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.printf("发送结果 %s,body=%s",sendResult.getSendStatus(),sendResult);
}
---------------07-------------------
顺序消息在电商应用。
顺序消息不能用异步的!!!!!!!!!!!!!!!!!!!!!
顺序消息是不支持广播的!!!!!!!!!!!!!!!!!!!!
----08----
代码:
顺序消息的讲解:
有序消费和并发消费:
如何做到顺序消费:同一个业务的id放在同一个队列里面。订单号的业务取模放在队列里面。同一个订单号就放在同一个队列里面了。
取模的话肯定不大于这个数。
同一个订单。
-----------------------09-------
原因:
看下官方的例子:
消费:
这个是比较古老的了。
-----------------------10-------
代码:换代码了-02-06模块的。
我们实现一个订单的支付步骤消息投递。
第一步:写生产订单。
第二步:发送订单,通过订单的编号去选择进入哪个队列。
@RequestMapping("/api/v2/pay_cb")
public Object callback() throws Exception {
List<ProductOrder> list = ProductOrder.getOrderList();
for(int i=0; i< list.size(); i++){
ProductOrder order = list.get(i);
Message message = new Message(JmsConfig.ORDERLY_TOPIC,"",
order.getOrderId()+"",order.toString().getBytes());
SendResult sendResult = payProducer.getProducer().send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Long id = (Long) arg;
long index = id % mqs.size();
return mqs.get((int)index);
}
},order.getOrderId());
System.out.printf("发送结果=%s, sendResult=%s ,orderid=%s, type=%s\n", sendResult.getSendStatus(), sendResult.toString(),order.getOrderId(),order.getType());
}
return new HashMap<>();
}
第三步:发送成功
顺序消费的消费者。
代码:
消费者线程池:
第一步:写consumer
1是我们原来用的,现在我们要用到新的2。
第二步:再写consumer
第三步查看消费:
第四步:思考多个consumer怎么办?
topic里面有多个queue,consumer会平均分配queue的数量,consumer是小于queue的。
---------------------------------
多consumer怎么办?
第一步:相同的工程启动两次,换端口号。
架构:
每个consumer两个queue。
8080的
8081的
第三步:启动三个consumer
则每个分一个队列。
第四步:总结
就在这里 和原来的不一样。
-------------------------11-------------------------