『』注意了!Kafka与RabbitMQ千万不要乱用…( 三 )


相反 , Kafka 会给每个主题配置超时时间 , 只要没有达到超时时间的消息都会保留下来 。
在消息留存方面 , Kafka 仅仅把它当做消息日志来看待 , 并不关心消费者的消费状态 。
消费者可以不限次数的消费每条消息 , 并且他们可以操作分区偏移来“及时”往返的处理这些消息 。
Kafka 会周期的检查分区中消息的留存时间 , 一旦消息超过设定保留的时长 , 就会被删除 。
Kafka 的性能不依赖于存储大小 。所以 , 理论上 , 它存储消息几乎不会影响性能(只要你的节点有足够多的空间保存这些分区) 。
获胜者:Kafka 设计之初就是保存消息的 , 但是 RabbitMQ 并不是 。所以这块没有可比性 , Kafka 是获胜者 。
容错处理
当处理消息 , 队列和事件时 , 开发者常常认为消息处理总是成功的 。毕竟 , 生产者把每条消息放入队列或者主题后 , 即使消费者处理消息失败了 , 它仅仅需要做的就是重新尝试 , 直到成功为止 。
尽管表面上看这种方法是没错的 , 但是我们应该对这种处理方式多思考一下 。首先我们应该承认 , 在某些场景下 , 消息处理会失败 。
所以 , 即使在解决方案部分需要人为干预的情况下 , 我们也要妥善地处理这些情况 。
消息处理存在两种可能的故障:
瞬时故障:故障产生是由于临时问题导致 , 比如网络连接 , CPU 负载 , 或者服务崩溃 。我们可以通过一遍又一遍的尝试来减轻这种故障 。
持久故障:故障产生是由于永久的问题导致的 , 并且这种问题不能通过额外的重试来解决 。比如常见的原因有软件 Bug 或者无效的消息格式(例如 , 损坏(poison)的消息)
作为架构师和开发者 , 我们应该问问自己:“对于消息处理故障 , 我们应该重试多少次?每一次重试之间我们应该等多久?我们怎样区分瞬时和持久故障?”
最重要的是:“所有重试都失败后或者遇到一个持久的故障 , 我们要做什么?”
当然 , 不同业务领域有不同的回答 , 消息系统一般会给我们提供工具让我们自己实现解决方案 。
RabbitMQ 会给我们提供诸如交付重试和死信交换器(DLX)来处理消息处理故障 。
DLX 的主要思路是根据合适的配置信息自动地把路由失败的消息发送到 DLX , 并且在交换器上根据规则来进一步的处理 , 比如异常重试 , 重试计数以及发送到“人为干预”的队列 。
查看这篇文章[1] , 它在 RabbitMQ 处理重试上提供了额外的可能模式视角 。
在 RabbitMQ 中我们需要记住最重要的事情是当一个消费者正在处理或者重试某个消息时(即使是在把它返回队列之前) , 其他消费者都可以并发的处理这个消息之后的其他消息 。
当某个消费者在重试处理某条消息时 , 作为一个整体的消息处理逻辑不会被阻塞 。
所以 , 一个消费者可以同步地去重试处理一条消息 , 不管花费多长时间都不会影响整个系统的运行 。
『』注意了!Kafka与RabbitMQ千万不要乱用…
文章图片

文章图片

消费者 1 持续的在重试处理消息 1 , 同时其他消费者可以继续处理其他消息
和 RabbitMQ 相反 , Kafka 没有提供这种开箱即用的机制 。在 Kafka 中 , 需要我们自己在应用层提供和实现消息重试机制 。
另外 , 我们需要注意的是当一个消费者正在同步地处理一个特定的消息时 , 那么同在这个分区上的其他消息是没法被处理的 。
由于消费者不能改变消息的顺序 , 所以我们不能够拒绝和重试一个特定的消息以及提交一个在这个消息之后的消息 。你只要记住 , 分区仅仅是一个追加模式的日志 。
一个应用层解决方案可以把失败的消息提交到一个“重试主题” , 并且从那个主题中处理重试;但是这样的话我们就会丢失消息的顺序 。


推荐阅读