【Kafka】消息订阅框架Kafka

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/gongxifacai_believe/article/details/81409409

1、Kafka的产生背景

假设现在有两个模块,分别是A和B,其中A模块产生数据(消息),B模块根据A模块产生的数据进行操作。现在A模块产生数据的速度远远大于B模块的数据消费速度,那么A模块产生的数据有阻塞/有剩余,且对数据的处理性能有一定的影响。解决方式是:A模块发送数据到中间队列,B模块从中间队列中获取数据,中间队列就形成了一种信息系统的中间体的结构,是一种消息队列/消息系统,Kafka就是消息队列的一种实现。

2、Kafka简介

Kafka由LinkedIn公司开发,之后贡献给Apache基金会,成为Apache的一个顶级项目,开发语言为Scala。提供了各种不同语言的API,具体参考Kafka的cwiki页面。Kafka是一个分布式的流处理平台,是一个分布式的、分区的、容错的日志收集系统。
(1)特性
1. 允许发布订阅消息,类似于一个消息系统
2. 高容错的存储数据(容错性&可用性&可靠性)
3. 高可扩展性
4. 快速
5. 分布式
6. 水平可扩展(扩展性)
(2)版本
Kafka 0.8.2版本的帮助文档:http://kafka.apache.org/082/documentation.html
(3)适用场景
消息系统,日志收集系统,Metrics监控系统等等。
(4)工作示意图

(5)基本术语
Message:消息,传递的数据对象,主要由四部分构成:offset(偏移量)、key、value、timestamp(插入时间)。
Broker:代理者,Kafka集群中的机器/服务被称为broker, 是一个物理概念,一般情况下,一台服务器一个部署broker,也可以部署多个,一个broker就是一个Kafka进程。
Topic:主题,维护Kafka上的消息类型被称为Topic,是一个逻辑概念,是Kafka中一组消息的一个整体概念,Producer将消息写入到对应的Topic,Consumer从对应的Topic读取消息。
Partition:分区,维护Kafka上的消息数据的最小单位,一个Topic可以包含多个分区,Producer发送到Topic的数据根据key的不同发送到不同的partition中。一个分区中的数据有两个特性:有序(按照进入kafka的时间排序)、数据不可变(进入到kafka集群的数据不可进行变动)。在数据的产生和消费过程中,不需要关注数据具体存储的Partition在那个Broker上,只需要指定Topic即可,由Kafka负责将数据和对应的Partition关联上。
Producer:数据生产者,负责将数据发送到Kafka对应Topic的进程。 Consumer:数据消费者,负责从对应Topic获取数据的进程。
ConsumerGroup:消费者组,每个Consumer都属于一个特定的group组,一个group组可以包含多个Consumer,多个Consumer共同进行数据消费,然后多个Consumer之间形成负载均衡的一个特性;一个ConsumerGroup中如果Consumer的数量和消费的Topic的Partition的数量一样多,那么每个Consumer消费一个Partition的数据,如果Consumer的数量超过Partition的数量,那么有部分consumer处于不消费数据的状态,如果Consumer的数量不足Partition的数量,就有一部分Consumer消费多个Partition。
Producer和Consumer示意图如下:

(6)Kafka 0.10.x版本新特性
Kafka不仅仅可以作为消息系统,还可以作为流式数据处理平台和数据存储平台,已经完全成为一个分布式的流式数据平台,在已有的概念之上,新增了两个新的功能概念,分别是:
Streams:处理Kafka上流式数据的一个模块/API,类似于Storm、SpearkStreaming等流式处理平台。
Connector:提供可重用的生产者、消费者,可以将Kafka中的数据持久化到存储系统或者从存储系统中读入数据,比较类似Flume的数据收集功能。
示意图如下:

3、Kafka的安装

