消息中间件之kafka
一、kafka是什么
kafka的官网说自己是一个事件流平台,我们通常认为kafka就是 一个消息中间件(rabbitmq)
kafka中存的是消息message/事件,消息是一种通知机制
数据库与消息中间件的区别
数据库中的数据是整个软件的状态(用户信息、课程、班级)
消息中间件中的消息,是多个任务协同工作的一种通知
二、为何要用kafka?用在哪?
2.1 储备知识:
生产者消费者模型(分布式高并发系统都会基于该模型开发程序)
生产者producer--------》(缓冲区)消息队列《-----------消费者consumer
优点:
1、解耦合:生产者与消费者解耦合
2、提升效率:生产者与消费者可以并行,平衡了生产者与消费者的速度差,不必互相等待
3、缓解压力:通过消息队列,平衡了生产者与消费者的速度差,
在消费者处理速度跟不上的情况下,系统依然可以平稳运行
4、灵活扩缩:可以按需扩缩生产者与消费者的数量
2.2 为何要用kafka
我们可以将很多高并发的分布系统内组件之间的交互视为生产者与消费者之间的交互
而生产者与消费者之间是基于消息队列来通信的,而kafka就是消费队列中的佼佼者
1、解耦、异步----生产者与消费者解耦合、分布式组件
2、灵活扩缩
3、削峰填谷
削峰:把峰值流量用消息中间件缓存下来,后面可以慢慢处理(有延迟,但可以保命)
填谷:在流量的低谷期,提前处理一些任务或者说处理哪些峰值流量
关键点:引入消息队列平衡了生产者与消费者的速度差,有延迟,但是可以保命---可用性
2.3 kafka的优良特性----了解
1、大数据处理:日志收集或流处理,提供高吞吐量的消息队列
2、数据持久性:可在磁盘上长期存储消息
3、消息积压处理:存储高峰期产生的数据在系统资源允许的情况下慢慢处理
4、并行处理:同时支持多生产者和多消费者,保证消息在消费者群组中的顺序
5、实时处理/流处理:支持实时流处理,在数据到达时立即对其进行处理
2.4 kafka应用场景
消息队列(主要)
日志收集
用户活动跟踪----大数据分析
运营指标 :记录运营监控数据
流式处理:实时处理和分析数据的方式,适用于实时响应的场景,例如实时分析和监控
2.5 引入消息队列的缺点
1、业务上增加响应延迟
2、架构复杂变高,增加不稳定因素
三、部署kafka
# 3.1 环境准备
setenforce 0
iptables -F
sed -i 's#enforcing#disabled#g' /etc/selinux/config
systemctl disable --now firewalld# 3.2 安装docker的依赖的系统包
yum install -y yum-utils device-mapper-persistent-data lvm2# 3.3 安装docker引擎
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce -y
# 3.4 为docker引擎配置镜像加速站
docker-------------》容器(相当于一个“操作系统 + 软件”----》镜像
镜像-------》来自镜像源,官方源docker.io(拉不下来)
使用:aliyun.com ----> 控制台-----》镜像服务-----》镜像工具---》镜像加速器sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://vj5aa9yj.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 3.5 先下载镜像
docker pull wurstmeister/zookeeper
docker pull wurstmeister/kafka
docker images# 3.6 后启动容器(用镜像启,容器里跑的就是镜像的内容)
# 启动zookeeper
docker run -d --name zookeeper -p 2181:2181 -t wurstmeister/zookeeper# 启动kafka
docker run -d --name kafka --publish 9092:9092 --link zookeeper \
--env KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
--env KAFKA_ADVERTISED_HOST_NAME=192.168.71.114 \ #自己的IP
--env KAFKA_ADVERTISED_PORT=9092 \
wurstmeister/kafka:latest
# 补充: 出问题后进行清理
# docker container rm -f kafka
# docker container rm -f zookeeper
四、使用简单示例
# 4.1 介绍
mysql是一个数据库管理软件------------------------》创建数据库(create database db1)
kafka准确的说应该是一个消息队列管理软件----------》创建消息队列
生产者----------------》 kafka管理的消息队列 《------------消费者
# 4.2 创建消息队列(kafka中创建的队列称之为topic)
[root@web03 /tmp]# docker exec -ti kafka sh #进入容器
/ # # 容器内的东西都是镜像的东西
/ #
/ # cd /opt/kafka/bin/ #进到容器里对应的目录下用指令
/opt/kafka_2.13-2.8.1/bin # kafka-topics.sh --create --zookeeper zookeeper:2181 \
--replication-factor 1 --partitions 2 --topic TopicA
###partition分区 replication-factor副本 topic消息队列 broker kafka实例
# 4.3 演示生产者与消费者通过消息队列通信
# ---------------------------------------生产者
$ docker exec -ti kafka sh
/ # cd /opt/kafka/bin
/ # kafka-console-producer.sh --bootstrap-server 192.168.71.114:9092 --topic TopicA
然后一行行输入,回车即发送一条消息#-----------------------------------------消费者
$ docker exec -ti kafka sh
/ # cd /opt/kafka/bin
/ # kafka-console-consumer.sh --bootstrap-server 192.168.71.114:9092 --topic TopicA --from-beginning
可以收到消息
五、kafka架构详解与名词解释
5.1 生产者Producer
基于某种编程语言编写程序
生产者与消费者都是操作topic(topic是逻辑层的队列,而底层实际的队列是分区partition)
5.2 kafka集群---》提供消息队列
kafka ------->消息队列管理软件
broker-------》kafka集群中的一个kafka节点/实例
topic主题----》kafka中创建出的消息队列(逻辑层面),实际队列底层用的分区
分区(实际的队列)--------》数据分片,多个分区来负载压力,性能提升----做负载均衡
补充:
增大分区可以提高该topic的吞吐率
但是不是越大越好(元数据维护压力变大)
每个分区都是多副本------------------------》高可用
一个分区的副本分成两类角色(主从)
leader:读写都与leader打交道
多个follower:只做备份,主动与leader同步数据
一旦leader挂掉,kafka会选出一个follower成新的leader注意:
每个副本会分布在不同的broker,不能在同一个broker
所以副本数 <= broker数
副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,
同一机器对同一个分区也只可能存放一个副本(包括自己)。
zookeeper:
存储kafka的集群元信息数据库,保证系统的可用性
5.3 消费者Consumer
1、可以一个单独一个消费者
2、也可以把多个消费者归纳到一个消费组ConsumerGroup
消费组的特点:
1、同一个组内的消费者可以消费同一个topic下不同分区的消息(并发)
2、同一个组内的多个消费者不能同时消费一个分区内的消息(相当于锁)
当我的topic下有5分区时,一个消费组中应该放5个消费者
如果只放1个消费者:消费能力太低
如果放了3个消费者:消费能力不高
如果放了7个消费者:有两个消费处于空闲状态# 根据分区数匹配消费者数,消费者组相当于kafka自带的锁机制
5.4 示例
六、工作流程
1、生产者往kafka中写数据的流程
1.1 储备
生产者-----》topic主题(就是队列)逻辑层面的队列 ----》多个分区partition(实际负责干活) 每一个分区都可以是多副本的
leader跟多个follower
读写都是跟leader打交道
follower只做备份
1.2 写入流程
先找到leader
(1)先从多个分区中选出一个分区(有三种选择策略)
(2)从分区的多个副本中找出leader,接下来生产者就是跟leader这个分区打交道了具体的写入流程
(1)生产发送消息给分区中的leader
(2)leader收到消息之后将消息存入本地硬盘
(3)所有follower从leader拉取pull数据到自己本地,完成数据同步,然后返回ack确认信息给leader
(4)leader收到所有follower的ack确认之后,就会发送ack
确认信息给生产者,完成写入流程
2、 kafka是如何从topic中的多个分区中找出某一个的
有三种选择策略
1、程序自己明确指定要写到哪个分区中,就以指定的为准
2、程序没有明确指定要写到那个分区中,但是设置了数据的key
那kafka会根据key算出 一个hash值来对应到具体的partition(类似于redis中分布数据的槽)
3、程序没有明确指定要写到那个分区中,也没有设置数据的key
则会轮询出一个partition
补充两个重要的点:
1、kafka写磁盘采用的是顺序写,而不是随机写(代码实现,kafka快的原因之一)
2、topic中的数据是有序还是无序
2.1、站在所有partition的角度去看,数据是无序的(具体指的是消息不是按照分区的编号去存的,而是会根据分区的三种选择策略来选择分区写入)
2.2、单看某一个partition中的数据,是有序的
3、生产者写数据(数据不丢)的三种ack策略
- acks=0:写入性能的极端:生产者提交完写请求后则结束,不需要等任何的ack(异步写写速度最快,但数据最不安全)
- acks=1:兼顾性能与数据安全:生产者要等到leader写完即可,不需等follower同步完毕
- acks=all:数据安全的极端:生产者写入流程的完成要一直等到所有follower 都完成同步并回复ack之后才算结束(写速度最慢,但是数据最安全)
在代码中指定
acks
acks=0
acks=1
acks=all
4、生产者往不存在的topic里写入数据会发生什么
如果auto.create.topics.enable设置为true(默认值),当生产者发送消息至不存在的主题时,Kafka将自动创建该主题并接收消息(分区和副本的数量根据默认配置都是1)
如果auto.create.topics.enable设置为false,当生产者发送消息至不存在的主题时,Kafka将不会创建该主题,而是会返回错误,此时生产者通常会捕捉到此错误并作出相应处理。
5、kafka会把消息持久化到硬盘中,在硬盘上是如何组织的
mysql管理软件-------》库------------------分库分表------------------》 文件夹(组织了文件)
kafka管理软件--------》topic主题------》包含了多个分区------ --》一个分区对应一个文件夹(组织了文件)
文件的组织方式:
把整体一份大数据,切成多段去存,每一段称之为一个segment,
1、每一个segment都会以自己存放的message消息的 [ 初始(第一个)offset号-1] 来命名
2、每一个segment包含三个关键文件
index和timeindex文件为索引文件,用于检索消息。----------》稀疏索引
log文件就实际是存储message的地方(每条消息都有自己的编号,称之为offset)
###mysql中是将所有数据放到一起ibd文件,然后建立B+树减少io次数;而kafka中则是将数据分段,加上offset位移号来进行快速查找定位。
例如:
6、kafka的存储策略、旧的数据何时被删除
基于时间,默认配置是168小时(7天)。
基于大小,默认配置是1073741824。
# kafka读取特定消息的时间复杂度是0(1),删除过期文件不会提高kafka性能
7、对一个message来说关键的构成
1、offset: 逻辑顺序
2、占用的到第几个字节:物理位置
8、查找数据的底层流程(稀疏索引)
假如现在需要查找一个offset为368801的message是什么样的过程呢?
1、根据待查找的368801、以及segment的文件名来确定查找范文处于那个segment(快速缩小查找范围)
假设确定在segment2中
2、计算出待查找的offset的相对位置
368801 - 368796 - 1= 5
3、索引的结构是稀疏索引
稀疏索引:每隔几条才会创建一个索引
4、采用二分法来确定待查找索引所处的稀疏索引的区间
然后根据后面的物理位置快速定位log文件的中起始位置
然后向后查找你的offset就能找到具体的某一条数据
关键点---》缩小查找范围
总结:(kafka为什么快)
这套机制是建立在offset为有序的基础上,利用segment+有序offset+稀疏索引+二分查找+顺序查找等多种手段来高效的查找数据
核心思路:减少io次数
9、消费者获取数据的两种模式
push消费模式只适合于消费速度远大于生产速度的场景,如果是大流量并发场景,基本还是以Pull消费为主, kafka采用的是拉取的方式(大流量并发场景,基本还是以Pull消费为主)。
1、消费者主动拉取---》pull
优点:
消费者可能综合自身处理能力来主动获取消息,避免消息过载
缺点:
会牺牲掉实时性,需要消费者定期轮询查询队列
2、消息队列推送消息给消费者----》push
优点:
实时性强,有消息则立即推送
缺点:
只适用于消费能力远远超过消息的产生速度的场景
10、消息队列的两种通信模式
2.1、点对点模式
点对点模式是消息在消息队列中存储,并且每条消息只有一个消费者来消费
2.2、发布订阅模式
发布订阅模式是消息被发送到主题topic中,然后被所有订阅该主题的消费者共享和消费
总结kafka采用的模式:
kafka其实融合了点对点+发布订阅的优点,且采用拉取的方式
点对点:一个消费组的多个线程不能同时消费一个partition
意味着一条消息同一时间只能被一个消费者处理
发布订阅:
kafka采用发布-订阅模式,生产者将消息发布到特定的主题,消费者订阅他们感兴趣的主题并消费消息
一旦有消息来则会收到通知,然后采用pull方式拉取消息
###建议一个topic的partition数与消费组里的消费者个数保持一致