5

消息中间件系列介绍-Kafka

 1 year ago
source link: https://www.51cto.com/article/721832.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者 | 葛贤亮,单位:中国移动智慧家庭运营中心

​Labs 导读

近年来,互联网技术发展迅猛,各行各业的信息量急剧膨胀。随着云计算和算力网络时代的到来,消息中间件在国内许多行业的关键应用中越来越受到重视。在高并发分布式场景下,合理地利用消息中间件往往能起到突破性能瓶颈与化繁为简的效果。

前期分别从“作用”与“协议”、“传输模式”与“消费模式”对消息中间件技术做了简要的介绍。本期从消息中间件产品角度介绍主流方案的设计与实现。

1、概念介绍

Apache Kafka是一种高吞吐量、分布式、多副本、基于发布/订阅的消息系统,最初由LinkedIn公司开发,使用Scala语言编写,目前是Apache的开源项目。Kafka已成为事件流处理动态数据的事实标准。

1.1 主要特性

  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒;
  • 可扩展性:kafka集群支持热扩展,数据迁移、扩容对用户透明;
  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失;
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败);
  • 高并发:支持数千个客户端同时读写;
  • 分布式架构:Broker、Producer和Consumer都原生自动支持分布式,自动实现负载均衡;
  • 支持同步和异步复制两种高可用机制;
  • 支持数据批量发送和拉取;
  • 零拷贝技术(zero-copy):减少 IO 操作步骤,提高系统吞吐量;
  • 其他特性:丰富的消息拉取模型、高效订阅者水平扩展、实时的消息订阅、亿级的消息堆积能力、定期删除机制。

1.2 Kafka优点

  • 客户端多语言支持:支持Java、.Net、PHP、Ruby、Python、Go等多种语言;
  • 高性能:单机写入TPS约在100万条/秒,消息大小10个字节;
  • 分布式架构,并有replica机制,拥有较高的可用性和可靠性,理论上支持消息无限堆积;
  • 支持批处理操作;
  • 消费者采用Pull方式获取消息。单分区内消息有序,通过控制能够保证所有消息被消费且仅被消费一次;
  • 在日志领域比较成熟,被多家公司和多个开源项目使用。

1.3 Kafka缺点

  • Kafka单机超过64个分区时,load时会发生明显的飙高现象。队列越多,负载越高,发送消息响应时间变长;
  • 使用短轮询方式,实时性取决于轮询间隔时间,对于不能批处理的消息,需考虑消费线程执行效率;
  • 需要引入ZooKeeper,部署成本相比其他MQ较高;
  • 不能保证消息100%到达,不支持事务消息。

1.4 主要应用场景

  • 消息系统:分布式消息系统,解耦生产者和消费者;
  • 日志收集:Kafka常与ELK(Logstash、ElasticSearch、Kibana)一起作为业务系统日志收集方案;
  • 业务埋点:对于可靠性要求不那么高的埋点数据(如浏览网页、点击、跳转等),可使用Kafka进行传输,消费者端收到消息后可根据需求做实时监控分析或装载到hadoop、数据仓库中做离线分析和挖掘;
  • 运营指标:Kafka可用来传输运营监控数据,以便统一归集分析、集中反馈;
  • 流式处理:Kafka提供了完整的流式处理类库,可以很方便的被集成至应用程序中,为流式处理框架(Flink、Spark、Storm等)提供可靠的数据来源。

1.5 Kafka为什么这么快?

Kafka可以轻松支持每秒百万级的写入请求,超过了大部分的消息中间件,这种特性使得Kafka在日志处理等海量数据场景得到广泛应用。

  • 并行处理:Kafka引入了Partition(分区)的概念,每个Topic 可包含一个或多个Partition,不同Partition可位于不同节点中,从而实现多磁盘并发读写;
  • 顺序读写:Kafka中每个Partition是一个有序、不可变的消息序列,新的消息只会被追加到Partition的末尾,而一个Partition又被分为多个Segment,清除旧数据时可直接删除Segment文件,避免随机写;
  • 页缓存(Page Cache):Kafka使用页缓存技术减少I/O操作次数,即使Kafka进程重启数据也不会丢失(机器宕机时,页缓存内的数据未及时写入磁盘会导致数据丢失,同步刷盘可以规避该问题,但会影响性能,默认使用异步刷盘机制);
  • 零拷贝技术:Kafka使用零拷贝技术,避免数据在内核空间的缓冲区和用户空间的缓冲区之间进行拷贝;
  • 批处理:Kafka支持批处理操作,以减少网络I/O操作;
  • 数据压缩:Kafka支持Snappy、Gzip、LZ4等算法对数据进行压缩传输。

2、架构设计

图片

图1 架构设计

3、核心概念

  • Producer:生产者,用来向Kafka Broker中发送数据(Record);
  • Kafka Cluster:Kafka集群,由一台或多台服务器组成;
  • Broker:Broker是指部署了Kafka实例的服务器节点,每个服务器上可安装一个或多个Kafka实例。每个Kafka集群内的Broker都有一个不重复的编号(如broker-0、broker-1等);
  • Topic:消息主题,用来区分不同类型信息。在每个Broker上可以创建多个Topic;
  • Partition:Topic的分区,每个Topic可以有一个或多个 Partition(分区),分区可实现负载均衡,支持并发写入读取,提高Kafka的吞吐量。一个分区内的数据只能被一个线程消费;
  • Replication:每一个分区可以有多个副本。当主分区(Leader)故障的时候会选择一个副本(Follower)成为新的Leader。在Kafka中副本的默认最大数量是10个,且副本的数量不能大于Broker的数量,Follower和Leader必须分布在不同的机器上,同一机器上同一分区只能存放一个副本(包括自己)。
  • Record:消息记录。每个Record包含了key、value和 timestamp;
  • Consumer:消费者,用来读取Kafka中的数据(Record)进行消费;
  • Consumer Group:消费者组,一个消费者组可以包含一个或多个消费者。在Kafka的设计中一个分区内的数据只能被消费者组中的某一个消费者消费,同一个消费者组的消费者可以消费某个Topic不同分区的数据;
  • Segment:实际存储消息的片段;一个Partition在物理上由一个或者多个Segment构成,每个Segment中保存真实的消息数据。