Kafka的安装方式主要有三种,分别是单机、伪分布式、完全分布式。
单机:一台服务器,只有一个broker。
伪分布式:一台服务器,上面部署有多个broker。
完全分布式:多台服务器。
搭建步骤参考:http://kafka.apache.org/082/documentation.html#quickstart。
Kafka用Scala语言开发,其支持语言参考:https://cwiki.apache.org/confluence/display/KAFKA/Clients。
伪分布式安装步骤如下:
1)安装JDK和Scala环境:jdk1.7.x,scala2.10.x。
2)安装Zookeeper:zookeeper3.4.5。
3)安装Kafka,Kafka配置相关参数参考:http://kafka.apache.org/082/documentation.html#brokerconfigs。
(1)下载Kafka安装压缩包
Apache:(根据scala的版本下载对应的kafka压缩包)
http://archive.apache.org/dist/kafka
http://archive.apache.org/dist/kafka/0.8.2.1/
http://archive.apache.org/dist/kafka/0.8.2.1/kafka_2.10-0.8.2.1.tgz
Cloudera:(基本不用)
http://archive.cloudera.com/kafka/kafka/
(2)将压缩包上传至/opt/softwares/目录并解压
tar -zxf /opt/softwares/kafka_2.10-0.8.2.1.tgz -C /opt/cdh-5.3.6/
cd /opt/cdh-5.3.6/kafka_2.10-0.8.2.1
(3)更改config文件夹中的Kafka服务配置项:server.properties文件中的信息
$ vim config/server.properties
broker.id=0
给定broker的id的值,在一个kafka集群中该参数必须唯一;
port=9092
监听的端口号,默认9092,需要保证该端口没有被使用;
host.name=hadoop-senior02.ibeifeng.com
监听的主机名,默认是localhost,需要更改为hostname;
log.dirs=/opt/cdh-5.3.6/kafka/data/0
指定kafka存储磁盘的路径,可以使用",“分割,给定多个磁盘路径;如果服务器挂载多个磁盘,可以将kafka的数据分别存储到不同的磁盘中(每个磁盘写一个路径),对于Kafka的数据的读写效率有一定的提升(场景:高并发、大数据量的情况);
zookeeper.connect:2181=hadoop-senior02.ibeifeng.com/kafka
配置kafka连接zk的相关信息,连接url以及kafka数据存储的zk根目录;这里的配置含义是:连接hadoop-senior02机器2181端口的zookeeper作为kafka的元数据管理zk,zk中使用/kafka作为kafka元数据存储的根目录,默认kafka在zk中的根目录是zk的顶级目录(”/");
(4)复制server.properties, 产生server1.properties、server2.properties、server3.properties三个配置文件,并修改参数:broker.id&port&log.dirs
$ cd config
$ cp server.properties server1.properties

server1.properties:

broker.id=1
port=9093
log.dirs=/opt/cdh-5.3.6/kafka_2.10-0.8.2.1/data/1

$ cp server.properties server2.properties

server2.properties:

broker.id=2
port=9094
log.dirs=/opt/cdh-5.3.6/kafka_2.10-0.8.2.1/data/2

$ cp server.properties server3.properties

server3.properties:

broker.id=3
port=9095
log.dirs=/opt/cdh-5.3.6/kafka_2.10-0.8.2.1/data/3

(5)启动Kafka服务
1)启动ZooKeeper:
cd /opt/modules/zookeeper-3.4.5
zookeeper-3.4.5]$ bin/zkServer.sh start
2)启动Kafka:
$ cd /opt/cdh-5.3.6/kafka:开始启动, 开启四个不同的shell客户端
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh config/server.properties
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh config/server1.properties
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh config/server2.properties
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh config/server3.properties
启动命令用法如下:
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh
USAGE: bin/kafka-server-start.sh [-daemon] server.properties
启动kafka需要给定kafka的server的配置信息,参数-daemon的含义是将kafka是否启动到后台,如果给定,kafka进程后台启动。
使用方式一:kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh config/server.properties
使用方式二:kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh -daemon config/server.properties
(6)关闭Kafka服务
$ cd /opt/cdh-5.3.6/kafka
kafka_2.10-0.8.2.1]$ bin/kafka-server-stop.sh
该命令会将当前机器上的所有broker全部关闭,如果想关闭某个broker,可以通过shell命令查看到pid后,通过kill命令关闭进程。
(7)Kafka的日志,默认存储在${KAFKA_HOME}/logs文件夹中,如果需要修改文件存储路径,修改/opt/cdh-5.3.6/kafka_2.10-0.8.2.1/config/log4j.properties,设定kafka.logs.dir=logs,给定一个具体的存储路径即可。
(8)Kafka在zookeeper中的元数据的描述
consumers:连接kafka的消费者信息,包括消费者&读取数据的偏移量。
config:topic的配置信息。
controller:topic分区各个副本之间leader选举时候用到的一个目录。
admin:kafka管理相关信息。
brokers:kafka集群中broker的相关描述信息。
controller_epoch:和controller类似。

4、Kafka的基本命令

