- 😃作者简介:前阿里淘天、现字节跳动高级 Java 开发工程师
- 💻称 号:CSDN 博客专家✨、阿里云博客专家🌟
- 🔍公众号:云服务小管家。免费💡的阿里云服务器☁ 和云环境直接使用
- 💪生活:专注于后端技术分享🎓迷茫时可来瞅瞅码农轨迹🚶♂️
- 📋服务:提供模拟面试和简历辅导,提供生产项目。📩内推可私信✉
- 💬卷卷群:可以和大家一起学习,一起进步👀
- 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🌟🌟🌟三连找UP免费领取阿里云服务器,可以测试本项目。
背景
本文已广告系统中的审核视频(广告素材)为例进行讲解。作为一个多租户的中台系统,上游承接着不同的租户。
抖音租户场景是先投后审,比如我先默认审核通过,等你真正审核的时候如果审核没通过我再把这个视频拉下线。
懂车帝场景是先审后投,只有通过的才投放。
针对这两种场景,抖音租户只需要感知审核拒绝的消息,而懂车帝租户只需要感知审核通过的消息。这里就是一个差异点。
如果租户C感知变更消息呢?如果租户D感知新建消息呢?那兼容这块代码那就屎山雕花了!!!
因此本项目解决是下游系统反向异步通知上游消息的标准化问题。
说人话:binlog消息标准化
方案设计
消息链路设计
通过将binlog消息标准化,然后发到MQ消息上,上游自行消费。通知消息与业务代码解耦。
层级设计
下面是一个例子,会更好理解一些。
-
领域AdDomain
DDD领域驱动设计中的领域,如果不理解可以理解成订单领域和物流领域两个区别。 -
领域实体DomainEntity
风控域的话审核多种类型,针对不同的类型,我这里把他区分为不同的实体,比如图片、视频、文案、落地页等等 -
数据源DomainDataSource
以视频为例,有一个主表,有一个附表,如果你是大宽表那就是一个主表。这里是指的真实的物理表映射。
-
领域事件DomainEvent
在上面的物理表上衍生的事件,还是以视频审核为例。
主表:新增视频事件、删除视频事件、审核状态变更事件
附表:外审状态变更事件
技术选型
- SpringBoot
- Canal
- MySQL
- Guava
本地缓存全部的配置数据,也不大 - RocketMQ
发送的MQ使用RocketMQ而不是Kafka,因为RocketMQ有sql-filter的能力,这样可能把过滤逻辑上抛到broker端而不是消费者。
环境搭建
🌟🌟🌟三连找UP免费领取阿里云服务器,可以测试本项目。
docker安装MySQL
首先,在本地创建一个 MySQL 配置文件,例如 my.cnf,并添加开启二进制日志的配置。
[mysqld]
log-bin=mysql-bin
binlog-format=ROW
docker启动
docker run --name mysql-86-20220702 -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /opt/mysql/my.cnf:/etc/mysql/my.cnf mysql:5.7
通过下面命令查看binlog
SHOW MASTER STATUS;
安装Canal的Server端
步骤1:安装JDK
检查是否已安装
java -version
如果没有安装,请先安装OpenJDK或Oracle JDK:
sudo yum install java-1.8.0-openjdk
步骤2:安装Canal的Server端
使用wget命令下载Canal:
wget https://github.com/alibaba/canal/releases/download/canal-1.1.5/canal.deployer-1.1.5.tar.gz
然后解压下载的文件:
mkdir /usr/local/canal
tar -zxvf canal.deployer-1.1.5.tar.gz -C /usr/local/canal
步骤 3: 配置Canal
进入Canal的配置目录进行必要的配置修改:
cd /usr/local/canal/conf
编辑example/instance.properties文件来设置你的MySQL连接信息:
# 修改为你的MySQL实例地址
canal.instance.master.address=your_mysql_host:3306
# MySQL用户名和密码
canal.instance.dbUsername=root
canal.instance.dbPassword=123456
步骤 4: 启动Canal
cd /usr/local/canal
sh bin/startup.sh
启动后,你可以查看日志文件以确认Canal是否正常运行
tail -f logs/canal/canal.log
源码
https://gitee.com/cbeann/domain-message
启动后可以安装下面的进行测试:
-
修改代码CanalListener中硬编码的IP,修改为你Canal的Server端IP
-
把resources/sql/domain_message导入到MySQL中,
其中【领域AdDomain】【领域实体DomainEntity】【数据源DomainDataSource】【领域消息事件DomainEvent】均在代码中加了几条数据。 -
测试插入领域事件
在domain_message库order表新增一条记录,领域事件在DomainEventRepository中的ORDER_NEW
-
测试修改领域事件
在domain_message库order表修改id=1的order_status变一下,领域事件在DomainEventRepository中的ORDER_STATUS_CHANGE
-
测试删除领域事件
在domain_message库order表删除id=1的记录,领域事件在DomainEventRepository中的ORDER_DELETE
项目面试题
使用了什么设计模式
使用了责任链模式。当收到binlog消息后,第一个处理器是做过滤逻辑(黑白名单用户、无关的表消息)。
第二个处理器是封装Event,第三个处理器是发送MQ。
为什么选择RocketMQ
发送的MQ使用RocketMQ而不是Kafka,因为RocketMQ有sql-filter的能力,这样可能把过滤逻辑上抛到broker端而不是消费者。
消息如何保证不丢失
任何MQ都保证不了,加对账保证100%不丢失。