kafka

一、异步通信原理

  1. 观察者模式
    作用:解耦
    我们不用频繁的、轮询的访问服务器,因为我们客户端不知道服务端什么时候更新数据,当服务器更新了通知我们即可。
    比如京东的到货通知、比如美团外卖来新订单了(老板不用时时刻刻上美团看有没有新订单)、再比如我的手机的操作系统过段时间就会通知更新。
    一个被观察者对象(发布者),一个观察者,当被观察对象(发布者)发生变化时,观察者被观察对象(发布者)发生变化的消息发送给关注他的人(订阅者)
  2. 生产者消费者模式
    生产者消费者模式并不属于23种设计模式中的一种,23种设计模式强调的是对象与对象之间的关系,而生产者消费者模式只是为了实现两个对象之间的解耦,更多的描述的是面向过程的东西。
    之前是流水线的方式,流水线1没干完活,流水线2就没法继续干活,同理,流水线3、4、5…都没法干活。耦合性太高。
    生产者消费者模式是生产者生产完消息,将其放到缓冲区中,消费者拿消息进行消费。这样的话上下游就得到了很好的解耦。异步通信。

美团外卖遵循生产者消费者模式,但是又不能让消费者一直去取数据,于是在缓冲区上加一个观察者模式,有了观察者模式,老板就不用一直刷新来取数据了,等着美团给他推送即可。

这两种模式结合在一起,非常适合传递消息的场景,非常适合生产层和消费层的解耦。


二、消息通信原理

缓冲区三大好处:解耦、支持并发、支持忙闲不均。即解耦、异步、削峰。

点对点消息传递:push可以保证实时处理数据,但是如果消费者消费能力不够,就会出现问题。
发布订阅消息传递:poll其实就是观察者模式,消息到达缓冲区后通知消费者来消费,消费者来poll消息。
现在的消息模型基本上以发布订阅消息模型为主。



三、kafka的系统架构

broker,可以看成节点(node)
topic,可以看成表(table)
es和kafka的对比:
在这里插入图片描述

如下图,虽然有4个broker(节点),但是我只有一个broker1中有我要读或者写的topic,剩下3个broker都没用到,这样就遇到了单点不能扩充的问题。
于是,在topic的基础上,有了partition这个概念。
一般情况下搞三个备份,同时坏两台机器的可能性不大。

生产者往topic里面写数据,topic通过它的路由规则,找到对应的leader(主),把leader的数据同步到follower(从)。
假如生产者要写6条数据,把数据存放在topic1–partition1–leader中的数据是:1、3、5;把数据存放在topic1–partition2–leader中的数据是:2、4、6。
注意:不同的partition内部是不保证有序的,但是同一个partition内部是保证有序的。
所以说partition没法保证数据的完全有序性,但是它可以保证数据的内部有序性。
如果你对数据的有序性要求比较强,那你只能搞一个partition。

kafka中消费者不能从follower中读取数据,只能从leader中读取数据。备用节点只是为了安全考虑,不参与服务(不参与读写 )。

在这里插入图片描述

再考虑这种情况,t1-p1-L中的数据被多个消费者所消费,比如消费者a消费了1,消费者b消费了3,那消费者1和消费者2读数据的时候,怎么记录读到哪了呢?
这时就用到了zookeeper,zk中会记录每个消费者的偏移量(offset)。zk会记录消费者a的偏移量是0,消费者b的偏移量是1。
那zk中什么时候记录数据就变得很关键了,消费者a和b读到数据1和3就开始记录呢(可能会导致消息被重复消费的现象)还是消费者a和b读到数据1和3后并处理完数据(可能会导致消息丢失)才开始记录呢?
kafka会交给我们来处理,让我们来设置。
同理,生产者生把消息传给topic就算传输完成(可能会导致消息丢失)还是topic记录下消息后才算传输完成(生产者发送给topic,topic节点崩了,就需要生产者重复的发送消息)?
kafka不帮你做决定,kafka给你策略,让你自己去选择。

生产者往kafka中写数据的时候,是写内存还是写硬盘?
写内存。
那如何保证数据不丢呢?就要保证flush的频率。如果想要效率高点,flush频率就低,如果想要安全性高,flush频率就高。

在这里插入图片描述
broker:
一个服务器节点就是一个broker,所以上图就有4个broker。

在这里插入图片描述
这幅图除了数据文件是存在你本机中,其他都存在zk中m,所以说,你的集群有多少个broker,“多少”这个数据就存在zk中。

topic:
为什么说一个topic存在于多个broker中?因为一个topic有多个partition,partition放在多个broker中。
用户只需要指定消息的topic即可生产或消费数据,而不需关心数据存于何处。因为kafka内部帮我们实现了消息的路由,让生产者或消费者所生产或消费的数据传输到对应的partition中。

