章节导航
- Kafka是什么?
- Kafka使用场景及特性
- Kafka架构
- Kafka配置
- 使用Kafka的两种方式:命令行和API
Kafka是什么?
试想一下我们现在有一个分布式的网站流量分析系统,我们有多台用于记录用户行为的服务器,前端经过负载均衡将用户行为记录在这些服务器上,每台服务器拥有一部分纪录。
然后问题来了,如何做到实时分析?不可能在每台机上部署一个分析程序,这样会存在数据同步和容错问题,所以我们有了kafka+storm/spark,kafka作为数据管道(Data pipline)的角色,从收数端向storm/spark发送数据,kafka保证数据同步,除此之外还会将数据持久化到磁盘。kafka用zookeeper来实现数据同步和宕机切换。
kafka is a distributed streaming platform, a streaming platform has three key capabilities:
- 发布和订阅数据流,在这方面它类似于消息队列或企业消息系统
- 以容错的方式处理数据流
- 在数据流发生处处理它
Kafka使用场景及特性
使用场景:
- 在收数端和实时计算或批处理计算框架之间做数据通道
- 作为处理流式数据的应用
特性:
- 支持多订阅,同一份数据集能被消费多次
- 保存数据到磁盘,能同时传送消息到实时和批处理消费者
- 内置数据冗余,保证高可用性
- 支持水平扩展,容错
Kafka架构
先了解一下kafka中的一些概念:
1. topic和partition
Kafka提供的对流式数据的抽象,即一个topic代表一个数据流。对每个topic,kafka集群持有分区日志(partitioned log),这些分区组成更高级的topic抽象,每个分区是一个有序的、可变的数据序列,kafka源源不断地向分区末端添加数据,读取时则通过一个offset来记录读取的位置,offset由consumer持有,consumer可以随意改变offset。
在设定的时长之内,Kafka为我们保存所有的数据,直到超时后才扔掉它们。
出于容错的考虑,Kafka会为每个分区在不同的服务器上建立副本(副本切换应该是由zookeeper实现),每个分区都有一个”leader”服务器和0到多个”followers”服务器,leader服务器承担处理读写请求的责任,如果leader宕机,则从其他followers中选出一个leader。每个服务器都是某一个分区的leader和其他分区的followers,以此实现负载均衡。
2.Producers
Produers向它们选择的topics生产数据,并且负责选择与数据绑定的分区,即哪些数据应该传到哪个partition。选择分区的过程可以由round-robin来简单地负载均衡,或由语义分区函数完成。大多数情况下用语义分区函数。
3.Consumers和Consumer group
与我们对订阅者下意识的印象不同的是,对数据的消费以consumer group为单位,每个group持有一个group.id,拥有相同group.id的consumer属于同一个consumer group,每个consumer可以来自于单独的进程或者单独的服务器。
每个consumer选择它们想要消费的topic,然后一旦用户使用API或者命令行发生拉取操作,consumer group就从注册了这个topic的consumer中选择一个来消费数据。具体的分配逻辑是:组内有一个consumer来负责负载均衡,consumer group将会通过周期性地刷新元数据来探测新分区,并把新分区分配给组内的consumer,每个consumer只消费这个分区,如果有一个consumer挂了,它持有的分区就会被分发给还存活的其他consumer。
由于kafka不保证分区的全局有序,只保证分区内有序,所以同一个组内的consumer不能并行读取数据。
Kafka对有序性的保证:
1. 保证同一个producer向同个partition生产的数据是有序的,即如果producer先发M1再发M2,则partition log里的顺序也是M1在M2之前,M1拥有更低的offset。
2. consumer看到的数据顺序和它们在partition log中存储的顺序相同
4.brokers
kafka消息中心,负责持有topic并为topic划分分区,每个broker可以持有多个topic。
Kafka在zookeeper中建立的znode:
Kafka配置
先配zookeeper,我选择用standalone模式,所以用默认配置即可;也可以用伪分布式,只要在zookeeper中配置server.x=本机IP:随便一个端口,一般是2888:随便一个端口,x和data文件夹下的myid相同。
由于默认配置dataDir是在tmp目录,关机即清零,还应该改一下dataDir。启动一下 zookeeper,查看zookeeper服务状态:
[root@localhost zookeeper-3.4.9]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost zookeeper-3.4.9]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: standalone
[root@localhost zookeeper-3.4.9]#
再来改kafka的配置,以下是基本配置:
broker config,修改server.properties
#如果要在一台机上配置多个代理,只要多复制几份配置文件,并且给broker.id设置不同的值,然后启动时在命令行后面写上配置文件路径(相对或绝对都行) broker.id=1 log.dirs=/data/kafka/logs zookeeper.connect=localhost:2181 #zookeeper host列表,格式是host:clientPort,多个host用“,”分隔
对于producer和consumer,还有相应的配置
从命令行启动kafka:bin/kafka-server-start.sh config/server.properties &,控制台打印出来的信息里下面这几行说明了kafka在zookeeper中创建znode的情况:
[2017-03-25 09:35:05,666] INFO zookeeper state changed (SyncConnected) (org.I0Itec.zkclient.ZkClient) [2017-03-25 09:35:05,678] INFO Creating /controller (is it secure? false) (kafka.utils.ZKCheckedEphemeral) [2017-03-25 09:35:05,684] INFO Result of znode creation is: OK (kafka.utils.ZKCheckedEphemeral) [2017-03-25 09:35:05,684] INFO 0 successfully elected as leader (kafka.server.ZookeeperLeaderElector) [2017-03-25 09:35:05,745] INFO re-registering broker info in ZK for broker 0 (kafka.server.KafkaHealthcheck$SessionExpireListener) [2017-03-25 09:35:05,745] INFO Creating /brokers/ids/0 (is it secure? false) (kafka.utils.ZKCheckedEphemeral) [2017-03-25 09:35:05,750] INFO Result of znode creation is: OK (kafka.utils.ZKCheckedEphemeral) [2017-03-25 09:35:05,750] INFO Registered broker 0 at path /brokers/ids/0 with addresses: PLAINTEXT -> EndPoint(localhost,9092,PLAINTEXT) (kafka.utils.ZkUtils) [2017-03-25 09:35:05,751] INFO done re-registering broker (kafka.server.KafkaHealthcheck$SessionExpireListener) [2017-03-25 09:35:05,751] INFO Subscribing to /brokers/topics path to watch for new topics (kafka.server.KafkaHealthcheck$SessionExpireListener) [2017-03-25 09:35:05,804] INFO New leader is 0 (kafka.server.ZookeeperLeaderElector$LeaderChangeListener)
命令行和API
命令行脚本
创建/修改/删除 topic
bin/kafka-topics.sh --zookeeper zk_host:port[/topicsrootpath] --create/--alter/--delete --topic topic\_name --partitions pnum --replication-factor rnum --config x=y
- partitions选项指定topic被分成几个分区,分区数决定了consumers的并行数
- replication-factor是副本数
- bin/kafka-topics.sh –help可以查看options手册
[root@localhost kafka_2.10-0.10.1.0]# bin/kafka-topics.sh --create --zookeeper localhost:2181 --topic testTopic --partitions 2 --replication-factor 1
[zk: localhost:2181(CONNECTED) 0] ls /brokers/topics
[testTopic]
命令行producer和consumer工具
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic streams-file-input <然后从linux标准输入获得数据>
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 \
--topic streams-wordcount-output \
--from-beginning \
--formatter kafka.tools.DefaultMessageFormatter \
--property print.key=true \
--property print.value=true \
--property key.deserializer=org.apache.kafka.common.serialization.StringDeserializer \
--property value.deserializer=org.apache.kafka.common.serialization.LongDeserializer
执行调用了kafka API的java程序
bin/kafka-run-class.sh org.apache.kafka.streams.examples.wordcount.WordCountDemo
均衡leadership
当一个broker停止后,其作为leader持有的partitions将会在follower里面重新选一个leader把leadership转移过去,因此当这个broker重启后它将是它的所有partitions的follower,这样会导致leadership的不均匀分布,可以使用bin/kafka-preferred-replica-election.sh --zookeeper zk_host:port[/topicsrootpath]
来尝试修复不均衡的leadership,也可以通过配置auto.leader.rebalance.enable=true
让kafka定时自动修复。查看consumers的位置
bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper localhost:2181 --group test
list,describe,delete consumer groups:
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list [--describe --group groupname]
扩展集群,把原有节点上的分区转移到新节点
bin/kafka-reassign-partitions.sh ...