中间件 - 消息队列 - Kafka

分区管理

分区副本机制

  • 一个topic可以有多个partition , 合理的分区规则设置, 可以均匀分散消息, 实现负载均衡和水平扩展
  • 多个订阅者可以从一个或多个分区中同时消费数据, 以支撑海量数据处理能力 ( 一个partition只能被同组的一个consumer消费 )
  • 消息以追加的方式存储到分区中, 多个分区顺序写磁盘的总效率要比随机写内存还要高, 是高吞吐率的重要保证之一

在这里插入图片描述

分区leader选举

  • 如果某个partition的leader挂了, followers会产生一个新leader,所以的读写都会转移到新leader
  • 并没有采用多数投票赢得选举的机制
  • zookeeper上针对每个topic会维护一个ISR的集合 ( in-sync replica 已同步的副本, 消息落后leader在容忍范围内 )
  • 在ISR集合中, 才有资格被选为leader, 先选第一个做为leader, 如果不行依次类推
  • 假设topic有f+1个副本, kafka可以容忍f个不可用
  • 当然如果ISR里面的副本都不可用, 那么还可以选择OSR ( out-sync replica 消息同步落后超过设置的阈值 ), 但是会存在数据的不一致

分区重新分配

修改副本因子

副本数量

.

kafka存储

kafka是基于scala和java实现的, 均需要在jvm上运行,高吞吐量会造成频繁的GC影响性能
考虑到这些因素, kafka是使用磁盘而不是broker进程内存来进行数据存储, 并且基于磁盘顺序读写和MMAP技术来实现高性能


存储结构介绍

kafka一个topic下可以存在很多个分区, 不考虑分区副本的情况下, 一个分区对应一个日志.
为了防止单个Log文件过大, Kafka又引入日志分段LogSegment的概念, 将Log切分为多个LogSegment, 相当于一个巨型文件被平均分配为多个相对较小的文件, 这样也便于消息的维护和清理
事实上, Log和LogSegment对应于磁盘上的一个日志文件和两个索引文件, 以及可能的其他文件
在这里插入图片描述

1. *.log 日志文件

存储完整的内容, 没啥可讲的

为了提高查找消息的性能,为每一个日志文件添加2个索引索引文件:OffsetIndex 和 TimeIndex, 分别对应着磁盘上两个索引文件,与FileMessageSet共同构成一个LogSegment对象。

2. *.index 偏移量索引文件
  • 每一个索引项为8字节,其中相对offset占用4字节,消息的物理地址(position)占用4个字节
  • 这样就实现了相对offset与物理地址的映射,相对offset表示消息相对于baseOffSet的偏移量,例如分段后的一个日志文件的baseOffset是32450,它的文件名就是32450.log,那么offset为32455的消息在相对offset就是32455-32450 = 5。
  • 另外OffsetIndex是稀疏索引,也就是说不会存储所有的消息的相对offset和position
    在这里插入图片描述
3. *.timeindex 时间戳索引文件

它是映射时间戳和相对offset, 时间戳和相对offset作为entry,供占用12字节,时间戳占用8字节,相对offset占用4字节,这个索引也是稀疏索引,没有保存全部的消息的entry
在这里插入图片描述


消息顺序写入 Producer

不允许删除和修改已写入的消息, 在kafka中只能在日志文件的末尾追加新的消息

通过消费位移offset来决定从哪个位置开始进行消息的消费

在这里插入图片描述

页缓存 Producer

为了再一次提高吞吐量, kafka采用了Memory Mapped Files ( mmap 内存映射文件)
操作系统本身有一层缓存, 叫做page cache, 是在内存里的缓存, 也可以称之为os cache
写入磁盘的时候, 直接写入这个os cache这个内存里, 就可以返回方法了, 接下来由os自己决定什么时候把os cache里的数据真的输入磁盘中(每5秒检查一次是否需要将页缓存数据同步到磁盘文件), 仅仅这一个步骤, 性能就可以提升很多
在这里插入图片描述
我的理解是, kafka为什么会有极高的性能:

  1. 直接写内存, 写partition线程就可以返回了, 后续输入磁盘的事 , 交给os线程去做
  2. 每5秒刷一次磁盘, 避免了频繁刷磁盘, 并且能把5秒内累计的数据, 尽可能的顺序写入磁盘

另外, 网友对于mmap可靠性的分析
从上面实验结果可以判断:

  • 如果使用mmap的进程挂了,写到mmap的数据不会丢失,因为已经写到page-cache;page-cache里面的数据对所有进程都是可见的。
  • 如果是机器挂掉,比如掉电,page-cache里的数据会丢掉;mmap会最多丢失30s左右的数据。
    由于机器挂掉概率较小,而且增量时可以自己做一些msync策略,比如更新1K次之后,主动调用一次msync,这样就可以减少数据丢失。
    有理解不对的,还请大家补充。

零拷贝技术 consumer

普通人的思路

假设什么优化都不做, 那么broker要把消息发送给consumer, 大致要走以下几步

  1. 先看看要读的数据在不在os cache里, 如果不在, 就从磁盘里读取数据放到os cache里
  2. 把 os cache里的数据拷贝到用户态缓存
  3. 用户态缓存再拷贝到操作系统层面的socket缓存里
  4. socket缓存的数据发送到网卡, 最后发给consumer
    在这里插入图片描述

优化后的流程

os cache缓存里的数据, 直接发送给网卡, socket缓存中仅仅会拷贝一个描述符过去, 不会拷贝数据到socket缓存
在这里插入图片描述
简化了两次拷贝的过程

  1. 从os cache拷贝到用户态缓存
  2. 从用户态缓存拷贝到socket缓存
    而且为了这两次拷贝, 需要两个线程, 线程的切换也加剧了性能的损耗
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值