消息服务百科全书——消息投递语义

消息投递语义(Message delivery semantics)
有如下几种可能的消息传递保障:
1、At most once:消息可能丢失,但是不会重复。
2、At least once:消息不会丢失,但是可能重复。系统保证每条消息至少会发送一次,但在有故障的情况下可能会导致重复发送。
3、Exactly once:仅仅一次—这种是人们实际想要的,每条消息只会而且仅会发送一次。
这里需要拆开为两个问题:发布消息保证和消费消息保证。

大多数系统号称支持Exactly once,但是仔细去看那些条款,就会被误导,例如,那些条款中不会说明是否支持消费者和生产者失败的场景,是否支持多个消费者,或是写磁盘数据丢失的场景。
消息服务百科全书——消息投递语义
Kafka的语义定义是很明确清晰的。
生产者发布一条消息被定义为“Commit”。当Producer向broker发送消息时,一旦这条消息被commit,因数replication的存在,它就不会丢。
为了说明,我们假定一种场景,如果Producer发送数据给broker后,遇到网络问题而造成通信中断,那Producer就无法判断该条消息是否已经commit。
虽然Kafka无法确定网络故障期间发生了什么,但是Producer可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了Exactly once。截止到目前(Kafka 0.8.2版本,2015-03-04),这一Feature还并未实现,有希望在Kafka未来的版本中实现。(所以目前默认情况下一条消息从Producer到broker是确保了At least once,可通过设置Producer异步发送实现At most once)。
并不是所有的用户都需要这样的强制保证,我们允许用户设置保证机制的时延,如设置10ms,消息发送之后如果10ms内没有得到响应就认为有问题。也可以指定消息发送的异步确认,或者等待直到leader(follow)确定收到消息。
接下来讨论的是消息从broker到Consumer的delivery guarantee语义。(仅针对Kafka consumer high level API)。Consumer在从broker读取消息后,可以选择commit,该操作会在Zookeeper中保存该Consumer在该Partition中读取的消息的offset。该Consumer下一次再读该Partition时会从下一条开始读取。如未commit,下一次读取的开始位置会跟上一次commit之后的开始位置相同。当然可以将Consumer设置为autocommit,即Consumer一旦读到数据立即自动commit。如果只讨论这一读取消息的过程,那Kafka是确保了Exactly once。但实际使用中应用程序并非在Consumer读取完数据就结束了,而是要进行进一步处理,而数据处理与commit的顺序在很大程度上决定了消息从broker和consumer的delivery guarantee semantic。
读完消息先commit再处理消息。这种模式下,如果Consumer在commit后还没来得及处理消息就crash了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息,这就对应于At most once
读完消息先处理再commit。这种模式下,如果在处理完消息之后commit之前Consumer crash了,下次重新开始工作时还会处理刚刚未commit的消息,实际上该消息已经被处理过了。这
就对应于At least once。在很多使用场景下,消息都有一个主键,所以消息的处理往往具有幂等性,即多次处理这一条消息跟只处理一次是等效的,那就可以认为是Exactly once。(认为这种说法比较牵强,毕竟它不是Kafka本身提供的机制,主键本身也并不能完全保证操作的幂等性。而且实际上我们说delivery guarantee 语义是讨论被处理多少次,而非处理结果怎样,因为处理方式多种多样,我们不应该把处理过程的特性——如是否幂等性,当成Kafka本身的Feature)
如果一定要做到Exactly once,就需要协调offset和实际操作的输出。精典的做法是引入两阶段提交。如果能让offset和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,Consumer拿到数据后可能把数据放到HDFS,如果把最新的offset和数据本身一起写到HDFS,那就可以保证数据的输出和offset的更新要么都完成,要么都不完成,间接实现Exactly once。(目前就high level API而言,offset是存于Zookeeper中的,无法存于HDFS,而low level API的offset是由自己去维护的,可以将之存于HDFS中)
总之,Kafka默认保证At least once,并且允许通过设置Producer异步提交来实现At most once。而Exactly once要求与外

猜你喜欢

转载自blog.51cto.com/13831707/2150277