文章目录
- Kafka特点
- 设计要点
- 高吞吐
- 负载均衡
- 拉取系统
- 可扩展性
- Kafka架构
- Kafka为什么要将Topic进行分区?
- 应用场景
- Kafka消息发送和消费的流程
- Kafka Producer有哪些发送模式
- Kafka的网络模型是怎么样的?
- Kafka的副本机制
- Zookeeper在Kafka中的作用
- Kafka如何实现高可用
- Kafka是否会弄丢数据
- Kafka消息的顺序性
Kafka特点
- 高吞吐量:每秒可生产25w消息(50MB),每秒可处理55w消息(110MB)
- 可持久化。将消息持久化到磁盘,因此可用于批量消费
- 分布式系统,易于向外扩展
- 消息被处理的状态都在consumer维护,而不由broker维护:消息是否被处理是由consumer提交消费进度给broker,而不是broker消息被consumer拉去后,就标记为已消费
设计要点
高吞吐
- 数据磁盘持久化:消息不在内存中缓存,直接写入磁盘,利用磁盘的顺序读写性能
- zero-copy:减少IO操作
1. 传统的数据发送需要4次上下文切换
2. 采用sendfile系统调用后,数据可以直接在内核态交互,系统上下文切换减少为2次,提高百分60的数据发送性能 - 数据批量发送
- 数据压缩
- Topic划分为多个partition,提高并行度
1. kafka以topic来进行消息管理,每个topic包含多个partition,每个partition对应一个逻辑log,有多个segment文件组成
2. 每个segment中存储多条消息,消息id由其逻辑位置决定,即从消息id可直接定位到消息的存储位置,避免id到位置的额外映射
3. 每个partition在内存中对应一个index,记录每个segment中的第一条消息偏移量
4. 发布者发到某个topic的消息会被均匀的分布到多个partition上,broker 收到发布消息往对应partition的最后一个segment上添加该消息
5. 当segment上的消息条数达到配置值或消息发布时间超过阈值时,segment上的消息会被flush到磁盘,只有flush到磁盘上的消息订阅者才能订阅到,segment达到一定的大小后将不会再往该segment写数据,broker会创建新的segment文件
负载均衡
- producer根据用户指定的算法,将消息发送到指定partition中
- topic存在多个partition,每个分区都在不同的broker节点上
- 相同的topic的多个partition会分配给不同的consumer进行拉取消息,消费
拉取系统
- 可以根据consumer消费能力自主控制消息拉去速度
- 可以根据consumer自身情况选择消费模式,例如:批量、重复、从尾端开始消费
可扩展性
通过zookeeper管理broker和consumer的动态加入与离开
- 当需要增加Broker节点时,新增的broker会向zookeeper注册,而producer和注册在zookeeper上的watcher感知这些变化,并及时做出调整
- 当新增和删除consumer节点时,相同topic的多个partition会分配给剩余的consumer
Kafka架构
分布式架构,主要包括producer、broker、consumer
- Producer,consumer实现kafka注册的接口
- 数据从producer发送到broker中,broker承担一个中间缓存和分发的作用
- broker分发注册到系统中的consumer。broker的作用类似于缓存,即活跃的数据和离线处理系统之间的缓存
基本概念:
- Topic:kafka处理的消息源的不同分类
- Partition:topic物理上的分组(分区),一个topic可以分为多个partition。每个partition都是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)
1. replicas:partition的副本集,保障partition的高可用
2. leader:replicas中的一个角色,producer和consumer只跟leader交互
3. follower:replicas中的一个角色,从leader中复制数据,作为副本,一旦leader挂掉,会从它的followers中选举出一个新的leader继续提供服务 - Message:消息,每个producer可以向一个Topic发布一些消息
- Producers:消息和数据生成者,向Kafka的一个Topic发布消息的过程
- Consumers:消息和数据消费者,订阅Topic,并处理其发布的消息的过程
1. consumer group:每个consumer都属于一个consumer group,每条小只能被consumer group中的一个consumer消费,但是可以被多个consumer group消费 - Broker:缓存代理
1. Controller:Kafka集群中,通过zookeeper选举某个broker作为controller,用来进行leader election 以及各种failover - Zookeeper:Kafka通过Zookeeper来存储集群的Topic、Partition等元信息
Kafka为什么要将Topic进行分区?
为了负载均衡,水平扩展
- Topic只是逻辑概念,面向的是producer和consumer,而partition则是物理概念。如果Topic不进行分区,而将Topic内的消息存储于一个Broker,那么关于该Topic的所有读写请求都将由一个Broker处理,吞吐量容易陷入瓶颈
- 有了Partition概念后,可以把流量分布到不同的服务器上
- 当Producer发布消息时,Producer客户端可以采用random、key-hash及轮询算法选定目标Partition
- 当Consumer拉取消息是,Consumer客户端可以采用随机、轮询算法分配partition,从不同的Broker拉取对应的Partition的leader分区
应用场景
- 消息队列
- 行为跟踪:跟踪用户浏览页面、搜索及其他行为,以及发布订阅的模式实时记录到对应的Topic里
- 元数据监控
- 日志手机
- 流处理
- 持久性日志
Kafka消息发送和消费的流程
- Producer,根据指定的partition方法,将消息发布到指定Topic的Partition里面
Producer采用push模式将消息发布到Broker
每条消息都被append到Patition,属于顺序写磁盘。
Producer发送消息到Broker时
会根据分区算法选择将其存储到哪一个Partition中
其路由机制:
1. 指定Partition
2. 未指定Partition,但指定了key,通过对key进行hash
3. Partition和key都未指定,使用轮询选出
写入流程:
1. 与zookeeper进行交互,在brokers/topic/state节点找到该partition的leader
2. Producer将消息发送给该leader
3. leader将消息写入本地log
4. followers从leader pull消息,写入本地log后向leader发送ack
5. leader收到所有ISR中的replica的ACK后,增加HW并向Producer发送ACK
- Kafka集群接收到Producer发过来的消息后,将其持久化到硬盘,并保留消息指定时长,而不关注消息是否被消费
存储的信息有:
1. 具体的日志文件 000000.log
2. 索引文件 000000.index
3. 时间索引文件 000000.timeindex
每个Partition分区又对应多个segment(分段)文件
每个segment文件都包含一组以上的存储文件
- Consumer,从Kafka集群pull数据并控制获取消息的offset。至于消费的进度,可手动或者自动提交给Kafka集群
consumer group 一个消息只能被group内的一个consumer所消费
且consumer消费信息时不关注offset
最后一个offset由zookeeper保存,下次消费时直接从记录的offset开始
1. 如果消费者线程大于Patition数量,则有些线程将收不到消息
2. 如果Patition数量大于消费线程数,则有些线程多收到多个Patition的消息
3. 如果一个线程消费多个Patition,则无法保证你收到的消息的顺序,而一个Patition内的消息是有序的
Consumer采用pul模式从Broker中读取数据
push模式,很难适应消费速率不同的消费者,因为发送速率由Broker决定
这样会造成consumer来不及处理消息
典型的表现为拒绝服务以及网络拥塞
Kafka Producer有哪些发送模式
- 同步
- 异步:以batch的形式push数据,默认是16kb,一定时间内若未满16kb也会发送,若在时间内满了16kb直接发送
Kafka的网络模型是怎么样的?
- KafkaClient ,单线程Selector模型(NIO)
- KafkaServer,Kafka Broker
- Broker内部的实现实际上为NettyServer的NIO方式
- Accept Thread负责与客户端建立连接链路,然后把Socket轮转交给Process Thread(相当于Netty的Boss EventLoop)
- Process Thread负责接收请求和响应数据,Process Thread每次基于Selector事件循环,首先从Response Queue读取响应数据,向客户端回复响应,然后接收到客户端请求后,读取数据放入Request Queue。(相当于Netty的Worker EventLoop)
- Work Thread负责业务逻辑、IO磁盘处理等,负责从Request Queue读取请求,并把处理结果放入Response Queue,待ProcessThread 发送出去(相当于业务线程池)
Kafka的副本机制
多个Broker节点对其他节点的Topic分区的日志进行复制。当集群中的某个节点出现故障,访问故障节点的请求会被转移到其他正常节点,Kafka每个主题的每个分区都有一个主副本和0个或多个副本,副本和主副本保持数据同步
在Kafka中并不是所有的副本都能来替代主副本,Kafka的Leader节点中维护着一个ISR(活跃组):
1. 节点必须与zookeeper保持连接
2. 在同步的过程中这个副本不能落后主副本太多
AR(副本全集),OSR(不活跃的副本),ISR(活跃的副本)
1. AR = OSR + ISR
2. ISR = leader+没有落后太多的副本
HW:consumer能够看到此partition的位置
LEO:每个partition的log最后一条message的位置
Producer向Leader发送数据时,可以设置 request.required.acks参数来设置数据可靠性级别:
1. 参数1(默认):只要Leader成功接收到则可以发送下一条message。若此时Leader宕机了,数据丢失
2. 参数0:不需要等待Broker的确认继续发送,数据可靠性最低
3. 参数-1:Broker需要等待ISR中所有的Follower都去人接受才发送下一条
Zookeeper在Kafka中的作用
- Broker在zookeeper中注册
- Topic在zookeeper中注册
- Consumer在zookeeper中注册
- Producer负载均衡
- Consumer负载均衡
- 记录消费进度Offset
- 记录Partition与Consumer的关系
Kafka如何实现高可用
- zookeeper部署2N+1节点,形成zookeeper集群,保证高可用
- kafka broker部署集群
- kafka consumer部署集群
Kafka是否会弄丢数据
- 消费端丢失数据
唯一可能导致消费者丢失数据的情况,你消费了这条消息,然后消费者自动提交了offset,让broker以为你已经消费好了这个消息,实际上你猜刚准备处理这个消息,但是还没处理完就挂了。此时肯定会重复消费一次,需自己保重幂等性 - Broker丢失数据
kafka某个broker宕机,重新选举partition的leader,此时其他的follower刚好还有些没有同步,结果此时的leader挂了,选举某个follower改成leader,丢失了一些数据
方案:
- 给Topic设置replication.factor 参数:这个值必须大于1,要求每个partition必须有至少2个副本
- 在kafka服务端设置min.insync.replicas参数:这个值必须大于1,这个是要求一个leader至少感知到有一个follower还跟自己保持联系
- 在producer端设置acks=all:要求每条数据,必须是写入所有replica之后才认为是写入成功
- 在producer端设置retries=max:这个是要求一旦写入失败就无限重试,卡在这里
- 生产者丢失数据
如果按照之前的思路设置acks=all,一定不会丢失数据,保持leader所有的follower都同步消息成功才保证本次写入成功
Kafka消息的顺序性
- consumer对每个partition内部单线程消费
- consumer拉去到消息后,写到N个内存queue,具有相同key的数据都到同一个内存queue。然后对于N个现场,每个线程分别消费一个内存queue即可