以前讨论了consumer和producer是怎么工做的,如今来讨论一下数据传输方面。数据传输的事务定义一般有如下三种级别:linux
最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输。网络
最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.异步
精确的一次(Exactly once): 不会漏传输也不会重复传输,每一个消息都传输被一次并且仅仅被传输一次,这是你们所指望的。ide
大多数消息系统声称能够作到“精确的一次”,可是仔细阅读它们的的文档能够看到里面存在误导,好比没有说明当consumer或producer失败时怎么样,或者当有多个consumer并行时怎么样,或写入硬盘的数据丢失时又会怎么样。kafka的作法要更先进一些。当发布消息时,Kafka有一个“committed”的概念,一旦消息被提交了,只要消息被写入的分区的所在的副本broker是活动的,数据就不会丢失。关于副本的活动的概念,下节文档会讨论。如今假设broker是不会down的。
若是producer发布消息时发生了网络错误,但又不肯定实在提交以前发生的仍是提交以后发生的,这种状况虽然不常见,可是必须考虑进去,如今Kafka版本尚未解决这个问题,未来的版本正在努力尝试解决。
并非全部的状况都须要“精确的一次”这样高的级别,Kafka容许producer灵活的指定级别。好比producer能够指定必须等待消息被提交的通知,或者彻底的异步发送消息而不等待任何通知,或者仅仅等待leader声明它拿到了消息(followers没有必要)。oop
如今从consumer的方面考虑这个问题,全部的副本都有相同的日志文件和相同的offset,consumer维护本身消费的消息的offset,若是consumer不会崩溃固然能够在内存中保存这个值,固然谁也不能保证这点。若是consumer崩溃了,会有另一个consumer接着消费消息,它须要从一个合适的offset继续处理。这种状况下能够有如下选择:spa
consumer能够先读取消息,而后将offset写入日志文件中,而后再处理消息。这存在一种可能就是在存储offset后还没处理消息就crash了,新的consumer继续从这个offset处理,那么就会有些消息永远不会被处理,这就是上面说的“最多一次”。日志
consumer能够先读取消息,处理消息,最后记录offset,固然若是在记录offset以前就crash了,新的consumer会重复的消费一些消息,这就是上面说的“最少一次”。orm
“精确一次”能够经过将提交分为两个阶段来解决:保存了offset后提交一次,消息处理成功以后再提交一次。可是还有个更简单的作法:将消息的offset和消息被处理后的结果保存在一块儿。好比用Hadoop ETL处理消息时,将处理后的结果和offset同时保存在HDFS中,这样就能保证消息和offser同时被处理了。事务