Kafa
1.概述
1.1 消息队列Queue(先进先出)
(1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
(2)发布/订阅模式(一对多,数据生产后,推送给所有订阅者)
为什么需要消息队列?
解耦、冗余、扩展性、灵活性与峰值处理能力、可恢复性、顺序保证、缓冲、异步通信
1.2 Kafka
分布式消息队列,集群;由Scala写成 kafka_2.11-0.11.0.2.tgz 2.11是Scale的版本
kafka集群、consumer依赖于zookeeper集群保存meta信息,保证系统可用性。
kafka对消息保存时根据Topic进行归类。发生消息者称为Producer,消息接受者称为Consumer,
此外Kafka集群由多个Kafka实例组成,每个实例称为broker。
1.3 架构
producer、kafka cluster、consumer zookeeper
topic主题、partition分区是为了做负载均衡、副本 leader与follower 不同机器同一分区备份用、一个分区一个leader
consumer group 同一个消费者组的消费者不可以同时消费同一分区的数据
一个消费者可以消费多个topic数据
kafka集群依赖于zookeeper,consumer offset保存在zookeeper
2.集群部署
[root@k8smaster ~]# cd /opt/
[root@k8smaster opt]# ls
cni rh
[root@k8smaster opt]# mkdir software
[root@k8smaster opt]# mkdir module
[root@k8smaster opt]# cd software/
拷贝kafka_2.11-0.11.0.2.tgz scala-2.11.8.tgz 到该目录
[root@k8smaster software]# ls
kafka_2.11-0.11.0.2.tgz scala-2.11.8.tgz
解压:[root@k8smaster software]# tar -zxvf kafka_2.11-0.11.0.2.tgz -C /opt/module/
[root@k8snode2 sofware]# cd …
[root@k8snode2 opt]# cd module/
[root@k8snode2 module]# mv kafka_2.11-0.11.0.2/ kafka
[root@k8smaster module]# cd kafka/
[root@k8smaster kafka]# ll config/
总用量 64
-rw-r–r-- 1 root root 906 11月 11 2017 connect-console-sink.properties
-rw-r–r-- 1 root root 909 11月 11 2017 connect-console-source.properties
-rw-r–r-- 1 root root 5807 11月 11 2017 connect-distributed.properties
-rw-r–r-- 1 root root 883 11月 11 2017 connect-file-sink.properties
-rw-r–r-- 1 root root 881 11月 11 2017 connect-file-source.properties
-rw-r–r-- 1 root root 1111 11月 11 2017 connect-log4j.properties
-rw-r–r-- 1 root root 2730 11月 11 2017 connect-standalone.properties
-rw-r–r-- 1 root root 1199 11月 11 2017 consumer.properties
-rw-r–r-- 1 root root 4696 11月 11 2017 log4j.properties
-rw-r–r-- 1 root root 1900 11月 11 2017 producer.properties
-rw-r–r-- 1 root root 6954 11月 11 2017 server.properties
-rw-r–r-- 1 root root 1032 11月 11 2017 tools-log4j.properties
-rw-r–r-- 1 root root 1023 11月 11 2017 zookeeper.properties
修改server.properties
#broker的全局唯一编号,不能重复
broker.id=0
#删除topic功能使能
delete.topic.enable=true
#处理网络请求的线程数量
num.network.threads=3
#用来处理磁盘IO的现成数量
num.io.threads=8
#发送套接字的缓冲区大小
socket.send.buffer.bytes=102400
#接收套接字的缓冲区大小
socket.receive.buffer.bytes=102400
#请求套接字的缓冲区大小
socket.request.max.bytes=104857600
#kafka运行日志存放的路径
log.dirs=/opt/module/kafka/logs
#topic在当前broker上的分区个数
num.partitions=1
#用来恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#配置连接Zookeeper集群地址
zookeeper.connect=192.168.138.132:2181,192.168.138.133:2181,192.168.138.131:2181
配置环境变量:
vi /etc/profile
#KAFKA_HOME
export KAFKA_HOME=/opt/module/kafka
export PATH=
P
A
T
H
:
PATH:
PATH:KAFKA_HOME/bin
启动kafka
之前先启动zookeeper
[root@k8snode2 kafka]# cd …
[root@k8snode2 module]# cd zookeeper-3.4.10/
[root@k8snode2 zookeeper-3.4.10]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/…/conf/zoo.cfg
Starting zookeeper … STARTED
[root@k8snode2 zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/…/conf/zoo.cfg
Mode: leader
启动kafka时报错:OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c0000000, 1073741824, 0) failed;
原因:kafka启动项中需要的内存当前配置不足以提供。
解决:修改启动文件配置,降低所需内存。
打开kafka安装位置,在bin目录下找到kafka-server-start.sh文件,将
export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"修改为
export KAFKA_HEAP_OPTS="-Xmx256M -Xms128M"。
启动kafka: bin/kafka-server-start.sh config/server.properties &
创建topic并查看: 两个分区 topic命名 first 两个副本
[root@k8smaster kafka]# bin/kafka-topics.sh --create --zookeeper 192.168.138.132:2181 --partitions 2 --replication-factor 2 --topic first
Created topic “first”.
[root@k8smaster kafka]# bin/kafka-topics.sh --list --zookeeper 192.168.138.132:2181
first
Kafka命令行操作
1)查看当前服务器中的所有topic
[root@k8smaster kafka]$ bin/kafka-topics.sh --zookeeper 192.168.138.132:2181 --list
2)创建topic
[root@k8smaster kafka]$ bin/kafka-topics.sh --zookeeper 192.168.138.132:2181
–create --replication-factor 3 --partitions 1 --topic first
选项说明:
–topic 定义topic名
–replication-factor 定义副本数
–partitions 定义分区数
3)删除topic
[root@k8smaster kafka]$ bin/kafka-topics.sh --zookeeper 192.168.138.132:2181 --delete --topic first
需要server.properties中设置delete.topic.enable=true否则只是标记删除或者直接重启。
4)发送消息
[root@k8smaster kafka]$ bin/kafka-console-producer.sh --broker-list 192.168.138.132:9092 --topic first
hello world
root root
5)消费消息
[root@k8snode1 kafka]$ bin/kafka-console-consumer.sh --zookeeper 192.168.138.132:2181 --from-beginning --topic first
–from-beginning:会把first主题中以往所有的数据都读取出来。根据业务场景选择是否增加该配置。
或者连集群 offset存本地 bin/kafka-console-consumer.sh --bootstrap-server 192.168.138.132:9092 --from-beginning --topic first
6)查看某个Topic的详情
[root@k8smaster kafka]$ bin/kafka-topics.sh --zookeeper 192.168.138.132:2181 --describe --topic first
3.工作流程分析
生产:producer采用push模式将消息发布到broker,每条消息都被追加到分区,属于顺序写磁盘
分区:消息发送时都被发送到一个topic,而topic是由一些Partition Logs(分区日志)组成
每个Partition中的消息都是有序的,生产的消息被不断追加到Partition log上,其中的每一个消息都被赋予了一个唯一的offset值。
1)分区的原因
(1)方便在集群中扩展,每个Partition可以通过调整以适应它所在的机器,而一个topic又可以有多个Partition组成,因此整个集群就可 以适应任意大小的数据了;
(2)可以提高并发,因为可以以Partition为单位读写了。
2)分区的原则
(1)指定了patition,则直接使用;
(2)未指定patition但指定key,通过对key的value进行hash出一个patition;
(3)patition和key都未指定,使用轮询选出一个patition。
副本:同一个partition可能会有多个replication(对应 server.properties 配置中的 default.replication.factor=N)。没有replication的情 况下,一旦broker 宕机,其上所有 patition 的数据都不可被消费,同时producer也不能再将数据存于其上的patition。引入replication 之后,同一个partition可能会有多个replication,而这时需要在这些replication之间选出一个leader,producer和consumer只与这个 leader交互,其它replication作为follower从leader 中复制数据。
写入流程:
1)producer先从zookeeper的 "/brokers/…/state"节点找到该partition的leader
2)producer将消息发送给该leader
3)leader将消息写入本地log
4)followers从leader pull消息,写入本地log后向leader发送ACK
5)leader收到所有ISR中的replication的ACK后,增加HW(high watermark,最后commit 的offset)并向producer发送ACK
保证生产者不丢数据:ack应答机制 设置为all 0-无需应答 1-保证leader应答 all保证leader+follower应答
存储
存储方式
物理上把topic分成一个或多个patition(对应 server.properties 中的num.partitions=3配置),每个patition物理上对应一个文件夹( 该文件夹存储该patition的所有消息和索引文件),如下:
[root@k8smaster first-0]# ll
总用量 8
-rw-r–r-- 1 root root 10485760 1月 1 11:06 00000000000000000000.index
-rw-r–r-- 1 root root 362 1月 1 11:53 00000000000000000000.log
-rw-r–r-- 1 root root 10485756 1月 1 11:06 00000000000000000000.timeindex
-rw-r–r-- 1 root root 8 1月 1 11:16 leader-epoch-checkpoint
存储策略
无论消息是否被消费,kafka都会保留所有消息。有两种策略可以删除旧数据:
1)基于时间:log.retention.hours=168
2)基于大小:log.retention.bytes=1073741824
需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关。
Zookeeper存储结构
注意:producer不在zk中注册,消费者在zk中注册。
消费
高级API
1)高级API优点
高级API 写起来简单
不需要自行去管理offset,系统通过zookeeper自行管理。
不需要管理分区,副本等情况,.系统自动管理。
消费者断线会自动根据上一次记录在zookeeper中的offset去接着获取数据(默认设置1分钟更新一下zookeeper中存的offset)
可以使用group来区分对同一个topic 的不同程序访问分离开来(不同的group记录不同的offset,这样不同程序读取同一个topic才不会 因为offset互相影响)
2)高级API缺点
不能自行控制offset(对于某些特殊需求来说)
不能细化控制如分区、副本、zk等
低级API
1)低级 API 优点
能够让开发者自己控制offset,想从哪里读取就从哪里读取。
自行控制连接分区,对分区自定义进行负载均衡
对zookeeper的依赖性降低(如:offset不一定非要靠zk存储,自行存储offset即可,比如存在文件或者内存中)
2)低级API缺点
太过复杂,需要自行控制offset,连接哪个分区,找到分区leader 等。
消费者组:
1)需求:测试同一个消费者组中的消费者,同一时刻只能有一个消费者消费。
2)案例实操
(1)在k8snode1、k8snode2上修改/opt/module/kafka/config/consumer.properties配置文件中的group.id属性为任意组名。
[root@k8snode1 config]$ vi consumer.properties
group.id=root
(2)在k8snode1、k8snode2上分别启动消费者
[root@k8snode1 kafka]$ bin/kafka-console-consumer.sh
–zookeeper 192.168.138.132:2181 --topic first --consumer.config config/consumer.properties
[root@k8snode2kafka]$ bin/kafka-console-consumer.sh --zookeeper 192.168.138.132:2181 --topic first --consumer.config config/consumer.properties
(3)在k8smaster上启动生产者
[root@k8smaster kafka]$ bin/kafka-console-producer.sh
–broker-list 192.168.138.132:9092 --topic first
hello world
(4)查看k8snode1、k8snode2的接收者。
同一时刻只有一个消费者接收到消息。