文章目录
一、Kafka介绍和架构
1.1介绍
Kafka
是一个分布式、分区的、多副本的、多订阅者,基于zookeeper
协调的分布式日志系统(也可以当做MQ系统),
常见可以用于访问日志,消息服务等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目
主要应用场景是:日志收集系统和消息系统
Kafka
是基于消息发布-订阅模式实现的消息系统,其主要涉及有以下特点:
- 1 消息持久化:以时间复杂度为O(1)的方式提供消息持久能力
虽然Kafka
的持久化在一定程度上来说比较依赖磁盘的性能,但是Kafka
中broker
先缓存后入磁盘,永远只在尾巴追加,减少磁盘IO选道,只做“线性写”,不做“磁盘寻道”,简言之就是永远往前走不回头,而“磁盘寻道”的时间消耗是“线性写”的几万级别。 - 2 分布式:支持消息分区以及分布式消费,并保证分区内的消息顺序
Kafka
对硬件能力要求不高,廉价PC机就可以做到Partition
的扩展,承载元数据管理的ZooKeeper
的水平扩展也很容易。扩展的结果就是同一个Topic
可以有N多个Partition
,可以同时被更多的Produce
r和Consumer
对接。 - 3 伸缩性:支持水平扩展
分布式是以Broker
为维度来讲的,伸缩性是以Partition
为维度来讲的,Topic
下Partition
的多少决定了Queue
的性能。consumer端
向broker
发送"fetch
"请求,并告知其获取消息的offset
;consumer
是个主动pull的动作,可以根据自己的能力决定什么时候去pull,pull多少回来 - 4 高吞吐:在廉价的商用机器上也能支持单机每秒10万条以上的吞吐
不管消息是否被消费,都会保留在partition
里,直到broker
配置时间点进行清除,无论是否消费清除。Consumer
每次来Partition
读取都是批量拿走。简然之Kafka
无论是消费、持久化、清理都是以块为单位而且是指针永远往前走不回头,而且可以通过压缩手段压榨CPU以提高速率
消息队列
消息队列又称消息引擎,消息中间件(kafka 、rabbitMQ)
不是永久的,是临时的。
消息队列的好处:
1)解耦:
允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
2)冗余:
消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
3)扩展性:
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。
4)灵活性 & 峰值处理能力:
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
5)可恢复性:
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
6)顺序保证:
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka保证一个Partition内的消息的有序性)
7)缓冲:
有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
8)异步通信:
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
消息队列的两种模式
消息队列分为
- 点对点模式
- 发布/订阅模式
(1)点对点模式(一对一,消费者主动拉取
数据,消息收到后消息清除)
点对点模型通常是一个基于拉取或者轮询的消息传送模型,这种模型从队列中请求信息,而不是将消息推送到客户端。这个模型的特点是发送到队列的消息被一个且只有一个接收者接收处理即使有多个消息监听者也是如此。
- 生产者生产消息发送到
Queue
中,然后消息消费者从Queue中取出并且消费消息。 - 消息被消费后就从队列queue移除该消息,所以消费者不可能再消费到
- 每条消息由一个生产者生产,且只被一个消费者消费(即使该队列有多个消费者)。
- 生产者和消费者是一对一模式
(2)发布/订阅模式(一对多,数据生产后,推送给所有订阅者,消费者消费数据之后不会清除消息)
发布订阅模型则是一个基于推送的消息传送模型。发布订阅模型可以有多种不同的订阅者,临时订阅者只在主动监听主题时才接收消息,而持久订阅者则监听主题的所有消息,即使当前订阅者不可用,处于离线状态。
- 所有订阅了该主题的消费者都能收到同样的消息
zk与kafka的关系
1、Broker注册
Broker
是分布式部署并且相互之间相互独立,但是需要有一个注册系统能够将整个集群中的Broker管理起来,此时就使用到了Zookeeper
。在Zookeeper
上会有一个专门用来进行Broker
服务器列表记录的节点:
/brokers/ids
每个Broker
在启动时,都会到Zookeeper
上进行注册,即到/brokers/ids
下创建属于自己的节点,如/brokers/ids/[0…N]。
Kafka
使用了全局唯一的数字来指代每个Broker服务器,不同的Broker
必须使用不同的Broker ID
进行注册,创建完节点后,每个Broker
就会将自己的IP地址和端口信息记录到该节点中去。其中,Broker
创建的节点类型是临时节点,一旦Broker
宕机,则对应的临时节点也会被自动删除。
Controller介绍:
Kafka
集群中有一个 broker
会被选举为Controller
,负责管理集群 broker
的上下线,所有 topic
的分区副本分配和 leader
选举等工作。
leader是针对partitions一个角色,leader是针对于ISR快速选举
controller是针对于broker的一个角色,controller是高可用的
Controller
的管理工作都是依赖于 Zookeeper
的。
以下为 partition 的 leader
选举过程 :
leader的负载均衡
如果某个broker crash
后,就可能导致partition的leader
分配不均,就是一个broker
存在一个topic
下的不同partition的leader
通过以下指令,可以将leader
分配到优先的leader
对应的broker
上,确保leader
是均匀的。
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --topic jyh --bootstrap-server --partitions 2 --election-type preferred
2、Topic注册
在Kafka
中,同一个Topic
的消息会被分成多个分区并将其分布在多个Broker
上,这些分区信息及与Broker
的对应关系也都是由Zookeeper
在维护,由专门的节点来记录,如:
/brokers/topics
Kafka中每个Topic都会以/brokers/topics/[topic]的形式被记录
,如/brokers/topics/login和/brokers/topics/search等。Broker服务器启动后,会到对应Topic节点(/brokers/topics
)上注册自己的Broker ID并写入针对该Topic的分区总数,如/brokers/topics/login/3->2,这个节点表示Broker ID为3的一个Broker服务器,对于"login"这个Topic的消息,提供了2个分区进行消息存储,同样,这个分区节点也是临时节点。
3、生产者负载均衡
由于同一个Topic
消息会被分区并将其分布在多个Broker
上,因此,生产者需要将消息合理地发送到这些分布式的Broker上,那么如何实现生产者的负载均衡,Kafka
支持传统的四层负载均衡,也支持Zookeeper
方式实现负载均衡。
(1) 四层负载均衡,根据生产者的IP地址和端口来为其确定一个相关联的Broker。通常,一个生产者只会对应单个Broker,然后该生产者产生的消息都发往该Broker。这种方式逻辑简单,每个生产者不需要同其他系统建立额外的TCP连接
,只需要和Broker维护单个TCP连接即可。但是,其无法做到真正的负载均衡,因为实际系统中的每个生产者产生的消息量及每个Broker
的消息存储量都是不一样的,如果有些生产者产生的消息远多于其他生产者的话,那么会导致不同的Broker接收到的消息总数差异巨大,同时,生产者也无法实时感知到Broker的新增和删除。
(2) 使用Zookeeper
进行负载均衡,由于每个Broker
启动时,都会完成Broker
注册过程,生产者会通过该节点的变化来动态地感知到Broker服务器列表的变更,这样就可以实现动态的负载均衡机制。
4、消费者负载均衡
与生产者类似,Kafka
中的消费者同样需要进行负载均衡来实现多个消费者合理地从对应的Broker
服务器上接收消息,每个消费者组包含若干消费者,每条消息都只会发送给分组中的一个消费者,不同的消费者分组消费自己特定的Topic下面的消息,互不干扰。
5、分区 与 消费者 的关系
消费组 (Consumer Group)
:
consumer group
下有多个 Consumer(消费者
)。
对于每个消费者组 (Consumer Group),Kafka
都会为其分配一个全局唯一的Group IDGroup 内部的所有消费者共享该 ID。订阅的topic
下的每个分区只能分配给某个 group 下的一个consumer(当然该分区还可以被分配给其他group)。
同时,Kafka为每个消费者分配一个Consumer ID,通常采用"Hostname:UUID"形式表示。
在Kafka中,规定了每个消息分区 只能被同组的一个消费者进行消费,因此,需要在 Zookeeper 上记录 消息分区 与 Consumer 之间的关系,每个消费者一旦确定了对一个消息分区的消费权力,需要将其Consumer ID
写入到Zookeeper
对应消息分区的临时节点上,例如:
/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]
其中,[broker_id-partition_id]就是一个 消息分区 的标识,节点内容就是该 消息分区 上 消费者的Consumer ID。
6、消息 消费进度Offset 记录
在消费者对指定消息分区进行消息消费的过程中,需要定时地将分区消息的消费进度Offset记录到Zookeeper上,以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息消费。Offset在Zookeeper中由一个专门节点进行记录,其节点路径为:
/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]
节点内容就是Offset的值。
7、消费者注册
消费者服务器在初始化启动时加入消费者分组的步骤如下
注册到消费者分组。每个消费者服务器启动时,都会到Zookeeper
的指定节点下创建一个属于自己的消费者节点,例如/consumers/[group_id]/ids/[consumer_id],
完成节点创建后,消费者就会将自己订阅的Topic信息写入该临时节点。
对 消费者分组 中的 消费者 的变化注册监听。每个 消费者 都需要关注所属 消费者分组 中其他消费者服务器的变化情况,即对/consumers/[group_id]/ids节点注册子节点变化的Watcher监听
,一旦发现消费者新增或减少,就触发消费者的负载均衡。
对Broker服务器变化注册监听消费者需要对/broker/ids/[0-N]
中的节点进行监听,如果发现Broker服务器列表发生变化,那么就根据具体情况来决定是否需要进行消费者负载均衡。
进行消费者负载均衡为了让同一个Topic
下不同分区的消息尽量均衡地被多个 消费者 消费而进行 消费者 与 消息 分区分配的过程,通常,对于一个消费者分组,如果组内的消费者服务器发生变更或Broker
服务器发生变更,会发出消费者负载均衡。
1.2 Kafka架构
1.2.1上图解释
# Kafka集群解释
上图Kafka集群有三个Borker(节点)
有三个Topic(类别)
TopicA有2个Partition(分区),每个分区有一个Leader(主),3个Follower(副本)
TopicB有1个Partition(分区),每个分区有一个Leader(主),2个Follower(副本)
TopicC有1个Partition(分区),每个分区有一个Leader(主),1个Follower(副本)
# Zookeeper解释
zk负责管理Kafka集群和消费者消费到的位置信息
只要多个Kafka节点,连接的是同一个zk或zk集群,那这些Kafka就组成一个集群
假设消费者挂掉,再启动起来,需要记录消费者挂之前消费到哪里了(offset),所以在0.9版本之前是存在zk中,0.9以后存在Kafka本地
改掉的目的?
因为消费者在消费时,跟kafka集群通信,然后Kafka集群还要跟zk通信,记录消费的位置,高并发情况下影响效率
0.9以后存在Kafka中的某个主题上,默认存7天
1.2.2 名词解释
# broker
Kafka 集群包含一个或多个服务器,服务器节点称为broker。
broker存储topic的数据。如果某topic有N个partition,集群有N个broker,那么每个broker存储该topic的一个partition
如果某topic有N个partition,集群有(N+M)个broker,那么其中有N个broker存储该topic的一个partition,剩下的M个broker不存储该topic的partition数据
如果某topic有N个partition,集群中broker数目少于N个,那么一个broker存储该topic的一个或多个partition。在实际生产环境中,尽量避免这种情况的发生,这种情况容易导致Kafka集群数据不均衡。
# Topic
每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。
物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处
# Partition
topic中的数据分割为一个或多个partition
每个topic至少有一个partition
每个partition中的数据使用多个segment文件存储
partition中的数据是有序的,不同partition间的数据丢失了数据的顺序
如果topic有多个partition,消费数据时就不能保证数据的顺序
在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1
# Producer
生产者即数据的发布者,该角色将消息发布到Kafka的topic中
broker接收到生产者发送的消息后,broker将该消息追加到当前用于追加数据的segment文件中
生产者发送的消息,存储到一个partition中,生产者也可以指定数据存储的partition
# Consumer
消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。
# Consumer Group
每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)
如果一个Topic被多组Consumer Group消费,一旦有消息投递过来,每个组内只能有一个Consumer能消费到这个消息,一个Consumer只能属于一个Group
同一个消费者组中的一个消费者,只能消费某个主题的一个分区数据:假设消费者组GroupA中的consumer0,消费了TopicA的Partition0,那么TopicA的Partition0,就不能被GroupA中的consumer1消费了
不同消费者组,是可以消费同一个主题的同一个分区数据的
把一个消费者组,当成一个大的消费者,之所以有组,就是为了提高消费能力,所以消费者组中的消费者,如果大于分区数,是没有意义的
# Leader
每个partition有多个副本,其中有且仅有一个作为Leader,Leader是当前负责数据的读写的partition
下正常情况follower仅仅作为备份
# Follower
Follower跟随Leader,所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步
如果Leader失效,则从Follower中选举出一个新的Leader,达到高可用
当Follower与Leader挂掉、卡住或者同步太慢,leader会把这个follower从“in sync replicas”(ISR)列表中删除,重新创建一个Follower
注意:
AR:表示一个topic下的所有副本
ISR:正在同步的副本(可以简单的理解为有几个follower是存活的)
OSR:不在同步的副本
AR=ISR+OSR
lead与follower区别:
- kafka中的leader和follower是相对于分区有意义的,不是相对broker
- kafka在创建topic的时候,会尽量分配分区的leader在不同的broker中,其实是负载均衡
- leader职责:读写数据
- follower职责:同步数据,参与选举。(leader挂掉之后,会选举一个follower重新成为分区leader)
- 注意kafka与zookeeper的区别?
- zk的leader可以负责读写,follower可以读写
- kafka的leader负责读写,follower不可以读写数据(确保每个消费者的数据是一致的),kafka一个topic有多个分区leader,一样可以实现数据操作的负载均衡。
1.3 Kafka为什么比其他MQ块
因为采用的是机制是顺序写入磁盘和Memory Mapped Files(内存映射文件)。
顺序写入:每个partition都是一个文件,kafka会把收到的message插入到文件末尾,每个consumer会对每个topic都有一个offset用来表示读取到了第几条数据。
kafka会把所有的数据都保留下来,但是数据落到磁盘后,会随着数据增加,而选择要不要删除,kafka目前提供两种机制来删除,一种是基于时间的,数据默认保留7天,一种是基于partition文件大小的。
Kafka不是实时的写入硬盘,充分利用操作系统的分页存储来提高I/O操作。64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上
二 Kafka安装
因为Kafka是基于java和Scala编写的,所以需要jdk的环境(Scala字节码也要运行在java虚拟机之上)
2.1 安装JDK8
其实单纯装kafka,使用jdk8就可以了,如果我们后期要使用一个第三方web管理界面,需要最低jdk11
下载地址:下载JDK8
直接下载rpm包安装【更多安装方式,详见 centos7安装jdk文章】
# 下载后使用rpm方式安装
rpm -ivh jdk-11.0.11_linux-x64_bin.rpm
# 查看被安装到哪个路径下了
which java
java: /usr/bin/java
# 切换到路径下,查看
cd /usr/bin/
ls -al |grep java
# 可以看到被安装到 /usr/java/jdk-11.0.11 路径下了
# 检查是否安装成功
java -version
2.2 下载kafka
wget https://mirrors.bfsu.edu.cn/apache/kafka/2.8.0/kafka_2.12-2.8.0.tgz
# 解压
tar -xzvf kafka_2.12-2.8.0.tgz
# 进入到目录,查看
cd kafka_2.12-2.8.0
ll
# 下图为根路径,bin路径和config路径截图
2.3 安装配置Zookeeper
Centos7 安装
第一种方法:
```bash
0.需要java环境 jdk8就行 rpm包也可以
# 1 下载地址:https://zookeeper.apache.org/releases.html
# 2 下载
wget https://mirror-hk.koddos.net/apache/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
# 3 解压
tar -xzf apache-zookeeper-3.7.0-bin.tar.gz
# 4 重命名,进入
mv apache-zookeeper-3.7.0-bin zk1
cd zk1
# 5 查看
ls # bin启动目录,conf配置文件目录
bin conf docs lib LICENSE.txt NOTICE.txt README.md README_packaging.md
# 6 修改配置文件
mkdir /root/zk1/data
vi conf/
tickTime=2000
dataDir=/root/zk1/data
clientPort=2181
# Zookeeper3.5的新特性,起了个http服务,浏览器访问,查看所有短句命令,默认8080
# http://10.0.0.100:8888/commands
admin.serverPort=8888
# 7 启动
# 这里命令写的长是为了便于知道ZooKeeper是如何使用配置文件的。
./bin/zkServer.sh start ./conf/zoo.cfg
注意:
# 启动zk
./bin/zookeeper-server-start.sh -daemon config/zookeeper.properties
# 加-daemon参数,可以在后台启动Zookeeper,输出的信息在保存在执行目录的logs/zookeeper.out文件中
# 8 查看ZooKeeper是否运行
ps aux |grep zookeeper
# 也可以使用jps ,可以看到java进程中有QuorumPeerMain列出来。
# 9 查看ZooKeeper的状态
./bin/zkServer.sh status
# 10 常用的ZooKeeper用法
./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
2.4 Kafka配置
# 1 修改kafka配置
vi server.properties
# 2 修改如下(其实不用改)
broker.id=0
port=9092
listeners=PLAINTEXT://10.0.0.20:9092 # 本机的ip
zookeeper.connect=localhost:2181
过滤修改的配置文件
grep -E ^[^#] server.properties
# 3 启动kafka
./bin/kafka-server-start.sh ./config/server.properties # 前台启动
./bin/kafka-server-start.sh -daemon ./config/server.properties # 以守护进程启动
# 4 停止kafka
./bin/kafka-server-stop.sh config/server.properties
配置信息解释
#broker的全局唯一编号,不能重复
broker.id=0(集群架构中不要使用0)
#用来监听链接的端口,producer或consumer将在此端口建立连接
port=9092
#处理网络请求的线程数量
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=/tmp/kafka-logs
#topic在当前broker上的分片个数
num.partitions=2
#用来恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#滚动生成新的segment文件的最大时间
log.roll.hours=168
#日志文件中每个segment的大小,默认为1G
log.segment.bytes=1073741824
#周期性检查文件大小的时间
log.retention.check.interval.ms=300000
#日志清理是否打开
log.cleaner.enable=true
#broker需要使用zookeeper保存meta数据
zookeeper.connect=10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181
#zookeeper链接超时时间
zookeeper.connection.timeout.ms=6000
#partion buffer中,消息的条数达到阈值,将触发flush到磁盘
log.flush.interval.messages=10000
#消息buffer的时间,达到阈值,将触发flush到磁盘
log.flush.interval.ms=3000
#删除topic需要server.properties中设置delete.topic.enable=true否则只是标记删除
delete.topic.enable=true
#此处的host.name为本机IP(重要),如果不改,则客户端会抛出:Producerconnection to localhost:9092 unsuccessful 错误!
host.name=0.0.0.0
# 本机的ip
listeners=PLAINTEXT://10.0.0.:9092
2.6 常见错误
# 如果报如下错误,是因为机器内存太小,开了三个服务都是基于jvm跑的,修改一下启动文件指定的jvm内存大小即可
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c0000000, 1073741824, 0) failed; error='Not enough space' (errno=12)
# 修改启动文件
vi kafka-server-start.sh
三 Kafka测试
创建topic(主题)
# 执行命令
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --create --topic jyh --partitions 2 --replication-factor 1
【命令解释】
# replication-factor:主题的副本数
每个主题可以有多个副本,副本位于集群中不同的broker上,也就是说副本的数量不能超过broker的数量,否则创建主题时会失败
# partitions:主题分区数
通过分区策略,将不同的分区分配在一个集群中的broker上,一般会分散在不同的broker上,当只有一个broker时,所有的分区就只分配到该Broker上
# topic:主题名字
随便起一个名字就可以了
查看主题
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --list
接收消息(消费端)
消费者跟zookeeper打交道,记录上一次消费到哪了需要给zookeeper备份
#加了–from-beginning 重头消费所有的消息)
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic jyh --from-beginning
( #不加–from-beginning 从最新的一条消息开始消费)
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic jyh
发送消息(生产端)
生产者不和zookeeper打交道
# 执行下面命令,会hold住,输入消息
#### 注意:如果kafka的配置文件中配的是ip,这里也要使用ip
# listeners=PLAINTEXT://10.0.0.100:9092 # 本机的ip
bin/kafka-console-producer.sh --broker-list 10.0.0.20:9092 --topic jyh
查看特定主题的详细信息
bin/kafka-topics.sh --zookeeper localhost:2181 --describe --topic jyh
查看所有话题的详细信息:
bin/kafka-topics.sh --zookeeper localhost:2181 --describe
删除主题
bin/kafka-topics.sh --zookeeper localhost:2181 --delete --topic jyh
修改配置
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --alter --topic jyh --config flush.messages=1
删除配置
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --alter --topic jyh --delete --config flush.messages=1
直接彻底删除
kafka配置文件里面配置:
delete.topic.enable=true
如果不配置,需要重启kafka服务才能删除主题
增加分区
只能增加partitions分区
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --alter --topic jyh --partitions 3
查看某个topic对应的消息数量
bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic test --time -1
显示所有消费者:
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list
获取正在消费的topic(console-consumer-63307)的group的offset:
bin/kafka-consumer-groups.sh --describe --group console-consumer-63307 --bootstrap-server localhost:9092
查看当前组的状态
bin/kafka-consumer-groups.sh --describe --group console-consumer-63307 --bootstrap-server localhost:9092 --state
查看消费组内成员的信息
bin/kafka-consumer-groups.sh --describe --group console-consumer-63307 --bootstrap-server localhost:9092 --members
删除消费组
bin/kafka-consumer-groups.sh --delete --group console-consumer-63307 --bootstrap-server localhost:9092
四、kafka集群部署
4.1kafka部署三台机器
1.准备环境
# 下载后使用rpm方式安装
rpm -ivh jdk-11.0.11_linux-x64_bin.rpm
# 查看被安装到哪个路径下了
which java
java: /usr/bin/java
# 切换到路径下,查看
cd /usr/bin/
ls -al |grep java
# 可以看到被安装到 /usr/java/jdk-11.0.11 路径下了
# 检查是否安装成功
java -version
2.下载安装包
wget https://mirrors.bfsu.edu.cn/apache/kafka/2.8.0/kafka_2.12-2.8.0.tgz
# 解
tar xf kafka_2.12-2.8.0.tgz -C /usr/local/
cd /usr/local/
mv kafka_2.12-2.8.0/ kafka
修改配置文件
[root@kafka kafka]# grep -E ^[^#] config/server.properties
broker.id=1 ##全局唯一,三台的话(1,2,3)
port=9092
delete.topic.enable=true
host.name=10.0.0.40 #本机ip(如果不改,则客户端会抛错)
listeners=PLAINTEXT://10.0.0.20:9092 #如果是虚拟机需要配置本机ip,例如自主挂载的windows,Ubuntu不需要配置
log.dirs=/usr/local/kafka/kafka-logs #日志目录
num.partitions=1
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
zookeeper.connect=10.0.0.20:2181,10.0.0.30:2181,10.0.0.40:2181
#与之关联的zookeeper地址,多个地址之间逗号隔离
zookeeper.connection.timeout.ms=18000
group.initial.rebalance.delay.ms=0
启动
前台:
./bin/kafka-server-start.sh ./config/server.properties
后台:
./bin/kafka-server-start.sh -demaon ./config/server.properties
查看
ps -ef | grep kafka
jps -l
五、zookeeper集群架构(三台)
1.环境准备
安装java环境
官网:下载地址:(https://www.oracle.com/java/technologies/javase-jdk8-downloads.html)
rpm -ivh jdk-8u181-linux-x64.rpm
下载zookeeper安装包
wget https://mirror-hk.koddos.net/apache/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
解压
tar xf apache-zookeeper-3.7.0-bin.tar.gz
2.创建目录
创建zookeeper目录
mkdir /usr/local/zookeeper-cluster/
mv apache-zookeeper-3.7.0-bin zookeeper
mv zookeeper/ /usr/local/zookeeper-cluster/
创建数据zookeeper目录
mkdir /usr/local/zookeeper-cluster/zookeeper/data
#myid文件,里面的内容为数字,用于标识主机,如果这个文件没有的话,zooKeep无法启动(3台机器分别为1,2,3)
echo 1 >/usr/local/zookeeper-cluster/zookeeper/data/myid
一般为集群为单数超过一半就会成master
如果有三个服务器,按顺序启动,第二个机器就是loader
3.修改zookeeper配置文件名称
cd /usr/local/zookeeper-cluster/zookeeper/conf
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg
[root@kafka conf]# grep -E ^[^#] zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper-cluster/zookeeper/data
clientPort=2181
server.1=10.0.0.20:2888:3888
server.2=10.0.0.30:2888:3888
server.3=10.0.0.40:2888:3888
解释:
servere.服务器id=服务器ip地址:服务器之间通信端口:服务器之间投票选举端口
4.启动zookeeper
/usr/local/zookeeper-cluster/zookeeper/bin/zkServer.sh start
5.查看集群状态
/usr/local/zookeeper-cluster/zookeeper/bin/zkServer.sh status
可以看到一个leader,两个follower
6.zookeeper常用命令
链接zookeeper客户端:sh zkCli.sh -server 127.0.0.1:2181 (zookeeper部署在本机)
查看zk支持的所有命令:help (前提链接进客户端)
查看指定路径:ls
查看已连接的broker:ls /brokers/ids
查看所有topic:ls /brokers/topic
创建一个节点:create /zk mydate (创建一个/zk节点,且其内容为 “mydata”)
显示节点信息:get /zk
设置节点内容:set /zk “anotherData”
删除一个节点:delete /zk
7.下线一个broker
背景:主动下线是指broker运行正常,因为机器需要运维(升级操作系统,添加磁盘等)而主动停止broker
分两种情况处理:
- 若所有的topic的replica >= 2
此时,直接停止一个broker
,会自动触发leader election
操作,不过目前leader election
是逐个partition
进行,等待所有partition
完成leader
election
耗时较长,这样不可服务的时间就比较长。为了缩短不可服务时间窗口,可以主动触发停止broker
操作,这样可以逐个partition
转移,直到所有partition
完成转移,再停止broker。
/usr/local/kafka/bin/kafka-run-class.sh kafka.admin.ShutdownBroker --zookeeper 127.0.0.1:2181 --broker 292 --num.retries 3 --retry.interval.ms 60
然后:
shutdown broker
/usr/local/kafka/bin/kafka-server-stop.sh
- 若存在topic的replica=1
当存在topic
的副本数小于2,只能手工把当前broker
上这些topic
对应的partition
转移到其他broker
上。当此broker
上剩余的topic
的replica
> 2时,参照上面的处理方法继续处理。
注意
一定要先启动zookeeper服务,再启动kafka服务。
六、分区
副本机制
leader选举
七、分片的重新分配
1.创建三个分片、三个副本
bin/kafka-topics.sh --zookeeper 10.0.0.20:2181 --create --topic jyh --partitions 2 --replication-factor 1
查看分片的详细信息
[root@kafka bin]# ./kafka-topics.sh --describe --zookeeper localhost:2181 --topic fxs
Topic: fxs TopicId: 9RAhpO_gTDaA113RHOSFuQ PartitionCount: 3 ReplicationFactor: 3 Configs:
Topic: fxs Partition: 0 Leader: 3 Replicas: 3,2,1 Isr: 3,2,1
Topic: fxs Partition: 1 Leader: 1 Replicas: 1,3,2 Isr: 1,3,2
Topic: fxs Partition: 2 Leader: 2 Replicas: 2,1,3 Isr: 2,1,3
2.连接zookeeper查看brocke节点
[root@kafka bin]# ./zkCli.sh -server localhost:2181
[zk: localhost:2181(CONNECTED) 0] ls /brokers/ids
[1, 2, 3]
3.新增加一个分区
[root@kafka bin]# ./kafka-topics.sh --zookeeper 10.0.0.20:2181 --alter --topic fxs --partitions 4
[root@kafka bin]# ./kafka-topics.sh --describe --zookeeper localhost:2181 --topic fxs
Topic: fxs TopicId: 9RAhpO_gTDaA113RHOSFuQ PartitionCount: 4 ReplicationFactor: 3 Configs:
Topic: fxs Partition: 0 Leader: 3 Replicas: 3,2,1 Isr: 3,2,1
Topic: fxs Partition: 1 Leader: 1 Replicas: 1,3,2 Isr: 1,3,2
Topic: fxs Partition: 2 Leader: 2 Replicas: 2,1,3 Isr: 2,1,3
Topic: fxs Partition: 3 Leader: 3 Replicas: 3,2,1 Isr: 3,2,1
以上看出新增加的节点没有分配之前主题的分区
再次新增加一个节点,也就是一台机器。
4.重新分配
1)确定要重启分配分区的主题,新建reassign.json json文件
{
"topics": [{"topic": "fxs"}],
"version":1
}
2)然后使用kafka-reassign-partitions.sh工具生成reassign plan
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --topics-to-move-json-file reassign.json --broker-list "0,1,2,3" –generate
--topics-to-move-json-file:指定分区重新分配的主题清单路径
--generate:指定类型参数
注意:
命令输入两个json字符串,第一个json内容为当前的分区副本分配情况,第二个为重新分配的候选方案,注意这里只是生成一份可执行方案,并没有真正执行分配的动作
我们将第二个json的内容保存到名为result.json文件里面(文件名不重要,文件格式也不一定要以json结尾,只要保证内容部是json即可),然后执行这些reassign.Plan
vim result.json
5.执行分配策略:
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file result.json --execute
6.查看分配的进度
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file result.json --verify
八、kafka存储结构
1.broker存储结构
每一个
partition
(文件夹)相当于一个巨型文件被平均分配到多个大小相等segment(段)
数据文件里。
但每一个段segment file
消息数量不一定相等,这样的特性方便oldsegment file
高速被删除。(默认情况下每一个文件大小为1G)
每一个partiton
仅仅须要支持顺序读写即可了。segment文件
生命周期由服务端配置參数决定。
partiton
中segment
文件存储结构:
segment file
组成:由2大部分组成,此2个文件一一相应,成对出现。
索引文件index file:后缀.index
数据文件data file:后缀.log
segment
文件命名规则:partion
全局的第一个segment从0
开始,兴许每一个segment
文件名称为上一个segment
文件最后一条消息的offset
值。
数值最大为64位long大小。19位数字字符长度,没有数字用0填充。
[root@kafka logs]# cd /tmp/kafka-logs/
[root@kafka kafka-logs]# ll
总用量 16
-rw-r--r-- 1 root root 0 8月 14 19:19 cleaner-offset-checkpoint
drwxr-xr-x 2 root root 167 8月 14 20:17 fxs-0
drwxr-xr-x 2 root root 167 8月 14 20:17 fxs-1
drwxr-xr-x 2 root root 167 8月 14 20:17 fxs-2
drwxr-xr-x 2 root root 167 8月 14 20:17 fxs-3
drwxr-xr-x 2 root root 167 8月 14 19:20 jyh-1
drwxr-xr-x 2 root root 167 8月 14 19:20 jyh_topic-1
-rw-r--r-- 1 root root 4 8月 14 21:05 log-start-offset-checkpoint
-rw-r--r-- 1 root root 88 8月 14 19:19 meta.properties
-rw-r--r-- 1 root root 58 8月 14 21:05 recovery-point-offset-checkpoint
-rw-r--r-- 1 root root 58 8月 14 21:06 replication-offset-checkpoint
[root@kafka kafka-logs]# cd fxs-1
[root@kafka fxs-1]# ll
总用量 8
-rw-r--r-- 1 root root 10485760 8月 14 19:50 00000000000000000000.index
-rw-r--r-- 1 root root 0 8月 14 19:50 00000000000000000000.log
-rw-r--r-- 1 root root 10485756 8月 14 19:50 00000000000000000000.timeindex
-rw-r--r-- 1 root root 8 8月 14 20:17 leader-epoch-checkpoint
-rw-r--r-- 1 root root 43 8月 14 20:17 partition.metadata
2.日志索引
2.1 数据文件的分段
kafka
姐姐查询效率的手段之一就是将数据文件分段,比如有100条消息,他们的offset
是从0到99。面,数据文件以该段中最小的offset
命名。这样在查找指定offset
的Message的时候,用二分查找就可以定位到该Message在哪个段中
2.2 偏移量索引
数据文件分段使得可以在一个较小的数据文件中查找对应offset
的Message了,但是这依然需要顺序扫描才能找到对应offset
的Message。为了进一步提高查找的效率,Kafka
为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index。
比如:要查找绝对 offset为7的Message:
首先是用二分查找确定它是在哪个LogSegment中,自然是在第一个Segment
中。 打开这个Segment的index文件
,也是用二分查找找到offset
小于或者等于指定offset的索引条目中最大的那个offset
。自然offset
为6的那个索引是我们要找的,通过索引文件我们知道offset
为6的Message在数据文件中的位置
为9807。
打开数据文件,从位置为9807的那个地方开始顺序扫描直到找到offset
为7的那条Message。
这套机制是建立在offset
是有序的。索引文件被映射到内存中,所以查找的速度还是很快的。
一句话,Kafka
的Message存储采用了分区(partition)
,分段(LogSegment)
和稀疏索引这几个手段来达到了高效性。
3 日志清理
3.1 日志删除
Kafka
日志管理器允许定制删除策略。目前的策略是删除修改时间在N天之前的日志(按时间删除),也可以使用另外一个策略:保留最后的N GB数据的策略(按大小删除)。为了避免在删除时阻塞读操作,采用了copy-on-write形式的实现,删除操作进行时,读取操作的二分查找功能实际是在一个静态的快
照副本上进行的,这类似于Java的CopyOnWriteArrayList。 Kafka消费日志删除思想:Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用
conf/server.properties
log.cleanup.policy=delete # 启动删除策略
直接删除,删除后的消息不可恢复,可配置以下两个策略:
清理超过指定之间清理
log.retention.hours=16
超过指定大小后,删除旧的信息
log.retention.bytes=1073741824
3.2 日志压缩
将数据压缩,只保留每个key最后一个版本的数据。
首先在broker
的配置中设置log.cleaner.enable=true
启用cleaner,这个默认是关闭的。
在Topic
的配置中设置log.cleanup.policy=compact
启用压缩策略。
压缩后的offset
可能是不连续的,比如上图中没有5和7,因为这些offset
的消息被merge
了,当从这些offset消费消息时,将会拿到比这个offset大的offset对应的消息,比如,当试图获取offset为5的消息时,实际上会拿到offset
为6的消息,并从这个位置开始消费。
这种策略只适合特殊场景,比如消息的key是用户ID,消息体是用户的资料,通过这种压缩策略,整个消息集里就保存了所有用户最新的资料。
压缩策略支持删除,当某个Key的最新版本的消息没有内容时,这个Key将被删除,这也符合以上逻辑。
除了消息顺序追加,页缓存等技术, Kafka还使用了零拷贝技术来进一步提升性能。“零拷贝技术”只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中(发送给不同的订阅者时,都可以使用同一个页面缓存),避免了重复复制操作。如果有10个消费者,传统方式下,数据复制次数为4*10=40次,而使用“零拷贝技术”只需要1+10=11次,一次为从磁盘复制到页面缓存,10次表示10个消费者各自读取一次页面缓存。
4 磁盘存储优势
Kafka在设计的时候,采用了文件追加的方式来写入消息,即只能在日志文件的尾部追加新的消息,并且不允许修改已经写入的消息,这种方式属于典型的顺序写入此判断的操作,所以就算是Kafka使用磁盘作为存储介质,所能实现的额吞吐量也非常可观。
Kafka中大量使用页缓存,这页是Kafka实现高吞吐
的重要因素之一。