共计 3408 个字符,预计需要花费 9 分钟才能阅读完成。
文|孙超
网易智慧企业资深后端开发工程师
官网定义
依据官网的介绍,kafka 是一个提供对立的、高吞吐、低提早的,用来解决实时数据的流式平台,它具备以下三个性:
- 流式记录的公布和订阅:相似于音讯零碎。
- 存储:在一个分布式、容错的集群中平安长久化地存储流式数据。
- 解决:编写流解决应用程序,对实时事件进行响应。
kafka 个别用在两大类利用中:
- 建设实时流数据管道,在零碎或利用之间实时地传输数据。
- 构建对数据流进行转换和解决的实时流应用程序。
在邮箱服务中,咱们次要将 kafka 作为音讯零碎,用于零碎内部消息的传输。为什么要采纳 kafka 呢?让咱们先从 kafka 的设计原理说起。
概念与存储机制
kafka 中是以 Topic 机制来对音讯进行分类的,同一类音讯属于同一个 Topic,你能够将每个 Topic 看成是一个音讯队列。生产者将音讯发送到相应的 Topic,而消费者通过从 Topic 拉取音讯来生产,没错,在 kafka 中是要求消费者被动拉取音讯生产的,它并不会被动推送音讯,这是它的一个特点,为什么会这样设计呢?咱们前面再说,先来看一下 Topic 的构造:
Partition 分区 , 每个 topic 能够有多个分区,这是 kafka 为了进步并发量而设计的一种机制:一个 topic 下的多个分区能够并发接管音讯,同样的也能供消费者并发拉取音讯,即分区之间互不烦扰,这样的话,有多少个分区就能够有多大的并发量。所以,如果要更精确的打比方,一个分区就是一个音讯队列,只不过这些音讯队列同属于一种音讯分类。
在 kafka 服务器,分区是以目录模式存在的,每个分区目录中,kafka 会按配置大小或配置周期将分区拆分成多个段文件(LogSegment), 每个段由三局部组成:
- 磁盘文件:*.log
- 位移索引文件:*.index
- 工夫索引文件:*.timeindex
其中 *.log 用于存储音讯自身的数据内容,*.index存储音讯在文件中的地位(包含音讯的逻辑 offset 和物理存储 offset),*.timeindex存储音讯创立工夫和对应逻辑地址的映射关系。
段文件结构图如下:
将分区拆分成多个段是为了管制存储的文件大小,如果整个分区只保留为一个文件,那随着分区里音讯的增多,文件也将越来越大,最初不可管制。而如果每个音讯都保留为一个文件,那文件数量又将变得微小,同样容易失去管制。所以 kafka 采纳段这种形式,管制了每个文件的大小,也不便管制所有文件的数量。同时,这些文件因为大小适中,能够很不便地通过操作系统 mmap 机制映射到内存中,进步写入和读取效率。这个设计的另一个益处是:当零碎要革除过期数据时,能够间接将过期的段文件删除,十分简洁。
然而这里也会有一个问题:如果每个音讯都要在 index 文件中保留地位信息,那么 index 文件也很容易变得很大,这样又会削弱上文所说的益处。所以在 kafka 中,index 设计为稠密索引来升高 index 的文件大小,这样,index 文件存储的理论内容为:该段音讯在音讯队列中的绝对 offset 和在 log 文件中的物理偏移量映射的稠密记录。
那么多少条音讯会在 index 中保留一条记录呢?这个能够通过系统配置来进行设置。索引记录固定为 8 个字节大小,别离为 4 个字节的绝对 offset(音讯在 partition 中全局 offset 减去该 segment 的起始 offset),4 个字节的音讯具体存储文件的物理偏移量。
index 文件结构图如下:
Kafka 不会在消费者拉取完音讯后马上就清理音讯,而是会保留段文件一段时间,直到其过期再标记为可清理,由后台程序定期进行清理。这种机制使得消费者能够反复生产音讯,满足更灵便的需要。
查问机制
下面说过,kafka 尽管作为音讯零碎,然而生产音讯并不是通过推送而是通过拉取来生产的,client 须要通过 offset 和 size 参数被动去查问音讯。
kafka 收到客户端申请后,对音讯的寻址会通过上面几个步骤:
- 查找具体的 Log Segment,kafka 将段信息缓存在跳跃表中,所以这个步骤将从跳跃表中获取段信息。
- 依据 offset 在 index 文件中进行定位,找到匹配范畴的偏移量 position,此时失去的是一个近似起始文件偏移量。
- 从 Log 文件的 position 地位处开始往后寻找,直到找到 offset 处的音讯。
kafka 读取示意图:
RabbitMQ vs kafka
介绍了 kafka 的实现原理,咱们再来比照一下同样作为音讯队列服务的 RabbitMQ。MQ 的利用也很宽泛,性能多而全,那么和 MQ 相比,kafka有哪些劣势呢?为什么咱们会应用 kafka 而摈弃了 RabbitMQ 呢?
RabbitMQ 流程图:
RabbitMQ 消费者只能从队列头部按序进行生产,音讯一旦被生产,就会被打上删除标记,紧接着生产下一条音讯,没方法进行回溯操作,这样的话一个消费者生产完音讯,另一个消费者就别想再生产了。而 Kafka 提供动静指定生产位点,可能灵便地进行回溯生产操作,只有该音讯还在生命周期内能够反复拉取,并且不同消费者能够互不烦扰的生产同一个音讯队列,这就比 RabbitMQ 灵便多了。
kafka 生产位点示意图:
RabbitMQ 如果要满足多个消费者生产同一个音讯队列,也能够借助 exchange 路由能力,然而这样会将音讯复制到多个队列,每个消费者须要绑定一个本人的队列进行生产。如果有几百个消费者,那么队列复制几百倍,引起 mq 的音讯水位猛涨,容易失控。而 kafka 就没这个问题,不论多少个消费者都只须要一个队列就能满足,每个消费者都能够残缺地不互相烦扰地生产队列中的所有音讯。
当然,RabbitMQ 也有其长处,它提供的 exchange,binding, queue 等形象实体,提供弱小的路由关系 (rounte key and bindkey) 和音讯过滤能力。作为传统音讯零碎提供了细粒度的音讯控制能力。而 Kafka 次要是面向高流量,大吞吐的批处理零碎,在路由形象方面化繁为简,重点关注零碎的高吞吐,所以应用上更为简洁。
kafka 还有传统解决方案无奈满足的高伸缩能力等劣势,这里就不一一介绍了。
Kafka 在邮件系统 data bus 中的使用
正因为 kafka 有着以上介绍的能力和劣势,咱们的邮箱服务中采纳了它作为音讯零碎,其中一个利用就是邮件系统的 data bus。
data bus 介绍
邮件系统用户收发信流程随同着大量的业务逻辑和子系统调用,如果将这些流程都强附丽在骨干枝上,将会对系统造成较大的压力,整个业务流程也将变得复杂而迟缓。所以通过数据总线将主次流程进行解耦,加重收发信主流程的复杂度,使其能够以更快的速度实现,放慢零碎响应工夫。主流程产生事件源,通过 kafka 的传输,触发多个主要流程,主要流程能够并发在零碎后盾实现,并且能够轻易的扩大多种多样的主要流程。
下图以简化后的信流程为例:
Kafka 在 data bus 中的使用
邮件系统在实现收发信流程后,会生成当次流程相干的零碎事件,比方新邮件事件。data bus 将这些事件写入到 kafka 集群的相应 topic 中,上游的一系列子系统对 topic 进行生产。
- 每个不同的流程会对应不必的 topic,以辨别不同类别的事件,比方新进邮件,邮件已读,邮件删除等。
- 每个 topic 能够依据各自的音讯吞吐量和并发需要划分成多个 partition,比方新进邮件量大能够划分成256 个分区,邮件删除量小则能够划分32 个分区。
- 每个事件按什么机制来调配到相应的分区呢?一般来说能够按邮筒来划分,同一个邮筒的事件进入同一个 partition,这样就保障了同一邮筒产生的事件的程序。
- 不同事件的时效性可能有不同,所以其须要保留的工夫也能够不同,能够依据业务的需要来设置 topic 的保留时长。
- 因为事件全副写入到 kafka 中,后台任务能够任意生产,所以能够灵便地减少不同的业务流程。
如下图所示,利用生产能力能借助 Kafka 集群实现弹性扩容
总 结
kafka 在邮件系统中的利用给咱们带来的益处:
- 时延敏感型业务: 通过进步业务 Topic 的 Partition 数量,一来留下了较好的机器扩容的空间,另一方面也能够通过进步消费者并发线程数来晋升利用整体生产速度,缩小时延。
- 慢速型业务: 有些不关怀时效性的上游业务,在思考音讯生命周期等因素,能够很好地利用 Kafka 的音讯沉积能力,磁盘存储能力,削峰填谷,让生产流速适应本人的解决能力,不至于因为忽然间的大量音讯冲击而解体。