参考:http://kafka.apache.org/082/documentation.html#quickstart
(1)启动服务
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh -daemon config/server.properties
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh -daemon config/server1.properties
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh -daemon config/server2.properties
kafka_2.10-0.8.2.1]$ bin/kafka-server-start.sh -daemon config/server3.properties
(2)查看topic操作脚本的相关帮助信息
创建Topic的时候给定的configuration可以参考http://kafka.apache.org/082/documentation.html#configuration中的Topic-level configuration栏目的内容。
获取帮助:kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --help
(3)创建Topic
注意:需要给定创建的topic名称,要求topic名称不存在。
需要给定zookeeper的连接url地址,其实就是配置在server.properties中的zk连接信息。需要给定topic的分区数目,这个可以任意,一般情况下,该值为broker服务数量的1-2倍。需要给定每个分区的副本因子,该值不能超过kafka集群中的broker服务的数量,一般不会超过3。
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --create --topic beifeng0 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --config max.message.bytes=12800000 --config flush.messages=1 --partitions 5 --replication-factor 3
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --create --topic beifeng1 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --replication-factor 1 --partitions 1
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --create --topic beifeng2 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --replication-factor 1 --partitions 2
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --create --topic beifeng3 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --replication-factor 1 --partitions 1 --config segment.bytes=10240
(4)查看当前kafka集群中Topic的情况
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --list
(5)查看Topic的详细信息
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --describe
kafka_2.10-0.8.2.1]$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --describe --topic beifeng0
(6)修改Topic信息
$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --alter --topic beifeng1 --config max.message.bytes=128000
$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --alter --topic beifeng1 --delete-config max.message.bytes
$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --alter --topic beifeng1 --partitions 10
$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --alter --topic beifeng1 --partitions 3:分区数量只允许增加,不允许减少
$ bin/kafka-topics.sh --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --alter --topic beifeng2 --replica-assignment 0:1:2,1:2:3
(7)删除Topic
$bin/kafka-topics.sh --delete --topic beifeng2 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka
默认情况下,删除是标记删除,没有实际删除这个Topic,如果要删除Topic,可以有两种方式:方式一:通过delete命令删除后,手动将本地磁盘以及zookeeper上的相关topic的信息删除即可,方式二:配置server.properties文件,给定参数delete.topic.enable=true,表示允许进行Topic的删除。
(8)测试Kafka集群的消息传递功能
1)启动服务;
2)启动数据生产者;
$ bin/kafka-console-producer.sh --broker-list hadoop-senior02.ibeifeng.com:9092,hadoop-senior02.ibeifeng.com:9093,hadoop-senior02.ibeifeng.com:9094,hadoop-senior02.ibeifeng.com:9095 --topic beifeng0
3)启动数据消费者
$ bin/kafka-console-consumer.sh --topic beifeng0 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka
不接收consumer启动前kafka中的数据。
$ bin/kafka-console-consumer.sh --topic beifeng0 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --from-beginning
从头开始接收kafka的数据(全部都接收)。
$ bin/kafka-console-consumer.sh --topic beifeng0 --zookeeper hadoop-senior02.ibeifeng.com:2181/kafka --from-beginning --consumer.config consumer.properties --delete-consumer-offsets
需要在根目录中创建一个consumer.properties,然后内部给定一个group.id, 结合java编写的consumerapi可以进行测试操作。

5、Kafka原理

(1)Kafka发送消息格式
一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成。header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成。当magic的值为1的时候,会在magic和crc32之间多一个字节的数据:attributes(保存一些相关属性,比如是否压缩、压缩格式等等);如果magic的值为0,那么不存在attributes属性。body是由N个字节构成的一个消息体,包含了具体的key/value消息。每个版本的Kafka消息格式是不一样的。
(2)Kafka Log消息格式
存储在磁盘的日志采用不同于Producer发送的消息格式,每个日志文件都是一个“log entries”序列,每一个log entry包含一个四字节整型数(message长度,值为1+4+N),一个字节的magic,四个字节的CRC32值,最终是N个字节的消息数据。每条消息都有一个当前Partition下唯一的64位offset,指定该消息的起始下标位置。这个“log entries”并非由一个文件构成,而是分成多个segment file(日志文件,存储具体的消息记录)和一个索引文件(存储每个segment文件的offset偏移量范围)。示意图如下:

