每个消息有唯一的messageID和自己的id。
分布式事务。
不同的微服务和不同的数据库。
------------------------------------------------01------------------------------
默认是储存的是3天的消息。
走一遍流程:
第一步:produce投递消息到broker
第二步:broker回传消息投递成功的信息
第三步:执行本地的事务
第四步:再给broker发信息如果事务成功,则给broker发送消息为可被消费走第五步,如果是Rollback删除半消息,三天之后删除,如果是网络不好的话就回查走第六步。
第五步:给consumer发消息订阅
第六步:服务端主动发个请求确认事务状态
第七步:本地事务检查,commit还是rollback
第八步:rollback的话不投递消息储存三天后删除
consumer重试消息失败的话就把失败的消息存到数据库里面去。
------------------------------------------------02-----------------------------
讲义所讲:
------------------------------------------------------------------------------------------
实战。
第一步:
consumer是不变的。
第二步:
// 本地的事物的
class TransactionListenerImpl implements TransactionListener{
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
return null;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
return null;
}
}
第三步:new事务的监听器。
//事务监听器
private TransactionListener transactionListener = new TransactionListenerImpl();
第四步:
Decapitator 2020/2/13 23:13:49
public TransactionProducer(){
producer = new TransactionMQProducer(producerGroup);
producer.setNamesrvAddr(JmsConfig.NAME_SERVER);
// 生产者设置事务监听器
producer.setTransactionListener(transactionListener);
producer.setExecutorService(executorService);
//指定NameServer地址,多个地址以 ; 隔开
start();
}
第五步:设置线程池,直接拷贝官方文档的代码 我们要开线程去回查的。
//一般自定义线程池的时候,需要给线程加个名称
private ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(2000), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("client-transaction-msg-check-thread");
return thread;
}
});
第六步:写controller
@Autowired
private TransactionProducer transactionMQProducer;
@RequestMapping("/api/v1/pay_cb")
public Object callback( String tag, String otherParam ) throws Exception {
Message message = new Message(JmsConfig.TOPIC, tag, tag+"_key",tag.getBytes());
SendResult sendResult = transactionMQProducer.getProducer().
sendMessageInTransaction(message, otherParam);
System.out.printf("发送结果=%s, sendResult=%s \n", sendResult.getSendStatus(), sendResult.toString());
return new HashMap<>();
}
----------------------------------------03----------------------------
第一步:我们启动下我们的代码
第一次为半消息,不能被消费。
第二步:
第一个:半消息投递成功,方法会被调用执行本地的事务
第二个:没有半消息相应的时候,回查事务的状态
我们注意到一点:otherParam会被传递到作为红框的参数。
第三步:我们写监听器本地事务的。
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
System.out.println("====executeLocalTransaction=======");
String body = new String(msg.getBody());
String key = msg.getKeys();
String transactionId = msg.getTransactionId();
System.out.println("transactionId="+transactionId+", key="+key+", body="+body);
// 执行本地事务begin TODO
// 执行本地事务end TODO
int status = Integer.parseInt(arg.toString());
//二次确认消息,然后消费者可以消费
if(status == 1){
return LocalTransactionState.COMMIT_MESSAGE;
}
//回滚消息,broker端会删除半消息
if(status == 2){
return LocalTransactionState.ROLLBACK_MESSAGE;
}
//broker端会进行回查消息,再或者什么都不响应
if(status == 3){
return LocalTransactionState.UNKNOW;
}
return null;
}
第四步:回查:根据上一步的返回值进行回查。提交消息。
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
System.out.println("====checkLocalTransaction=======");
String body = new String(msg.getBody());
String key = msg.getKeys();
String transactionId = msg.getTransactionId();
System.out.println("transactionId="+transactionId+", key="+key+", body="+body);
//要么commit 要么rollback
//可以根据key去检查本地事务消息是否完成
return LocalTransactionState.COMMIT_MESSAGE;
}
第五步:我们实际的演练下
我们演示消息成功的情况。参数是1。
我们输入网址测试:
http://localhost:8081/api/v1/pay_cb?tag=order_pay&otherParams=1
消费了。
第六步:我们如何回查消息
http://localhost:8081/api/v1/pay_cb?tag=order_pay&otherParams=3
过一会就回去会查了:
第七步:我们模拟rollback的message。
http://localhost:8081/api/v1/pay_cb?tag=order_pay&otherParams=2
这次我们不会进入到回查的函数的,是因为再broker删除了。
总结:
1.可被消费2.broker端把消息进行删除3.回查
-------------------------
回查:知识点:
我们会通过这个key作为校验的。
----
注意点:
这个必须是唯一的,不能和普通的一样,会冲突。
---------------
回顾:
第一步:produce首先会发送半消息到broker端。
相当于第一步,第二步。
第二步:执行本地事务操作对应的代码
第三步:
提交给broker信息。
是不是可以消费,可以消费consumer进行打印。
第四步:
返回的是rollback则直接删除broker里面的消息不进行回查的。
第五步:
或者什么都不相应。
回查消息。
一般拿到key就是唯一的标识,比如订单号。
---------------------04------------------
源码剖析:
第一步,源码的查看。
这部分源码的查看。
在这一步把消息变成一个半消息。
sendmsg:就是发送简单的消息。
再往下:
设置默认是为UNKNOW。
再往下:
这里点进去就是检查本地的事务。
再往下:
点进去:
传进来两个值。
第一步是事务的id,第二步是告诉broker找对应的消息。
判断。发送给broker。
注意L:
事务的id和msgId是一致的。
--------------------------------------------------------------------------05--------------------