关于Kafka消息队列原理的总结

目录
  • Kafka消息队列原理
    • Kafka的逻辑数据模型
    • Kafka的分发策略
    • Kafka的物理存储模型和查找数据的设计
    • Kafka的持久化策略设计
    • Kafka的节点间的数据一致性策略设计
    • Kafka的备份和负载均衡
  • Kafka消息队列内部实现原理

Kafka消息队列原理

最近在测试kafka的读写性能,所以借这个机会了解了kafka的一些设计原理,既然作为分布式系统,我们还是按照分布式的套路进行分析。

Kafka的逻辑数据模型

生产者发送数据给服务端时,构造的是ProducerRecord<Integer, String>(String topic, Integer key,String value)对象并发送,从这个构造函数可以看到,kafka的表面逻辑数据模型是key-value。

当然api再发送前还会在这个基础上加入若干校验信息,不过这个对用户而言是透明的。

Kafka的分发策略

跟很多分布式多备份系统类似,kafka的基本网络结构如下:

一个节点(Broker)中存有不同partition的备份,一个parittion存在多份备份保存在不同节点上并且选举出一个作为leader跟客户端交互,一个topic拥有多个parittion。

默认的kafka分发算法是hash(key)%numPartitions,简单来就是哈希再取模。当然这个算法可以自定义,只要重写相关接口。

如上图在一个四台主机上创建了一个有两个备份,四个分区partion的话题topic,但生产者需要发送某个key-value对象到消息队列里面时,创建连接时通过访问zookeeper,获取到一份leader partion列表(Broker1. Partition-0, Broker2. Partition1, Broker3. Partition-2, Broker4.Partition-3),再根据分发算法计算出这个对象应该要发送到哪个leader partion中。

Kafka的物理存储模型和查找数据的设计

Kafka的物理存储模型比较简单,在kafka的物理持久化的存储中有分Segment的概念,每个Segment有两种类型的文件:索引文件***.index和日志文件(数据文件)***.log。两者的命名规则都是以这个Segment的第一条的消息逻辑偏移量作为文件名。索引是稀疏索引,目的在于减少索引文件的数据量,其文件的内容是key-value结构,key是消息的偏移量offeset(就是一个自增的序列号),value是对应的log文件的实际物理磁盘偏移量。

值得一提的是,跟其他正常分布式不一样,kafka并不支持根据给定的key查找该key对应的value值的能力,某种意义而言,逻辑数据模型中的key只是用来实现分发计算用的,所以使用kafka查找数据只能以指定消息的偏移量的放松实现。

整个查找过程:当要查找offset=888及后续的消息时,kafka先到该节点上找到对应的Segment。通过该Segment的index文件上用二分查找的方法找到最接近offset=888的纪录,比如886,然后找到886对应的物理磁盘偏移量999,这样就从log的磁盘偏移量找起,连续遍历了两个消息后就能找到888这个消息的数据(log文件中保留了每条消息的逻辑偏移量,长度和数据)。

Kafka的持久化策略设计

Kafka的持久化设计是非常有特色的,和其他分布式系统不同,它没有自己维护一套缓存机制,而是直接使用了操作系统的文件系统(操作系统的文件系统自带pagecache)。这样的好处是减少了一次内存拷贝的消耗。其他分布式系统比如cassandra,自己在服务端维护了一份数据缓冲内存块datacache,当需要持久化时再调用操作系统的文件系统写入到文件中,这样就多了一次datacache到pagecache的拷贝消耗。这样的话,kafka的持久化管理关键是管理文件系统的pagecache的刷盘。

由于kafka采用了这种特别的持久化策略,所以在kafka中并没有其他分布式系统的重做日志。所以kafka在出现故障后的数据恢复策略有自己的一套:首先,kafka会通过配置文件配置pagecache定时或者定量刷盘的频率以保证即使出现故障也能把丢失的数据降低到最少。其次,pageche本身是操作系统管理维护的,跟kafka自身的服务进程没有关系,如果是kafka本身挂了的话,重启后还是能访问到pageche中的数据的。最后如果很不幸是kafka所在的一个节点的主机挂掉的话,那么重启主机和kafka后也可以从其他备份节点重新同步丢失的数据。

Kafka高性能的和持久化策略关系非常密切,这部分内容,也是整个kafka设计的精髓所在:

传统的观念认为磁盘的读写是非常低效的,所以一般系统都会自己管理一块内存datacache充当磁盘的缓存,只有需要的时候才去和磁盘交互。