partition:
0、1、2、3、4…对应的是消息的编号,0可能存的数据是张三,1可能存的数据是李四…
partition其实就是一个队列,队尾写消息,对头读消息。
例如下图就是在0开始读消息,12写消息。读到哪个位置会通过offset来记录。
在这里插入图片描述

leader和follower:
假设每个leader所在的broker为a,那么follower所在的broker就是a+1.
在这里插入图片描述

kafka要求所有的数据必须从主节点读取,从节点只负责备份,这是为了保证数据的一致性。
类比zk,我们从zk中读取的数据不一定是最新的数据,因为zk追求的是最终一致性。有可能半数的从节点的数据都同步到最新了,但可能我读到的是另一半未更新的节点。
类比redis,redis读取到的数据也不一定是最新的数据。


四、kafka环境搭建

在这里插入图片描述
一个consumer Group中的2个consumer不会消费到相同的数据,这样岂不是出现重复消费的问题。
图中1个leader有2个follower。
kafka的具体映射关系都会存储在zk上。

一个consumer可以读多个partition,但是一个partition只能给一个consumer读。

环境搭建
1、安装zookeeper
下载地址:https://zookeeper.apache.org/releases.html
在这里插入图片描述
解压:tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz

liushihao06@liushihao06deMacBook-Pro development_tools % cd apache-zookeeper-3.7.0-bin
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % ls
LICENSE.txt		README_packaging.md	docs
NOTICE.txt		bin			lib
README.md		conf
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % cd conf
liushihao06@liushihao06deMacBook-Pro conf % ls
configuration.xsl	log4j.properties	zoo_sample.cfg
liushihao06@liushihao06deMacBook-Pro conf % mv zoo_sample.cfg zoo.cfg 	# 修改zoo_sample.cfg文件名为zoo.cig
liushihao06@liushihao06deMacBook-Pro conf % ls
configuration.xsl	log4j.properties	zoo.cfg

liushihao06@liushihao06deMacBook-Pro conf % vim zoo.cfg 
# 修改配置文件中dataDir=/tmp/zookeeper为dataDir=/opt/module/zookeeper/zkData.  我暂时没有修改

启动:

liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % cd bin
liushihao06@liushihao06deMacBook-Pro bin % ls 	# 最常用的是zkCli.sh、zkServer.sh
README.txt		zkEnv.sh		zkSnapShotToolkit.sh
zkCleanup.sh		zkServer-initialize.sh	zkSnapshotComparer.cmd
zkCli.cmd		zkServer.cmd		zkSnapshotComparer.sh
zkCli.sh		zkServer.sh		zkTxnLogToolkit.cmd
zkEnv.cmd		zkSnapShotToolkit.cmd	zkTxnLogToolkit.sh
liushihao06@liushihao06deMacBook-Pro bin % cd ..

# 服务端
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % bin/zkServer.sh start		# 启动服务端
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/liushihao06/development_tools/apache-zookeeper-3.7.0-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % jps
72353 Launcher
75872 
85831 Jps
85817 QuorumPeerMain	# 服务端进程
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % bin/zkServer.sh status	# 查看服务端状态
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/liushihao06/development_tools/apache-zookeeper-3.7.0-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: standalone	# 单机模式


# 客户端
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % bin/zkCli.sh   # 启动客户端
[zk: localhost:2181(CONNECTED) 1] ls /		# 查看根节点
[zookeeper]
[zk: localhost:2181(CONNECTED) 2] quit		# 退出客户端进程
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % bin/zkServer.sh stop		# 退出服务端进程

https://www.bilibili.com/video/BV1PW411r7iP?p=7

2、安装kafka
下载地址:https://kafka.apache.org/downloads
在这里插入图片描述
解压:
tar -zxvf kafka_2.12-2.8.0.tgz

liushihao06@liushihao06deMacBook-Pro development_tools % cd kafka_2.12-2.8.0
liushihao06@liushihao06deMacBook-Pro kafka_2.12-2.8.0 % ls
LICENSE		bin		libs		site-docs
NOTICE		config		licenses
liushihao06@liushihao06deMacBook-Pro kafka_2.12-2.8.0 % cd config
liushihao06@liushihao06deMacBook-Pro config % ls
connect-console-sink.properties		consumer.properties
connect-console-source.properties	kraft
connect-distributed.properties		log4j.properties
connect-file-sink.properties		producer.properties
connect-file-source.properties		server.properties
connect-log4j.properties		tools-log4j.properties
connect-mirror-maker.properties		trogdor.conf
connect-standalone.properties		zookeeper.properties
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % ls
LICENSE.txt		README_packaging.md	docs
NOTICE.txt		bin			lib
README.md		conf			logs
liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % cd bin
liushihao06@liushihao06deMacBook-Pro bin % ls
README.txt		zkEnv.sh		zkSnapShotToolkit.sh
zkCleanup.sh		zkServer-initialize.sh	zkSnapshotComparer.cmd
zkCli.cmd		zkServer.cmd		zkSnapshotComparer.sh
zkCli.sh		zkServer.sh		zkTxnLogToolkit.cmd
zkEnv.cmd		zkSnapShotToolkit.cmd	zkTxnLogToolkit.sh


liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % bin/zkServer.sh start		# 启动服务端
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/liushihao06/development_tools/apache-zookeeper-3.7.0-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED


liushihao06@liushihao06deMacBook-Pro apache-zookeeper-3.7.0-bin % bin/zkCli.sh		# 启动客户端

kafka的元数据信息都记录在zookeeper上。


六、Kafka数据检索机制

在这里插入图片描述
log.segment.ms:如果花了7天的时间还没写满1GB,仍会创建一个segment。
也就是说,创建一个segment有两个条件;

  1. 数据量大小达到1GB
  2. 时间达到7天

.log为真正的数据文件
.index为数据的索引信息

在这里插入图片描述
00000900.log的数据从00000901开始
1,1235表示偏移量是1(900往后偏移一位),数据是1235
901,1235表示901这条数据对应的值是1235


七、数据的安全性 (七到九是数据从producer到leader过程)

在这里插入图片描述

根据request.required.acks来选择哪种数据安全性。
这个参数可以确定数据会不会丢失。丢失体现在生产者往MQ写数据的时候,应该多久写一次。

At least once:消息绝对不会丢,先发消息再写日志。有可能消息已经发送但是日志中没记录,日志中没记录,那就得重写发送一次。可能会造成重复消费问题。
At most once:先写日志再发消息,日志写好后,从偏移量后面去读。可能会造成消息的丢失。

acks = 0 :producer发送消息给leader,leader收到并确认后producer才会发送下一条消息。如果leader中途宕机,没确认,此时producer就会重新发送消息给leader。这样就造成重复消费问题。
acks = 1:producer不会等leader确认。如果leader宕机,没收到消息,就会造成消息的丢失。
acks = all:producer发送消息给leader,leader要同步消息到所有的follower,leader和所有的follower都确认后producer才能接着发送消息。这样的话效率最低,但是安全性最高。

如何选择acks要看业务,如果你的数据都是日志数据,丢失无所谓,选at most once,如果是银行流失,一定是不能丢的,选at least once。

重复消费可以从代码层面上解决这个问题,比如说收到重复的流水号就不处理了,或者标记出重复的流水号,最后再做二次处理。


八、kafka的ISR机制

在这里插入图片描述

follower从leader中同步数据,但是每个follower同步的数据量或者和leader的差的数据量事不一致的。
这样就会有一个问题,当leader挂掉的时候就要从follower中选一个为主,肯定选同步数据最多的。
那怎样知道哪个follower同步的数据最多呢?kafka想了个办法,维护一个链表,这个链表就叫ISR。
如果leader认为某个follower和他相差无几,就将其维护到ISR链表中去,将来leader挂掉选候选人的时候就会从ISR中去选。
OSR说白了就是和leader相差太多的follower。

ISR的作用是快速从候选节点中选主节点。

在这里插入图片描述
判断标准:
1、follower超过10s没同步数据,就把该follower从ISR中剔除。
2、follower和leader相差4000条数据,就把该follower从ISR中剔除。

脏选举:
当你的leader刚刚收到producer发送的数据,还未来得及同步给follower时候,leader就挂了,这时所有的follower中都没有这条最新的数据。可还得选,这就叫做脏选举(虽然你不完美,但我也只能选你)。


九、Broker的数据存储机制

在这里插入图片描述


十、数据的安全性 (从consumer端如何保证?)

在这里插入图片描述

  • autocommit(exactly once):读到数据和处理数据是有一个时间点的,如果读到后未处理就出现问题,但我已经把业务提交了。这样就会出现丢失数据的问题。

  • 读完消息先commit再处理消息(at most once):读完消息1001后commit,此时consumer group宕机,下次重启后,因为已经commit消息1001,就会认为消息1001已经消费,此时就会消费消息1002。这样会造成消息丢失问题。

  • 读完消息先处理消息再commit(at least once):读完消息1001并处理完后,此时consumer group宕机,下次重启后,因为消息1001还未commit,就会认为消息1001还未消费,此时就会重新读取消息1001并处理完再commit。这样会造成消息的重复消费问题。

at most once 和 at least once 的性能消耗都是比较小的,而exactly once的性能消耗较大。
要做到exactly once,即精确的消费一条数据不丢失也不重复,怎么做呢?
两阶段提交。(待学习)

在这里插入图片描述


十一、Kafka的java代码的实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-玫瑰少年-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值