第二十一章 短链服务冗余双写-链路测试和异常消息处理实战
第1集 冗余双写MQ架构-消费者配置自动创建队列和集群测试
简介: 冗余双写MQ架构-MQ消费者配置自动创建队列
- controller-service层开发
- 配置文件配置MQ
##----------rabbit配置--------------
spring.rabbitmq.host=120.79.150.146
spring.rabbitmq.port=5672
#需要手工创建虚拟主机
spring.rabbitmq.virtual-host=dev
spring.rabbitmq.username=admin
spring.rabbitmq.password=password
#消息确认方式,manual(手动ack) 和auto(自动ack)
spring.rabbitmq.listener.simple.acknowledge-mode=auto
-
大家遇到的问题 (不会自动创建队列)
- 加了@bean配置交换机和queue,启动项目却没自动化创建队列
- RabbitMQ懒加载模式, 需要配置消费者监听才会创建,
@RabbitListener(queues = "short_link.add.link.queue")
-
另外种方式(若Mq中无相应名称的队列,会自动创建Queue)
@RabbitListener(queuesToDeclare = { @Queue("short_link.add.link.queue") })
-
链路测试-多节点启动
第2集 冗余双写架构-MQ消费者异常重试处理方案链路
简介: 冗余双写架构-MQ消费者异常处理方案讲解
- 消费者异常情况处理
- 业务代码自己重试
- 组件重试
- RabbitMQ配置重试
#开启重试,消费者代码不能添加try catch捕获不往外抛异常
spring.rabbitmq.listener.simple.retry.enabled=true
#最大重试次数
spring.rabbitmq.listener.simple.retry.max-attempts=4
# 重试消息的时间间隔,5秒
spring.rabbitmq.listener.simple.retry.initial-interval=5000
- 问题:多次重试失败怎么处理?
- 解决方式:RepublishMessageRecoverer
- 消息重试一定次数后,用特定的routingKey转发到指定的交换机中,方便后续排查和告警
第3集 冗余双写架构-MQ消费者异常重试处理方案编码实战
简介: 冗余双写架构-MQ消费者异常重试处理方案编码实战
- 解决方式:RepublishMessageRecoverer
- 消费消息重试一定次数后,用特定的routingKey转发到指定的交换机中,方便后续排查和告警
- 注意
- 消息消费确认使用自动确认方式
@Configuration
@Data
public class RabbitMQErrorConfig {
private String shortLinkErrorExchange = "short_link.error.exchange";
private String shortLinkErrorQueue = "short_link.error.queue";
private String shortLinkErrorRoutingKey = "short_link.error.routing.key";
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 异常交换机
* @return
*/
@Bean
public TopicExchange errorTopicExchange(){
return new TopicExchange(shortLinkErrorExchange,true,false);
}
/**
* 异常队列
* @return
*/
@Bean
public Queue errorQueue(){
return new Queue(shortLinkErrorQueue,true);
}
/**
* 队列与交换机进行绑定
* @return
*/
@Bean
public Binding BindingErrorQueueAndExchange(Queue errorQueue,TopicExchange errorTopicExchange){
return BindingBuilder.bind(errorQueue).to(errorTopicExchange).with(shortLinkErrorRoutingKey);
}
/**
* 配置 RepublishMessageRecoverer
* 用途:消息重试一定次数后,用特定的routingKey转发到指定的交换机中,方便后续排查和告警
*
* 顶层是 MessageRecoverer接口,多个实现类
*
* @return
*/
@Bean
public MessageRecoverer messageRecoverer(){
return new RepublishMessageRecoverer(rabbitTemplate,shortLinkErrorExchange,shortLinkErrorRoutingKey);
}
}
第二十二章 短链服务冗余双写问题抛出-MQ消费者链路开发
第1集 冗余双写架构-高并发下短链码生成端问题抛出
简介: 冗余双写架构-短链码生成端问题抛出
- 短链码是哪里生成?生产者端 还是消费者端
- 生产者生成短链码,下面的情况
- 用户A生成短链码AABBCC,查询数据库不存在,发送MQ,插入数据库成功
- 用户B生成短链码AABBCC,查询数据库不存在,发送MQ,插入数据库失败
- 消费者生成短链码,下面的情况
- 用户A生成短链码AABBCC ,C端先插入,B端还没插入
- 用户B也生成短链码AABBCC ,B端先插入,C端还没插入
- 用户A生成短链码AABBCC ,B端插入
- 用户B生成短链码AABBCC ,C端插入
- 生产者生成短链码,下面的情况
第2集 冗余双写架构-商家创建短链-C端消费者开发实战
简介: 冗余双写架构-商家创建短链-C端消费者开发实战
- C端消费者开发实战
//判断短链域名是否合法
//判断组名是否合法
//生成长链摘要
//生成短链码
//加锁
//查询短链码是否存在
//构建短链对象
//保存数据库
第3集 冗余双写架构-商家创建短链-B端消费者开发实战
简介: 冗余双写架构-商家创建短链-B端消费者开发实战
- B端消费者开发实战
//生成长链摘要
//判断短链域名是否合法
//判断组名是否合法
//生成短链码
//加锁(加锁再查,不然查询后,加锁前有线程刚好新增)
//查询短链码是否存在
//构建短链mapping对象
//保存数据库
public boolean handlerAddShortLink(EventMessage eventMessage) {
Long accountNo = eventMessage.getAccountNo();
String messageType = eventMessage.getEventMessageType();
ShortLinkAddRequest addRequest = JsonUtil.json2Obj(eventMessage.getContent(), ShortLinkAddRequest.class);
//短链域名校验
DomainDO domainDO = checkDomain(addRequest.getDomainType(), addRequest.getDomainId(), accountNo);
//校验组是否合法
LinkGroupDO linkGroupDO = checkLinkGroup(addRequest.getGroupId(), accountNo);
//长链摘要
String originalUrlDigest = CommonUtil.MD5(addRequest.getOriginalUrl());
//生成短链码
String shortLinkCode = shortLinkComponent.createShortLinkCode(addRequest.getOriginalUrl());
//TODO 加锁
//先判断是否短链码被占用
ShortLinkDO ShortLinCodeDOInDB = shortLinkManager.findByShortLinCode(shortLinkCode);
if(ShortLinCodeDOInDB == null){
//C端处理
if (EventMessageType.SHORT_LINK_ADD_LINK.name().equalsIgnoreCase(messageType)) {
ShortLinkDO shortLinkDO = ShortLinkDO.builder()
.accountNo(accountNo)
.code(shortLinkCode)
.title(addRequest.getTitle())
.originalUrl(addRequest.getOriginalUrl())
.domain(domainDO.getValue())
.groupId(linkGroupDO.getId())
.expired(addRequest.getExpired())
.sign(originalUrlDigest)
.state(ShortLinkStateEnum.ACTIVE.name())
.del(0)
.build();
shortLinkManager.addShortLink(shortLinkDO);
return true;
} else if (EventMessageType.SHORT_LINK_ADD_MAPPING.name().equalsIgnoreCase(messageType)) {
//B端处理
GroupCodeMappingDO groupCodeMappingDO = GroupCodeMappingDO.builder()
.accountNo(accountNo)
.code(shortLinkCode)
.title(addRequest.getTitle())
.originalUrl(addRequest.getOriginalUrl())
.domain(domainDO.getValue())
.groupId(linkGroupDO.getId())
.expired(addRequest.getExpired())
.sign(originalUrlDigest)
.state(ShortLinkStateEnum.ACTIVE.name())
.del(0)
.build();
groupCodeMappingManager.add(groupCodeMappingDO);
return true;
}
}
return false;
}
第4集 同个URL生成短链码随机库表位问题和解决方案讲解
简介: 同个URL生成短链码随机库表位问题和解决方案讲解
-
需求
- App的下载链接,需要进行投放广告,并验证不同渠道的效果质量
- 渠道:抖音、百度、新浪微博、知乎、B站、头条等
- 最终下载地址一样,但是需要区分不通渠道效果质量
-
问题抛出
-
MurmurHash对同个url产生后的值是一样的,但是随机拼接了库表位,最终生成的短链码就导致可能不一致的情况,怎么解决?
-
问题重现
-
答案
- MurmurHash后的短链码,拼接随机库表位需要固定
- 采用hashCode取模生成对应的库表位
-
第5集 MurmurHash短链码改进之生成固定库表位编码实战
简介: MurmurHash短链码改进之生成固定库表位编码实战
- 编码实战
/**
* 获取随机的后缀
* @return
*/
public static String getRandomTableSuffix(String code){
int hashCode = code.hashCode();
int num = Math.abs(hashCode) % tableSuffixList.size();
return tableSuffixList.get(num);
}
/**
* 获取随机的前缀
* @return
*/
public static String getRandomDBPrefix(String code){
int hashCode = code.hashCode();
int num = Math.abs(hashCode) % dbPrefixList.size();
return dbPrefixList.get(num);
}
第6集 同个URL生成不唯一短链码问题和解决方案讲解
简介: 同个URL生产唯一短链码问题和解决方案讲解
-
需求
- App的下载链接,需要进行投放广告,并验证不同渠道的效果质量
- 渠道:抖音、百度、新浪微博、知乎、B站、头条等
- 最终下载地址一样,但是需要区分不通渠道效果质量
-
问题抛出:
-
解决了随机库表问题后,一个URL怎么生成多个不一样的短链码
-
URL重复生成短链问题
- 如果原始URL不做处理,则重复概率很高
- 方案:原始url 拼接随机串,访问前去除
-
问题重现
-
答案
- 生产者发送消息携带一个时间戳 或 随机id
- 原始URL开头拼接特殊字段
- 原生 https://baidu.com
- 拼接后 1469558440337604610||https://baidu.com
- 如果冲突,则编号递增1
- 访问前截取去除
-
第7集 同个URL生成不唯一短链码问题和解决方案编码实战
简介: 同个URL生成不唯一短链码问题和解决方案编码实战
- 工具类编写
/**
* URL增加前缀
* @param url
* @return
*/
public static String addUrlPrefix(String url){
return IDUtil.geneSnowFlakeID()+"&"+url;
}
/**
* URL移除前缀
* @param url
* @return
*/
public static String removeUrlPrefix(String url){
String originalUrl = url.substring(url.indexOf("&")+1);
return originalUrl;
}
/**
* 如果短链码重复,则调用这个方法
* url前缀编号递增1,如果还是用雪花算法,则容易C和B端不一致,所以采用原先的id递增1
* @param url
* @return
*/
public static String addUrlPrefixVersion(String url){
String result = url.substring(0,url.indexOf("&"));
//原始地址
String originalUrl = url.substring(url.indexOf("&")+1);
//新id编号
Long newIdValue = Long.parseLong(result)+1;
return newIdValue+"&"+originalUrl;
}
- 编码实战
//发送MQ消息
@Override
public JsonData createShortLink(ShortLinkAddRequest request) {
Long accountNo = LoginInterceptor.threadLocal.get().getAccountNo();
String originalUrl = CommonUtil.addUrlPrefix(request.getOriginalUrl());
request.setOriginalUrl(originalUrl);
EventMessage eventMessage = EventMessage.builder().accountNo(accountNo)
.content(JsonUtil.obj2Json(request))
.messageId(IDUtil.geneSnowFlakeID().toString())
.eventMessageType(EventMessageType.SHORT_LINK_ADD.name())
.build();
rabbitTemplate.convertAndSend(rabbitMQConfig.getShortLinkEventExchange(), rabbitMQConfig.getShortLinkAddRoutingKey(),eventMessage);
return JsonData.buildSuccess();
}
//短链解析,客户端请求
@GetMapping(path = "/{shortLinkCode}")
public void dispatch(@PathVariable(name = "shortLinkCode") String shortLinkCode,
HttpServletRequest request, HttpServletResponse response) {
try {
log.info("短链码:{}", shortLinkCode);
//判断短链码是否合规
if (isLetterDigit(shortLinkCode)) {
//查找短链
ShortLinkVO shortLinkVO = shortLinkService.parseShortLinkCode(shortLinkCode);
//判断是否过期和可用
if (isVisitable(shortLinkVO)) {
String originalUrl = CommonUtil.removeUrlPrefix(shortLinkVO.getOriginalUrl());
response.setHeader("Location", originalUrl);
//302跳转
response.setStatus(HttpStatus.FOUND.value());
} else {
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
}
} catch (Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
第二十三章 短链码生成端选择和Lua分布式锁实战
第1集 短链码是生成端选择-生产者端-消费者端方案对比
简介: 短链码是生成端选择-生产者端-消费者端方案对比
-
短链码是哪里生成?生产者端 还是消费者端
-
方案一:生产者端生成短链码code
- 加分布式锁 key=code,配置过期时间(加锁失败则重新生成)
- 需要查询一次数据库或其他存储源,判断是否存在
- 发送MQ
- C端插入
- B端插入
- 解分布式锁(锁过期自动解锁)
方案二:消费者端生成短链码code
-
生产者发送消息
-
C端生成
- 加锁key=code
- 查询数据库,如果存在,则ver版本递增,重新生成短链码
- 保存数据库
- 解分布式锁
- 加锁key=code
-
B端生成,
- 加锁key=code
- 查询数据库,如果存在,则ver版本递增,重新生成短链码
- 保存数据库
- 解分布式锁
- 加锁key=code
第2集 分布式锁知识基础+进阶-可重入锁在分布式下的应用
简介:分布式锁知识基础+进阶-可重入锁在分布式下的应用
-
不知大家是否还记得,消费者生成短链码,高并发的情况
- 1)用户A生成短链码AABBCC ,C端先插入,B端还没插入
- 2)用户B也生成短链码AABBCC ,B端先插入,C端还没插入
- 3)用户A生成短链码AABBCC ,B端插入
- 4)用户B生成短链码AABBCC ,C端插入
-
需要的结果是
- 1、3可以成功, 2、4可以成功
-
避免短链码高并发下重复
- 加锁
- 本地锁:synchronize、lock等,锁在当前进程内,集群部署下依旧存在问题
- 分布式锁:redis、zookeeper等实现,虽然还是锁,但是多个进程共用的锁标记,可以用Redis、Zookeeper、Mysql等都可以
- 加锁
-
设计分布式锁应该考虑的东西
- 排他性
- 在分布式应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行
- 容错性
- 分布式锁一定能得到释放,比如客户端奔溃或者网络中断
- 满足可重入、高性能、高可用
- 注意分布式锁的开销、锁粒度
- 排他性
-
方案就是加锁
-
单节点可重入锁
- 可重入锁: JDK指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的,synchronized 和 ReentrantLock 都是可重入锁
-
分布式下的可重入锁
- 进程单位,当一个线程获取对象锁之后,其他节点的同个业务线程可以再次获取本对象上的锁
-
第3集 短链码基于Redis实现分布式锁的坑你是否踩过《上》
简介:基于Redis实现分布式锁的几种坑
-
实现分布式锁 可以用 Redis、Zookeeper、Mysql数据库这几种 , 性能最好的是Redis且是最容易理解
- 分布式锁离不开 key - value 设置
key 是锁的唯一标识,一般按业务来决定命名,比如想要给一种商品的秒杀活动加锁,key 命名为 “seckill_商品ID” 。value就可以使用固定值,比如设置成1。 短链码可以:short_link:code:xxxx
-
基于redis实现分布式锁,文档:http://www.redis.cn/commands.html#string
- 加锁 SETNX key value
setnx 的含义就是 SET if Not Exists,有两个参数 setnx(key, value),该方法是原子性操作 如果 key 不存在,则设置当前 key 成功,返回 1; 如果当前 key 已经存在,则设置当前 key 失败,返回 0
- 解锁 del (key)
得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入,调用 del(key)
- 配置锁超时 expire (key,30s)
客户端奔溃或者网络中断,资源将会永远被锁住,即死锁,因此需要给key配置过期时间,以保证即使没有被显式释放,这把锁也要在一定时间后自动释放
- 综合伪代码
methodA(){ String key = "short_link:code:abcdef" if(setnx(key,1) == 1){ expire(key,30,TimeUnit.MILLISECONDS) try { //做对应的业务逻辑 } finally { del(key) } }else{ //睡眠100毫秒,然后自旋调用本方法 methodA() } }
- 存在哪些问题,大家自行思考下
第4集 短链码基于Redis实现分布式锁的坑你是否踩过《下》
简介:短链码基于Redis实现分布式锁的坑你是否踩过
-
存在什么问题?
- 多个命令之间不是原子性操作,如
setnx
和expire
之间,如果setnx
成功,但是expire
失败,且宕机了,则这个资源就是死锁
使用原子命令:设置和配置过期时间 setnx / setex 如: set key 1 ex 30 nx java代码里面 String key = "short_link:code:abcdef" redisTemplate.opsForValue().setIfAbsent(key,1,30,TimeUnit.MILLISECONDS)
- 看业务应用情况还有更多问题,可以看Redis6课程 或者 第一个高并发大课
- 业务超时,如何避免其他线程勿删
- 业务执行时间过长,如何实现锁的自
- 多个命令之间不是原子性操作,如
之前说的方案二,消费者端生成短链码code
-
那C端或者B端其中一个加锁成功后,另外一个怎么加锁?
-
答案:通过value判断是否是同个账号,如果是则认为是加锁成功
-
即下面步骤
-
C端生成
-
加锁key=code,value=account
- 查询数据库,如果存在,则ver版本递增,重新生成短链码
- 保存数据库
-
解分布式锁(锁过期自动解锁)
-
B端生成
- 加锁key=code,value=account
- 查询数据库,如果存在,则ver版本递增,重新生成短链码
- 保存数据库
- 解分布式锁(锁过期自动解锁)
-
- 流程:加锁的方式需要保证原子性
- 先判断是否有,如没这个key,则设置key-value,配置过期时间,加锁成功
- 如果有这个key,判断value是否是同个账号,是同个账号则返回加锁成功
- 如果不是同个账号则加锁失败
- 解决方式,配置key过期时间久,比如2~5天
第5集 Lua脚本分布式重入锁+redis原生代码编写
简介:Lua脚本分布式重入锁+redis原生代码编写
-
前面说了redis做分布式锁存在的问题
- 核心是保证多个指令原子性,加锁使用setnx setex 可以保证原子性,那解锁使用判断和设置等怎么保证原子性
- 文档:http://www.redis.cn/commands/set.html
- 多个命令的原子性:采用 lua脚本+redis, 由于【判断和删除】是lua脚本执行,所以要么全成功,要么全失败
-
流程
* 先判断是否有,如没这个key,则设置key-value,配置过期时间,加锁成功
* 如果有这个key,判断value是否是同个账号,是同个账号则返回加锁成功
* 如果不是同个账号则加锁失败
- 代码
//key1是短链码,ARGV[1]是accountNo,ARGV[2]是过期时间
String script = "if redis.call('EXISTS',KEYS[1])==0 then redis.call('set',KEYS[1],ARGV[1]); redis.call('expire',KEYS[1],ARGV[2]); return 1;" +
" elseif redis.call('get',KEYS[1]) == ARGV[1] then return 2;" +
" else return 0; end;";
Long result = redisTemplate.execute(new
DefaultRedisScript<>(script, Long.class), Arrays.asList(code), value,100);
- 加入redis配置
#-------redis连接配置-------
spring.redis.client-type=jedis
spring.redis.host=120.79.150.146
spring.redis.password=xdclass.net
spring.redis.port=6379
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=100
spring.redis.jedis.pool.max-wait=60000
第6集 短码服务冗余双写-B端+C端分布式锁代码整合
简介:短码服务冗余双写-B端+C端分布式锁代码整合
- 整合编码实战
第二十四章 短链服务-冗余双写B端分库分表和链路测试
第1集 GroupCodeMapping表分库分表配置实战
简介: GroupCodeMapping表分库分表配置实战
- 数据量预估
- 首年日活用户: 10万
- 首年日新增短链数据:10万*50 = 500万
- 年新增短链数:500万 * 365天 = 18.2亿
- 往高的算就是100亿,支撑3年
- 分库分表策略
- 分库分表
- 8个库, 每个库128个表,总量就是 1024个表
- 本地开发 2库,每个库2个表
- 分片键:
- 分库PartitionKey:account_no
- 分表PartitionKey:group_id
- 分库分表
- 接口访问量
- C端解析,访问量大
- B端查询,访问量少,单个表的存储数据可以多点
- 配置
##---------- 组+短链码mapping表,策略:分库+分表--------------
# 先进行水平分库,然后再水平分表, 水平分库策略,行表达式分片
spring.shardingsphere.sharding.tables.group_code_mapping.database-strategy.inline.sharding-column=account_no
spring.shardingsphere.sharding.tables.group_code_mapping.database-strategy.inline.algorithm-expression=ds$->{account_no % 2}
# 分表策略+行表达式分片
spring.shardingsphere.sharding.tables.group_code_mapping.actual-data-nodes=ds$->{0..1}.group_code_mapping_$->{0..1}
spring.shardingsphere.sharding.tables.group_code_mapping.table-strategy.inline.sharding-column=group_id
spring.shardingsphere.sharding.tables.group_code_mapping.table-strategy.inline.algorithm-expression=group_code_mapping_$->{group_id % 2}
第2集 短链服务-冗余双写架构全链路测试实战
简介: 短链服务-冗余双写架构全链路测试实战
- 全链路测试
- 数据库检查
- 创建短链
{
"groupId":1468878230818746370,
"title":"全链路测试测试标题",
"originalUrl":"https://baidu.com",
"domainId":1,
"domainType":"OFFICIAL",
"expired":-1
}
第3集 短链服务-B端接口-分页查找短链开发实战
简介: 短链服务-B端接口-分页查找短链开发实战
- 分页查找某个分组下的短链数据
@Data
public class ShortLinkPageRequest {
private int page;
private int size;
private long groupId;
}
/**
* 分页查找短链
*
* @return
*/
@RequestMapping("page")
public JsonData pageShortLinkByGroupId(@RequestBody ShortLinkPageRequest request) {
Map<String, Object> pageResult = shortLinkService.pageShortLinkByGroupId(request);
return JsonData.buildSuccess(pageResult);
}
-
注意点
- IDEA可能有缓存,导致分库分表不生效,mvn clean清理下
-
删除标记位增加
- 解析
- 查找
第二十五章 短链服务-冗余双写架构删除和更新开发实战
第1集 短链服务-冗余双写架构举一反三的能力应用
简介: 冗余双写架构举一反三的能力应用
- 完成了短链接口的新增,采用了冗余双写的方式
- 那其他接口呢
- 删除
- 更新
第2集 短链服务-删除和更新Controller层开发实战
简介: 短链服务-删除和更新Controller层开发实战
- 删除接口
- controller
- service
- 构建消息
@Data
public class ShortLinkDelRequest {
/**
* 组
*/
private Long groupId;
/**
* groupCodeMapping映射id
*/
private Long mappingId;
/**
* 短链码
*/
private String code;
}
- 更新接口
- controller
- service
- 构建消息
public class ShortLinkUpdateRequest {
/**
* 组
*/
private Long groupId;
/**
* groupCodeMapping映射id
*/
private Long mappingId;
/**
* 短链码
*/
private String code;
/**
* 短链标题
*/
private String title;
/**
* 域名id
*/
private Long domainId;
/**
* 域名类型
*/
private String domainType;
}
- 消息类型
public enum EventMessageType {
/**
* 短链创建
*/
SHORT_LINK_ADD,
/**
* 短链创建 C端
*/
SHORT_LINK_ADD_LINK,
/**
* 短链创建 B端
*/
SHORT_LINK_ADD_MAPPING,
/**
* 更新创建
*/
SHORT_LINK_UPDATE,
/**
* 更新 C端
*/
SHORT_LINK_UPDATE_API,
/**
* 更新 B端
*/
SHORT_LINK_UPDATE_MAPPING,
/**
* 删除
*/
SHORT_LINK_DEL,
/**
* 删除 C端
*/
SHORT_LINK_DEL_API,
/**
* 删除 B端
*/
SHORT_LINK_DEL_MAPPING,
}
第3集 冗余双写MQ实现-删除短链-交换机和队列绑定配置实战
简介: 冗余双写MQ架构实现-删除短链-交换机和队列绑定配置讲解
- 删除短链MQ架构图
- 更新短链MQ架构图
第5集 短链服务-删除和更新模块发送MQ消息验证
简介: 短链服务-删除和更新模块发送MQ消息验证
-
删除 发送消息
-
更新 发送消息
-
RabbitMQ控制台查看
private String title;/**
- 域名id
*/
private Long domainId;
/**
- 域名类型
*/
private String domainType;
- 域名id
}
- 消息类型
```java
public enum EventMessageType {
/**
* 短链创建
*/
SHORT_LINK_ADD,
/**
* 短链创建 C端
*/
SHORT_LINK_ADD_LINK,
/**
* 短链创建 B端
*/
SHORT_LINK_ADD_MAPPING,
/**
* 更新创建
*/
SHORT_LINK_UPDATE,
/**
* 更新 C端
*/
SHORT_LINK_UPDATE_API,
/**
* 更新 B端
*/
SHORT_LINK_UPDATE_MAPPING,
/**
* 删除
*/
SHORT_LINK_DEL,
/**
* 删除 C端
*/
SHORT_LINK_DEL_API,
/**
* 删除 B端
*/
SHORT_LINK_DEL_MAPPING,
}
第3集 冗余双写MQ实现-删除短链-交换机和队列绑定配置实战
简介: 冗余双写MQ架构实现-删除短链-交换机和队列绑定配置讲解
- 删除短链MQ架构图
- 更新短链MQ架构图
[外链图片转存中…(img-1sasDsYr-1723078707796)]
第5集 短链服务-删除和更新模块发送MQ消息验证
简介: 短链服务-删除和更新模块发送MQ消息验证
- 删除 发送消息
- 更新 发送消息
- RabbitMQ控制台查看