kafka

学习kafka必会名词

  1. producer:生产者,就是它来生产“鸡蛋”的。
  2. consumer:消费者,生出的“鸡蛋”它来消费。
  3. topic:你把它理解为标签,生产者每生产出来一个鸡蛋就贴上一个标签(topic),消费者可不是谁生产的“鸡蛋”都吃的,这样不同的生产者生产出来的“鸡蛋”,消费者就可以选择性的“吃”了。相当于“队列”
  4. broker:就是篮子了。

kafka是一个高吞吐的分布式消息系统
kafka作为一个集群运行在一个或多个服务器上。
kafka集群存储的消息是以topic为类别记录的。
每个消息(也叫记录record,我习惯叫消息)是由一个key,一个value和时间戳构成。

包括四大核心接口

Producer API允许了应用可以向Kafka中的topics发布消息;
Consumer API允许了应用可以订阅Kafka中的topics,并消费消息;
Streams API允许应用可以作为消息流的处理者,比如可以从topicA中消费消息,处理的结果发布到topicB中;
Connector API提供Kafka与现有的应用或系统适配功能,比如与数据库连接器可以捕获表结构的变化;

kafka
topic:就像消息队列,生产者写入消息,消费者读取消息,topic支持多个生产者或者消费者同时订阅,topic由多个partition组成,每个partition消息都有序,topic由多个partition,系统根据算法分配到指定分区,如果需要所有消息都有序,最好只用一个分区。Topic分成一个或多个Partition,每个Partition在物理上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件。
kafka
不同消费者对同一分区的消息读取互不干扰,消费者可以通过设置消息位移(offset)来控制自己想要获取的数据,比如可以从头读取,最新数据读取,重读读取等功能。
kafka
Topic被分为四个分区(P0-P4)分别被分配在两个节点上,另外还有两个消费者组(GA,GB),其中GA有两个消费者实例,GB有四个消费者实例。
kafka
上面可以看出topic有一个原则就是:
若消费者数小于partition数,且消费者数为一个,那么它就消费所有消息;
若消费者数小于partition数,假设消费者数为N,partition数为M,那么每个消费者能消费的分区数为M/N或M/N+1;
若消费者数等于partition数,那么每个消费者都会均等分配到一个分区的消息;
若消费者数大于partition数,则将会出现部分消费者得不到消息分区,出现空闲的情况;

数据持久化
Kafka也不是partition一有数据就立马将数据写到磁盘上,它会先缓存一部分,等到足够多数据量或等待一定的时间再批量写入(flush)。也就是说先写缓存,然后数据量足够大了再批量写入磁盘。
生产者消费者都是跟主分区互动,备份分区不做读写,如果有一个挂壁了,那就选举出备份分区
kafka
kafka
消费者组可以一次取三个数据量
kafka

如果消费者组中的某个消费者挂了,那么其中一个消费者可能就要消费两个partition了
如果只有三个partition,而消费者组有4个消费者,那么一个消费者会空闲
如果多加入一个消费者组,无论是新增的消费者组还是原本的消费者组,都能消费topic的全部数据。(消费者组之间从逻辑上它们是独立的)

作者:半兽人
链接:https://www.orchome.com/5
来源:OrcHome
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

生产者发送到一个特定的Topic的分区上,消息将会按照它们发送的顺序依次加入,也就是说,如果一个消息M1和M2使用相同的producer发送,M1先发送,那么M1将比M2的offset低,并且优先的出现在日志中。
消费者收到的消息也是此顺序。
如果一个Topic配置了复制因子(replication factor)为N, 那么可以允许N-1服务器宕机而不丢失任何已经提交(committed)的消息。

