kafka官方0.10版文档学习
1:入门基础
1.1:基础知识
1.1.1:kafka的作用
1:建立实时流数据管道,以可靠地在系统或应用程序之间获取数据
2:构建实时流应用程序,以转换或响应数据流
1.1.2:基本概念
controller/master:集群中控制器,它负责管理整个集群中所有分区和副本的状态和元数据的管理
Producer:消息生产者,就是向 kafka broker 发消息的客户端;
Consumer:消息消费者,向 kafka broker 取消息的客户端;
Consumer Group(CG):消费者组,由多个consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。
所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
Broker:一台kafka服务器就是一个broker。一个集群由多个 broker 组成。一个 broker可以容纳多个 topic。
为了支持Producer直接向Leader Partition写数据,所有的Kafka服务节点都支持Topic Metadata的请求,返回哪些Server节点存活的、Partition的Leader节点的分布情况。
Topic:可以理解为一个队列,生产者和消费者面向的都是一个 topic;
Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,
一个 topic可以分为多个partition,每个partition是一个有序的队列;
Replica:副本,为保证集群中的某个节点发生故障时,该节点上的partition数据不丢失,且kafka仍然能够继续工作,kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower。
leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。
follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和 leader数据的同步。leader发生故障时,某个follower会成为新的 follower。
1:controller/master的作用
具备控制器身份的broker需要比其他普通的broker多一份职责,具体细节如下:
- 1·监听partition相关的变化。为Zookeeper中的/admin/reassign_partitions节点注册PartitionReassignmentListener,用来处理分区重分配的动作。
为Zookeeper中的/isr_change_notification节点注册IsrChangeNotificetionListener,用来处理ISR集合变更的动作。
为Zookeeper中的/admin/preferred-replica-election节点添加PreferredReplicaElectionListener,用来处理优先副本的选举动作。 - 2·监听topic相关的变化。为Zookeeper中的/brokers/topics节点添加TopicChangeListener,用来处理topic增减的变化;为Zookeeper中的/admin/delete_topics节点添加TopicDeletionListener,用来处理删除topic的动作。
- 3·监听broker相关的变化。为Zookeeper中的/brokers/ids/节点添加BrokerChangeListener,用来处理broker增减的变化。
从Zookeeper中读取获取当前所有与topic、partition以及broker有关的信息并进行相应的管理。对于所有topic所对应的Zookeeper中的/brokers/topics/[topic]节点添加PartitionModificationsListener,用来监听topic中的分区分配变化。 - 4·启动并管理分区状态机和副本状态机。
- 5·更新集群的元数据信息。
如果参数auto.leader.rebalance.enable设置为true,则还会开启一个名为“auto-leader-rebalance-task”的定时任务来负责维护分区的优先副本的均衡。
1.1.3:四大核心api
- produce:API允许应用程序发布流记录到一个或多个卡夫卡的话题。
- consumer:API允许应用程序订阅一个或多个主题,并处理所产生的对他们记录的数据流。
- stream:API允许应用程序充当流处理器,从一个或多个主题消耗的输入流,并产生一个输出流至一个或多个输出的主题,有效地将所述输入数据流,以输出流。
- connect:该连接器API允许构建和运行可重复使用的生产者或消费者连接卡夫卡主题,以现有的应用程序或数据系统。例如,关系数据库的连接器可能会捕获对
1.1.4:主题topic
主题是将记录发布到的类别或订阅源名称。每个主题Tipic都是由多个分区组成的,并且分区是有序的,对于每个主题,Kafka集群都会维护一个分区日志。
1:主题的保留期限
Kafka群集使用可配置的保留期限来保留所有已发布的记录(无论是否已被使用)。例如,如果将保留策略设置为两天,则在发布记录后的两天内,该记录可供使用,之后将被丢弃以释放空间。Kafka的性能相对于数据大小实际上是恒定的,因此长时间存储数据不是问题
实际上,基于每个消费者保留的唯一元数据是该消费者在日志中的偏移量或位置。此偏移量由使用者控制:如图
2:分区的主从
每个分区都有一个充当“领导者”的服务器和零个或多个充当“跟随者”的服务器。领导者处理对分区的所有读写请求,而跟随者则被动地复制领导者。
1.1.5:生产者:produce
生产者将数据发布到他们选择的主题。生产者负责选择将哪个记录分配给主题中的哪个分区,通过轮询可以达到负载均衡
1.1.6:消费者:consumer
消费者使用消费者组名称标记自己,并且发布到主题的每条记录都会传递到每个订阅消费者组中的一个消费者实例,如图消费者组A,消费者组B
- 消费者组的再平衡机制
再均衡(Rebalance)本质上是一种协议,规定了一个消费组中所有消费者如何达成一致来分配订
阅主题的每个分区。
比如某个消费组有20个消费组,订阅了一个具有100个分区的主题。正常情况下,Kafka平均会为每
个消费者分配5个分区。这个分配的过程就叫再均衡。
Kafka提供了一个角色:Group Coordinator来执行对于消费组的管理
1.2:kafka性能为什么这么高
1:避免小的I/O请求,将消息组合在一起(同分区的消息一起发送)并分摊网络往返的开销,而不是一次发送单个消息。服务器依次将消息块一次性附加到其日志中,而消费者一次获取大的线性块。
这种简单的优化会产生数量级的加速。批处理导致更大的网络数据包、更大的顺序磁盘操作、连续的内存块等等,所有这些都允许 Kafka 将突发的随机消息写入流转换为流向消费者的线性写入。
优化方式:数据设置批处理大小,异步发送
2:磁盘的顺序写入性能比随机写高很多倍。
优化方式:分区内只顺序追加写入
3:生产和消费时数据的字节频繁复制。写入时副本间的复制,读取时的多次复制。
数据从文件传输到套接字的常用数据路径:
- 操作系统从磁盘读取数据到内核空间的pagecache中
- 应用程序从内核空间读取数据到用户空间缓冲区
- 应用程序将数据写回内核空间到套接字缓冲区
- 操作系统将数据从套接字缓冲区复制到 NIC 缓冲区,然后通过网络发送
优化方式:采用Java 中[ sendfile 和零拷贝支持](https://developer.ibm.com/articles/j-zerocopy/)
4:数据压缩避免网络带宽瓶颈。Kafka 支持 GZIP、Snappy 和 LZ4 压缩协议
1.3:部署使用
忽略,自行查找
1.4:log日志详解
在broker的log存储文件下,除了存储这各个topic的文件夹,还存在这几个checkpoint文件。分别是
- recovery-point-offset-checkpoint 负责记录topic已经被写入磁盘的offset
- replication-offset-checkpoint 负责记录已经被复制到别的topic上的文件
- __consumer_offsets存储各个topic的offset。但是,他的只有一份。
1.5:kafka的选举机制
kafka的选举总体依照公平竞争和第一顺位原则,谁优先注册成功或者谁是第一个值谁就是leader,具体实践如下。
1.5.1:控制器controller/master选举机制
在Kafka集群中会有一个或者多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态。当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。当使用kafka-topics.sh脚本为某个topic增加分区数量时,同样还是由控制器负责分区的重新分配。
Kafka中的控制器选举的工作依赖于Zookeeper,成功竞选为控制器的broker会在Zookeeper中创建/controller这个临时(EPHEMERAL)节点
选举过程:根据临时节点的值是否为-1或者是否有临时节点来判断是否有conrtoller需要选举。
- 初次选举或者controller异常后回出发选举过程,所有的broker都有权力去往临时节点注册自己的信息brokerid,但是只有一个会注册成功,成功后其他的节点停止注册,保存controller的元数据信息。
1.5.2:分区leader选举机制
分区leader副本的选举由Kafka Controller 负责具体实施。
选举总体流程:leader异常---->触发后查找AR集合---->找到AR顺序第一个---->查找ISR是否存在,存在选举成功,不存在继续AR第二个元素
当创建分区(创建主题或增加分区都有创建分区的动作)或分区上线(比如分区中原先的leader副本下线,此时分区需要选举一个新的leader上线来对外提供服务)的时候都需要执行leader的选举动作。
创建分区时:如果不指定,leader则为分区的第一个副本。
重选举时:基本思路是按照AR集合中副本的顺序查找第一个存活的副本,并且这个副本在ISR集合中。一个分区的AR集合在分配的时候就被指定,并且只要不发生重分配的情况,集合内部副本的顺序是保持不变的,而分区的ISR集合中副本的顺序可能会改变。注意这里是根据AR的顺序而不是ISR的顺序进行选举的。这个说起来比较抽象,有兴趣的读者可以手动关闭/开启某个集群中的broker来观察一下具体的变化。
还有一些情况也会发生分区leader的选举,比如当分区进行重分配(reassign)的时候也需要执行leader的选举动作。这个思路比较简单:从重分配的AR列表中找到第一个存活的副本,且这个副本在目前的ISR列表中。
再比如当发生优先副本(preferred replica partition leader election)的选举时,直接将优先副本设置为leader即可,AR集合中的第一个副本即为优先副本。
1.5.3:消费者组的leader选举
1:如果消费组内还没有leader,那么第一个加入消费组的消费者即为消费组的leader。
2:如果某一时刻leader消费者由于某些原因退出了消费组,那么会重新选举一个新的leader,取HashMap中(key消费者id,v元数据)的第一个键值对的key。具有随机性。
2:API使用
produce:API允许应用程序发布流记录到一个或多个卡夫卡的话题。
consumer:API允许应用程序订阅一个或多个主题,并处理所产生的对他们记录的数据流。
stream:API允许应用程序充当流处理器,从一个或多个主题消耗的输入流,并产生一个
输出流至一个或多个输出的主题,有效地将所述输入数据流,以输出流。
connect:该连接器API允许构建和运行可重复使用的生产者或消费者连接卡夫卡主题,
以现有的应用程序或数据系统。例如,关系数据库的连接器可能会捕获
1:maven依赖
kafka-clients的jar包是官方提供的kafka操作服务端的客户端代码
<dependency>
<groupId> org.apache.kafka </ groupId>
<artifactId> kafka-clients </ artifactId>
<version> 0.10.0.0 </ version>
</ dependency>
2.1:生产者
包括两个低级生产者-同步和异步
同步:kafka.producer.SyncProducer
异步:kafka.producer.async.AsyncProducer
1 生产的分区策略
默认的分区策略是hash(key)%numPartitions。如果键为null,则选择一个随机代理分区。还可以使用partitioner.class config参数插入自定义分区策略(实现接口Partitioner)。
2:批处理的大小
可以通过一些配置参数来控制。当事件进入队列时,它们将被缓冲在队列中,直到到达queue.time或为止batch.size
3:参数配置
包括生产者消费者和broker集群等的配置 新版本的配置说明
注意新旧版的参数,也就是0.9之前和之后
4:kafka的设计
4.1:kafka的3种消息传递语义acks
- 最多一次——消息可能会丢失,但永远不会重新传递。
- 至少一次——消息永远不会丢失,但可以重新传递。
- 恰好一次——这就是人们真正想要的,每条消息都只传递一次。
acks是生产数据时候可设置的参数。
4.1.1:生产者语义
对于生产者而言其实是消息发送成功的确认保证,对acks的配置以及ISR副本同步机制
最多一次:只需要异步不断的发送即可,效率也比较高,只发送不管成功与否,消息可能会丢失,但永远不会重新发送。
至少一次:只需要同步确认即可(确认方式分为(acks配置)只需要 leader 确认以及所有副本都确认,第二种更加具有容错性),
生产者可以重试,直到接收到成功提。
恰好一次 :人们真正想要的是,每条消息只传递一次,也只有一次,目前在 producer 端还不能保证精确一次,
在未来有可能实现,实现方式如下:在同步确认的基础上为每一条消息加一个主键,如果发现主键曾经接受过,则丢弃
4.1.2:消费者语义
最终其实是消息的消费和偏移量的提交之间的均衡选择。
最多一次:先提交偏移量后消费
至少一次:先消费后提交偏移量
恰好一次:保存了offset后提交一次,消息处理成功之后再提交一次。还有一个方法,
将处理后的结果和offset同时保存在HDFS中,这样就能保证消息和offser同时被处理了。
4.2:偏移量迁移:zk和kafka
offsets.storage:偏移量的保存位置,zookeeper还是kafka,0.10版本后建议kafka
较早版本中的Kafka使用者默认将其偏移量存储在ZooKeeper中。
通过执行以下步骤,可以迁移这些使用者以将偏移量提交到Kafka中:
zk到kafka:
在用户配置中设置offsets.storage=kafka和dual.commit.enabled=true。
对您的消费者进行滚动反弹,然后确认您的消费者健康。
dual.commit.enabled=false在使用者配置中设置。
对您的消费者进行滚动反弹,然后确认您的消费者健康。
Kafka迁移回ZooKeeper:
offsets.storage=zookeeper。
4.3:zookeeper目录设计
4.3.1:代理节点(服务器)注册
临时节点
/brokers/ids/[0...N]
代理节点通过在/ brokers / ids下创建一个逻辑代理id为znode来注册自己
4.3.2:topic主题注册
(临时节点)
/brokers/topics/[topic]/partitions/[0...N]/state-> {“ controller_epoch”:...,“ leader”:...,“ version”:...,“ leader_epoch “:...,” isr“:[...]}
4.3.3:消费者注册
(临时节点)
/consumers/[group_id]/ids/[consumer_id] --> {"version":...,"subscription":{...:...},"pattern":...,"timestamp":...}
4.3.3:消费者偏移量注册
(持久节点)
/ consumers / [group_id] / offsets / [topic] / [partition_id]-> offset_counter_value
4.3.4:分区所有者注册:owners
(临时节点)
/ consumers / [group_id] / owners / [topic] / [partition_id]-> Consumer_node_id
5:kafka的集群shell操作
6:集群运行
可使用集群管理工具mirrormaker进行数据迁移等。
集群监控推荐工具 confluent
6.1:消费者群组管理
1:先查看消费者群组名称
bin/kafka-consumer-groups.sh --zookeeper localhost:2181 --list
2:再使用查看出来的消费者群组检查消费位置
0.10版本以前
bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper localhost:2181 --group test
0.10版本以后:
kafka.admin.ConsumerGroupCommand(或bin / kafka-consumer-groups.sh脚本)来管理使用者组
bin/kafka-consumer-groups.sh --zookeeper localhost:2181 --describe --group test-consumer-group
6.2:kafka集群间的数据镜像
这种镜像的常见用例是在另一个数据中心中提供副本
这是一个示例,显示了如何从两个输入集群中镜像单个主题(名为my-topic):
> bin/kafka-mirror-maker.sh
--consumer.config consumer-1.properties --consumer.config consumer-2.properties
--producer.config producer.properties --whitelist my-topic
我们使用–whitelist选项指定主题列表。此选项允许使用Java风格的正则表达式的任何正则表达式,如:–whitelist “*”
6.3:集群扩容
6.3.1:添加服务器
将服务器添加到Kafka集群很容易,只需为其分配唯一的代理ID,然后在新服务器上启动Kafka。但是,不会为这些新服务器自动分配任何数据分区,因此,除非将分区移至它们,否则在创建新主题之前它们将不会做任何工作。因此,通常在将计算机添加到群集时,您将需要将一些现有数据迁移到这些计算机
6.3.2:数据迁移(重分区)
服务器间的分区数据迁移,保证负载均衡。
1:使用
分区重新分配工具可用于将某些主题从当前代理集移到新添加的代理。
以下示例将主题foo1,foo2的所有分区移动到新的集群服务器5,6。在此步骤结束时,主题foo1和foo2的所有分区仅存在于服务器5,6上
该工具将主题的输入列表作为json文件接受
2:准备迁移主题的json文件
vi topics-to-move.json
{"topics": [{"topic": "foo1"},
{"topic": "foo2"}],
"version":1
}
3:使用分区重新分配工具生成候选分配
新的分配配置应保存在json文件(例如,expand-cluster-reassignment.json,只要是json文件即可,命名没有规定)
执行重分配:5/6为kafka配置的id
> 该命令会打印tipic partition的原始分布情况,以及重生的分布情况。见下图。
> bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --topics-to-move-json-file topics-to-move.json --broker-list "5,6" --generate
执行结果
当前分区副本分配
{"version":1,
"partitions":[{"topic":"foo1","partition":2,"replicas":[1,2]},
{"topic":"foo1","partition":0,"replicas":[3,4]},
{"topic":"foo2","partition":2,"replicas":[1,2]},
{"topic":"foo2","partition":0,"replicas":[3,4]},
{"topic":"foo1","partition":1,"replicas":[2,3]},
{"topic":"foo2","partition":1,"replicas":[2,3]}]
}
Proposed partition reassignment configuration(建议的分区重新分配配置)
新的分配配置应保存在json文件(例如,expand-cluster-reassignment.json,只要是json文件即可,命名没有规定)
复制以下内容保存到json文件中
{"version":1,
"partitions":[{"topic":"foo1","partition":2,"replicas":[5,6]},
{"topic":"foo1","partition":0,"replicas":[5,6]},
{"topic":"foo2","partition":2,"replicas":[5,6]},
{"topic":"foo2","partition":0,"replicas":[5,6]},
{"topic":"foo1","partition":1,"replicas":[5,6]},
{"topic":"foo2","partition":1,"replicas":[5,6]}]
}
4:根据新的json文件执行重分布
此处的json即为3步骤中保存的json文件
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file expand-cluster-reassignment.json --execute
5:检查重分布的执行状态
会显示各分区的重分布执行状态。
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file expand-cluster-reassignment.json --verify
6.4:增加topic的副本数
此步骤看需求是否需要
只需在自定义重新分配json文件中指定额外的副本,然后将其与–execute选项一起使用即可增加指定分区的复制因子。
示例:
将主题foo的分区0的复制因子从1增加到3。在增加复制因子之前,该分区的唯一副本存在于代理5上。作为增加复制因子的一部分,我们将放在服务器6和7。
1:第一步是在json文件中手动制作自定义重新分配计划:
vi increase-replication-factor.json
{"version":1,
"partitions":[{"topic":"foo","partition":0,"replicas":[5,6,7]}]}
2:执行:execute
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file increase-replication-factor.json --execute
3:查看执行状态:verify
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file increase-replication-factor.json --verify
4:查看现在topic的详细状态
bin / kafka-topics.sh --zookeeper localhost:2181 --topic foo --describe
7:kafka的服务器配置
7.1:服务器配置
一个实例的服务器配置示例
#复制配置
num.replica.fetchers = 4
copy.fetch.max.bytes = 1048576
copy.fetch.wait.max.ms = 500
复制副本.high.watermark.checkpoint.interval.ms = 5000
copy.socket.timeout.ms = 30000
copy.socket.receive.buffer.bytes = 65536
copy.lag.time.max.ms = 10000
controller.socket.timeout.ms = 30000
controller.message.queue.size = 10
#日志配置
num.partitions = 8
message.max.bytes = 1000000
auto.create.topics.enable = true
log.index.interval.bytes = 4096
log.index.size.max.bytes = 10485760
log.retention.hours = 168
log.flush.interval.ms = 10000
log.flush.interval.messages = 20000
log.flush.scheduler.interval.ms = 2000
log.roll.hours = 168
log.retention.check.interval.ms = 300000
log.segment.bytes = 1073741824
#ZK配置
zookeeper.connection.timeout.ms = 6000
zookeeper.sync.time.ms = 2000
#套接字服务器配置
num.io.threads = 8
num.network.threads = 8
socket.request.max.bytes = 104857600
socket.receive.buffer.bytes = 1048576
socket.send.buffer.bytes = 1048576
queued.max.requests = 16
fetch.purgatory.purge.interval.requests = 100
producer.purgatory.purge.interval.requests = 100
7.2:服务器硬件
内存:缓存大小*30s
硬盘:通常,磁盘吞吐量是性能瓶颈,并且磁盘越多越好
内存使用率查看:cat / proc / meminfo
7.3:zookeeper
当前稳定分支为3.4,该分支的最新版本为3.4.6,这是ZkClient 0.7使用的分支。ZkClient是Kafka用于与ZooKeeper交互的客户端层。