Kafka集群是准实时数据平台NRDP中重要的一环, Kafka为我行上下游应用(系统)间实现实时通信提供了可能。Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域。早期 Kafka 的定位是一个高吞吐的分布式消息系统,目前则演变成了一个成熟的分布式消息引擎以及流处理平台。本文主要针对Kafka的架构体系和Kafka消息的订阅和发布进行介绍。
一
Kafka的定义
Kafka是一个分布式、数据流平台,本质上属于消息队列(Message Queue),主要应用于大数据实时处理领域,具备以下基本能力:
1.发布、订阅消息流;
2.容错方式存储消息流到存储介质;
3.处理即时消息。
二
Kafka的特点
1.解耦
允许独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
2.冗余
消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要处理系统明确的指出该消息已经被处理完毕,从而确保数据被安全的保存直到使用完毕。
3.扩展性
因为消息队列解耦了处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。
4.灵活性、峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
5.可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
6.顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)
7.缓冲
有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
8.异步通信
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
三
Kafka的架构图及相关
概念
Kafka发送端采用push模式将消息发送到Broker,Kafka消费端采用pull模式订阅并消费信息。如图3.1所示:
图3.1 Kafka架构图
图3.1大致的工作流程:Kafka集群将 Record 流存储在称为Topic的类别中,每个记录由一个键、一个值和一个时间戳组成。Kafka存储的消息来自任意多被称为Producer生产者的进程,Producer生产的数据会不断追加到该log文件末端,且每条数据都有自己的Offset。数据可以被发布到不同的Topic主题下的不同 Partition分区。在一个分区内,这些消息被索引并连同时间戳存储在一起。被称为Consumer消费者的进程可以从分区订阅消息,消费者组中的每个消费者,都会实时记录自己消费到了哪个Offset,以便出错恢复时,从上次的位置继续消费。目前,Kafka依靠Zookeeper做分布式协调服务,负责存储和管理Kafka集群中的元数据信息,包括集群中的broker信息、topic信息、topic的分区与副本信息等。
四
Kafka相关术语概念
1.producer:消息生产者,发布消息到 kafka 集群的终端或服务。
2.broker:kafka 集群中安装Kafka的服务器。
3.topic:Topic是逻辑上的概念,每条发布到 kafka 集群的消息属于的类别,即 kafka 是面向topic的(相当于数据库中的表)。
4.partition:partition是物理上的概念,每个topic包含一个或多个 partition。kafka分配的单位是partition。
5.consumer:从 kafka 集群中消费消息的终端或服务。
6.Consumer group:high-level consumer API中,每个consumer都属于一个consumer group,每条消息只能被consumer group 中的一个 Consumer 消费,但可以被多个consumer group消费。
7.replica:partition的副本,保障partition的高可用。
8.leader:replica中的一个⻆色,producer和consumer只跟leader交互。
9.follower:replica中的一个⻆色,从 leader中复制数据。
10.zookeeper:kafka 通过zookeeper来存储集群的meta信息。
11.offset:偏移量,分区中的消息位置,由Kafka自身维护,Consumer消费时也要保存一份offset以维护消费过的消息位置。Kafka 0.9 版本之前,Consumer默认将Offset保存在Zookeeper中,从0.9 版本开始,Consumer默认将Offset保存在Kafka一个内置的Topic中:__consumer_offsets。
12.message:消息,或称日志消息,是Kafka服务端实际存储的数据,每一条消息都由一个key、一个value 以及消息时间戳timestamp组成。
五
Kafka消息订阅和发布
1.Kafka消息订阅和发布图
图5.1 Kafka消息订阅和发布图
图5.1是Kafka消息发布/订阅的基本流程图:一对多,生产者将消息发布到Topic中,有多个消费者订阅该主题,发布到Topic的消息会被所有订阅者消费,被消费的数据不会立即从Topic清除。
2.Kafka消息发送机制
Kafka 生产端发送消息的机制非常重要,这也是Kafka高吞吐的基础,生产端的基本流程如下图所示:
图5.2 Kafka生产端的基本流程图
图5.2大致过程可以概括为:Kafka自从0.8.2版本就引入了新版本 Producer API,新版Producer完全是采用异步方式发送消息。生产端构建的 ProducerRecord先是经过keySerializer、valueSerializer序列化后,再是经过 Partition 分区器处理,决定消息落到 topic具体某个分区中,最后把消息发送到客户端的消息缓冲池accumulator 中,交由一个叫作Sender的线程发送到broker端。
按照上图所示的流程,消息发送机制的设计主要分为:异步发送、批量发送和消息重试。针对这三个方面的设计有如下简单总结:
(1)缓冲池 accumulator的最大大小由参数 buffer.memory 控制,默认是32M,当生产消息的速度过快导致buffer满了的时候,将阻塞 max.block.ms时间,超时抛异常,所以buffer的大小可以根据实际的业务情况进行适当调整。
(2)发送到缓冲buffer中消息将会被分为一个一个的batch,分批次的发送到broker端,批次大小由参数 batch.size 控制,默认16KB。一般减小 batch 大小有利于降低消息延时,增加batch大小有利于提升吞吐量。Kafka生产端提供了另一个重要参数 linger.ms,该参数控制了batch 最大的空闲时间,超过该时间的 batch 也会被发送到 broker 端。
(3)Kafka生产端支持重试机制,对于某些原因导致消息发送失败的,比如网络抖动,开启重试后 Producer 会尝试再次发送消息。该功能由参数 retries控制,参数含义代表重试次数,默认值为0表示不重试,建议设置大于0比如3。
六
Kafka存储机制
在谈论存储机制之前,我们可以了解一下Broker的存储策略,无论消息是否被消费,Kafka都会保留所有消息。有两种策略可以删除旧数据:
1.基于时间:log.retention.hours=168
2. 基于大小:log.retention.bytes=1073741824
需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关。
图6.1中Topic是逻辑上的概念,而Partition是物理上的概念,由于生产者生产的消息会不断追加到log文件末尾,为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制。每个Partition分为多个Segment,每个Segment对应两个文件:“.index”索引文件和 “.log”数据文件。
图6.1 Kafka存储机制的流程图
七
Kafka分区机制
1.分区原因
方便在集群中扩展,每个 Partition 可以通过调整以适应它所在的机器,而一个Topic又可以有多个Partition组成,因此可以以 Partition 为单位读写了。可以提高并发,因此可以以Partition为单位读写了。
注:Kafka并不支持读写分区,生产消费端所有的读写请求都是由leader副本处理的,follower副本的主要工作就是从leader副本处异步拉取消息,进行消息数据的同步,并不对外提供读写服务。
2.分区原则
Kafka 有两种分配策略,一个是RoundRobin(下面会提及到,轮询算法),一个是 Range,默认为Range(按主题进行分区),当消费者组内消费者发生变化时,会触发分区分配策略(方法重新分配)。
我们需要将Producer发送的数据封装成一个ProducerRecord对象。该对象需要指定一些参数:
topic:string类型,NotNull。
partition:int 类型,可选。
timestamp:long类型,可选。
key:string类型,可选。
value:string类型,可选。
headers:array类型,Nullable。
(1)指明Partition的情况下,直接将给定的Value作为Partition的值。
(2)没有指明Partition但有Key的情况下,将Key的Hash值与分区数取余得到Partition值。
(3)既没有 Partition 也没有Key的情况下,第一次调用时随机生成一个整数(后面每次调用都在这个整数上自增),将这个值与可用的分区数取余,得到Partition值,也就是常说的Round-Robin轮询算法。
八
准实时数据平台Kafka
应用
1. Kafka 版本
我行大数据基础平台(包含准实时数据平台与大数据应用开发平台)使用CDH5.16.2作为大数据版本,其中kafka版本为2.2.1-kafka-4.1.0。
2.NRDP Kafka部署环境信息
图8.1 NRDP kafka部署信息
当前,NRDP已经在生产域、大数据域、IT管理域部署Kafka集群,三域之间通过Mirrormaker进行数据同步(仅支持生产域到大数据域,IT管理域到大数据域的同步)。