kafka的topic如果一开始没有做合理拆分,在业务不断膨胀的情况下,容易产生消息堆积,问题难以定位排查。以下是几种不同情况下做拆分或迁移的方案
一、发送者不变、topic不变、新增consumer group
二、新增发送者、从原topic拆出部分消息作为新topic、consumer group不变
三、新增发送者、从原topic拆出部分消息作为新topic、新增consumer group
四、新增发送者、从原topic拆出部分消息作为新topic、旧topic消息不变
这种场景是最混乱的,新旧topic同时存在,生产者也是分开的,意味着消息体无法保证完全一致(时间戳),同时产生两份消息,而上线期间新旧消费者也同时存在,需要避免重复消费和乱序消费。
这种场景,通常存在于一个topic多方在消费,而只新增新的一个topic希望拆分出某个服务下的独立topic和消费者。旧topic不能动。所以是不能停止旧生产者的。
我的思路是,新旧消费者一定要以某种方式区分开彼此必须消费对方不消费的key,为什么是key呢,因为key相同可以保证是同一状态序列的对象,比如同一个订单的key是相同的订单号,发到同一个partition从而避免消费顺序错乱。并且一段时间后新消费者自动消费全部消息,旧消费者不再消费任何消息,实现新服务上线的自动切换。
要实现这种思路,我的第一个想法就是使用时间戳区分。发送消息的时候携带订单创建时间时间戳。新旧消费者同时加一段逻辑,当时间戳为空或者小于上线后的某个时间点a,旧消费者消费消息。时间戳存在且大于等于a则旧消费者不消费、新消费者消费消息。时间点a是静态的,与机器时间无关。
细节是:旧消费逻辑加一个开关,如果开关开且大于a则旧消费者不消费。出现问题可以回滚开关
上线期间,先上线旧消费者,稳定消费后上线新消费者,新消费者无流量。如果新旧消费者在一个服务里也没有关系。此时是时间戳为空,旧消费者稳定消费消息。
再上线新生产者,新旧生产者如果在同一个服务也没关系。此时现象是由于时间点在a之前,因此只有创建时间小于a的数据,旧消费者稳定消费消息,新消费者丢弃消息。
当时间点大于a后,新消费者开始消费,新旧消费者同时有消息在消费。旧消费者仅消费订单创建时间小于a的消息,新消费者仅消费订单创建时间大于等于a的消息,旧消费者消费的消息新消费者绝不会消费,新消费者消费的消息旧消费者绝不会消费,数据是根据创建时间也即id(key)天然隔离的。
当创建时间小于a的消息完全终态后,旧消费者只丢弃消息,新消费者消费全部消息。旧消费者可以下线。
线上稳定运行后,新消费者可以去掉判断逻辑。
这种方案,需要可以在新旧消息体中添加创建时间字段,且数据必须具有创建时间这一属性。

序号

动作

状态

1

上线旧消费者,当创建时间时间戳为空或者小于上线后的某个时间点a,旧消费者消费消息

时间戳为空,旧消费者稳定消费

2

上线新消费者

旧消费者稳定消费消息,新消费者无流量

3

上线旧生产者,携带时间戳

旧消费者稳定消费消息,新消费者无流量

4

上线新生产者,携带时间戳

旧消费者稳定消费消息,新消费者丢弃消息

5

时间点a到来之前

旧消费者稳定消费消息,新消费者丢弃消息

6

时间点a之后

旧消费者仅消费订单创建时间小于a的订单,新消费者仅消费订单创建时间大于等于a的订单

7

创建时间小于a的订单消息全部消费完成后

旧消费者只丢弃消息,新消费者消费全部消息

8

旧消费者下线

新消费者稳定消费全部消息,旧topic稳定发送给其它需要旧消息的消费者

9

新消费者端去掉判断逻辑

新消费者稳定消费全部消息

五、新增发送者、旧发送者下线、新增topic