(3)Kafka消息存储机制
一个Topic分为多个Partition来进行数据管理,一个Partition中的数据是有序、不可变的,使用偏移量(offset)唯一标识一条数据,是一个long类型的数据。
Partition接收到producer发送过来数据后,会产生一个递增的offset偏移量数据,同时将数据保存到本地的磁盘文件中(文件内容追加的方式写入数据);Partition中的数据存活时间超过参数值(log.retention.{ms,minutes,hours},默认7天)的时候进行删除(默认)。
consumer根据offset消费对应Topic的Partition中的数据(也就是每个Topic的Partition都拥有自己的offset偏移量)。
Kafka的数据消费是顺序读写的,磁盘的顺序读写速度(600MB/sec)比随机读写速度(100k/sec)快。
(4)Kafka分布式机制
一个Topic中的所有数据分布式的存储在kafka集群的所有机器(broker)上,以分区(partition)的形式进行数据存储;每个分区允许存在备份数据/备份分区(存储在同一kafka集群的其它机器上的分区)。
每个数据分区在Kafka集群中存在一个broker节点上的分区叫做leader,存储在其它broker上的备份分区叫做followers;只有leader节点负责该分区的数据读写操作,followers节点作为leader节点的热备节点,从leader节点备份数据;当leader节点挂掉的时候,followers节点中会有一个节点变成leader节点,重新提供服务。Kafka集群的Partition的leader和followers切换依赖Zookeeper。
(5)Kafka消息产生/收集机制
Kafka集群中由producer负责数据的产生,并发送到对应的Topic,Producer通过push的方式将数据发送到对应Topic的分区。相关参数配置参考:http://kafka.apache.org/082/documentation.html#producerconfigs。
Producer发送到Topic的数据是由key/value键值对组成的,Kafka根据key的不同的值决定数据发送到不同的Partition,默认采用Hash的机制发送数据到对应Topic的不同Partition中,配置参数为{partitioner.class}。
Producer发送数据的方式分为sync(同步)和async(异步)两种,默认为同步方式,由参数{producer.type}决定;Producer提供重试机制,默认失败重试发送3次。
(6)Kafka消息消费机制
Kafka有两种模式消费数据:队列和发布订阅;在队列模式下,一条数据只会发送给customer group中的一个customer进行消费;在发布订阅模式下,一条数据会发送给多个customer进行消费。
Kafka的Customer基于offset对kafka中的数据进行消费,对于一个customer group中的所有customer共享一个offset偏移量。
Kafka中通过控制Customer的参数{group.id}来决定kafka是什么数据消费模式,如果所有消费者的参数值是相同的,那么此时的kafka就是类似于队列模式,这个时候相同group.id的consumer组成一个consumer group组,数据只会发送到一个customer,此时类似于负载均衡;否则就是发布订阅模式。
Kafka的数据是按照分区进行排序的(按照进入kafka集群的时间),也就是每个分区中的数据是有序的。在Consumer进行数据消费的时候,也是对分区的数据进行有序的消费的,但是不保证所有数据的有序性(多个分区)。
Consumer Rebalance:当一个consumer group组中的消费者数量和对应Topic的分区数量一致的时候,此时一个Consumer消费一个Partition的数据;如果不一致,那么可能出现一个Consumer消费多个Partition的数据或者不消费数据的情况,这个机制是根据Consumer和Partition的数量动态变化的。
Consumer通过poll的方式主动从Kafka集群中获取数据。
Push和Poll方式的区别:
Push是指将数据发送给第三方,不考虑第三方的框架的数据处理能力。
Poll是指根据自己的处理能力,从数据产生方获取数据。
(7)Kafka Replication
Kafka的Replication指的是Partition的复制,一个Partition的所有分区中只有一个分区是leader节点,其它分区是follower节点。前提:replication factor大于1的。
Topic: beifeng0 Partition: 0 Leader: 3 Replicas: 3,0,1 Isr: 3,0,1
leader是brokerid为3的服务,Replicas:复制节点3,0,1; Isr: 3,0,1 指定当前partition活跃的partition(leader + 活跃follower)。
建议:一般情况下,每个分区的replication factor为3-5比较合适;通过shell脚本监控分区的变化,当有效分区数量过少的时候,通知开发人员手动参与进去修改分区节点数。
Replication对Kafka的吞吐率有一定的影响,但是极大的增强了可用性。
Follower节点会定时的从leader节点上获取增量数据,一个活跃的follower节点必须满足以下两个条件:

  1. 所有的节点必须维护和zookeeper的连接(通过zk的heartbeat实现)。
  2. follower必须能够及时的将leader上的writing复制过来,不能“落后太多”; “落后太多”由参数{replica.lag.time.max.ms}和{replica.lag.max.messages}决定。

