Kafka进阶知识
消息概念
消息指的是通信的基本单位。由消息生产者(producer)发布关于某个话题(topic)的消息。简单来说:消息以一种物理方式被发送给了作为代理(broker)的服务器(可能是另外一台机器)。若干的消息使用者(consumer)订阅(subscribe)某个话题,然后生产者所发布的每条消息都会被发送给所有的使用者。
Kafka的生产者、使用者和代理都可以运行在作为一个逻辑单位的、进行相互协作的集群中不同的机器上。生产者和代理没有什么关系,但是使用者都是属于一个使用者小组的。准确地说,每条消息都只会发送给每个使用者小组中的一个进程。因此,使用者小组使得许多进程或多台机器在逻辑上作为一个单个的使用者出现
Kafka的broker
因为Kafka生产了消息后,Kafka不会直接把消息传递给消费者,而是要先在broker中进行存储,持久化是保存在kafka的日志文件中的。消息在Broker中通过Log追加(保存在文件的最后面,是有序的)。为了减少磁盘写入的次数,broker会将消息暂时存在buffer中,当消息的个数(或尺寸)达到一定阀值时,再flush到磁盘,以此来减少磁盘IO调用的次数。
需要注意的是:
- Broker没有副本一说,但是消息本身是有副本的,因此不会丢失。Broker在宕机后,再读取消息的日志就可以了。
- Broker不保存订阅者的状态,由订阅者自己保存。
- 无状态导致消息的删除成为难题(可能删除的消息正在被订阅),kafka采用基于时间的SLA(服务水平保证),消息保存一定时间(通常为7天)后会被删除。这个地方的无状态感觉指的是消息本身,对于消费者而言,zookeeper会帮助记录哪条信息已经消费了,哪条消息没有消费。
- 消息订阅者可以rewind back到任意位置重新进行消费,当订阅者故障时,可以选择最小的offset(id,即偏移量)进行重新读取消费消息。
Message组成
Kafka中的Message是以topic为基本单位组织的,不同的topic之间是相互独立的。每个topic又可以分成几个不同的partition(每个topic有几个partition是在创建topic时指定的),每个partition存储一部分Message。
1.消息是无状态的,消息的消费先后顺序是没有关系的
2.每一个partition只能由一个consumer来进行消费,但是一个consumer是可 以消费多个partition,是一对多的关系。
假设有2个分区的主题“my_topic”,它将由2个目录构成(my_topic_0和my_topic_1),用于存放该主题消息的数据文件。日志文件的格式是一个“日志条目”序列。每条日志条目都由一个存储消息长度的4字节整型N和紧跟着的N字节消息组成。其中每条消息都有一个64位整型的唯一标识offset,offset(偏移量)代表了topic分区中所有消息流中该消息的起始字节位置。每条消息在磁盘上的格式如下:每个日志文件用第一条消息的offset来命名的,因此,创建的第一个文件将是00000000000.kafka,并且每个附加文件都将是上一个文件S字节的整数命名,其中S是配置中设置的最大日志文件大小。
消息是二进制格式并作为一个标准接口,所以消息可以在producer,broker,client之间传输,无需再copy或转换。
格式如下:On-disk format of a messagemessage length : 4 bytes (value: 1+4+n) "magic" value : 1 bytecrc : 4 bytespayload : n bytes一个叫做“my_topic”且有两个分区的的topic,它的日志有两个文件夹组成,my_topic_0和my_topic_1,每个文件夹里放着具体的数据文件,每个数据文件都是一系列的日志实体,每个日志实体有一个4个字节的整数N标注消息的长度,后边跟着N个字节的消息。每个消息都可以由一个64位的整数offset标注,offset标注了这条消息在发送到这个分区的消息流中的起始位置。每个日志文件的名称都是这个文件第一条日志的offset.所以第一个日志文件的名字就是00000000000.kafka.所以每相邻的两个文件名字的差就是一个数字S,S差不多就是配置文件中指定的日志文件的最大容量。 消息的格式都由一个统一的接口维护,所以消息可以在producer,broker和consumer之间无缝的传递
写操作
消息被不断的追加到最后一个日志的末尾,当日志的大小达到一个指定的值时就会产生一个新的文件。对于写操作有两个参数,一个规定了消息的数量达到这个值时必须将数据刷新到硬盘上,另外一个规定了刷新到硬盘的时间间隔,这对数据的持久性是个保证,在系统崩溃的时候只会丢失一定数量的消息或者一个时间段的消息。
读操作
读取是通过定义的64位逻辑的消息和S-byte块大小的offset来完成。返回一个迭代器,它包含在S-byte缓冲区的消息。S比单个消息大,但是在消息很大的情况下,读取可重试多次,每次的缓冲区大小加倍,直到消息被成功的读取。可以指定最大消息和缓冲区的大小,使服务器拒绝一些超过这个大小的消息。
在实际执行读取操纵时,首先需要定位数据所在的日志文件,然后根据offset计算出在这个日志中的offset(前面的的offset是整个分区的offset),然后在这个offset的位置进行读取。定位操作是由二分查找法完成的,Kafka在内存中为每个文件维护了offset的范围。
参考文档:[]