但是实际上,磁盘的低效的原因不在于磁盘io,而在于磁头的随机寻址。如果数据是顺序读写的话(也就是一次磁头寻址,连续io),其实速度是非常快的((Raid-5,7200rpm):顺序 I/O: 600MB/s)。

而在传统的设计中虽然加入了内存作为缓存,但是为了保证数据的安全性还是得提供一份重做日志(每次的修改操作都要记录在重做日志redo.log中,以保证内存丢失后能根据重做日志进行恢复),并且当datacache里面的数据达到一定容量时刷新到磁盘的data文件中。

但是kafka并没有使用这套常规设计,并没有自己维护一套datacache而是另辟蹊径,直接使用操作系统中的文件系统,并利用文件系统原有的pagecache作为数据缓存。

减少了datacache到pagecache的拷贝消耗。并且顺序地进行磁盘io,这样大大提高了kafka写数据时持久化的效率。

对于kafka的读数据这块,kafka也使用了Sendfile技术来提高读的效率,传统的读方案是读取磁盘的数据到pagecache中,然后从pagecache拷贝一份到用户进程的datacache中,datacache再拷贝到内核的socket缓存区中,最后从socket缓存区拷贝数据到网卡中发送。而Sendfile技术跳过了用户进程的datacache这一环节,直接读取磁盘的数据到pagecache中,然后从pagecache拷贝一份到socket缓存区中,最后从socket缓存区拷贝数据到网卡中发送。整个过程减少了两次拷贝消耗。

Kafka的节点间的数据一致性策略设计

对于任何多节点多备份的分布式系统而言,数据的一致性问题都是绕不开的难点,一般的选择是要么优先考虑效率,这样可能就造成数据不一致甚至是数据丢失,要么选择保障数据一致性和数据安全性牺牲效率。在kafka的身上也存在这样的矛盾。

Kafka是一种分partion,多节点多备份的分布式系统,每个partion都可以存在多份备份,每个备份在不同的节点上。多个备份中会根据zookpeer的注册信息通过算法选举出其中一份作为leader,这个leader负责和客户端的读写访问进行交互。

其他备份不参与跟客户端的交互。而是去跟leader partion交互同步数据。这样一来就可能出现主备之间数据不一致的情况。Kafka在客户端提供了一个配置选项props.put("acks", "all");--其中all表示生产者等待确认所有的备份数据都写入pagecache后再返回。

可以设置为0(不等待任何确认),1(leader确认)或者其他小于备份数的数字。其他备份节点会异步去同步leader partion的数据,保持一致,当然如果在同步的过程中,leader partion出现数据丢失,那么这部分数据将永远丢失。

Kafka的备份和负载均衡

Kafka的备份很明显,上文已经说过是通过讨论一致性问题已经交待清楚,至于Kafka的负载均衡,个人发现是严重依赖于zookeeper上的注册信息,通过一套算法来选取leader partion来实现kafka多节点的负载均衡。

Zookeeper中保存了kafka几乎一切的重要信息,比如topic,每个topic下面的多个partion信息,主机节点信息(包括ip和端口),每个节点下的多个partion信息,每个partion的主备份信息,消费客户端的group_id分组信息,每个消费者信息等。

通过这一堆信息进行算法计算最后得出负载均衡的方案,主要体现是选出让kafka效率性能达到最好的每个partion的leader。并且在zookeeper中注册监视器,一旦发现上述信息有变动则更新负载均衡方案。

