作者|葛先亮单位:中国移动智能家居运营中心实验室简介近年来,互联网技术飞速发展,各行各业的信息量急剧膨胀。随着云计算和算力网络时代的到来,消息中间件在国内众多行业的重点应用中越来越受到重视。在高并发分布式场景下,合理使用消息中间件往往可以突破性能瓶颈,简化复杂度。前期从“功能”与“协议”、“传输方式”、“消费方式”等方面简要介绍了消息中间件技术。本期从消息中间件产品的角度介绍主流方案的设计与实现。一、概念介绍ApacheKafka是一个高吞吐量、分布式、多副本、基于发布/订阅的消息系统。它最初由LinkedIn开发,用Scala语言编写。目前是Apache的一个开源项目。Kafka已成为动态数据事件流处理的事实标准。1.1主要特点高吞吐、低延迟:Kafka每秒可处理数十万条消息,延迟低至几毫秒;可扩展性:Kafka集群支持热扩容,数据迁移扩容对用户透明;持久性、可靠性:消息持久化到本地磁盘,支持数据备份,防止数据丢失;容错性:允许集群中的节点发生故障(如果副本数为n,则允许n-1个节点发生故障);高并发:支持数千个多个客户端同时读写;分布式架构:Broker、Producer、Consumer都原生自动支持分布式、自动负载均衡;支持同步复制和异步复制两种高可用机制;支持批量发送和拉取数据;零拷贝技术(zero-copy):减少IO操作步骤,提高系统吞吐量;其他特点:丰富的消息拉取模型、高效的订阅者水平扩展、实时消息订阅、亿级消息积累能力、周期删除机制。1.2KafkaClient多语言支持优势:支持Java、.Net、PHP、Ruby、Python、Go等语言;高性能:单机写入TPS约为100万条/秒,消息大小为10字节;distribution架构有副本机制,具有高可用性和可靠性,理论上支持消息无限堆积;支持批量操作;消费者使用Pull方法获取消息。单个partition中的消息是有序的,通过控制可以保证所有的消息都被消费并且只消费一次;在日志领域比较成熟,被很多公司和多个开源项目使用。1.3Kafka的缺点当Kafka单机超过64个分区时,负载会明显增加。队列越多,负载越高,发送消息的响应时间越长;使用短轮询方式,实时性取决于轮询间隔时间。对于不能批量处理的消息,需要考虑消费者线程的执行效率;需要引入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文件,避免乱写;页缓存(PageCache):Kafka使用页缓存技术来减少I/O操作的次数。即使重启Kafka进程,数据也不会丢失(当机器宕机时,pagecache中的数据没有及时写入磁盘,会造成数据丢失。同步刷可以避免这个问题,但会影响性能,默认使用异步刷机机制);零拷贝技术:Kafka使用零拷贝技术避免内核空间缓冲区和用户空间缓冲区之间的数据拷贝;批处理:Kafka支持批处理,减少网络I/O操作;数据压缩:Kafka支持Snappy、Gzip、LZ4等算法对数据进行压缩传输。二、架构设计图1架构设计3、核心概念Producer:Producer,用于向KafkaBroker发送数据(Record);KafkaCluster:Kafka集群,由一台或多台服务器组成;Broker:Broker是指部署一个或多个Kafka实例,可以安装在每台服务器上。Kafka集群中的每个Broker都有一个唯一的编号(比如broker-0,broker-1等);Topic:消息主题,用于区分不同类型的信息。每个Broker上可以创建多个Topic;Partition:Topic分区,每个Topic可以有一个或多个Partition(分区),分区可以实现负载均衡,支持并发写入和读取,提高Kafka的吞吐量。一个分区中的数据只能被一个线程消费;复制:每个分区可以有多个副本。当主分区(Leader)失效时,会选出一个副本(Follower)成为新的Leader。Kafka默认最大副本数为10,副本数不能大于Brokers数。Follower和Leader必须分布在不同的机器上。同一台机器上的同一个分区只能存放一个副本(包括它自己)。记录:消息记录。每个Record包含key、value和timestamp;Consumer:消费者,用于读取Kafka中的数据(Record)进行消费;ConsumerGroup:消费组,一个消费组可以包含一个或多个消费者。在Kafka的设计中,一个partition中的数据只能被consumergroup中的某个consumer消费,同一个consumergroup的consumer可以消费一个topic的不同partition中的数据;Segment:实际存放消息的段;一个Partition在物理上由一个或多个Segment组成,每个Segment存储真实的消息数据。4.工作流程图2工作流程Kafka的大致工作流程如下(根据ACK响应策略可能会有一些差异):生产者直接与Leader交互,首先从集群中获取Topic对应分区的Leader元数据;获取Leader分区元数据后发送消息;KafkaBroker对应的Leader分区收到消息,写入文件进行持久化;Follower拉取Leader消息并进行数据同步;Follower完成消息拉取后向Leader发送ACK;Leader和Follower分区完成数据同步后,Leader分区向生产者回复ACK确认。
