activeMq 启动报错:
https://blog.csdn.net/wenghaoduan/article/details/51295388
消息怎么保证顺序性,以及消息发送后,但是接收方宕机了,消息怎么保证能重复发送。
即:MQ,如何做到消息必达 https://blog.csdn.net/babylovewei/article/details/80825946
顺序性的保证在 后面学习 rocketMq时 研究。
DCL模型
定时补偿+幂等消费
推拉结合
Event-Sourcing和MQ,实现RPC式分布式事务
java中,回调函数的使用
见网址: https://blog.csdn.net/u010211479/article/details/51490152
https://blog.csdn.net/jiahao1186/article/details/81988866
写一个基于 activeMq 的分布式事务项目:
以用户注册场景为例,需求是新用户注册之后 给该用户现在一条积分记录。 假设用户有服务和积分两个服务,用户服务使用数据库db1, 积分服务使用数据库db2. 服务调用者只需要使用用户新增服务, 由服务内部 既保证db1 新增用户记录, db2新增积分记录。 这是一个分布式问题。
通过 本地表 加上 消息队列的模式来解决这个问题。
两个需要考虑的意外场景:
第一:用户服务在保存用户记录后 没来得及给消息队列发消息就 宕机了,得保证新增用户记录后 一定有消息发送到消息队列。
第二:积分服务接收到消息后 没来得及保存积分记录就宕机了,得保证重启系统后,不丢失积分记录。
一共四张表:其实是通过事件表和新增用户记录的db1 的本地数据库事务的绑定 以及 事件表和新增积分记录的db2 的本地数据库事务的绑定 来达到 事务一致性。
CREATE TABLE `t_user` (
`id` varchar(50) NOT NULL,
`user_name` varchar(100) DEFAULT NULL COMMENT '用户名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_event`;
CREATE TABLE `t_event` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(30) DEFAULT NULL COMMENT '事件类型',
`process` varchar(30) DEFAULT NULL COMMENT '表示事件进行到了哪个环节',
`content` text COMMENT '事件包含的内容',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
CREATE TABLE `t_point` (
`id` varchar(50) NOT NULL,
`user_id` varchar(50) DEFAULT NULL COMMENT '关联的用户ID',
`amount` int(11) DEFAULT NULL COMMENT '积分金额',
PRIMARY KEY (`id`)
) ENGINE=Inno DB DEFAULT CHARSET=utf8
;
DROP TABLE IF EXISTS `t_event`;
CREATE TABLE `t_event` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(30) DEFAULT NULL COMMENT '事件类型',
`process` varchar(30) DEFAULT NULL COMMENT '表示事件进行到了哪个环节',
`content` text COMMENT '事件包含的内容',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
整个的操作图 如下:
操作图描述如下:
db1:用户表t_user, 事件表t_event ,
db2:积分表t_point , 事件表t_event 。
第一步:用户服务在接受 到请求之后再 t_user 创建一条用户记录,并在t_event新增一条process为NEW的事件记录, 同时要创建的积分数据 以JSON字符串的形式 保存到 db1的t_event的content中, 提交事务。
第二步:在用户系统中,开启一个定时任务 查询db1的t_event表中 process为NEW的记录, 一旦有记录,则向消息队列发送消息, 消息内容就是第一步保存在 db1的t_event的content中的数据; 消息发送成功后,把process改为PUBLISHED,提交事务。
第三步:积分系统 接收到消息后,在db2的t_event表中 新增一条process为 PUBLISHED的记录, content保存接收到的消息内容, 保存t_event成功后返回,提交事务。
第四步:在积分系统中 开始定时任务, 轮询db2的t_event表 中 所有 proesss为 PUBLISHED的记录, 拿到表记录后将 content字段内容 转化成积分对象,保存积分记录, 保存成功后,修改t_event的process的 PROCESSED, 提交事务。
结束。
该方案 基本上能保证两个数据源db1和db2的一致性, 但是没有考虑mq的稳定性, 以及逻辑设计的比较复杂。
后面rocketMq 有更好的一致性方案。
代码地址:
git@github.com:tuyf/activeMq.git