Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica)、 基于zookeeper协调的分布式消息系统,它最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、Storm/Spark流式处理引擎、web/nginx 日志、访问日志、消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为其顶级开源项目。
优势:
高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒;
可扩展性:kafka集群支持热扩展;
持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失;
容错性:允许集群中节点故障(若副本数量为n,则允许n-1个节点故障);
高并发:支持数千个客户端同时读写。
版本演进:
Kafka 0.8 之后引入了副本机制, Kafka 成为了一个分布式高可靠消息队列解决方案。
0.8.2.0 版本社区引入了新版本 Producer API , 需要指定 Broker 地址,但是bug比较多。
0.9.0.0 版本增加了基础的安全认证 / 权限功能,同时使用 Java 重写了新版本 Consumer API ,还 引入了 Kafka Connect 组件用于实现高性能的数据抽取,同样bug也多 。
0.10.0.0 是里程碑式的大版本,因为该版本引入了 Kafka Streams。从这个版本起,Kafka 正式升级成分布式流处理平台 。0.11.0.0 版本,引入了两个重量级的功能变更:一个是提供幂等性 Producer API 以及事务 (Transaction) API ; 另一个是对 Kafka 消息格式做了重构。
1.0和2.0 主要是对Kafka Streams 的各种改进,在消息引擎方面并未引入太多的重大功能特性
官网:http://kafka.apache.org/
Record(消息): Kafka 处理的主要对象。
Topic(主题):主题是承载消息的逻辑容器,在实际使用中多用来区分具体的业务。 Kafka中的 Topics总是多订阅者模式,一个topic可以拥有一个或者多个消费者来订阅它的数据。
Partition(分区):一个有序不变的消息序列。每个Topic下可以有多个分区。
Offset(消息位移):表示分区中每条消息的位置信息,是一个单调递增且不变的值。
Replica(副本): Kafka 中同一条消息能够被拷贝到多个地方以提供数据冗余,这些地方就是所谓的副本。副本还分为领导者(leader)副本和追随者(follower)副本,各自有不同的角色划分。副本是在分区层级下的,即每个分区可配置多个副本实现高可用。
Broker(代理) :Kafka以集群的方式运行,集群中的每一台服务器称之为一个代理(broker) 。
Producer(生产者):消息生产者,向Broker发送消息的客户端。
Consumer(消费者):消息消费者,从Broker读取消息的客户端。
Consumer Offset(消费者位移):表征消费者消费进度,每个消费者都有自己的消费者位移。
Consumer Group(消费者组):每个Consumer属于一个特定的Consumer Group,一条消息可以被多个不同的 Consumer Group消费,但是一个 Consumer Group中只能有一个Consumer 能够消费该消息。
每一个Topic,下面可以有多个分区(Partition)日志文件 。 Partition是一个有序的message序列,这些 message按顺序添加到一个叫做commit log的文件中。每个partition中的消息都有一个唯一的编号, 称之为offset,用来唯一标示某个分区中的message。 每个consumer是基于自己在commit log中的消费进度(offset)来进行工作的。在kafka中,消费offset由consumer自己来维护;一般情况下我们按照顺序逐条消费commit log中的消息,当然我可以通过指定offset来重复消费某些消息,或者跳过某些消息。
传统的消息传递模式有2种:queue 和 publish-subscribe
queue模式:多个consumer从服务器中读取数据,消息只会到达一个consumer。
publish-subscribe模式:消息会被广播给所有的consumer。
Kafka基于这2种模式提供了一种consumer的抽象概念:consumer group。
queue模式:所有的consumer都位于同一个consumer group 下。
publish-subscribe模式:所有的consumer都有着自己唯一的consumer group。
主要应用于两大类别的应用:
构造实时流数据管道,它可以在系统或应用之间可靠地获取数据 (相当于message queue) 。
构建实时流式应用程序,对这些流数据进行转换或者影响 (就是流处理,通过kafka stream topic和topic之间内部进行变化)
日志收集:用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer;
消息系统:解耦生产者和消费者、缓存消息等;
用户活动跟踪:kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后消费者通过订阅这些topic来做实时的监控分析,亦可保存到数据库;
运营指标:kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告;
流式处理:比如spark streaming和storm。
Kafka是用Scala语言开发的,运行在JVM上,在安装Kafka之前需要先安装JDK。
kafka依赖zookeeper,需要先安装zookeeper 并启动。
[root@localhost ~]# cd /usr/src
[root@localhost src]# wget https://archive.apache.org/dist/kafka/2.1.0/kafka_2.11-2.1.0.tgz
[root@localhost src]# tar -xzf kafka_2.11-2.1.0.tgz
[root@localhost src]# mv kafka_2.11-2.1.0 /usr/local/
[root@localhost src]# cd /usr/local/kafka_2.11-2.1.0/
[root@localhost kafka_2.11-2.1.0]# ll
总用量 52
drwxr-xr-x 3 root root 4096 11月 10 2018 bin
drwxr-xr-x 2 root root 4096 11月 10 2018 config
drwxr-xr-x 2 root root 4096 5月 16 11:11 libs
-rw-r--r-- 1 root root 32216 11月 10 2018 LICENSE
-rw-r--r-- 1 root root 336 11月 10 2018 NOTICE
drwxr-xr-x 2 root root 44 11月 10 2018 site-docs
# 启动
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-server-start.sh -daemon config/server.properties
[root@localhost kafka_2.11-2.1.0]# jps
8099 Kafka
8131 Jps
6814 QuorumPeerMain
conf/server.properties 部分配置解读
Property | Default | Description |
---|---|---|
broker.id | 0 | 每个broker都可以用一个唯一的非负整数id进行标识;这个id可以作为broker的“名字”,你可以选择任意你喜欢的数字作为id,只要id是唯一的即可 |
log.dirs | /tmp/kafka-logs | kafka存放数据的路径。这个路径并不是唯一的,可以是多个,路径之间只需要使用逗号分隔即可;每当创建新partition时,都会选择在包含最少 partitions的路径下 |
listeners | 9092 | server接受客户端连接的端口 |
zookeeper.connect | localhost:2181 | zooKeeper连接字符串的格式为: hostname:port,此处hostname和port分别是 ZooKeeper集群中某个节点的host和port; zookeeper如果是集群,连接方式为 hostname1:port1, hostname2:port2, hostname3:port3 |
log.retention.hours | 168 | 每个日志文件删除之前保存的时间。默认数据保存时间对所有topic都一样 |
min.insync.replicas | 1 | 当producer设置acks为-1时,min.insync.replicas 指定replicas的最小数目(必须确认每一个repica的写数据都是成功的),如果这个数目没有达到, producer发送消息会产生异常 |
delete.topic.enable | false | 是否允许删除主题 |
producer 常用配置:
Property | Description |
---|---|
metadata.broker.list=host1:port1, host2:port2 | broker服务器集群列表 |
producer.type=sync | 消息发送类型同步还是异步,默认为同步 |
partitioner.class=kafka.producer.DefaultPartitioner | 指定分区处理类。默认kafka.producer.DefaultPartitioner,表通过key哈希到对应分区 |
compression.codec=none | 消息的压缩格式,默认为none不压缩,也可以为gzip, snappy, lz4 |
serializer.class=kafka.serializer.DefaultEncoder | 指定序列化处理类 |
compressed.topics= | 如果要压缩消息,这里指定哪些topic要压缩消息,默认empty,表示不压缩。如果上面启用了压缩,那么这里就需要设置 |
request.required.acks=0 | 发出消息持久化机制参数(1)acks=0:表示producer不需要等待任何broker确认收到消息的回复,就可以继续发送下 一条消息。性能最高,但是最容易丢消息(2)acks=1: 至少要等待leader已经成功将数据写入本地log,但是不需要等待所有 follower 是否成功写入。就可以继续发送下一条消息。这种情况下,如果follower没有成功备份数据,而此时leader又挂掉,则消息会丢失(3)acks=-1或all: 这意味着leader需要等待所有备份(min.insync.replicas配置的备份个数) 都成功写入日志,这种策略会保证只要有一个备份存活就不会丢失数据。这是最强的数据保证。一般除非是金融级别,或跟钱打交道的场景才会使用这种配置。 |
request.timeout.ms=10000 | 在向producer发送ack之前,broker允许等待的最大时间 ,如果超时,broker将会向producer发送一个error ACK.意味着上一次消息因为某种原因未能成功(比如follower未能同步成功) |
queue.buffering.max.ms = 5000 | 在async模式下,当message被缓存的时间超过此值后,将会批量发送给broker,默认为5000ms。此值和batch.num.messages协同工作 |
queue.buffering.max.messages=10000 | 异步情况下,缓存中允许存放消息数量的大小,如果消息的条数达到阀值,将会导致producer端阻塞或者消息被抛弃,默认为10000条消息 |
batch.num.messages=200 | 如果是异步,指定每次批量发送数据量,默认为200 |
queue.enqueue.timeout.ms=-1 | -1: 不限制阻塞超时时间,让produce一直阻塞,这个时候消息就不会被抛弃;0: 立即清空队列,消息被抛弃。在生产端的缓冲池中,消息发送出去之后,在没有收到确认之前,该缓冲池中的消息是不能被删除的,但是生产者一直在生产消息,这个时候缓冲池可能会被撑爆,所以这就需要有一个处理的策略。有两种处理方式,一种是让生产者先别生产那么快,阻塞一下,等会再生产;另一种是将缓冲池中的消息清空。当消息在producer端沉积的条数达到"queue.buffering.max.meesages"后阻塞一定时间后,队列仍然没有enqueue(producer仍然没有发送出任何消息),此时producer可以继续阻塞或者将消息抛弃,此timeout值用于控制"阻塞"的时间 |
message.send.max.retries=3 | 当producer接收到error ACK,或者没有接收到ACK时,允许消息重发的次数,因为broker并没有完整的机制来避免消息重复,所以当网络异常时(比如ACK丢失),有可能导致broker接收到重复的消息,默认值为3. |
topic.metadata.refresh.interval.ms=60000 | producer刷新topic metada的时间间隔,producer需要知道partition leader的位置,以及当前topic的情况。因此producer需要一个机制来获取最新的metadata,当producer遇到特定错误时,将会立即刷新(比如topic失效,partition丢失,leader失效等),此外也可以通过此参数来配置额外的刷新机制,默认值60000 |
consumer 常用配置:
Property | Description |
---|---|
zookeeper.connect=host1:port1, host2:port2 | zookeeper集群 |
zookeeper.session.timeout.ms=5000 | zookeeper的session过期时间,默认5000ms,用于检测消费者是否挂掉 |
zookeeper.connection.timeout.ms=10000 | 当消费者挂掉,其他消费者要等该指定时间才能检查到并且触发重新负载均衡 |
zookeeper.sync.time.ms=2000 | 消费者更新offset到zookeeper中的时间周期 |
group.id=**** | 指定消费 |
auto.commit.enable=true | 消费者是否自动提交偏移量,默认值是true,为了尽量避免重复数据和数据丢失,可以把它设置为false,自己控制合适的提交偏移量,如果设置为true, 可以通过设置 auto.commit.interval.ms属性来控制提交的频率 |
auto.commit.interval.ms=1000 | 偏移量自动提交周期 |
conusmer.id=**** | 当前consumer的标识,可以设定,也可以有系统生成,主要用来跟踪消息消费情况 |
client.id=xxxx | 消费者客户端编号,用于区分不同客户端,默认客户端程序自动产生 |
queued.max.message.chunks=50 | 最大取多少块缓存到消费者(默认10) |
fetch.min.bytes=6553600 | 每拉取一批消息的最大字节数 ,broker不会像consumer输出大于此值的消息chunk ,提升此值,将会消耗更多的consumer端内存 |
fetch.wait.max.ms=5000 | 当消息的字节数达到配置数或者达到指定时间内但未达到指定字节数,均会发往consumer |
socket.receive.buffer.bytes=655360 | 当消息的字节数达到配置数或者达到指定时间内但未达到指定字节数,均会发往consumer |
derializer.class=kafka.serializer.DefaultDecoder | 指定序列化处理类 |
auto.offset.reset=largest | 如果zookeeper没有offset值或offset值超出范围。那么就给个初始的offset。有smallest、largest、anything可选,默认largest |
使用:
# 创建分区数是1,副本数是1的主题为meixi的topic
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic meixi
Created topic "meixi".
# 查看topic列表
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-topics.sh --list --zookeeper localhost:2181
meixi
# 启动producer发送消息
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic meixi
>11111
>22222
>33333
>44444
# 启动Consumer消费消息
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic meixi --group consumer1
33333
44444
# 查看消费组
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list
consumer1
单播消息: kafka中,在同一个消费组里 ,一条消息只能被某一个消费者消费
多播消息: 针对Kafka同一条消息只能被同一个消费组下的某一个消费者消费的特性,要实现多播只要保证这些消费者属于不同的消费组
集群配置:
[root@localhost kafka_2.11-2.1.0]# cp config/server.properties config/server-1.properties
[root@localhost kafka_2.11-2.1.0]# cp config/server.properties config/server-2.properties
[root@localhost kafka_2.11-2.1.0]# vim config/server-1.properties
broker.id=1
listeners=PLAINTEXT://:9093
log.dir=/tmp/kafka-logs-1
[root@localhost kafka_2.11-2.1.0]# vim config/server-2.properties
broker.id=2
listeners=PLAINTEXT://:9094
log.dir=/tmp/kafka-logs-2
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-server-start.sh -daemon config/server-1.properties
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-server-start.sh -daemon config/server-2.properties
# 创建一个副本数为3,分区数为3,主题为cluo的topic
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 3 --topic cluo
Created topic "cluo".
# 查看topic情况
[root@localhost kafka_2.11-2.1.0]# ./bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic cluo
Topic:cluo PartitionCount:3 ReplicationFactor:3 Configs:
Topic: cluo Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0
Topic: cluo Partition: 1 Leader: 2 Replicas: 2,0,1 Isr: 2,0,1
Topic: cluo Partition: 2 Leader: 0 Replicas: 0,1,2 Isr: 0,1,2
leader节点负责给定partition的所有读写请求。
replicas 表示某个partition在哪几个broker上存在备份。不管这个节点是不是”leader“,甚至这个节点挂了,也会列出。
isr 是replicas的一个子集,它只列出当前还存活着的,并且已同步备份了该partition的节点。