4、工作流程

图片

图2 工作流程

Kafka一般工作流程如下(根据ACK应答策略会存在部分差异):

  • 生产者与Leader直接交互,先从集群获取Topic对应分区的Leader元数据;
  • 获取到Leader分区元数据后进行消息发送;
  • Kafka Broker对应的Leader分区收到消息后写入文件进行持久化;
  • Follower拉取Leader消息,进行数据同步;
  • Follower完成消息拉取后给Leader回复ACK确认;
  • Leader和Follower分区完成数据同步后,Leader分区给生产者回复ACK确认。

👇 ACK应答机制

通过配置request.required.acks属性来配置ACK策略:

  • 0代表生产者往集群发送数据不需要等待集群的返回,不确保消息是否发送成功。安全性最低但是效率最高。
  • 1(默认)代表生产者往集群发送数据只要Leader应答就可以发送下一条,只确保Leader发送成功(Leader不需要等待Follower完成数据同步即返回生产者ACK确认)。
  • all代表生产者往集群发送数据需要所有的Follower都完成数据同步才会发送下一条,确保Leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。

5、Kafka数据存储设计

5.1 Topic和数据日志

Topic是同一类别的消息记录(Record)的集合。在Kafka中,一个Topic又可以被划分成多个Partition,分区数据日志文件结构如下:

图片

图3 Topic和数据日志-分区数据日志文件结构

每个Partition是一个有序、不可变的消息序列,新的消息只会被追加到Partition的末尾。在每个Partition中,通过offset(偏移量)标识消息。由此可见,在同一个Partition内消息是有序的,在不同Partition之间,不能保证消息被有序消费。

Kafka可以通过log.retention配置项设定消息日志在集群内的留存时间,默认为168小时(即7天)。

5.2 Partition结构

Partition在服务器上是以文件夹形式存在的,每个Partition文件夹内会有多组Segment文件,每组Segment文件又包含.index、.log、.timeindex三个文件,其中.log是实际存储消息日志的地方,而.index和.timeindex为索引文件,用于检索消息。

Q:为什么有了Partition还要有Segment?

Segment对应一个文件(实现上对应两个文件,一个数据文件,一个索引文件),一个Partition对应一个文件夹,一个Partition内理论上可以包含任意多个Segment。

如果不引入Segment ,所有消息日志都直接写在Partition文件内,会导致Partition文件一直增大。同时,在做data purge时,需要把文件的前面部分给删除,不符合Kafka文件的顺序写优化设计方案。引入Segment后,消息日志被分散在多个Segment中, 每次做data purge,只需要把旧的Segment整个文件删除即可,保证了每个Segment的顺序写。

5.3 Partition的数据文件(offset、MessageSize、data)

Partition中的每条消息包含三个属性:offset、MessageSize、data,其中offset表示消息在这个Partition中的偏移量,offset 不是实际存储位置,而是逻辑上一个值,用来唯一标识Partition内的一条消息,相当于消息id;MessageSize表示消息内容data的大小;data为消息的具体内容。 

5.4 数据文件分段Segment(顺序读写、分段命令、二分查找)

Partition物理上由多个Segment文件组成,每个Segment大小相等(大致)。每个Segment数据文件以该段中最小的offset命名,文件扩展名为.log。这样在查找指定offset消息的时候,用二分查找法可以快速定位到该消息在哪个Segment数据文件中。 

5.5 数据文件索引(分段索引、稀疏存储)

Kafka为每个Segment建立了索引文件(文件名与数据文件一致,扩展名为.index)。具体是采用稀疏索引方式,每隔一定字节的数据建立一条索引。这样做的好处是减少了索引体积,以便保留在内存中;坏处是查询时命中需要消耗更多时间(相对)。

图片

图4 数据文件索引-稀疏索引

6、生产者&消费者设计

6.1 负载均衡(Partition会均衡分布到不同Broker上) 

由于一个Topic可以有多个Partition,不同Partition均衡分布在不同的Broker上。基于该特性,生产者可通过随机、轮询或hash等策略,将消息平均发送至多个Broker中,实现负载均衡。

6.2 批量发送

生产者在本地内存中进行消息聚合,以单次请求发送批量数据的方式,减少网络I/O操作(副作用是一定程度上会影响消息实时性,以时延换取吞吐量)。

6.3 压缩(Snappy、Gzip、LZ4)

生产者通过Snappy、Gzip、LZ4等算法对数据进行压缩传输,减少传输数据量,减轻网络压力(以CPU资源换取网络时延的降低)。

Kafka凭借其架构与性能优势,愈来愈受到众厂商的青睐。依托其完善的社区环境,Kafka构建了庞大而成熟的生态,已成为大数据及流计算领域中至关重要的一环。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK