kafka

kafka从入门到精通

介绍

# kafka是一个分布式、多分区、多副本、多订阅者,基于zookeepear协调的分布式日志系统(也可以当做MQ的系统)

# 主要应用场景是:日志收集系统和消息系统

Kafka是基于消息发布-订阅模式实现的消息系统,其主要涉及有以下特点:
# 1 消息持久化:以时间复杂度为O(1)的方式提供消息持久能力
	虽然Kafka的持久化在一定程度上来说比较依赖磁盘的性能,但是Kafka中broker先缓存后入磁盘,永远只在尾巴追加,减少磁盘IO选道,只做“线性写”,不做“磁盘寻道”,简言之就是永远往前走不回头,而“磁盘寻道”的时间消耗是“线性写”的几万级别。

# 2 分布式:支持消息分区以及分布式消费,并保证分区内的消息顺序
	Kafka对硬件能力要求不高,廉价PC机就可以做到Partition的扩展,承载元数据管理的ZooKeeper的水平扩展也很容易。扩展的结果就是同一个Topic可以有N多个Partition,可以同时被更多的Producer和Consumer对接。
    
# 3 伸缩性:支持水平扩展
	分布式是以Broker为维度来讲的,伸缩性是以Partition为维度来讲的,Topic下Partition的多少决定了Queue的性能。consumer端向broker发送"fetch"请求,并告知其获取消息的offset; consumer是个主动pull的动作,可以根据自己的能力决定什么时候去pull,pull多少回来
    
# 4 高吞吐:在廉价的商用机器上也能支持单机每秒10万条以上的吞吐
	不管消息是否被消费,都会保留在partition里,直到broker配置时间点进行清除,无论是否消费清除。Consumer每次来Partition读取都是批量拿走。简然之Kafka无论是消费、持久化、清理都是以块为单位而且是指针永远往前走不回头,而且可以通过压缩手段压榨CPU以提高速率

架构

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

1.3 Kafka为什么比其他MQ块

因为采用的是机制是顺序写入磁盘和Memory Mapped Files(内存映射文件)。
顺序写入:每个partition都是一个文件,kafka会把收到的message插入到文件末尾,每个consumer会对每个topic都有一个offset用来表示读取到了第几条数据。
kafka会把所有的数据都保留下来,但是数据落到磁盘后,会随着数据增加,而选择要不要删除,kafka目前提供两种机制来删除,一种是基于时间的,数据默认保留7天,一种是基于partition文件大小的。
Kafka不是实时的写入硬盘,充分利用操作系统的分页存储来提高I/O操作。64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上

Kafka安装

2.1 安装JDK11

其实单纯装kafka,使用jdk8就可以了,但是我们后期要使用一个第三方web管理界面,需要最低jdk11

下载地址:https://www.oracle.com/java/technologies/javase-jdk11-downloads.html

# 下载后使用rpm方式安装
rpm -ivh jdk-11.0.11_linux-x64_bin.rpm
# 查看被安装到哪个路径下了
whereis java
java: /usr/bin/java
# 切换到路径下,查看
cd /usr/bin/
ls -al |grep java
# 可以看到被安装到 /usr/java/jdk-11.0.11 路径下了
# 检查是否安装成功
java -version

2.2 下载kafka

下载地址:https://kafka.apache.org/downloads

# 解压
tar -xzvf kafka_2.12-2.8.0.tgz
# 进入到目录,查看
cd kafka_2.12-2.8.0
ll
# 下图为根路径,bin路径和config路径截图

2.3 安装配置Zookeeper

# 当前下载的Kafka会自带Zookeeper,可以直接使用,也可自己安装

#我们使用自带的zk
#kafka自带的zk使用bin/zookeeper-server-start.sh,以及bin/zookeeper-server-stop.sh来启动和停止
# 配制文件是config/zookeeper.properties,可以修改其中的参数
【配置文件不用改,直接启动即可】

# 1 启动zk
 /tmp/kafka_2.12-2.8.0/bin/zookeeper-server-start.sh -daemon /tmp/kafka_2.12-2.8.0/config/zookeeper.properties

# 启动一定要绝对路径不如会找不到文件
# 加-daemon参数,可以在后台启动Zookeeper,输出的信息在保存在执行目录的logs/zookeeper.out文件中

# 2 查看是否启动
ps aux |grep zookeeper

# clientPort=2181

# 3 关闭zk
./bin/zookeeper-server-stop.sh

2.4 Kafka配置

# 1 修改kafka配置
vi server.properties
# 2 修改如下(其实不用改)
broker.id=0
port=9092
listeners=PLAINTEXT://10.0.0.88:9092 # 本机的ip
zookeeper.connect=localhost:2181
# 3 启动kafka
./bin/kafka-server-start.sh ./config/server.properties          # 前台启动
/tmp/kafka_2.12-2.8.0/bin/kafka-server-start.sh -daemon  /tmp/kafka_2.12-2.8.0/config/server.properties  # 以守护进程启动

# 4 停止kafka
 /tmp/kafka_2.12-2.8.0/bin/kafka-server-stop.sh  /tmp/kafka_2.12-2.8.0/config/server.properties

配置信息

#broker的全局唯一编号,不能重复
broker.id=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

2.5 配置web管理界面

# 原名:kafka-manager现在更名为CMAK,雅虎开源的一款管理kafka集群的web界面
# github地址:https://github.com/yahoo/CMAK
# 下载地址:https://github.com/yahoo/CMAK/releases

# 解压,修改配置文件
vim conf/application.conf
# 修改zk集群地址(我们就一个,就写一个就行,多个用 , 分隔)
kafka-manager.zkhosts="10.0.0.100:2181"
cmak.zkhosts="10.0.0.100:2181"

# 启动(指定端口)
./bin/cmak -Dconfig.file=./conf/application.conf -Dhttp.port=8080  # 前台启动
nohup ./bin/cmak -Dconfig.file=./conf/application.conf & # 后台启动,把输出忽略

# jps查看java程序

# 在浏览器访问:
http://10.0.0.100:9000/

# 新增集群

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测试

3.1 创建topic

# 执行命令
bin/kafka-topics.sh --create --zookeeper 10.0.0.88:2181 --replication-factor 1 --partitions 2 --topic gjl_topic

【命令解释】
# replication-factor:主题的副本数
每个主题可以有多个副本,副本位于集群中不同的broker上,也就是说副本的数量不能超过broker的数量,否则创建主题时会失败
# partitions:主题分区数
通过分区策略,将不同的分区分配在一个集群中的broker上,一般会分散在不同的broker上,当只有一个broker时,所有的分区就只分配到该Broker上
# topic:主题名字
随便起一个名字就可以了

3.2 查看主题

bin/kafka-topics.sh --list --zookeeper 10.0.0.88:2181

image-20230830114526855

3.3 发送消息

# 执行下面命令,会hold住,输入消息
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic gjl_topic

#### 注意:如果kafka的配置文件中配的是ip,这里也要使用ip
# listeners=PLAINTEXT://10.0.0.100:9092 # 本机的ip
bin/kafka-console-producer.sh --broker-list 10.0.0.88:9092 --topic gjl_topic

3.4 接收消息

bin/kafka-console-consumer.sh --bootstrap-server 10.0.0.88:9092  --topic gjl_topic --from-beginning

3.5 查看特定主题的详细信息

bin/kafka-topics.sh --zookeeper 10.0.0.88:9092  --describe  --topic gjl_topic

3.6 删除主题

bin/kafka-topics.sh --zookeeper 10.0.0.88:9092  --delete  --topic gjl_topic

Python操作Kafka

安装模块
pip3 install kafka-python
https://github.com/dpkp/kafka-python

4.1 生产者示例

from kafka import KafkaProducer
import time
producer = KafkaProducer(bootstrap_servers='10.0.0.88:9092')
for _ in range(10):
    time.sleep(1)
    producer.send('gjl_topic', b'llnb')

# 在kafka服务端启动接收
bin/kafka-console-consumer.sh --bootstrap-server 10.0.0.88:9092  --topic gjl_topic --from-beginning

4.2 消费者示例

from kafka import KafkaConsumer
consumer = KafkaConsumer('gjl_topic', bootstrap_servers=['10.0.0.88:9092'])
for msg in consumer:
    recv = "%s:%d:%d: key=%s value=%s" % (msg.topic, msg.partition, msg.offset, msg.key, msg.value)
    print(recv)

# 在kafka服务端启动发送
bin/kafka-console-producer.sh --broker-list 10.0.0.88:9092 --topic gjl_topic

集群搭建

只要多个Kafka节点,连接的是同一个zk或zk集群,Kafka自然就组成了集群
所以我们只需要在多台机器上启动次Kafka服务,配置文件连接的zk地址一样即可
posted @ 2023-08-30 20:18  秋洛尘  阅读(95)  评论(0)    收藏  举报