Kafka消息队列内部实现原理

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 消息队列-kafka消费异常问题

    目录 概述 重试一定次数(消息丢失) 加入到死讯队列(消息不丢失) 总结 概述 在kafka中,或者是说在任何消息队列中都有个消费顺序的问题.为了保证一个队列顺序消费,当当中一个消息消费异常时,必将影响后续队列消息的消费,这样业务岂不是卡住了.比如笔者举个最简单的例子:我发送1-100的消息,在我的处理逻辑当中 msg%5==0我就进行 int i=1/0操作,这必将抛异常,一直阻塞在msg=5上,后面6-100无法消费.下面笔者给出解决方案. 重试一定次数(消息丢失) @KafkaHandle

  • Spring boot 整合KAFKA消息队列的示例

    这里使用 spring-kafka 依赖和 KafkaTemplate 对象来操作 Kafka 服务. 一.添加依赖和添加配置项 1.1.在 Pom 文件中添加依赖 <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> 1.2.添加配置项 spring: kafka: b

  • 大数据Kafka:消息队列和Kafka基本介绍

    目录 一.什么是消息队列 二.消息队列的应用场景 异步处理 应用耦合 限流削峰 消息驱动系统 三.消息队列的两种方式 点对点模式 发布/订阅模式 四.常见的消息队列的产品 1) RabbitMQ 2) activeMQ: 3) RocketMQ 4) kafka 五.Kafka的基本介绍 一.什么是消息队列 消息队列,英文名:Message Queue,经常缩写为MQ.从字面上来理解,消息队列是一种用来存储消息的队列 .来看一下下面的代码 上述代码,创建了一个队列,先往队列中添加了一个消息,然后

  • Kafka中消息队列的两种模式讲解

    目录 Kafka消息队列的两种模式 1.点对点模式 2.发布/订阅模式 Kafka消息队列模型 Kafka消息队列的两种模式 消息队列包括两种模式,点对点模式(point to point, queue)和发布/订阅模式(publish/subscribe,topic) 1.点对点模式 点对点模式下包括三个角色: 消息队列 发送者 (生产者) 接收者(消费者) 消息发送者生产消息发送到queue中,然后消息接收者从queue中取出并且消费消息.消息被消费以后,queue中不再有存储,所以消息接收

  • kafka 消息队列中点对点与发布订阅的区别说明

    目录 背景知识 1.JMS中定义 2.二者分析与区别 2.1 点对点模式 2.2 发布订阅模式 3.流行的消息队列模型比较 3.1 RabbitMQ 3.2 Kafka 背景知识 JMS一个在 Java标准化组织(JCP)内开发的标准(代号JSR 914).2001年6月25日,Java消息服务发布JMS 1.0.2b,2002年3月18日Java消息服务发布 1.1. Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM

  • 关于Kafka消息队列原理的总结

    目录 Kafka消息队列原理 Kafka的逻辑数据模型 Kafka的分发策略 Kafka的物理存储模型和查找数据的设计 Kafka的持久化策略设计 Kafka的节点间的数据一致性策略设计 Kafka的备份和负载均衡 Kafka消息队列内部实现原理 Kafka消息队列原理 最近在测试kafka的读写性能,所以借这个机会了解了kafka的一些设计原理,既然作为分布式系统,我们还是按照分布式的套路进行分析. Kafka的逻辑数据模型 生产者发送数据给服务端时,构造的是ProducerRecord<In

  • 通过pykafka接收Kafka消息队列的方法

    没有Kafka环境,所以也没有进行验证.感觉今后应该能用到,所以借抄在此,备查. pykafka使用示例,自动消费最新消息,不重复消费: # -* coding:utf8 *- from pykafka import KafkaClient host = '192.168.200.38' client = KafkaClient(hosts="%s:9092" % host) print client.topics # 生产者 # topicdocu = client.topics['

  • PHP高级编程之消息队列原理与实现方法详解

    本文实例讲述了PHP高级编程之消息队列原理与实现方法.分享给大家供大家参考,具体如下: 1. 什么是消息队列 消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式 2. 为什么使用消息队列 消息队列技术是分布式应用间交换信息的一种技术.消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读出.通过消息队列,应用程序可独立地执行,它们不需要知道彼此的位置.或在继续执行前不需要等待接收程序接收此消息. 3. 什么场合使用消息队列 你首先需要弄清楚,消息

  • Java分布式学习之Kafka消息队列

    目录 介绍 Kafka核心相关名称 kafka集群安装 kafka使用 kafka文件存储 Springboot整合kafka 介绍 Apache Kafka 是分布式发布-订阅消息系统,在 kafka官网上对 kafka 的定义:一个分布式发布-订阅消息传递系统. 它最初由LinkedIn公司开发,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目.Kafka是一种快速.可扩展的.设计内在就是分布式的,分区的和可复制的提交日志服务. 注意:Kafka并没有遵循JMS规范(

  • KOA+egg.js集成kafka消息队列的示例

    Egg.js : 基于KOA2的企业级框架 Kafka:高吞吐量的分布式发布订阅消息系统 本文章将集成egg + kafka + mysql 的日志系统例子 系统要求:日志记录,通过kafka进行消息队列控制 思路图: 这里消费者和生产者都由日志系统提供 λ.1 环境准备 ①Kafka 官网下载kafka后,解压 启动zookeeper: bin/zookeeper-server-start.sh config/zookeeper.properties 启动Kafka server 这里conf

  • 浅谈Java消息队列总结篇(ActiveMQ、RabbitMQ、ZeroMQ、Kafka)

    一.消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ. 二.消息队列应用场景 以下介绍消息队列在实际应用中常用的使用场景.异步处理,应用解耦,流量削锋和消息通讯四个场景. 2.1异步处理 场景说明:用户注册后,需要发注册邮件和注册短信.传统的做法有两种 1.串行的方式;2.并行方式 a.串

随机推荐