深入理解Kafka(一)之基础概念

简介

Kafka是用scala语言编写,最初由Linkedin公司开发,后贡献给了Apache基金会并成为顶级开源项目。是一个分布式、支持分区的(partition)、多副本的(replication),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等。
Kafka是一个类JMS消息队列,结合了JMS中的两种模式,可以有多个消费者主动拉取数据。虽然它提供了类似于JMS的特性,但是在设计实现上完全不同,此外它并不是JMS规范的实现,在JMS中只有点对点模式才有消费者主动拉取数据。
特性

特性

  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partitionconsumer grouppartition 进行consume操作。
  • 可扩展性:kafka集群支持热扩展
  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
  • 高并发:支持数千个客户端同时读写
  • 顺序性:由生产者发送到一个特定的主题分区的消息将被以他们被发送的顺序来追加。也就是说,
    如果一个消息M1和消息M2都来自同一个生产者,M1先发,那么M1将有一个低于M2的偏移,会更早在日志中出现。
    消费者看到的记录排序就是记录被存储在日志中的顺序。

设计思想

动机

各种应用系统诸如商业、社交、搜索、浏览等像信息工厂一样不断的生产出各种信息,在大数据时代,我们面临如下几个挑战:

  • 如何收集这些巨大的信息

  • 如何分析它

  • 如何及时做到如上两点

    以上几个挑战形成了一个业务需求模型,即生产者生产(produce)各种信息,消费者消费(consume)(处理分析)这些信息,而在生产者与消费者之间,需要一个沟通两者的桥梁-消息系统。从一个微观层面来说,这种需求也可理解为不同的系统之间如何传递消息
    1.Kafka 必须具有高吞吐量来支持高容量事件流,例如实时日志聚合;
    2.Kafka 需要能够正常处理大量的数据积压,以便能够支持来自离线系统的周期性数据加载;
    具有低延迟、分区、分布式、实时处理以及容错。

基础概念

Broker

kafka 集群由多个 kafka 实例组成,每个实例 (server) 称为 broker ,在集群中每个broker都有一个唯一brokerid,不得重复。 无论是 kafka 集群,还是 producer 和 consumer 都依赖于 zookeeper 来保证系统可用性,为集群保存一些 meta (元数据)信息。

Topics/Log

Topic 就是数据主题,是数据记录发布的地方,可以用来区分业务系统。Kafka中的Topics总是多订阅者模式,一个topic可以拥有一个或者多个消费者来订阅它的数据。
对于每一个topicKafka集群都会维持一个分区日志,如下所示:
在这里插入图片描述

每个分区都是有序且顺序不可变的记录集,并且不断地追加到结构化的commit log文件。分区中的每一个记录都会分配一个id号来表示顺序,我们称之为offsetoffset用来唯一的标识分区中每一条记录。
Kafka 集群保留所有发布的记录—无论他们是否已被消费—并通过一个可配置的参数——保留期限来控制. 举个例子, 如果保留策略设置为2天,一条记录发布后两天内,可以随时被消费,两天过后这条记录会被抛弃并释放磁盘空间。Kafka的性能和数据大小无关,所以长时间存储数据没有什么问题.

在这里插入图片描述

事实上,在每一个消费者中唯一保存的元数据是offset(偏移量)即消费在log中的位置.偏移量由消费者所控制:通常在读取记录后,消费者会以线性的方式增加偏移量,但是实际上,由于这个位置由消费者控制,所以消费者可以采用任何顺序来消费记录。例如,一个消费者可以重置到一个旧的偏移量,从而重新处理过去的数据;也可以跳过最近的记录,从"现在"开始消费。
这些细节说明Kafka 消费者是非常廉价的—消费者的增加和减少,对集群或者其他消费者没有多大的影响。比如,你可以使用命令行工具,对一些topic内容执行 tail操作,并不会影响已存在的消费者消费数据。

offset

Kafka 消费者端有位移( offset)的概念。

  • 每条消息在某个 partition 的位移是固定的,但消费该 partition 的消费者的位移会随着消费进度不断前移
  • 消费者位移不可能超过该分区最新一条消息的位移 。
    Kafka 中的一条消息其实就是一个<topic,partition,offset>三元组(tuple),通过该元组值我们可以在 Kafka 集群中找到唯一对应的那条消息。
    在这里插入图片描述

Partition

topic 物理上的分组,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列(分区可以间接理解成数据库的分表操作)
一般来说:
(1)一个 TopicPartition 数量大于等于 Broker 的数量,可以提高吞吐率。
(2)同一个 PartitionReplica 尽量分散到不同的机器,高可用。
日志中的 partition(分区)有以下几个用途:

第一,当日志大小超过了单台服务器的限制,允许日志进行扩展。每个单独的分区都必须受限于主机的文件限制,不过一个主题可能有多个分区,因此可以处理无限量的数据。

第二,可以作为并行的单元集。

Producer

生产者可以将数据发布到所选择的topic(主题)中。生产者负责将记录分配到topic的哪一个 partition(分区)中。可以使用循环的方式来简单地实现负载均衡,也可以根据某些语义分区函数(例如:记录中的key)来完成。
默认是:

defaultPartition Utils.abs(key.hashCode) % numPartitions

Consumer

每个 Consumer 进程都会划归到一个逻辑的Consumer Group中,逻辑的订阅者是Consumer Group,同一个 Consumer Group 中的 Consumer 可以在不同的程序中,也可以在不同的机器上。所以一条message可以被多个订阅该 message 所在的topic的每一个Consumer Group 所消费,也就好像是这条message被广播到每个Consumer Group一样。而每个Consumer Group中,类似于一个QueueJMS中的Queue)的概念差不多,即topic中的一条message只会被Consumer Group中的一个Consumer消费
在这里插入图片描述

replia

partition 是有序消息日志,为了实现高可靠性,Kafka保存了多个备份日志,在 Kafka 中被称为副本( replica ),它们存在的唯一目的就是防止数据丢失。副本分为两类 : 领导者副本( leader replica )和追随者副本( follower replica

  • leader 对外提供服务
  • follower 只是被动地追随 leader 的状态,保持与 leader 的同步。follower 存在的唯一价值就是充当 leader的候补:一旦 leader 挂掉立即就会有一个追随者被选举成为新的 leader 接替它的工作。

ISR

kafkaISR是什么?
在zk中会保存ARAssigned Replicas)列表,其中包含了分区所有的副本,其中 AR = ISR+OSR
ISRin sync replica):是kafka动态维护的一组同步副本,在ISR中有成员存活时,只有这个组的成员才可以成为leader,内部保存的为每次提交信息时必须同步的副本(acks = all时),每当leader挂掉时,在ISR集合中选举出一个follower作为leader提供服务,当ISR中的副本被认为坏掉的时候,会被踢出ISR,当重新跟上leader的消息数据时,重新进入ISR
OSRout sync replica): 保存的副本不必保证必须同步完成才进行确认,OSR内的副本是否同步了leader的数据,不影响数据的提交,OSR内的follower尽力的去同步leader,可能数据版本会落后。
什么情况下OSR中的replica会重新加入到ISR

replica重新追上leader的时候,会回到ISR中
LEOlast end offset):当前replica存的最大的offset的下一个值,LEO=10,则表示在该副本日志上已经保存了10条消息,偏移量范围为[0,9]
HWhigh watermark):俗称高水位,小于 HW 值offset所对应的消息被认为是「已提交」或「已备份」的消息,才对consumer可见,offset只能拉取这个offset之前的消息。任何一个副本对象的HW的值一定不大于其LEO的值(这里强调的是同一个副本的HW和LEO大小的比较)

  • leader HW值 = 所有副本LEO最小值
  • follower HW值 =min(follower自身LEO 和 leader HW)
    在这里插入图片描述

HW能保证数据的一致性

LSO

在这里插入图片描述
如上图所示,它代表一个日志文件,这个日志文件中有 9 条消息,第一条消息的 offset( logStartOffset)为 0,最后一条消息的 offset 为 8,offset 为 9 的消息用虚线框表示,代表下一条待写入的消息。日志文件的 HW 为 6,表示消费者只能拉取到 offset 在 0 至 5 之间的消息, 而 offset 为 6 的消息对消费者而言是不可见的。

LWLow Watermark 的缩写,俗称“低水位”,代表 AR 集合中最小的 logStartOffset 值。副本的拉取请求(FetchRequest,它有可能触发新建日志分段而旧的被清理,进而导致 logStartOffset 的增加)和删除消息请求(DeleteRecordRequest)都有可能促使 LW 的增长。

Kafka 的日志管理器中会有一个专门的日志删除任务来周期性地检测和删除不符合保留条件的日志分段文件,这个周期可以通过 broker 端参数 log.retention.check.interval.ms来配置,默认值为 300000,即 5 分钟。当前日志分段的保留策略有 3 种:基于时间的保留策略、基于日志大小的保留策略和基于日志起始偏移量的保留策略。而“基于日志起始偏移量的保留策略”正是基于 logStartOffset来实现的。

一般情况下,日志文件的起始偏移量 logStartOffset 等于第一个日志分段的 baseOffset,但这并不是绝对的,logStartOffset 的值可以通过 DeleteRecordsRequest 请求(比如使用 KafkaAdminClientdeleteRecords()方法、使用 kafka-delete-records.sh 脚本、日志的清理和截断等操作进行修改。

基于日志起始偏移量的保留策略的判断依据是某日志分段的下一个日志分段的起始偏移量 baseOffset 是否小于等于 logStartOffset,若是,则可以删除此日志分段。如下图所示。

在这里插入图片描述
假设 logStartOffset 等于 25,日志分段 1 的起始偏移量为 0,日志分段 2 的起始偏移量为 11, 日志分段 3 的起始偏移量为 23,那么通过如下动作收集可删除的日志分段的文件集合 deletableSegments:

  1. 从头开始遍历每个日志分段,日志分段 1 的下一个日志分段的起始偏移量为11,小于logStartOffset 的大小,将日志分段1加入 deletableSegments
  2. 日志分段 2 的下一个日志偏移量的起始偏移量为 23,也小于 logStartOffset 的大小, 将日志分段 2 页加入 deletableSegments
  3. 日志分段 3 的下一个日志偏移量在 logStartOffset 的右侧,故从日志分段 3 开始的所有日志分段都不会加入 deletableSegments

Reference

https://honeypps.com/mq/kafka-basic-knowledge-of-lw-and-logstartoffset/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值