zookeeper是kafka的一个重要依赖:
探测broker和consumer的添加或移除。
负责维护所有partition的领导者/从属者关系(主分区和备份分区),如果主分区挂了,需要选举出备份分区作为主分区。
维护topic、partition等元配置信息
kafka
总结

  1. Kafka天然是分布式的,往一个topic丢数据,实际上就是往多个broker的partition存储数据
  2. Kafka会将partition以消息日志的方式(落磁盘)存储起来,通过 顺序访问IO和缓存(等到一定的量或时间)才真正把数据写到磁盘上,来提高速度。
  3. Kafka会将数据写到partition,单个partition的写入是有顺序的。如果要保证全局有序,那只能写入一个partition中。如果要消费也有序,消费者也只能有一个。
  4. 凡是分布式就无法避免网络抖动/机器宕机等问题的发生,很有可能消费者A读取了数据,还没来得及消费,就挂掉了。Zookeeper发现消费者A挂了,让消费者B去消费原本消费者A的分区,等消费者A重连的时候,发现已经重复消费同一条数据了。
  5. 很多问题,先看看能不能通过现有配置解决掉(学多了框架,你就会发现很多官方的就已经支持解决了,你做的可能改改配置/参数就完事了)
  6. 顺序保证,保证数据会按照特定顺序取处理,避免了数据不一致的情况。
  7. 缓冲,消息队列通过缓冲层来帮助任务最高的执行,写入队列的处理会尽可能快速。
  8. 异步通信,很多时候,用户不需要立即处理,可以把消息先放到队列,在需要的时候就可以处理。

kafka的架构
kafka
一个典型的Kafka包含若干Producer,若干broker(Kafka支持水平扩展,一般broker越多,吞吐量越高),若干Consumer Group,以及一个zookeeper集群,通过zookeeper管理集群配置,选举leader,Producer使用push将消息发送到broker,Consumer使用pull模式从broker订阅并消费消息。
Kafka会为每一个Consumer Group保留一些metadata信息——当前消费的消息的position,也即offset。这个offset由Consumer控制。正常情况下Consumer会在消费完一条消息后递增该offset。

使用Consumer high level API时,同一Topic的一条消息只能被同一个Consumer Group内的一个Consumer消费,但多个Consumer Group可同时消费这一消息。
kafka

要实现Kafka HA,要将replica均匀分布到整个集群上,topic的Partition数量大于Broker数量,Kafka分配Replica的算法如下:

  1. 将所有Broker(假设共n个Broker)和待分配的Partition排序
  2. 将第i个Partition分配到第(i mod n)个Broker上
  3. 将第i个Partition的第j个Replica分配到第((i + j) mode n)个Broker上
    消息传递同步策略
    Producer再发布消息到某个Partition时,先通过ZooKeeper找到并发送消息到Partition的Leader,leader会将消息写入本地的log,灭个Follower都从Leader pull数据。Follower存储的数据顺序与Leader能保持一致。Follower接收消息并写入后,给Leader发送ACK,Leader收到了ISR所有的Replica的ACK,消息就被commit了。为了提高性能,每个Follower再接收到数据后,立马向Leader发送ACK,而非等到数据写入Log中,对于已经commit的消息,Kafka只能保证它被存于多个Replica的内存中,而不能保证它们被持久化到磁盘中,也就不能完全保证异常发生后该条消息一定能被Consumer消费。Consumer读消息也是从Leader读取,只有被commit过的消息才会暴露给Consumer。
    kafka
    对于Kafka而言,定义一个Broker是否“活着”包含两个条件:
    一是它必须维护与ZooKeeper的session(这个通过ZooKeeper的Heartbeat机制来实现)。
    二是Follower必须能够及时将Leader的消息复制过来,不能“落后太多”。
    Leader会跟踪与其保持同步的Replica列表,该列表称为ISR(即in-sync Replica)。如果一个Follower宕机,或者落后太多,Leader将把它从ISR中移除。这里所描述的“落后太多”指Follower复制的消息落后于Leader后的条数超过预定值。
    kafka之间是无法互相发现对方的,每个kafka向zk注册,说我是A节点(broker.id),我是B节点,这样组成了一个kafka集群。每个人通过zk来发现彼此。
    Leader Election算法
    Leader选举本质上是一个分布式锁,有两种方式实现基于ZooKeeper的分布式锁:
    节点名称唯一性:多个客户端创建一个节点,只有成功创建节点的客户端才能获得锁
    临时顺序节点:所有客户端在某个目录下创建自己的临时顺序节点,只有序号最小的才获得锁

