kafka 的简单笔记
文章目录
一、存储:TOPIC的存储
吞吐量TPS 单位时间的访问量;QPS 每秒的访问量
1.1 术语
noun | description |
---|---|
massage | kafka中最基本的传递对象,有固定的格式。(不做研究) |
topic | MQ中发布订阅模式中一个主题,为某一类消息。(理解MQ中的PTP和PS模式) |
producer | 产生信息的主体,可以是服务器日志信息等。 |
consumer | 消费producer产生话题消息的主体。 |
broker | 消息处理结点(服务器),多个broker组成kafka集群。 |
partition | topic的物理分组及物理文件,每个partition都是一个有序队列。 |
segment | 多个大小相等的段组成了一个partition。 |
offset | 一个连续的用于定位被追加到分区的每一个消息的***,最大值为64位的long大小,19位数字字符长度。区别于物理意义的offset(存储指针),这里的offset是有producer、topic、partion组合生成的标记 |
1.2 MQ的消息保障机制
noun | description |
---|---|
At most once | 消息被最多发送一次,如果产生网络延迟等原因消息就会有丢失 |
At least once | 消息至少会被发送一次,上面既然有消息会丢失,那么给它加一个消息确认机制即可解决,但是消息确认阶段也还会出现同样问题,这样消息就有可能被发送两次 |
Exactly once | 消息只会被发送一次,这是我们想要的效果 |
1.3 kafa的解决方案
1.3.1 描述
分片存储参考wiki
broker将数据流划分为一组互相独立的分区。这些分区的语义由producer定义,由producer指定每条消息属于哪个分区。一个分区内的消息以到达broker的时间为准排序,将来按此顺序将消息发送给consumer。这样一来,就用不着为每一条消息保存一条元数据(比如标记该消息已使用)了,我们只需要为producer、topic、partition的每种组合记录一个“最高水位标记”(high water mark)即可。我们把这个最高水位标记称作偏移量offset。
解析
kafka中一个TOPIC由多个partition来存储的,partition是具有物理意义的文件夹。对于Broker而言,存储的系统由无数个TOPIC-partion
组成,每一条的消息会被放置到TOPIC-partion
中去,所以信息流会被对应到一块一块独立的TOPIC-partion
中去,事实上proucer能去指定消息存储到具体的TOPIC-partion
。同时message在Partion中的存储是有序的,有序表现在一个新的message是以append方式添加的,这样不仅在时间意义上有序,在物理意义上也有序(最大限度的按照OS文件系统分配的磁盘空间连续存贮,这是读写高效的原因)。这样带来的好处是,当CONSUMER需要消费时,CONSUMER自己控制信息的指针
。当多个CONSUMER并行读取是,根据自己的指针
去主动读取(pull模式),所以不会冲突,不需要TOPIC-partion
额外的存储message被消费的记录,kafka只需要定期或定存储的释放消息即可。上面提到的指针
就是术语offset,虽然不是物理指针,但是也提供定位message的功能。offset具体是由producer、topic、partition生成的,可以使kafaka的broker根据offset解析到具体提的message。而partion中的存储也是一系列offset
1.3.2 topic、partition、segment、offset的关系
partition、segment、offset都是为topic服务的,每个topic可以分为多个partition,一个partition相当于一个大目录,每个partition下面有多个大小相等的segment文件,这个segment是由message组成的,而每一个的segment不一定由大小相等的message组成。segment大小及生命周期在server.properties文件中配置。offset用于定位位于段里的唯一消息。
解析
parition 下等大小segment ,segmnent用上一个segmnent的末位message的offset来命名。segment的大小和生命周期,kafuka可以管理
1.3.2.1 segment
segment由index和data文件组成,两个文件成对出现,分别存储索引和数据。
segment文件命名规则:对于所有的partition来说,segment名称从0开始,之后的每一个segment名称为上一个segment文件最后一条消息的offset值。
1.3.2.2 offset查找机制
先找到该message所在的segment文件,通过二分查找的方式寻找小于等于345552的offset,假如叫S的segment符合要求,如果S等于345552则S上一个segment的最后一个message即为所求;如果S小于345552则依次遍历当前segment即可找到
实际上offset的存储采用了稀疏索引,这样对于稠密索引来说节省了存储空间,但代价是查找费点时间。
稀疏索引与稠密索引
二、分布式的原理
每个分区在Kafka集群的若干服务中都有副本,这样这些持有副本的服务可以共同处理数据和请求,副本数量是可以配置的。副本使Kafka具备了容错能力。
每个分区都由一个服务器作为“leader”,零或若干服务器作为“followers”,leader负责处理消息的读和写,followers则去复制leader.如果leader down了,followers中的一台则会自动成为leader。集群中的每个服务都会同时扮演两个角色:作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。
三、Producers
Producer将消息发布到它指定的topic中,并负责决定发布到哪个分区。通常简单的由负载均衡机制随机选择分区,但也可以通过特定的分区函数选择分区。使用的更多的是第二种。
四、Consumers
发布消息通常有两种模式:队列模式(queuing)和发布-订阅模式(publish-subscribe)。队列模式中,consumers可以同时从服务端读取消息,每个消息只被其中一个consumer读到;发布-订阅模式中消息被广播到所有的consumer中。Consumers可以加入一个consumer 组,共同竞争一个topic,topic中的消息将被分发到组中的一个成员中。同一组中的consumer可以在不同的程序中,也可以在不同的机器上。如果所有的consumer都在一个组中,这就成为了传统的队列模式,在各consumer中实现负载均衡。如果所有的consumer都不在不同的组中,这就成为了发布-订阅模式,所有的消息都被分发到所有的consumer中。更常见的是,每个topic都有若干数量的consumer组,每个组都是一个逻辑上的“订阅者”,为了容错和更好的稳定性,每个组由若干consumer组成。这其实就是一个发布-订阅模式,只不过订阅者是个组而不是单个consumer。
由两个机器组成的集群拥有4个分区 (P0-P3) 2个consumer组. A组有两个consumerB组有4个相比传统的消息系统,Kafka可以很好的保证有序性。
传统的队列在服务器上保存有序的消息,如果多个consumers同时从这个服务器消费消息,服务器就会以消息存储的顺序向consumer分发消息。虽然服务器按顺序发布消息,但是消息是被异步的分发到各consumer上,所以当消息到达时可能已经失去了原来的顺序,这意味着并发消费将导致顺序错乱。为了避免故障,这样的消息系统通常使用“专用consumer”的概念,其实就是只允许一个消费者消费消息,当然这就意味着失去了并发性。
在这方面Kafka做的更好,通过分区的概念,Kafka可以在多个consumer组并发的情况下提供较好的有序性和负载均衡。将每个分区分只分发给一个consumer组,这样一个分区就只被这个组的一个consumer消费,就可以顺序的消费这个分区的消息。因为有多个分区,依然可以在多个consumer组之间进行负载均衡。注意consumer组的数量不能多于分区的数量
,也就是有多少分区就允许多少并发消费。
Kafka只能保证一个分区之内消息的有序性,在不同的分区之间是不可以的,这已经可以满足大部分应用的需求。如果需要topic中所有消息的有序性,那就只能让这个topic只有一个分区,当然也就只有一个consumer组消费它。
kafka参考文档一 原理讲解
kafka参考文档二 实践案例
kafka参考文档三 offset原理