作者回复: 1. 你是说那个内存队列?就是载体不同。如果是内存队列,那么宕机就没了。 2. 一样会有数据不均匀的问题,但是更加容易解决,因为你开启队列的时候,自己应用一下一致性哈希之类的算法就可以解决了。 不过其实你可以考虑只用一个队列,线程都从这里面取。就是在最后要协调大家停下来批量提交麻烦一点,倒也还可以接受。
作者回复: 老大难的问题了,哈哈哈哈。 说实在的,我也没特别好的的办法。如果你们本身就有那种排序机制,比如说我可以通过状态来判定消息是不是失序了,比如说当状态还是未支付的时候,你收到取消消息,这肯定是乱序了。那么你就可以尝试把取消消息重新发回去原本的消息队列上。 另外一种有漏洞的做法就是借助延迟消息。比如说你 A1 消息在重试,A2 不管知不知道 A1 在重试,直接自己延迟一分钟发送。“一分钟”是假定你的 A1 肯定能在一分钟之内重试完成。 当然,如果 A2 的发送者有办法知道 A1 还没发,那么就可以优化成只有当 A1 没发,A2 才会延迟,当然 A3,A4... 显然也要跟着延迟。 比如说,你可以借助 redis,假设 key1=1 的时候,代表 A1 还没发。key1=2 的时候,A1 已经发了。那么 A2 的发送者看一眼 Redis 就知道了。 不过,我的个人看法是……除非是面试吹牛,不然实践中直接告警拉到。就是在真的发现消息失序的时候,告警,人手工微调一下就可以。可用性高的话,你可能一个月才有一个两个这种失序的问题。
作者回复: 不不不,这个的关键点是你可以引入逻辑上槽的概念,你不一定非得用 CRC16 来计算槽。你可以说选择你的业务特征,用几个哈希函数,一通猛算,得到一个值,这个值就是你的槽的号。我这里用 1024 只是举个例子。 更好的做法是固定分配。比如说我直接指定,一通猛算出来的值如果是 1,2,1023,345 就到分区 0。就有点你手动分配槽到 Redis 节点上的意思。借助配置中心还可以动态更新这个分配,也很方便。
作者回复: 分区挂了倒还好,毕竟生产者都发不出来。要解决 rebalance,有一个不太好的办法,但是勉强能用。就是消费者这边手动指定分区。 这样做的话,就是要做好监控。一旦消费特定分区的消费者崩溃了,要及时启动另外一个消费者来消费同样地分区。
作者回复: 好问题。盲猜你是用了不同的 topic 是不是?就是退单的消息用了一个 topic,但是下单的用了另外一个 topic。 如果你是这种的话,只能用我提到的跨 topic 有序的方案,要有一个协调者进来,这个协调者在收到退单的时候,要先去看看有没有收到下单的消息。 但是一般用不着这样,以为你只需要检测有没有这个订单,或者状态是否符合,不符合你就丢回去原本的 topic 里面。或者你设定一个时间,比如说三十分钟之后再处理这个退单消息,然后预期三十分钟内应该能收到下单消息。
作者回复: 可以。你的思路就是,如果我前置消息不满足,我就临时放一个地方。控制住重试就可以。
作者回复: 你的思考很有深度! 你说的是两件事,但是可以通过一个手段来解决。要保持异步消费还要有序,是不能用线程池的,理由你已经分析到了。你只能考虑手动启动多个线程。当然,如果你用的是 JAVA,那么你可以用只有一个线程的线程池。而后,剩下的事情就都是你分发的事情了,比如说你可以说编号为 1,2,3 的线程池就是给你不忙的业务用的,其它就是给你忙的业务用的。
作者回复: 1. 你在设计槽的时候,根据业务特征来确定的槽,那就不会。比如说你用 ID % 1024 来选择槽,那么同一个 ID 的肯定在同一个槽。 2. 不成立……我没听 Kafka 的团队出来说我们就是为了大数据搞出来的。相反,先在稍微有点规模的公司,都会使用。但是也得承认, Kafka 在大数据下表现极其优异。
作者回复: 1. 感谢勘误! 2. 没……应该说思路都是要协调,不过怎么协调是有很多做法的。比如说可以考虑事件驱动中的前置事件检测,也可以考虑中间引入一个什么东西来辅助排队。不过都是协调者的事情。 3. 答案就是你的槽只要足够多,就不会有均匀性问题。如果你只有十个槽,那么可能某个槽数据很多。但是你有一万个槽,那么你就可以通过合理分配业务到不同的槽上,保证数据均匀分散了。 4. 哈哈哈,虽然没用过你的思路,但是我一琢磨还是可以的,这个东西可以让中间件研发的人来封装。难点我觉得应该是我发现 topic 数量修改了之后,我该发消息到原本的分区,那么什么时候发到新的分区呢?