目录
15、kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?
1、如何获取 topic 主题的列表
bin/kafka-topics.sh --list --zookeeper localhost:2181
2、生产者和消费者的命令行是什么?
生产者在主题上发布消息:
bin/kafka-console-producer.sh --broker-list 192.168.43.49:9092 -- topic Hello-Kafka
注意这里的 IP 是 server.properties 中的 listeners 的配置。接下来每个新行就是输入一条新消息。消费者接受消息:bin/kafka-console-consumer.sh --zookeeper localhost:2181 -- topic Hello-Kafka -- from-beginning
3、consumer 是推还是拉?
这里讲一下两种模式:
1.push
一些消息系统比如 Scribe 和Apache Flume采用了push 模式,将消息推送到下游的 consumer。由broker决定消息推送的速率,对不同消费速率的consumer无法统一。消息系统都致力于让consumer以最大的速率最快速的消费消息,push模式下,当 broker推送的速率远大于consumer消费的速率时,consumer趋于崩溃。而采用较低的推送速率,将可能导致一次只推送较少的消息而造成浪费。必须在不知道下游consumer消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。
2.pull
Pull 模式下,consumer 可以自主决定是否批量的从 broker 拉取数据,可以根据自己的消费能力去决定这些策略。Pull的缺点是如果broker没有可供消费的消息,将导致consumer不断在循环中轮询,直到新消息到达。为了避免这点,Kafka有个参数可以让consumer阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发送)。
Kafka遵循了一种大部分消息系统共同的传统的设计:producer将消息推送到 broker,consumer 从 broker 拉取消息。
4、kafka 维护消费状态跟踪的方法
大部分消息系统在 broker 端的维护消息被消费的记录:一个消息被分发到 consumer 后 broker就马上进行标记或者等待customer的通知后进行标记。这样也可以在消息在消费后立马就删除以减少空间占用。
存在的问题:
1.如果一条消息发送出去之后就立即被标记为消费过的,一旦 consumer 处理消息时失败了(比如程序崩溃)消息就丢失了。为了解决这个问题,很多消息系统提供了另外一个个功能:当消息被发送出去之后仅仅被标记为已发送状态,当接到 consumer 已经消费成功的通知后才标记为已被消费的状态。这虽然解决了消息丢失的问题,但产生了新问题,首先如果consumer处理消息成功了但是向broker发送响应时失败了,这条消息将被消费两次。
2.broker 必须维护每条消息的状态,并且每次都要先锁住消息然后更改状态然后释放锁。这样麻烦又来了,且不说要维护大量的状态数据,比如如果消息发送出去但没有收到消费成功的通知,这条消息将一直处于被锁定的状态,
Kafka 采用了不同的策略。Topic 被分成了若干分区,每个分区在同一时间只被一个 consumer 消费。这意味着每个分区被消费的消息在日志中的位置仅仅是一个简单的整数:offset。这样就很容易标记每个分区消费状态就很容易了,仅仅需要一个整数而已。这样消费状态的跟踪就很简单了。这带来了另外一个好处:consumer 可以把 offset 调成一个较老的值,去重新消费老的消息。这对传统的消息系统来说看起来有些不可思议,但确实是非常有用的,谁规定了一条消息只能被消费一次呢?