一种非常常用的选举leader的方式是“Majority Vote”(“少数服从多数”),如果我们有2f+1个Replica(包含Leader和Follower),那在commit之前必须保证有f+1个Replica复制完消息,为了保证正确选出新的Leader,fail的Replica不能超过f个。因为在剩下的任意f+1个Replica里,至少有一个Replica包含有最新的所有消息。这种方式有个很大的优势,系统的latency只取决于最快的几个Broker,而非最慢那个。Majority Vote也有一些劣势,为了保证Leader Election的正常进行,它所能容忍的fail的follower个数比较少。如果要容忍1个follower挂掉,必须要有3个以上的Replica,如果要容忍2个Follower挂掉,必须要有5个以上的Replica。也就是说,在生产环境下为了保证较高的容错程度,必须要有大量的Replica,而大量的Replica又会在大数据量下导致性能的急剧下降。这就是这种算法更多用在ZooKeeper这种共享集群配置的系统中而很少在需要存储大量数据的系统中使用的原因。

Kafka在ZooKeeper中动态维护了一个ISR(in-sync replicas),这个ISR里的所有Replica都跟上了leader,只有ISR里的成员才有被选为Leader的可能。在这种模式下,对于f+1个Replica,一个Partition能在保证不丢失已经commit的消息的前提下容忍f个Replica的失败。在大多数使用场景中,这种模式是非常有利的。事实上,为了容忍f个Replica的失败,Majority Vote和ISR在commit前需要等待的Replica数量是一样的,但是ISR需要的总的Replica的个数几乎是Majority Vote的一半。

虽然Majority Vote与ISR相比有不需等待最慢的Broker这一优势,但是Kafka作者认为Kafka可以通过Producer选择是否被commit阻塞来改善这一问题,并且节省下来的Replica和磁盘使得ISR模式仍然值得。

如何处理所有Replica都不工作
在ISR中至少有一个follower时,Kafka可以确保已经commit的数据不丢失,但如果某个Partition的所有Replica都宕机了,就无法保证数据不丢失了。这种情况下有两种可行的方案:

1.等待ISR中的任一个Replica“活”过来,并且选它作为Leader
2.选择第一个“活”过来的Replica(不一定是ISR中的)作为Leader

kafka

Kafka应用场景:

消息
kafka更好的替换传统的消息系统,消息系统被用于各种场景(解耦数据生产者,缓存未处理的消息,等),与大多数消息系统比较,kafka有更好的吞吐量,内置分区,副本和故障转移,这有利于处理大规模的消息。

根据我们的经验,消息往往用于较低的吞吐量,但需要低的端到端延迟,并需要提供强大的耐用性的保证。

在这一领域的kafka比得上传统的消息系统,如的ActiveMQ或RabbitMQ的。

网站活动追踪
kafka原本的使用场景:用户的活动追踪,网站的活动(网页游览,搜索或其他用户的操作信息)发布到不同的话题中心,这些消息可实时处理,实时监测,也可加载到Hadoop或离线处理数据仓库。

每个用户页面视图都会产生非常高的量。

指标
kafka也常常用于监测数据。分布式应用程序生成的统计数据集中聚合。

日志聚合
许多人使用Kafka作为日志聚合解决方案的替代品。日志聚合通常从服务器中收集物理日志文件,并将它们放在*位置(可能是文件服务器或HDFS)进行处理。Kafka抽象出文件的细节,并将日志或事件数据更清晰地抽象为消息流。这允许更低延迟的处理并更容易支持多个数据源和分布式数据消费。

流处理
kafka中消息处理一般包含多个阶段。其中原始输入数据是从kafka主题消费的,然后汇总,丰富,或者以其他的方式处理转化为新主题,例如,一个推荐新闻文章,文章内容可能从“articles”主题获取;然后进一步处理内容,得到一个处理后的新内容,最后推荐给用户。这种处理是基于单个主题的实时数据流。从0.10.0.0开始,轻量,但功能强大的流处理,就可以这样进行数据处理了。

除了Kafka Streams,还有Apache Storm和Apache Samza可选择。

事件采集
事件采集是一种应用程序的设计风格,其中状态的变化根据时间的顺序记录下来,kafka支持这种非常大的存储日志数据的场景。

提交日志
kafka可以作为一种分布式的外部日志,可帮助节点之间复制数据,并作为失败的节点来恢复数据重新同步,kafka的日志压缩功能很好的支持这种用法,这种用法类似于Apacha BookKeeper项目。