简介:
最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,可以实时的处理大量数据以满足各种需求场景,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。
特性:
- 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,延迟最低只有几毫秒,topic可以分多个partition, consumer group 对partition进行consume操作。
- 可扩展性:kafka集群支持热扩展
- 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
- 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
- 高并发:支持数千个客户端同时读写
Kakfa的设计思想:
Kakfa Broker Leader的选举:Kakfa Broker集群受Zookeeper管理。所有的Kafka Broker节点一起去Zookeeper上注册一个临时节点,因为只有一个Kafka Broker会注册成功,其他的都会失败,所以这个成功在Zookeeper上注册临时节点的这个Kafka Broker会成为Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。(这个过程叫Controller在ZooKeeper注册Watch)。
同时这个Controller会监听其他Kafka Broker的所有信息,如果这个kafka broker controller宕机了,在zookeeper上面的那个临时节点就会消失,此时所有的kafka broker又会一起去Zookeeper上注册一个临时节点,重复之前操作。
Consumer Group:
各个consumer可以组成一个组,partition中的每个message只能被组中的一个consumer消费,如果一个message可以被多个consumer消费的话,那么这些consumer必须在不同的组。
新的组里面的consumer启动后会重新读取topic,它不能像AMQ那样可以多个BET作为consumer去互斥的并发处理message。如果想多个不同的业务都需要这个topic的数据,
起多个consumer group就好了,大家都是顺序的读取message,offsite的值互不影响。这样没有锁竞争,充分发挥了横向的扩展性,吞吐量极高。这也就形成了分布式消费的概念。
最佳实践:
一个consumer group处理一个topic的message,consumer group里面consumer的数量等于topic里面partition的数量,
如果这个consumer group里面consumer的数量小于topic里面partition的数量,就会有consumer thread同时处理多个partition
Topic & Partition:
Topic相当于传统消息系统MQ中的一个队列queue,producer端发送的message必须指定是发送到哪个topic,但是不需要指定topic下的哪个partition,
因为kafka会把收到的message进行load balance,均匀的分布在这个topic下的不同的partition上( hash(message) % [broker数量] )。这个topic会分成一个或多个partition,每个partiton相当于是一个子queue。
在物理结构上,每个partition对应一个物理的目录(文件夹),文件夹命名是topicname[序号],一个topic可以有无数多的partition,根据业务需求和数据量来设置。
在kafka配置文件中可随时更高num.partitions参数来配置更改topic的partition数量,在创建Topic时通过参数指定parittion数量。Topic创建之后也可以修改partiton数量。
Partition Replica:
每个partition可以在其他的kafka broker节点上存副本,以便某个kafka broker节点宕机不会影响这个kafka集群。存replica副本的方式是按照kafka broker的顺序存。
replica副本数目不能大于kafka broker节点的数目,如果某个broker宕机,其实整个kafka内数据依然是完整的。replica副本数越高,系统虽然越稳定,但是也会消耗资源和性能,反之,亦然。
Replica策略是基于partition,而不是topic;kafka将每个partition数据复制到多个server上,任何一个partition有一个leader和多个follower(可以没有);备份的个数可以通过broker配置文件来设定。
Partition leader与follower:
partition也有leader和follower之分。leader是主partition,producer写kafka的时候先写partition leader,再由partition leader push给其他的partition follower。
partition leader与follower的信息受Zookeeper控制,一旦partition leader所在的broker节点宕机,zookeeper会冲其他的broker的partition follower上选择follower变为parition leader。
消息在broker上的可靠性:
消息会持久化到磁盘上,所以如果正常关闭一个broker,其上的数据不会丢失;但是如果不正常退出,可能会使存在页面缓存来不及写入磁盘的消息丢失,这可以通过配置flush页面缓存的周期、阈值缓解,但是同样会频繁的写磁盘会影响性能,具体根据实际情况配置。
Kafka提供的是“At least once”模型,消息的读取进度由offset提供,offset可以由消费者自己维护也可以维护在zookeeper里,但是当消息消费后consumer挂掉,offset没有即时写回,就有可能发生重复读的情况,这种情况同样可以通过调整commit offset周期、阈值缓解,甚至消费者自己把消费和commit offset做成一个事务解决。
Partition ack:
当ack=0,表示不会等待broke的确认信息,效率最高。
当ack=1,表示producer写partition leader成功后,broker就返回成功,无论其他的partition follower是否写成功。
当ack=2,表示producer写partition leader和其他一个follower成功的时候,broker就返回成功,无论其他的partition follower是否写成功。
当ack=-1[parition的数量]的时候,表示只有producer全部写成功的时候,才算成功,kafka broker才返回成功信息。
这里需要注意的是,如果ack=1的时候,一旦有个broker宕机导致partition的follower和leader切换,会导致丢数据。
message状态:
在Kafka中,消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。
message持久化:
Kafka中会把消息持久化到本地文件系统中。Kafka作为吞吐量极高的MQ,可以非常高效的将message持久化到文件,速度非常快,这也是高吞吐量的原因。
由于message的写入持久化是顺序写入的,因此message在被消费的时候也是按顺序被消费的,保证partition的message是顺序消费的。一般的机器,大约单机每秒100k条数据。
Kafka高吞吐量:
Kafka的高吞吐量体现在读写上,分布式并发的读和写都非常快,写的性能体现在以o(1)的时间复杂度进行顺序写入。读的性能体现在以o(1)的时间复杂度进行顺序读取,对topic进行partition分区,consume group中的consume线程可以以很高能性能进行顺序读。
Kafka delivery guarantee(message传送保证):
- At most once消息可能会丢,绝对不会重复传输;消费者fetch消息,然后保存offset,然后处理消息;当client保存offset之后,但是在消息处理过程中consumer进程失效(crash),导致部分消息未能继续处理.那么此后可能其他consumer会接管,但是因为offset已经提前保存,那么新的consumer将不能fetch到offset之前的消息(尽管它们尚没有被处理),这就是"at most once"
- At least once 消息绝对不会丢,但是可能会重复传输;消费者fetch消息,然后处理消息,然后保存offset.如果消息处理成功之后,但是在保存offset阶段zookeeper异常或者consumer失效,导致保存offset操作未能执行成功,这就导致接下来再次fetch时可能获得上次已经处理过的消息,这就是"at least once"
- Exactly once每条信息肯定会被传输一次且仅传输一次;最少1次+消费者的输出中额外增加已处理消息最大编号:由于已处理消息最大编号的存在,不会出现重复处理消息的情况。
分区机制partition:
Kafka的broker端支持消息分区partition,Producer可以决定把消息发到哪个partition,在一个partition中message的顺序就是Producer发送消息的顺序,一个topic中可以有多个partition,具体partition的数量是可配置的。
partition的概念使得kafka作为MQ可以横向扩展,吞吐量巨大。partition可以设置replica副本,replica副本存在不同的kafka broker节点上,第一个partition是leader,其他的是follower,message先写到partition leader上,再由partition leader push到parition follower上。
所以说kafka可以水平扩展,也就是扩展partition。
push-and-pull :
Kafka中的Producer和consumer采用的是push-and-pull模式,即Producer只管向broker push消息,consumer只管从broker pull消息,两者对消息的生产和消费是异步的。
Kafka集群中broker之间的关系:
不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。
负载均衡:
Kafka提供了一个 metadata API来管理broker之间的负载(对Kafka0.8.x而言,对于0.7.x主要靠zookeeper来实现负载均衡)。
同步异步:
Producer采用异步push方式,极大提高Kafka系统的吞吐率(可以通过参数控制是采用同步还是异步方式)。