如果MQ没有类似数据库事务结构和保证,是不可能达到消息投递100%可靠的,极端情况下消息投递要么丢失或重复。
下面咋们从producer,broker,consumer的角度分析一下Kafka中会出现哪些情况。
1.Producer发送消息到Broker
目前生产者发送消息(request.required.acks)有三种方式。
acks = 0: producer不会等待broker发送ack ,因为发送消息网络超时或broker crash (1.Partition的Leader还没有commit消息 2.Leader与Follower数据不同步),既有可能丢失也可能会重发。
acks = 1: 当leader接收到消息之后发送ack,丢会重发,丢的概率很小。
acks = -1: 当所有的follower都同步消息成功后发送ack. 丢失消息可能性比较低。
2.Consumer从Broker拉取消息
Kafka中有两种consumer接口,分别为Low-level API和High-levelAPI
(1). Low-level API SimpleConsumer
这套接口比较复杂的,使用者必须要考虑很多事情,优点就是对Kafka可以有完全的控制。
(2). High-level API ZookeeperConsumerConnector
High-level API使用比较简单,已经封装了对partition和offset的管理,默认是会定期自动commit offset,这样可能会丢数据的,因为consumer可能拿到数据没有处理完crash。 High-level API接口的特点,自动管理,使用简单,但是对Kafka的控制不够灵活。
3. Broker存储消息
(1). 对于broker,落盘的数据,除非磁盘坏了,一般不会丢的。
(2). 对于内存脏(没有flush磁盘)数据,broker重启会丢。
可以通过log.flush.interval.messages和log.flush.interval.ms来配置flush间隔,interval大丢的数据多些,小会影响性能。
但在0.8.x版本以后,可以通过replication机制保证数据不丢,代价就是需要更多资源,尤其是磁盘资源,kafka当前支持GZIP和Snappy压缩,来缓解这个问题。
是否使用replication取决于在可靠性和资源代价之间的平衡。
总结
Kafka只是能保证at-least once消息语义,即数据是可能重复的,这个在应用上需要可以容忍。
对于Kafka consumer,一般情况下推荐使用high-level API接口,最好不要直接使用low-level API,自己写起来比较麻烦和困难。