概念
- kafka是一个分布式的基于发布/订阅模式的消息引擎系统
- 支持分区(partition),多副本(replica),基于zookeeper的协调的分布式消息系统
特性
- 削峰填谷
- 应用解耦
- 异步处理
- 高吞吐
- 高性能
通信方式
-
点对点
-
发布-订阅
架构图
组成部分
- 生产者:Producer(向主题Topic发布新消息的应用程序)
- 消费者:Consumer(从主题Topic订阅新消息的应用程序)
- 消息:Record(Kafka是消息引擎,这里的消息指Kafka处理的主要对象)
- Topic(主题是承载消息的逻辑容器,在实际使用的时候主要是用来区分具体的业务)
- 分区:Partition(一个有序不变的消息序列,每个主题下可以有多个分区)
- 消息位移:Offset(表示分区中每条消息的位置信息,是一个单调递增且不变的值)
- 副本:Replica(Kafka中同一条消息能够被拷贝到多个地方以提供数据冗余,这些地方就是所说的副本。副本也可以分为领导者副本和追随者副本,各自有不同的角色划分。副本是在分区层级下,也就是每个分区可以配置多个副本来实现高可用)
- 消费者位移:Consumer Offset(表征消费者消费进度,每个消费者都有自己的消费位移)
- 消费者组:Consumer Group(多个消费者实例共同组成一个组,同时消费多个分区以实现高吞吐)
- 重平衡:Rebalance(消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。Rebalance是Kafka消费者端实现高可用的重要手段)
总结
kafka的高可用和高性能
-
kafka的高可用
-
可以采用集群模式,多副本的方式(ISR,AR)
-
采用了HW和LEO
-
采用设置ack标识来实现不同的可用性
ack=0:发送成功就可以, ACK=1:master返回成功就可以,ack=-1 所有的ISR的副本去全部返回成功,才可以(真正实现高可用)
-
-
kafka的高性能
- 消息时顺序读写。
- 数据存储是通过分段存储在不同segment中,快速查询
- 内容读写通过零拷贝
- 使用页缓存,增加读写效率
kafka的日志存储
Kafka中的消息时以主题(Topic)为基本单位进行归类的,各个主题在逻辑上相互独立。每个主题又可以分为一个或多个分区,分区数量可以在主题创建的时候指定,也可以在之后修改。每条消息在发送的时候会根据分区规则追加到指定的分区中,分区中的每条消息都会被分配一个唯一的序列号,也就是通常所说的偏移量(Offset)
如果不考虑多副本的情况下,一个分区对应一个日志Log。为了防止Log过大,Kafka又引入了日志分段(LogSegment),将Log切分为多个LogSegment,相当于一个巨型文件被平均分成多个相对较小的文件,方便后期对于消息的维护和清理
在向主题topic-log中发送一定量的消息的时候,某一时刻topic-log-0目录中的布局:
分区副本解释
Kafka通过多副本的机制来实现故障转移,在kafka集群中某个broker节点失效后仍然可以保证服务的可用性
1、如何保证副本中的所有数据都是一致性呢?
通过ack机制可以保证 -1 , 0 , 1
2、当生产者发送消息到某个主题后,消息时如何同步到对应的所有副本中
采用基于领导者(Leader-based)的副本机制
副本分为:
1、 领导者副本(Leader Replica)
2、追随者副本(Follower Replica)
3、优先副本:创建分区时指定的优先leader。如果不指定,则为分区的第一个副本。
Follower副本是不对外提供服务,任何一个追随者副本都不能响应消费者和生产者的读写请求。所有的请求都必须由领导者副本来处理,或者说,所有的读写请求都必须发往到领导者副本所在的Broker,由该Broker负责处理
当领导者副本挂掉后,或者是领导者副本所在的Broker宕机后,Kafka依托于Zookeeper提供的监控功能能够实现感知,并立即开启新一轮的领导者的选举,从追随者副本中选择一个作为新的领导者。老Leader副本重启后,只能作为追随者副本加入到集群中
ISR,AR
-
ISR(ISR指的是与Leader副本保持同步状态的副本集合,当然Leader副本本身也就是这个集合的一员)
-
AR(分区中的所有副本统称为AR)
失效副本
正常情况下,分区的所有副本都处于ISR集合中,但是难免会有异常情况发生,从而某些副本被剥离出ISR集合中。在ISR集合之外,也就是处于同步失效或功能失效(比如副本处于非存活状态)的副本统称为失效副本,失效副本对应的分区也就称为同步失效分区,即under-replicated分区。
LEO和HW
LEO标识每个分区中最后一条消息的下一个位置,分区的每个副本都有自己的LEO,ISR中最小的LEO即为HW,俗称高水位,消费者只能拉取到HW之前的消息
如何Leader宕机,则未同步成功的消息会在产生新leader中丢弃
可靠性ack
仅依靠副本来支撑可靠性是远远不够的,还可以使用生产者客户端参数
request.required.acks
- 对于acks=1的时候,生产者将消息发送到leader副本,leader副本在成功写入本地日志之后会告知生产者已经提交成功,如果此时ISR集合的follower副本还没及时拉取到leader中新写入的消息,leader就宕机了,那此次发送的消息就会丢失
- 对于ack=-1的时候,生产者将消息发送到leader副本,leader副本在成功写入本地日志之后还需要等待ISR中的follower副本全部同步完成才告知生产者已经成功提交,所以即使leader副本宕机,消息也不会丢失
- 对于ack=0的时候,生产者producer无需等待来自broker的确认而继续发送下一批消息。这种情况传输的效率最高,但是数据的可靠性是最低的。
磁盘顺序读写
kafka采用的是磁盘顺序读写的方式,也极大地提升了读写性能
使用了页缓存
一般的磁盘I/O的场景有:
- 用户调用标准C库进行I/O操作,数据流为:应用程序buffer -> C库标准IObuffer -> 文件系统页缓存 -> 通过具体文件系统到磁盘
- 用户调用文件I/O,数据流为:应用程序buffer -> 文件系统页缓存 -> 通过具体文件系统到磁盘
- 用户打开文件时使用O_DIRECT,绕过页缓存直接读写磁盘
- 用户使用类似dd工具,并使用direct参数,绕过系统cache与文件系统直接写磁盘
零拷贝
所谓的零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由程序之手。零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换
- 调用read()时,文件A中的内容被复制到内核模式下的Read Buffer中
- CPU控制将内核模式数据复制到用户模式下
- 调用write()时,将用户模式下的内容复制到内核模式下的Socket Buffer中
- 将内核模式下的Socket Buffer的数据复制到网卡设备中传送
零拷贝则是直接绕过用户模式
使用
常用命令
-
ZK
cd /user/zookeeper/bin ./zkServer start ./zkCli
-
kafka
cd /user/kafka/bin ./kafka-server-start.sh ../config/server.properties log /tmp/kafka-logs
-
创建topic
./kafka-topics.sh --create --zookeeper 127.0.0.1:2181 --replication-factor 1 --partitions 1 --topic test_1
-
查看topic列表
./kafka-topics.sh --zookeeper 127.0.0.1:2181 --list
-
生产
./kafka-console-producer.sh --broker-list 127.0.0.1:9092 --topic test_1
-
消费
./kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic test_1 --group group_1 --from-beginning
-
查看kafka配置
./kafka-configs.sh --zookeeper 127.0.0.1:2181 --entity-type brokers --entity-default --describe ./kafka-configs.sh --zookeeper 127.0.0.1:2181 --entity-type brokers --entity-name 0 --describe