CMQ 有两种模式:
- 队列模式(pull):创建的是队列;
- 订阅模式(push):创建的是主题;
订阅模式
把消息 publish 到主题后,这个主题会主动把消息推送(push)给订阅者,订阅者可以是队列,也可以是 http endpoint。
我尝试了 http endpoint,这个 endpoint 是一个 tcb 云函数,每次发送消息给主题后,这个云函数都会被触发,函数将接收到消息内容和消息属性。
订阅模式不能设置延迟,所以你发送了多少消息到主题,主题都会一股脑儿不分先后地调用这个云函数,如果消息数量很多,可能会超过云函数的并发限制。
消息主题如何判断自己的消息是否成功投递?它是根据订阅方返回的内容进行判断的:云函数返回 2xx 状态码,则认为投递成功。
投递失败后的处理:如果返回非 2xx 的状态码,又或者根本没返回(例如函数出错),则被认为投递失败,失败后会自动重试,重试一定次数后停止重试,并在生命周期结束后自动丢弃。
在主题中,需要关注消息堆积数量,堆积有 3 种情况:
- 还没有投递;
- 投递了,但是失败,等待重试;
- 重试多次依然失败,等待丢弃;
所以对于订阅模式,消费者无法控制消息的丢弃,如果订阅者出错,有可能会导致消息永远发不出去,并且用户可能无法知道这些发不出去的消息是什么。
队列模式
队列的工作模式:
- 发送消息到队列;
- 消费者设置一个定时器,定时从队列中获取消息;
- 如果队列有消息,消费者获取消息,如果没有,下次再询问;
- 消费者获得了消息后的一定时间内,消息会处于不可见状态,在这段时间内,消费者应该处理完消息,并告诉队列删除这条消息;
- 如果消费者不告诉队列删除这条消息,过了不可见时限后,消费者可再次从队列中获取这条消息,有可能造成重复消费;
- 如何判断消息是否被成功处理?就看消费者是否请求删除消息,如果在隐藏时间内没有收到消费者的删除请求,被视为失败处理;
- 队列可以设置失败处理一定次数后,或者在一定时间内没有被成功消费后,把这条消息移到死信队列,如果不关联死信队列,那这条消息会一直保存在该队列中,直到生命周期结束后被丢弃;
- 如果设置了死信队列,消费者可以在生命周期结束前,随时获取这些消息进行重新处理,我觉得这是和订阅模式最大的区别,订阅模式一旦确认投递失败,即使在生命周期内也无法重新获取这些信息;
- 死信队列可以避免消息堆积在正常队列中,让正常队列的消息保持为新消息,新消息需要及时处理,旧消息的重要性通常大幅下降,不需要及时处理,避免旧消息反复占用资源;
- 队列还支持消息回溯功能,相当于把队列中的消息重置到过去某一个时间点,进一步降低消息丢失的可能,但可回溯的时间不能超过生命周期限制;
假设队列中突然出现 1000 条消息,我怎么拉起一个高并发的函数去快速地处理它们呢?有批量消费信息的 api,但最多只能同时消费 16 条消息,假设消费一批消息用 1s,那消费完这 1000 条消息岂不是用 1000/16 秒?解决方法:用腾讯云 api 的 cmq 管理端 api 查询各队列的消息数量,根据数量唤醒 n 个云函数取处理消息。
在订阅模式中,主题会主动拉起多个并发实例,直接拉起几百个实例几秒钟就能处理完 1000 条消息。亚马逊的 sqs 的 pull 模式支持绑定云函数,云函数不需要主动 pull,sqs 的队列中的消息会作为事件主动触发云函数,看起来好像是订阅模式,但它支持队列该有的功能(例如删除被视为成功消费,支持死信队列等),但 tdmq 的 cmq 不支持这个功能。
和阿里 MNS 的区别
费用的区别:
- CMQ 可以分别创建 5 个免费队列和主题,MNS 没有免费的队列或主题,而是按照每个队列或者主题每天收取费用,比如华东地区的队列是 0.5 元/个/天,如果创建 3 个,那每个月费用为 45 元;
- CMQ 收取消息存储费,但有 10GB 免费额度,MNS 不收取消息存储费;
- API 调用价格都是 2 元/百万次;
使用限制的区别:
- CMQ 支持向队列或主题发送最大 1MB 的消息,MNS 的队列是 64KB,MNS 的主题体积限制,文档没有说明,官方建议使用 OSS 传递大于 64KB 的消息;
- CMQ 和 MNS 队列的 QPS 分别是 5000、3000,主题的 QPS 分别是 5000、500;
- MNS 支持日志管理,可查看每条消息的完整生命周期事件,包括发送、接收和删除,方便问题排查,但 CMQ 没有这些功能;
以上不是 CMQ 和 MNS 的全部区别,只是我个人关注的区别。MNS 创建队列或主题的费用对个人开发者来说太高,但 CMQ 可免费创建 5 个队列和 5 个主题,这是我选择 CMQ 的原因。
相关文章: