1.深入学习kafka,我们要搭建一个kafka集群,配置好,运行起来,完成消息的发布与接收其实实现起来很简单,但是在kafka的底层是如何实现的,如何在大量消息中快速找到想要的消息,消息怎样才会在传递中不丢失,运行过程中会会经常遇到哪些比较棘手的问题接下来我们进入kafka高级的探入。
2.Kafka的结构组成以及详细解释:
2.1Producer:生产者,用于消息的生产,通过Producer我们将消息push到kafka集群中。
2.2Topic:某一类消息的高度抽象,理解成一些消息的集合,每一个topic将被分为多个partition(区),在集群中的配置文件中配置。
2.3Partition:分区的意思,它可以被存放在不同的服务器上,实现数据存储的横向扩展,每一个partition都是一个有序的队列,其中的每一条消息都会被分配一个有序的id(offset)。kafka 只保证按一个 partition 中将消息顺序的发给 consumer,不保证一个 topic 的整体(多个 partition 间)的顺序。
2.4Segment:组成partition的单元,但是每一个segment又包含了两部分,一个是.log文件,一个是.index文件。
2.5.log:存放日志文件,所有的数据都是以日志文件的形式存储到了kafka集群中。
2.6.index:索引文件,记录了所有.log文件每一条消息的索引,便于以后快速的查找某一条消息记录。
2.7Broker:kafka的服务器,一个broker就代表一个服务器节点,一个broker可以容纳多个topic。
2.8Offset:记录消息的id,格式是offset.kafka,作用是方便查找,格式例如:00000000002568.kafka。表示的是第2569条记录。
2.9Replication:Kafka 支持以 Partition 为单位对 Message 进行冗余备份,每个 Partition 都可以配置至少 1 个 Replication(当仅 1 个 Replication 时即仅该 Partition 本身)。
2.10Leader:每个 Replication 集合中的 Partition 都会选出一个唯一的 Leader,所有的读写请求都由Leader 处理。其他 Replicas 从 Leader 处把数据更新同步到本地,过程类似大家熟悉的 MySQL中的 Binlog 同步。每个 Cluster 当中会选举出一个 Broker 来担任 Controller,负责处理 Partition的 Leader 选举,协调 Partition 迁移等工作。
2.11Consumer:消费者,消费kafka中的消息信息。
3.kafaka的分区与副本机制:
我们使用kafka之前会创建一个topic,创建执行命令如下(举例)
kafka-topics.sh --create --zookeeper zk01(服务器地址):2181 --replication-factor 1 --partitions 1 --topic test
在这个命令中需要指定replication副本数与partitions 分区情况
分区(Partition):简单来说就是当数据量很大的时候,一个服务器存储不下,我们会将数据分成多份,存储到不同的服务器上,那么每一个服务器上的数据就叫做一个分区。
副本:为了防止某一个分片丢失造成整体数据不完整的情形,kafka有副本机制来解决这个问题,例如将a服务器上存储的数据分片备份到b服务器上。(hdfs当中也有类似机制,但都是解决数据完整性问题)
4.Kafka的消息存储于查询机制:
存储的路径是我们设置好的,因为是kafka集群所以不同的服务器存储的路径是一样的,数据分区都会存储到kafka目录中,然后在这个目录中有以topic命名的文件,在这个文件里面就是很多Segment,每个Segment(包含.log与.index)默认最大存储容量是1G,
那么为什么要把我们的消息数据在存储的时候这样切分呢?作用是什么?
我们的kafka不是数据库,它的作用是消息中间键,需要把以前的消息、过期的消息、过时的消息删除,如果不切分,那么就会整体删除,这样就很麻烦,所以这样的分段底层存储方式就完美的解决了这个问题(kafka中消息数据默认存储的时间是7天,如果需要调整周期,这个时间可以在kafka的配置文件中修改)。
我们的每个Segment段中包含的.log与.index文件命名规格如下所示(举例):
0000000000.index
0000000000.log
0000055663.index
0000055663.log
0000112556.index
0000112556.log
相同前缀名的.log与.index文件为同一个段,每一个段记录的消息数据量就是下一个段的前缀减去当前前缀,其中.index文件记录了其对应的.log文件每一条消息数据的索引,这样当我们去查找offset=4589的消息的时候,就会锁定段信息之后再找到段里面的消息数据信息。从而完成精确查找。
5.Kafka数据生产分发策略:
我们在实际开发应用中,kafka是主要用来完成实时大数据分析项目的。消息源作为生产者源源不断的产生数据到kafka,然后我们的消费者一般情况是storm(大数据领域用来进行实时分析的流式处理框架,以后我会单独发一篇关于storm的博客)。那么这里有个问题,数据源发布消息到kafka集群(kafka集群:多个配置拥有broker的服务器),那么该到哪一个broker上进行存储呢?源源不断的消息是怎样进行存储分配的呢?接下来就来说明这个问题。
在数据的生产端就给定了分发的规定,有多种方式。
5.1在编写produce record方法的时候,指定发往哪一个分区partition。
5.2 如果生产者没有指定partition那么就会根据消息中key的hash值来分区(在给定了分区与key两种条件下,会以给定分区这种方式为主。如果key是用户指定的,不变的,那么hash算法取模就会永远是数据落到一个分区里,这样就失去了多分区的意义,所以用这样的方式的时候最好要保证key的值是不同的、变化的)。
5.3 如果既没有指定partition也没有key的时候,就会根据轮询的方式发送。(实际开发项目中比如我们刚刚搭建完实时数据分析平台,一般默认此模式分发数据机制。但是如果有特殊情况,也可以通过以上的方式来更改,是整个平台更加优化。)
6.kafka的消费者的负载均衡机制:
试想这样一个问题,假设在实际的实时生产开发中,如果生产者的效率与速度(每秒钟假设生产500条消息)远远大于消费者的效率与速度(假设每秒钟消费150条消息)就会造成大量的数据积压,使整个系统平台滞后并且延迟增加。
Kafka的负载均衡就解决了这个问题,首先是一个分区partition只能被一个消费者消费,可以增加消费者的数量来消费减轻压力(但是消费者的数量不要大于分区partition的数量,因为kafka默认会将多出来的消费者处于空闲状态),同时一个消费者可以消费多个分区partition(理解为一对多的关系),另一方面,partition的数量一定要大于broker的数量,这样leader partition就会均匀分布在各个broker中,实现负载均衡。
7.kafka消息不丢失机制:
在生产者端:
Kafka有ack机制,ack有三个状态值,发送数据的时候都是在这三个状态值控制下的。
状态值0:表示生产者指发送数据,不管消息是否丢失(实际开发中不建议设置为0)。
状态值1:表示partition的leader接收到数据,响应状态码。
状态值-1:表示所有节点都接受到数据,并且响应状态码。
因为可以设定,并且得到响应状态码,从未就确保了消息不丢失。但是这时还会出现一个问题,在实际开发中我们的消息数量是非常多的,如果每一条消息都返回一个状态码,那么就会占用很多带宽,使我们的整个系统平台压力非常大。解决办法就是用异步模式来解决。
异步模式:通过缓冲池(buffer)来控制数据的发送,当满足时间阈值(可以在配置文件中设定)或者消息数量阈值(可以在配置文件中设定)的时候,统一发送,这里注意需要设置buffer的模式,有两种一种是当buffer消息满了的时候立即删除模式(不建议使用这个模式),另一个是buffer满了之后处于阻塞模式(等待)。
在broker端:
我们是通过partition副本机制来保证消息不丢失。
在消费者端:通过offset来记录每一次消费到了那一条数据,在低速消费模式情况下,offset记录是在本地磁盘上,高速消费模式下,是记录在zk(zookeeper)的节点上(kafka0.8版本以前,但在新的版本是存储在kafka自己的内置topic上(topic:consumer_offsets))。无论是哪个版本都是记录的offset的值来保证消息数据的不丢失。
8.Kafka与其他技术的整合:这个以后会单独写一篇博客来说明。