按照发送的特点分
1.同步发送
a.同步发送, 线程阻塞, 投递completes阻塞结束
b.如果发哦是哪个失败, 会在默认的超时时间3秒内进行重试, 最多重试2次
c.投递completes不代表投递成功, 要check SendResult来判断是否投递成功
d.SendResult里面有发送状态的枚举, SendResult同步的消息投递有一个返回值
e.retry的实现原理: 只有ack的SendResult=SEND_OK才会通知retry(SendResult=SEND_OK只代表消息成功写入了MQ当中, 并不代表该消息成功被Consumer消费了)
public enum SendStatus {
SEND_OK,
FLUSH_DISK_TIMEOUT,
FLUSH_SLAVE_TIMEOUT,
SLAVE_NOT_AVAIABLE
}
2.异步发送
a.异步调用的话, 当前线程一定要等待异步线程回调结束再关闭producer, 因为是异步的, 不会阻塞, 提前关闭producer会导致未回调链接就断开了
b.异步消息不会retry, 投递失败回调onException()方法, 只有同步消息才会retry
c.异步发送一般用于链路耗时教程, 对RT相应时间较为敏感的业务场景, 例如用户上传视频后通知启动转码服务, 转码完成后通知推送转码结果等
3.单向发送
a.消息不可靠, 性能高, 只负责往服务器发送一条消息, 不会重试也不关心是否发送成功
b.此方式发送消息的过程耗时非常短, 一般在微妙级别
总结
发送方式 | 发送TPS | 发送结果反馈 | 可靠性 |
---|---|---|---|
同步发送 | 快 | 有 | 不丢失 |
异步发送 | 快 | 有 | 不丢失 |
单向发送 | 最快 | 无 | 可能丢失 |
按照使用功能特点分
1.普通消息
普通消息是我们在业务开发中用到最多的消息类型, 生产者需要关注消息发送成功即可, 消费者消费到消息即可, 不需要保证消息的顺序, 所以消息可以大规模的并发的发送和消费, 吞吐量很高, 适合大部分场景
2.顺序消息
顺序消息分为分区顺序消息和全局顺序消息, 全局顺序消息比较容易理解, 也就是哪条消息先进入, 那条消息就会被先消费, 符合我们的FIFO, 很多时候全局顺序消息的实现代价很大, 所以就出现了分区顺序消息
3.延时消息(可用于订单超时库存归还)
延时的机制是在服务端实现的, 也就是Broker收到了消息, 但是经过一段时间以后才发送, 服务器按照1~N定义了如下级别: “1s 5s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”; 若要发送定时消息, 在应用层初始化Message消息对象之后, 调用Message.serDelayTimeLevel(int level)方法来设置延迟级别, 按照顺序取相应的延迟级别, 例如level=2, 则延迟为5秒
a.发送消息的时候如果消息设置了DelayTimeLevel, 那么该消息会被丢到scheduleMessageService.SCHDULE_TOPIC这个Topic里面
b.根据DeleyTimeLevel选择对应的queue
c.再把真是的topic和queue信息封存起来, set到msg里面
d.然后每个SCHDULE_TOPIC_XXXX的每个DelayTimeLevelQueue, 有定时任务去刷新, 是否有投递的消息
e.每10s定时持久化发送进度