(8)Kafka Leader Election
Kafka提供了一个in-sync replicas(ISR)来确保Kafka的Leader选举,ISR是一个保存分区node的集合,如果一个node宕机了或数据“落后太多”,leader会将该node节点从ISR中移除,只有ISR中的follower节点才有可能成为leader节点。
Leader节点的切换基于Zookeeper的Watcher机制,当leader节点宕机的时候,其他ISR中的follower节点会竞争的在zk中创建一个文件目录(只会有一个follower节点创建成功),创建成功的follower节点成为leader节点。当原来的leader节点重新恢复后,会成为一个新的follower节点,添加到ISR列表中(会同步数据)。
(9)Message Delivery Semantics
MessageDeliverySemantics是消息系统中数据传输的可靠性保证的一个定义,主要分为三种类型:
At most once(最多一次):消息可能会丢失,但是不可能重复发送。
At least once(最少一次):消息不可能丢失,但是可能重复发送。
Exactly once(仅仅一次):消息只发送一次,但不存在消息的丢失。
Kafka的Producer通过参数{request.required.acks}来定义确定Producer和Broker之间是那种消息传递类型。
Kafka的数据是分区存储的,每个分区中的数据是按照进入kafka的时间进行排序的,这样不需要为每条数据存储一个元数据(是否消费),只需要为每个Consumer记录一个对应分区数据消费的最高标记位,Kafka中叫做“偏移量”(offset)。
Kafka中实现数据传输的可靠性方式:
数据存储过程中的可靠性保证是通过Kafka Partition Replication以及Kafka Leader Election来保证的。
Producer端:
功能:生产者将数据发送给kafka。
可靠性实现方式:通过参数request.required.acks来决定的,acks是生产者等待kafka集群的接收确认返回值,主要有三个参数:
0:表示Producer不等待Kafka的返回结果,有可能存在数据丢失。
1:表示Producer等待Kafka的一个分区的保存成功的返回结果,有可能数据在分区的备份分区copy数据的时候宕机,导致数据丢失。
-1:表示Producer等待Kafka Topic的所有分区返回保存数据成功的标志。
Consumer端:
功能:消费Kafka中对应Topic中的数据。
可靠性保证:每个Parition中的数据是有序的,每条数据在每个Partiiton中都存在一个offset偏移量(数据是按照offset递增的顺序排列的), Kafka中的数据是否被某个Consumer消费,就根据该Consumer的Offset的值决定数据是否会被消费;offset表示了consumer消费偏移量小于offset的数据,大于等于offset的数据是没有被消费的。
(10)消息系统是否可以使用
核心要求:消息不丢失(可靠性)。
发送消息:重复发送、消息丢失。
消息处理:消息重复处理、消息漏处理。
消息传输速度是否足够快:快速。
消息系统能够标识消息是否被处理:希望不重复处理消息,kafka中对应同一个consumer group通过offset偏移量实现了消息不重复处理的机制。
可以非常简单进行扩容:可扩展性。
(11)Why Kafka is Fast?为什么kafka的性能比较高?
1)消息集(message set):Producer可以将多条消息一次发送给Kafka集群,Kafka可以一次将所有的数据追加到文件中,减少磁盘零碎的磁盘IO;同时consumer也可以一次性的请求一个数据集的数据。
2)二进制传输:同时消息在传递过程中是基于二进制进行传递的,不需要进行反序列化,在高负载的情况下,对性能是有一定的提升的。
3)顺序读写磁盘: 根据offset递增的顺序读取磁盘,而且每次读取数据是多条数据一起读取的。Kafka的所有数据操作都是基于文件操作的,而操作文件的方式都是顺序读写,而顺序读写磁盘的速度会比随机读写快6000倍左右。
4)“零”拷贝:kafka在传输数据的时候,log文件中的数据直接通过系统内存(内核)直接网络传输,不经过应用(kafka)的内存的数据的交换。在Kafka服务中,数据发送到consumer的过程中采用的是“零拷贝”,比普通的读写文件方式减少了两次操作,速度能够提高50%。
5)端到端数据压缩:Producer可以将需要发送的数据/数据集进行压缩后发送到Kafka集群,Kafka集群直接将数据保存到文件,然后Consumer消费数据的时候,将压缩后的数据获取到,进行解压缩操作。在性能瓶颈是网络带宽的情况下,非常有效。 Kafka默认支持三种压缩方式:lz4(一般不用)、gzip、snappy(最常用)。配置参数,需要在Producer中进行配置:参数是:compression.codec,参数值默认为none,表示不进行压缩。

没有更多推荐了,返回首页