Kafka
Kafka 是一个分布式的基于发布/订阅模式的消息队列
Kafka介绍
目前有两种模式
- 点对点
- 消费者消费数据之后,发送收到,然后清除信息
- 发布,订阅模式
- 有多个主题(流量,点赞,收藏,评论等)
- 消费之后不删除数据(类似于广播模式)
- 信息默认保留7天
- offset保证不重复消费
kafka基本概念
名称 | 解释 |
---|---|
Broker | 消息中间件处理节点,⼀个Kafka节点就是⼀个broker,⼀个或者多个Broker可以组成⼀个Kafka集群 |
Topic | Kafka根据topic对消息进⾏归类,发布到Kafka集群的每条消息都需要指定⼀个topic |
Producer | 消息⽣产者,向Broker发送消息的客户端 |
Consumer | 消息消费者,从Broker读取消息的客户端 |
ConsumerGroup | 每个Consumer属于⼀个特定的Consumer Group,⼀条消息可以被多个不同的Consumer Group消费,但是⼀个Consumer Group中只能有⼀个Consumer能够消费该消息 |
Partition | 物理上的概念,⼀个topic可以分为多个partition,每个partition内部消息是有序的 |
Broker
因为kafka通常时进行分布式部署,所以一个物理服务器(一个操作系统)通常只部署启动一个kafka实例,所以在这种场景下Broker代理就可以理解是一台服务器
主题与主题分区
topic国内叫做主题,可以理解为一个MQ消息队列的名字
topic可以实现消息的分类,不同消费者订阅不同的topic
为了实现扩展性,一个非常大的topic可以分布到多个 broker(即服务器)上,一个topic(主题)可以分为多个partition(分区)
每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体 (多个partition间)的顺序
分区的作用
- 可以分布式存储
- 可以并行写
分区只能增加,不能减少
分区是一个实实在在的物理存在的队列数据结构用于存放数据,占用系统内存以及磁盘数据存储等资源。
消费者组
为了配合分区,就有了消费者组,同一组内每个消费者并行消费(比如一个消费者只能消费其中一个分区)
多个消费同一主题Topic数据的消费者线程,可以组成一个消费者组
一个消费者组可以订阅多个主题,消费多个主题下的数据
但是别的消费者组也能对这些分区进行消费(广播模式)
形成一个组的条件,所有消费者的分组id相同
- 组内消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费
- 消费者组之间互不影响,消费者组是逻辑上的一个订阅者
分区副本与高可用
分区可以设置备份,叫做副本
副本可以分布到多个broker上
为了高可用,给分区添加副本
默认生产和消费主分区(leader),主分区挂了,副本(follower)成为主分区
- kafka集群中由多个broker组成
- 一个broker中存放一个topic的不同partition——副本
分区副本的数据同步
生产者和消费者只和主分区进行数据通信,那么从副本的数据从哪里来的?从副本( Follower )的数据是从主副本(Leader)那里同步过来的
一般生产环境只分配2个副本,保证磁盘不浪费 ,也保证了高可用
2.8版本之前,kafak元数据存储到zookeeper中,需要zookeeper集群
zookeeper作用
- 记录了哪些分区上线了
- 记录每个分区,哪个是leader
2.8版本之后,官方宣告4.0正式弃用zookeeper,可以配置不采用zookeeper
- kraft模式替代zookeeper
isr,ar,osr
Ar = 所有副本统称
isr = 和leader保持同步的follower集合
isr中如果follower长时间未向leader发送通信请求或同步数据,将被提出isr放到osr中,默认是30秒
osr = follower和leader副本同步时,延迟过多的副本
故障处理细节
LEO(long end offset):多个副本最后一个offset,leo其实就是最新的offset+1
HW(hign watermark高水位线):isr中最小的leo(木桶原理),每个副本都有的
follower挂掉之后:
- 被踢出isr
- leader和其他follower继续接受数据
- 故障follower恢复后,读取本地磁盘记录的上次hw线,并将log文件高于hw的部分截取掉,从hw开始进行同步
- 等故障的leo大于等于分区的hw线时,重新加入isr
leader挂掉:
- 从isr选出新的leader
- 为了保证副本之间数据的一致性,其余的follower先将各自的log文件高于hw的部分截取掉,从新的leader同步
文件存储机制
topic是逻辑概念,partition是物理概念,每个分区对应一个log文件,
存储的是producer生产的数据,会不断的追加到log文件末尾,
为了防止log文件过大导致数据定位效率低下,采取了分片和索引机制
将每个分区分为多个segment(分段),
每个分段包括(默认是1g大小)
- .index文件,为了快速定位数据,创建索引
- index为稀疏索引,大约每往log文件写入4kb数据,会往index文件写入一条索引
- .log文件等 真正存储数据的文件
- index和log文件以当前segment的第一条消息的offset命名
- 这些文件都放在一个文件夹下,topic名称+分区序号,比如first-0
高效读写
kafka天生是分布式集群,采用分区技术,并行度高
数据采用稀疏索引,可以快速定位要消费的数据
顺序写磁盘
- 写的过程是一直追加到文件末端,官网数据表明,顺序写能达到600m一秒,随机写只有100k,因为省去了大量磁头寻址时间
零拷贝技术
- 数据加工处理交给生产者和消费者处理,broker应用层不关心存储的数据,所以不用走应用层,效率高
非零拷贝工作流程
- 生产者发送到kafka,然后交给内核,内核进行页缓存
- 依赖底层操作系统的pageCache功能,有写操作时,将数据写入pagecache,读操作时,先从pageCache查找,找不到,在去磁盘中读取
- 消费者拉取数据,走了用户态
- 然后内核态再通过网卡发送给消费者
零拷贝
- 生产者发送到kafka,然后交给内核,内核进行页缓存
- 依赖底层操作系统的pageCache功能,有写操作时,将数据写入pagecache,读操作时,先从pageCache查找,找不到,在去磁盘中读取
- 然后内核态再通过网卡发送给消费者
kraft模式
2.8之前
元数据存在zookeeper中,动态选举controller,由controller进行kafak集群管理
2.8之后
kraft,不依赖zookeeper集群,使用三台controller节点代替zookeeper,元数据保存在controller中,由controller直接进行kafak集群管理
RabbitMq和kafak区别
同样是消息队列,之前都是用的RabbitMq,现在做一个比较
Rabbit配置少,kafka需要依赖zookeeper集群,配置多
看业务,假设需要延迟消息的功能
-
RabbitMq有ttl机制,可以很方便的完成这个功能
-
Kafka 要实现延迟队列就很麻烦了。
-
你先需要把消息先放入一个临时的 topic。
-
然后得自己开发一个做中转的消费者。让这个中间的消费者先去把消息从这个临时的 topic 取出来。
-
取出来,这消息还不能马上处理啊,因为没到时间呢。也没法保存在自己的内存里,怕崩溃了,消息没了。所以,就得把没有到时间的消息存入到数据库里。
-
存入数据库中的消息需要在时间到了之后再放入到 Kafka 里,以便真正的消费者去执行真正的业务逻辑。
-
数据的处理
- RabbitMQ消息消费之后就会被删除
- Kafka 消息会被持久化一个专门的日志文件里。不会因为被消费了就被删除。可以根据offset选择位置消费
消息监控
- RabbitMQ自带监控
- Kafka 需要安装Efak进行一个监控