kafka以前的定义是一个分布式的基于发布订阅的消息队列,现在的kafka的定义已经是一个分布式的流处理平台,用于数据通道处理,数据流分析,数据集成等现在消息队列只是kafka其中一个功能。kafka做消息队列使用注意应用于数据量非常大丢几个也无所谓的大数据处理不太适合用于业务处理。
kafka优势高吞吐、可持久化、可水平拓展、支持流处理。
Kafka允许消费者非实时读取消息,因为Kafka将消息按一定顺序持久化到磁盘,保证了数据不会丢失,顺序写磁盘的效率比随机写内存还要高,而且以时间复杂度为O(1)的方式提供消息持久化能力,消息消费后不会马上删除到了过期时间后才会从磁盘删除。
基于发布订阅每秒可以生产25W消息、处理55W消息。
kafka可以横向拓展生产者、消费者、broker使集群可以处理巨大的信息流,能保证消息亚秒级别的消息延迟,实时性高。
kafka消息都会在集群中进行备份,每个分区都有一台server作为leader其他的server作为followers,当leader宕机后follower中的一台server会自动成为新的leader,容错较高且集群负载均衡。
是用户的活动追踪,网站的活动(网页游览,搜索或其他用户的操作信息)发布到不同的话题中心,这些消息可实时处理实时监测也可加载到Hadoop或离线处理数据仓库。
kafka也常常用于监测数据,分布式应用程序生成的统计数据集中聚合
许多人使用Kafka作为日志聚合解决方案的替代品,日志聚合通常从服务器中收集物理日志文件,
并将它们放在中央位置(可能是文件服务器或HDFS)进行处理。Kafka抽象出文件的细节,并将日志或事件数据更清晰地抽象为消息流。这允许更低延迟的处理并更容易支持多个数据源和分布式数据消费。
spark/storm/flink
一个kafka架构包括若干个Producer(服务器日志、业务数据、web前端产生的page view等),若干个Broker(kafka支持水平扩展,一般broker数量越多集群的吞吐量越大),若干个consumer group,一个Zookeeper集群(kafka通过Zookeeper管理集群配置、选举leader、consumer group发生变化时进行rebalance)
broker代表了kafka的实体服务在消息队列领域中,它其实指的就是消息队列本身。在kafka中就是kafka server 。每部署一个kafka server 就是一个broker
生产者就是产生消息的服务器。就是消息队列的业务数据来源。
消费者就是消费消息的服务器。kafka的consumer采用的是消息队列的拉模型
用于管理和协调broker
ZooKeeper服务主要用于通知生产者和消费者Kafka系统中存在任何新代理或Kafka系统中代理失败。 根据Zookeeper接收到关于代理的存在或失败的通知,然后生产者和消费者采取决定并开始与某些其他代理协调他们的任务。
控制器是集群中的概念,每个集群中会选择出一个 Broker 担任控制器的角色,控制器是 Kafka 集群的中心,可以把它看做是个leader。
在Kafka中该协调者称之为控制器(Controller),其实该控制器并没有什么特殊之处,它本身也是一个普通的Broker,只不过需要负责一些额外的工作(追踪集群中的其他Broker,并在合适的时候处理新加入的和失败的Broker节点、Rebalance分区、分配新的leader分区等).
注意:Kafka集群中始终只有一个Controller Broker。
集群指的是由多个 Broker 所共同构成的一个整体,对外提供统一的服务,这类于我们在部署系统时都会采用集群的方式来进行。借助于集群的方式,Kafka 消息队列系统可以实现高可用和容错性,即一台 Borker 挂掉了也不影响整个消息系统的正常运行,集群中的各个 Borker是通过心跳的方式来检测其他机器是否还存活。
这个主题只是一个虚拟的概念,是kafka下消息的类别。一个broker里面可以有多个topic。kafka中的消息是以topic为单位去归类的,生产者发送的每条消息都要有主题,而消费者要订阅主题来消费。物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处。一个topic可以有多个分区也就是partition
Kafka数据存储的基本单元,这个其实是物理上的概念
同一个topic的数据,会被分散的存储到多个partition中,这些partition可以在同一台机器上,也可以是在多台机器上,这种方式在大多数分布式存储中都可以见到,比如MongoDB、Elasticsearch的分片技术,其优势在于:有利于水平扩展,避免单台机器在磁盘空间和性能上的限制,同时可以通过复制来增加数据冗余性,提高容灾能力,为了做到均匀分布,通常partition的数量通常是Broker Server数量的整数倍。一个分区只能被一个消费者消费,通常消费者集群的数量小于分区数量。
分区扩容时候只能少变多不能多变少,比如有4个分区可以扩容成8个但是8个分区不能变成4个分区,一个partition可以有多个副本也就是replication。
每一个分区都有多个副本,副本的作用是做备胎防止分区的服务器宕机数据丢失,主分区(Leader)会将数据同步到从分区(Follower)
当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为 Leader,在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本。副本是以partition为维度进行分配的。
不同的分区(partition)数据是不一致的,不同的副本(Replication)中的数据是一致的。
在Kafka中,每个topic都可以配置多个分区以及多个副本
每个分区都有一个leader以及0个或者多个follower,在创建topic时,Kafka会将每个分区的leader均匀地分配在每个broker上,我们正常使用kafka是感觉不到leader、follower的存在的。
Kafka中的leader负责处理读写操作,而follower只负责拉取同步leader的消息数据
如果leader出现故障,其他follower会被重新选举为leader
follower像一个consumer一样,拉取leader对应分区的数据,并保存到日志数据文件中。
指的是从broker推向consumer,即consumer被动的接收消息,有broker主动发送
消息实时性高,broker接收到消息后立即推送给consumer
当生产者向消费者推送的速率大于消费者消费的速率时随着时间的增长可能会把消费者搞宕机。
要通过qos来控制消息的流速,不太好定义,并且要增加通信成本。
指的是consumer主动向broker请求拉取消息,broker被动发送消息到consumer。
拉模型的主动权在消费者,消费者根据自身的情况来发起拉取消息的请求,消费者如果自己消费不过来了可以根据一定的策略停止拉取,获取间隔拉取都可以。
拉模型也更加适合消息的批处理。推模型不知道消费者一次型处理消息的能力,拉模型可以参考消费者请求的信息来决定缓存多少消息后批量发送。
消息有延迟,消费者只能通过不断的拉取来获取消息,考虑到性能又不能过于频繁的请求broker,比如2s请求一次broker那么消息就延迟2s。
因为拉模式是consumer不断的请求broker 所以如果间隔几个小时才有一条消息那么者几个小时中消费者所有向broker的请求都是无效的,都是在做无用功,这就是消息忙请求。
rocketmq和kafka都选择的是拉模型。
长轮询模式:kafka请求中有参数可以使消费者的请求在长轮询中等待,消费者去broker拉取消息时,会定义一个超时时间,也就是说消费者向broker拉取消息时如果有马上获取消息,如果没有会等着直到超时后然后再次发起请求。
kafka发送消息都是异步发送,同步也是通过future.get()控制前一条消息没有发送成功后一条消息等待。
producer生产者 – interceptor(拦截器:可以对消息和key做处理消息幂等性处理等都可以在这做) – serializer序列化器(消息转换为二进制流) – partitioner分区器(根据策略决定这个消息属于哪个分区)-- 内存缓冲池(最大32M,Map
由sender线程异步的拉取内存缓冲池的消息
拉取到消息 – networkclient缓存消息 – selector – kafka broker 指定的 partition – 成功后通知selector – 确认消息到达broker删除networkclient
networkclient可以标识出已发送broker broker未确认的消息。
如连接错误可以重新连接,主分区宕机分区重新选取主分区后重新发送
如消息太大异常会直接抛出,要调整message.max.bytes的值才行
实现producerInterceptor可以在发送消息前以及消息提交成功后写入业务。
应用:比如在发送消息前将这个消息落库状态为0,发送成功后将消息改为1,定时器扫描状态为0的数据重新发送这样可以消息防丢失
也可以做一些消息加前缀后缀等等
实现ConsumerInterceptor可以在消费消息前以及提交位移后编写特定逻辑。
Kafka遵守生产者消费者模式,这中间涉及到序列化与反序列化。Producer发送消息要通过序列化器(Serializer)将消息对象转换成字节数组,才能通过网络传输到服务端,消费端则需要通过反序列化器(Deserializer)从服务端拉取字节数组转成消息对象。消费端使用的反序列化器要和生产端的序列化器要一一对应。自定义的序列化器类需要实现Kafka提供的Serializer接口。
生产者配置key.serializer和value.serializer
消费者配置key.deserializer和value.deserializer
也可以引用依赖org.apache.avro 用apache avro kakfa来做序列化和反序列化这样效率更高
kafka消息分区的分区策略是决定生产者将消息发送到哪个分区的算法同时它也支持你自定义分区策略,常见的分区策略包含以下几种:轮询策略、随机策略 、按消息键保序策略
在指定partition的情况下,直接将消息发送到指定的partittion
没有指定partition时但有key时,将key的hash值与topic的partition总数取余得到partition。
没有指定partition也没有指定key时,kafka采用黏性分区器,会随机选择一个分区并会尽可能的用这个分区,分区的batch满了或者已完成再随机一个分区投递消息。
实现partitioner接口重写partition并添加自定义分区策略配置可以自定义分区策略。
发送效率高producer不需要等待服务器响应,但是会数据丢失,适用于消息很大并且不重要的消息。
同步发送send()方法会返回 Futrue 对象,通过调用 Futrue 对象的 get() 方法,等待直到结果返回,根据返回的结果可以判断是否发送成功。第一条消息发送失败了第二条无法发送。
消息发送到内存缓冲池后可以继续发送,成功到达后异步返回发送结果。如果业务需要知道消息发送是否成功,并且对消息的顺序不关心,那么可以用异步+回调的方式来发送消息
producer发送消息的时候,在kafka客户端内部,会把属于同一个topic分区的消息先汇总起来,形成一个batch,真正发往kafka服务器的消息都是以batch为单位的
为了使kafka的性能更高发送消息时不是直接发送到kafka broker 而是要先发送到消息缓冲池,然后由sender异步线程发送到broker。缓冲池的大小由buffer.memiry控制默认为32M,如果消息发送速率过快buffer满了会阻塞,阻塞超时会抛出异常。buffer的大小应该根据业务场景做适当的调整。
批量发送的大小由batch.size控制,默认是16kb一发送。减小这个参数会使消息延迟更低,增加这个参数会使吞吐量提升。
producer发送消息时候也提供了linger.ms来控制batch的最大空闲时间,超过该时间这个batch也会发送到broker端,默认的超时时间是0这样是不会批发送的,可以根据业务需求将它设置为50ms,100ms等提高吞吐量。妈祖16K或者超过超时时间消息才会发送。
kafka使用池化技术避免了jvm的垃圾回收stw保证了kafka的吞吐量。内存缓冲池是不会回收的,有个0,1的标识标识使用中和消息已发送,已完成的可以直接覆盖使用。
Producer 一上来就会占用一个固定大小的内存块,比如 32MB,然后将 32 MB 划分成 M 个小内存块(比如一个小内存块大小是 16KB)当需要创建一个新的 Batch 时,直接从内存池中取出一个 16 KB 的内存块即可,然后往里面不断写入消息,但最大写入量就是 16 KB,接着将 Batch 发送给 Broker ,此时该内存块就可以回到缓冲池中继续复用了,根本不涉及垃圾回收。
设置多个分区进行发送,一般分区数尽量不要大于kafka broker的节点数。分区也不要过多,kafka的topic到达瓶颈后topic越多性能下降越厉害,其实也就是分区到达瓶颈后分区越多性能下降越厉害(通常分区数量大于500时比较明显,小于500其实影响不大)。分区过多顺序写会变成随机写。
compression.type 默认为 none 如果服务器的cpu很好的话可以启用数据压缩将参数修改为snappy。
相对于rabbitmq和rocketmq kafka是没有broker和消费者端的消息保证的,没有死信队列和手动ack,通常kafka用于流式计算和处理还有行为采集以及日志处理,较少应用于业务开发中,单纯的业务开发如果使用kafka是比较复杂的。
Kafka的topic是可以分区的,并且可以为分区配置多个副本,改配置可以通过replication.factor 参数实现。比如配置为4就是一个领导者副本leader加三个追随者副本follower。
Kafka中的分区副本包括两种类型:领导者副本(Leader Replication)和追随者副本(Follower Replication),每个分区在创建时都要选举一个副本作为领导者副本,其余的副本自动变为追随者副本。注意领导者副本和追随者副本是不在一台服务器的不然冗余备份就变得没有意义了,它们是自动交叉部署的。查看服务器副本分布指令:sh bin/kafka-topics.sh --zookeeper zookeeper:2181 --describe --topic test(主题名称)
在 Kafka 中,追随者副本是不对外提供服务的,也就是说,任何一个追随者副本都不能响应消费者
和生产者的读写请求,所有的请求都必须由领导者副本来处理,换句话说,所有的读写请求都必须发往领导者副本所在的 Broker,由该 Broker 负责处理。
追随者副本不处理客户端请求,它唯一的任务就是从领导者副本异步拉取消息,并写入到自己的提交日志中,从而实现与领导者副本的同步。follower副本的唯一作用就是当leader副本出现问题时,通过ZooKeeper 提供的监控功能能够实时感知到,并立即开启新一轮的领导者选举,从follower副本中选一个作为新的领导者。实现副本的目的就是冗余备份,且仅仅是冗余备份。
AR就是ISR和OSR的统称,默认情况下kafka的replicaiton为1只有一个副本,为了确保消息的可靠性通常要将offsets.topic.replication.factor(副本因子)设置为大于等于2的值。
ISR 是同步中的副本 Kafka 为了同步leader副本和follower副本中的数据提供的数据复制算法,如果 leader 发生故障或挂掉,就会从ISR队列中选举出来一个新 leader 。因为follower拉取leader的消息是异步的所以follower需要追赶leader的进度。当producer发送一条消息到broker后,leader写入消息,并复制到所有follower(follower拉取数据),消息提交之后才被成功复制到所有的同步副本,消息复制延迟受到最慢的follower限制,重要的是快速检测慢副本。
OSR是未同步的副本,如果follower落后太多或者失败,leader将会把他从ISR中删除并添加到OSR中。在OSR中的副本节点只是失去了选举权,它仍然会继续同步数据,直到它追赶上进度再从OSR中删除放回到ISR中重新获取选举权。
副本节点必须能与zookeeper通过心跳机制保持会话
副本能同步 leader 上的所有写操作,并且不能落后太多(卡主或滞后的副本控制由replica.lag.time.max.ms 配置默认10S,如果10秒没有拉数据就默认落后太多去OSR呆会儿吧)
acks参数指定了多少个分区副本成功收到消息生产者才认为消息写入成功,acks确认机制是针对ISR队列,这个参数对于kafka生产者可靠性保障很重要,这个参数是配置在生产者代码中的。
这个配置吞吐量是最高的,不过没有任何可靠性保障,一旦出现问题会消息丢失。只管发送消息不关心是否接收成功也没有重试机制通常应用于日志场景。
领导者副本收到消息时,生产者就会接收到来自服务器的响应消息,消息写入leader副本分区就ok了,不过如果leader宕机了follower写没写入成功我们就无从知晓了,仍然会在isr队列中选取一个follower做leader,不过这个选取为主节点的follower是否写入成功我们就不知道了,对比acks = 0 的配置 asks = 1 有了很大的可靠性保障提升,不过也存在消息丢失的可能性。
只有所有参与复制的leader节点和follower节点(ISR列表的副本)全部收到消息时,生产者才会接收到来自服务器的响应。这种模式是最高级别的,也是最安全的,可以确保不止一个Broker接收到了消息,不过缺点是该延迟会比较高。
在acks = all 时,如果有3个副本节点,一个leader和两个follower,如果两个follower的同步进度都比较慢都去了OSR队列,而asks确认机制只针对ISR队列,这时候ISR里面就只有一个leader节点即使acks配置的是all也无法提供完善的消息保障,当leader副本节点挂掉后,follower节点都在OSR队列选主后无法保证消息不丢失。kafka为了解决这个问题broker端提供了一个参数min.insync.replicas,该参数控制的是消息至少被写入到多少个副本才算是写入成功,该值默认值为1,生产环境设定为一个大于1的值可以提升消息的持久性,如果同步的副本的数量低于该配置值,则生产者会收到错误响应,从而确保消息不丢失。
最小副本数的配置,只在于配置了acks = all时才生效。
如果acks = all min.insync.replicas = 2 如果有3个副本节点都在ISR还是会等待3个节点全部成功了broker才会将消息投递成功告知producer。
这个配置是每个kafka broker所在的服务器都要配置的。
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
KAFKA_MIN_INSYNC_REPLICAS: 3
配置这个参数要特别注意要兼容到其他的topic!!! 如果某些主题只有一个副本节点,你在全局配置将这个最小副本数改为2,那么所有只有一个副本节点的主题就都会消费失败,这是要出生产事故的。
如果有一个broker宕机了那么最小同步副本数量就不可能等于副本总数,这样消息永远发送不成功会一直重试到integer的最大值,这个最小同步副本个数通常设置为2或者3就可以了。
这里要控制好,生产者的重试时间要大于故障修复时间(kafka选举恢复时间),可以使用 retry.backoff.ms 参数来控制重试的时间,默认重试次数Integer.MAX_VALUE