如题所述,最近在看 kafka,对消费者组的实际应用有点疑惑,求各位赐教。
希望可以展开说说:
topic 在业务中如何定义
partition 在业务中如何定义,对于生产者和消费者而言,partition 意味着什么
消费者组在业务中的应用场景是什么样的?
kafka 在不同业务中有哪些最佳实践和骚操作?
1
humpy 2021-09-21 00:56:33 +08:00 3
1. topic 在业务中如何定义
可以简单类比为 RDS 里的数据表 2. partition 在业务中如何定义,对于生产者和消费者而言,partition 意味着什么 简单来说,每个消息都有 topic 、key 、value -> kafka 根据消息 key 将消息派发到 topic 下不同的 partition -> 同一个 group 的 consumer 各自接收不同 partition 的消息 -> 相同 key 的消息被且只被同一个 consumer 消费。 1) producer 发送消息的时候,可以指定消息的 key,相同 key 的消息会被发往同一个的 partition ; - 如果 key 为 null,默认的 partitioner 会按 round-robin 的方式将消息负载均衡地随机指派一个可用的 partition ; - 如果 key 不为 null,默认的 partitioner 会将 key hash (使用自带的 hash 算法),根据 hash 后的值指派对应的 partition 。 2) 同一个 group 的 consumer,将会接收到一个 topic 下面不同的 partition 的消息。partition 和 consumer 的关系是,一个 consumer 可以消费多个 partition (具体能消费几个 partition 看 consumer 数量),一个 partition 只能被一个 consumer 消费,如果 consumer 多于 partition,多余的 consumer 将被闲置。这样的设计带来的好处是: - 同一个消息只被一个消费者消费,避免同一个消息的问题被多个消费者消费导致的各种问题(类似并发问题); - 只要消费者没有 rebalance,同一个 key 的消息就始终只被同一个消费者消费,那么就可以做一些,比如用本地缓存、或者保存处理上下文; 3. 消费者组在业务中的应用场景是什么样的? 怎么说呢,topic 跟 group 同一级别,partition 跟 consumer 同一级别。一个 group 可以消费多个 topic,对每个 topic 都有独立的 offset 记录,这样消费同一个 topic 的 group 之间就不会互相影响。 不同业务需要消费同一个 topic,每个业务就需要单独的 group 。比如 A 部门要消费事件 topic,它就需要一个单独的 group A,B 部门也需要消费事件 topic,它就也需要一个 group B 。 4. kafka 在不同业务中有哪些最佳实践和骚操作? consumer 配置很重要、rebalance 很恶心、用 spring-kafka 😊 |
2
cernard OP @humpy 谢谢回复!我猜测在实际业务中,可以将 topic 理解为一个抽象的消息组,partition 才是最终的消息容器,这样对吗?比如有需要收集埋点数据的业务,那么“埋点数据”可以作为一个 topic,不同客户端可以通过各自指定的 key 将消息发送给 topic 的指定分区,例如在埋点数据 topic 中可能有“web 端”、“android 端”、“ios 端”这样的 key 组成的 partition,这样对吗?
至于消费者组对一个 topic 的消费,其组内和 partition 之间是点对点一对一的。如果按照上面将 kafka 的 partition 理解为*同类消息*最终落地的地方,那么在消费者组内只有一个业务服务可以消费这个 partition 。例如在上面例子中“web 端 partition”需要一个“web 数据 consumer”来消费,以此类推,就有下面这样的结对: - “web 埋点 partition”:“ web 数据 consumer” - “android 埋点 partition”:“android 数据 consumer” - “iOS 埋点 partition”:“ios 数据 consumer” 上面 partition 和 consumer 点对点的消费数据,web 、android 、ios 三个 consumer 组成了一个消费者组,这样这个消费者组内如果有多个消费者,那这些消费者就得是*不同的业务服务*组成的。如果在负载均衡的场景中,多个相同服务副本需要在不同的消费者组中才能对同一 topic 的同一 partition 同时消费。这样的理解对吗?那么再概况一下,消费者组可以理解为“某个大业务需求的细分实现服务组”,对吗? 但我感觉我的理解不太对。如果是上面这样的话,Kafka 为什么会通过 RoundRobin 或 range 的模式为 consumer 分配多个 partition 呢?为某个业务消费者分配多个不同的业务业务消息本身就是冲突的地方。所以感觉还是对 Kafka 的实际实践一头雾水。 |
3
humpy 2021-09-21 16:04:31 +08:00
@cernard #2 不是这样的,可能我没说清楚
你了解并发编程里的 producer-consumer 模式吗?其实是一样的,consumer 是同一套消费逻辑的多个实例。线程池里的 consumer 线程们从同一个 queue 通过并发锁抢任务。而 kafka 是每个 consumer 事先就分派好了各自的 queue,这个 queue 就是 partition 。 partition 算是 kafka 的实现细节,你需要知道它,但业务逻辑不能依赖它来做设计。它的主要作用是提供消费处理扩容能力(即消费跟不上了可以加机器)以及顺带的避免并发消费问题。 比如一个 topic 有 8 个 partition,最开始只有 2 个 consumer,每个 consumer 负责 4 个 partition,然后处理不过来,消息积压了,这时候就可以再加两台机器,总共 4 个 consumer,rebalance 后每个 consumer 负责 2 个 partition...不够再加,最多可以加到 8 个 consumer (即一个 consumer 对应一个 partition ),再加就没用了。 你的埋点数据的例子,实际做的话有两种方式,一是用一个 topic,消息里用一个类型字段区分 web 、android 或 ios,在消费逻辑里写 if else 做筛选和处理;另一种是每种埋点数据单独一个 topic,业务根据自己需要,消费对应的 topic 。 再说下消息的 key,因为它影响消息被分发的 partition,所以 key 最好是能让消息均匀分布的,不然就会有的 partition 消息多、有的消息少,导致有的 consumer 消息太多,消费不过来,消息堆积,并且这种消息积压增加 consumer 都没用。有的 consumer 消息太少,一直空闲,浪费资源。 说起来有点绕,其实挺简单的,最好实际用一下,写写代码,理解起来就很轻松了。书可以看 OReilly.Kafka.The.Definitive.Guide.2017.9.pdf ,JD 有中文版。 |