Kafka入门:简介及集群搭建

- kafka简介
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统。每条发布到kafka的消息是根据Topic进行归类,每个Topic包含一个或多个Partition,发布消息到Kafka broker的是Producer(生产者),向Kafka broker读取消息的客户端成为Consumer。Kafka集群由多个实例组成,每个实例(server)成为broker。无论是kafka集群,还是producer和consumer都依赖于zookeeper来保证系统可用性集群保存一些meta信息。
在这里插入图片描述


- 基本概念

1. Topics

  • Topics是发布消息的类别或提要名称,一个Topic可以认为是一类消息,每个topic将被分成多个partition(区),如体育类别(Topic)消息下可以分为足球、篮球等分区(partitions)。在Kafka中一个Topic通常被多个consumers订阅,也就是说可以有0个、1个或多个订阅写入主题的数据的使用者。
    在这里插入图片描述
    而在一个Topic中的每个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型数字,它是唯一标记一条消息。kafka并没有提供其他额外的索引机制来存储offset,因为在kafka中几乎不允许对消息进行“随机读写”。
    在这里插入图片描述
  • Kafka集群使用一个可配置的保留期持久地保存所有已发布的记录(不管它们是否已被消耗)。例如,如果保留策略设置为2天,那么在发布记录后的2天内,记录是可用的,在此之后将丢弃记录以释放空间。Kafka的性能在数据大小方面实际上是恒定的,因此长时间存储数据不是问题。
  • 实际上,在每个consumer的基础上保留的唯一元数据是该consumer在日志中的偏移量或位置。这个偏移量由consumer控制:通常情况下,使用者在读取记录时将线性地推进其偏移量,但实际上,由于位置由使用者控制,所以它可以按照自己喜欢的任何顺序消费记录。例如,使用者可以重置到旧的偏移量来重新处理过去的数据,或者跳到最近的记录并从“现在”开始消费。
  • kafka集群几乎不需要维护任何consumer和producer状态信息,这些信息有zookeeper保存;因此producer和consumer的客户端实现非常轻量级,它们可以随意离开,而不会对集群造成额外的影响。例如,您可以使用命令行工具“跟踪”任何Topic的内容,而不更改任何现有使用者使用的内容。

------- 注意⚠️: Topics只是逻辑上的概念,物理上真正存在的上partitions

2. Partitions
Partition是物理上的概念,每个Topic包含一个或多个Partition。partitions的设计目的有多个。最根本原因是kafka基于文件存储。通过分区,可以将日志内容分散到多个server上,来避免文件尺寸达到单机磁盘的上限,每个partiton都会被当前server(kafka实例)保存。

3. Distribution

  • 一个Topic的多个partitions,被分布在kafka集群中的多个server上;每个server(kafka实例)负责partitions中消息的读写操作;此外为了提高容错性kafka还可以配置partitions需要备份的个数(replicas),每个partition将会被备份到多台机器上。
  • 基于replicated方案,每个partition都有一个server为"leader",还有零个或多个服务器充当“follower”;leader负责所有的读写操作,如果leader失效,那么将会有其他follower来接管(成为新的leader);follower只是单调的和leader跟进、同步消息即可。由此可见作为leader的server承载了全部的请求压力,因此从集群的整体考虑,有多少个partitions就意味着有多少个"leader",kafka会将"leader"均衡的分散在每个broker(实例)上来确保整体的性能稳定。

4. Producers
生产者将消息发布到他们选择的主题(Topic)。生产者负责选择要分配给主题(Topic)中的哪个分区(Partition)的记录。这可以采用循环方式来完成,只是为了平衡负载,也可以根据一些语义划分函数(比如基于记录中的某个键)来完成。

5. Consumers

  • 每个consumer属于一个consumer group;反过来说,每个group中可以有多个consumer。发送到Topic的消息,只会被订阅此Topic的每个group中的一个consumer消费。
  • 如果所有的consumer都具有相同的group,这种情况和queue模式很像;消息将会在consumers之间负载均衡。
  • 如果所有的consumer都具有不同的group,那这就是"发布-订阅";消息将会广播给所有的消费者。
    在这里插入图片描述
    在kafka中,一个partition中的消息只会被group中的一个consumer消费;每个group中consumer消息消费互相独立;我们可以认为一个group是一个"订阅"者;一个Topic中的每个partions,只会被一个"订阅者"中的一个consumer消费,不过一个consumer可以消费多个partitions中的消息。kafka只能保证一个partition中的消息被某个consumer消费时,消息是顺序的。

6. Guarantees

  • 由生产者发送到特定主题分区的消息将按其发送的顺序追加。也就是说,如果记录M1与记录M2由同一生产者发送,并且M1首先发送,那么M1的偏移量将小于M2,并且出现在日志的更早位置。
  • 使用者实例按照存储在日志中的顺序查看记录。
  • 对于具有复制因子N的Topic,我们将容忍最多N-1个服务器故障,而不会丢失提交到日志中的任何记录。

- Kafka特性

1. 持久性

  • Kafka存储布局简单:Topic的每个Partition对应一个逻辑日志
  • 每次生产者发布消息到一个分区,代理就将消息追加到最后一个行文件中
  • 与传统的消息系统不同,Kafka系统中存储的消息没有明确的消息Id
  • 消息通过日志中的逻辑偏移量来公开
  • kafka是对日志文件进行append操作,因此磁盘检索的开支是较小的;同时为了减少磁盘写入的次数,broker会将消息暂时buffer起来,当消息的个数(或尺寸)达到一定阀值时,再flush到磁盘,这样减少了磁盘IO调用的次数

2. 传输效率(zero-copy)

  • kafka为了减少字节拷贝,采用了大多数系统都会提供的sendfile系统调用:将文件的数据映射到系统内存中,socket直接读取相应的内存区域即可,而无需进程再次copy和交换
    在这里插入图片描述
    在这里插入图片描述
  • 其实对于producer/consumer/broker三者而言,CPU的开支应该都不大,因此启用消息压缩机制是一个良好的策略;压缩需要消耗少量的CPU资源,不过对于kafka而言,网络IO更应该需要考虑。可以将任何在网络上传输的消息都经过压缩。kafka支持gzip/snappy等多种压缩方式。

3. 消息传输策略
对于JMS实现,消息传输担保非常直接:有且只有一次(exactly once)。在kafka中稍有不同:

  • at most once: 最多一次,这个和JMS中"非持久化"消息类似。消息可能会丢,但绝不会重复传输
  • at least once: 消息至少发送一次,如果消息未能接受成功,可能会重发,直到接收成功。消息绝不会丢,但可能会重复传输
  • exactly once: 消息只会发送一次
    Kafka默认采用at least once的消息投递策略。消费者fetch消息,然后处理消息,然后保存offset。如果消息处理成功之后,但是在保存offset阶段zookeeper异常导致保存操作未能执行成功,这就导致接下来再次fetch时可能获得上次已经处理过的消息,这就是"at least once",原因offset没有及时的提交给zookeeper,zookeeper恢复正常还是之前offset状态。

4. 副本管理
在这里插入图片描述

  • kafka将每个partition数据复制到多个server上,任何一个partition有一个leader和0个或多个follower;备份的个数可以通过broker配置文件来设定。
  • leader处理所有的read-write请求,follower需要和leader保持同步。Follower和consumer一样,消费消息并保存在本地日志中。
  • leader负责跟踪所有的follower状态,如果follower"落后"太多、“卡住”或者失效,leader将会把它从replicas同步列表中删除。至于落了多远 才叫远由replica.lag.max.messages配置,而表示复本“卡住”由replica.lag.time.max.ms配置
  • 当所有的follower都将一条消息保存成功,此消息才被认为是"committed",那么此时consumer才能消费它。即使只有一个replicas实例存活,仍然可以保证消息的正常发送和接收,只要zookeeper集群存活即可。
  • kafka动态的维护了一组in-sync(ISR)的复本,表示已追上了leader,只有处于该状态的成员组才是能被选择为leader。这些ISR组会在发生变化时被持久化到 zookeeper中。通过ISR模型和f+1复本,可以让kafka的topic支持最多f个节点挂掉而不会导致提交的数据丢失。
  • 当leader失效时,需在followers中选取出新的leader。选择follower时需要兼顾一个问题,就是新leader server上所已经承载的partition leader的个数,如果一个server上有过多的partition leader,意味着此server将承受着更多的IO压力。在选举新leader,需要考虑到"负载均衡"。

5. 日志
如果一个topic的名称为"my_topic",它有2个partitions,那么日志将会保存在my_topic_0和my_topic_1两个目录中;日志文件中保存了一序列"log entries"(日志条目),每个log entry格式为"4个字节的数字N表示消息的长度" + “N个字节的消息内容”;每个日志都有一个offset来唯一的标记一条消息,offset的值为8个字节的数字,表示此消息在此partition中所处的起始位置。每个partition在物理存储层面,有多个log file组成(称为segment)。segmentfile的命名为"最小offset".kafka。例如"00000000000.kafka";其中"最小offset"表示此segment中起始消息的offset
在这里插入图片描述

  • 每个partiton中所持有的segments列表信息会存储在zookeeper中。
  • 当segment文件尺寸达到一定阀值时(可以通过配置文件设定,默认1G),将会创建一个新的文件;当buffer中消息的条数达到阀值时将会触发日志信息flush到日志文件中,同时如果"距离最近一次flush的时间差"达到阀值时,也会触发flush到日志文件。如果broker失效,极有可能会丢失那些尚未flush到文件的消息。因为server意外失效,仍然会导致log文件格式的破坏(文件尾部),那么就要求当server启动时需要检测最后一个segment的文件结构是否合法并进行必要的修复。
  • 获取消息时,需要指定offset和最大chunk尺寸,offset用来表示消息的起始位置,chunk size用来表示最大获取消息的总长度(间接的表示消息的条数)。根据offset,可以找到此消息所在segment文件,然后根据segment的最小offset取差值,得到它在file中的相对位置,直接读取输出即可。

6. zookeeper分布式协调
由于kafka中一个topic中的不同分区只能被消费组中的一个消费者消费,就避免了多个消费者消费相同的分区时会导致额外的开销(如要协调哪个消费者消费哪 个消息,还有锁及状态的开销)。kafka中消费进程只需要在代理和同组消费者有变化时进行一次协调(这种协调不是经常性的,故可以忽略开销)。kafka使用zookeeper来存储一些meta信息,并使用了zookeeper watch机制来发现meta信息的变更并作出相应的动作。

  • Broker Node Registry: 当一个Kafka broker启动后,首先会向zookeeper注册自己的节点信息(临时znode),同时当broker宕机或没有相应时,此znode也会被删除。
    格式:/brokers/ids/[0…N] --> host:port (ephemeral node)
  • Broker Topic Registry: 当一个broker启动时,会向zookeeper注册自己持有的topic和partitions信息,仍然是一个临时znode。
    格式:/broker/topics/[topic]/[0…N] 其中[0…N]表示partition索引号
  • Consumer and Consumer group: 每个consumer客户端被创建时,会向zookeeper注册自己的信息;此作用主要是为了"负载均衡"。一个group中的多个consumer可以交错的消费一个topic的所有partitions;简而言之,保证此topic的所有partitions都能被此group所消费,且消费时为了性能考虑,让partition相对均衡的分散到每个consumer上。
  • Consumer Id Registry: 每个consumer在/consumers/[group_id]/ids下创建一个瞬时的唯一的consumer_id,用来描述当前该group下有哪些consumer是alive的,如果消费进程挂掉对应的consumer_id就会从该节点删除。
    格式:/consumers/[group_id]/ids/[consumer_id] --> {“topic1”: #streams, …, “topicN”: #streams} (ephemeral node)
  • Consumer Offset Tracking: consumer把每个partition的消费offset记录保存在该节点下。
    格式:/consumers/[group_id]/offsets/[topic]/[partition_id] --> offset_counter_value ((persistent node)
  • Partition Owner registry: 用来标记partition被哪个consumer消费。
    格式:/consumers/[group_id]/owners/[topic]/[broker_id-partition_id] --> consumer_node_id (ephemeral node)

以上是关于kafka一些基础说明,在其中我们知道如果要kafka正常运行,必须配置zookeeper,否则无论是kafka集群还是客户端的生存者和消费者都无法正常的工作的,以下是对zookeeper的部署进行一些简单的介绍


- Zookeeper集群安装部署
下面开始介绍Zookeeper的安装部署。安装部署分三种模式:单机模式、伪分布式模式和分布式模式。单机模式和为分布式比较简单,多用于本地测试调试,下面介绍分布式模式安装部署。

注意: 3台机器都需要安装zk。对于Zookeeper集群的话,官方推荐的最小节点数为3个。

1. 环境信息

主机名操作系统版本IP地址安装软件
masterMac10.xxx.xx.2jdk1.8.0 zookeeper3.8.4
slaver1Centos710.xxx.xx.4jdk1.8.0 zookeeper3.8.4
slaver2Centos710.xxx.xx.5jdk1.8.0 zookeeper3.8.4

2. 安装jdk1.8(此处不在赘述)

3. 安装配置zookeeper(以master为例)

  • 将zookeeper安装包拷贝至/app文件夹(本人所有安装的组件都在此文件夹下)

  • 解压安装配置
    1)tar -zxvf zookeeper-3.4.8.tar.gz
    2)cd zookeeper-3.4.8
    3)创建快照日志存放目录:mkdir -p dataDir
    4)创建事务日志存放目录:mkdir dataLogDir
    【注意】: 如果不配置dataLogDir,那么事务日志也会写在dataDir目录中。这样会严重影响zk的性能。因为在zk吞吐量很高的时候,产生的事务日志和快照日志太多
    5)修改配置文件,添加如下内容:
    cd conf
    cp zoo_sample.cfg zoo.cfg
    vim zoo.cfg
    在这里插入图片描述
    在我们配置的dataDir指定的目录下面,创建一个myid文件,里面内容为一个数字,用来标识当前主机,conf/zoo.cfg文件中配置的server.X中X为什么数字,则myid文件中就输入这个数字。

  • 远程复制到另外两台机器上,并修改myid文件内容为2,3
    scp -r zookeeper-3.4.8 hongqiang@slaver1:/app/
    scp -r zookeeper-3.4.8 hongqiang@slaver2:/app/

4.启动和关闭zookeeper

  • zookeeper集群的启动和关闭与Hadoop集群不同,需要在每个节点分别启动和关闭
    1)master:~ hongqiang$ zkServer.sh start(启动)
    2)master:~ hongqiang$ zkServer.sh status(查看状态)
    3)master:~ hongqiang$ zkServer.sh start(停止)
    在这里插入图片描述
  • 另外,可以通过客户端脚本,连接到ZooKeeper集群上。对于客户端来说,ZooKeeper是一个整体,连接到ZooKeeper集群实际上感觉在独享整个集群的服务,所以,你可以在任何一个结点上建立到服务集群的连接。命令如下:
    zkCli.sh -server slaver1:2181

5. zookeeper配置实现自动清理日志

  • 在使用zookeeper过程中,我们知道,会有dataDir和dataLogDir两个目录,分别用于snapshot和事务日志的输出(默认情况下只有dataDir目录,snapshot和事务日志都保存在这个目录中,正常运行过程中,ZK会不断地把快照数据和事务日志输出到这两个目录,并且如果没有人为操作的话,ZK自己是不会清理这些文件的,很快zookeeper日志就会填满磁盘空间。
  • 从3.4.0开始,zookeeper提供了自动清理snapshot和事务日志的功能,通过配置 autopurge.snapRetainCount 和 autopurge.purgeInterval 这两个参数能够实现定时清理了。这两个参数都是在zoo.cfg中配置的:
    1)autopurge.purgeInterval 这个参数指定了清理频率,单位是小时,需要填写一个1或更大的整数,默认是0,表示不开启自己清理功能。
    2)autopurge.snapRetainCount 这个参数和上面的参数搭配使用,这个参数指定了需要保留的文件数目。默认是保留3个。
    通过配置 autopurge.snapRetainCount 和 autopurge.purgeInterval 这两个参数能够实现定时清理了。

- Kafka安装与配置

#打开环境变量配置文件
vim ~/.bash_profile
#添加如下两行代码
export KAFKA_HOME=/app/kafka_2.11-2.1.1
export PATH=$PATH:$KAFKA_HOME/bin
#保存.bash_profile后,执行一下命令使环境变量生效
source .bash_profile

#修改Kafka配置文件server.properties
cd /app/kafka_2.11-2.1.1/config/
vim server.properties

修改一下几处:

– broker.id=0 #broker id,全局不重复
– listeners=PLAINTEXT://master:9092 #监听的IP地址以及端口号
– log.dirs=/tmp/kafka-logs #日志存放地址
– zookeeper.connect=master:2181,slaver1:2181,slaver2:2181 #zookeeper连接地址及端口号

  • 将master节点上的Kafka安装包分发到slaver1和slaver2节点
scp -r kafka_2.11-2.1.1/ hongqiang@slaver1:/app
scp -r kafka_2.11-2.1.1/ hongqiang@slaver2:/app
  • 配置slaver1节点
    1)添加环境变量,见(master节点配置)
    2)修改Kafka配置文件server.properties
    修改一下几处:
    – broker.id=1 #broker id,全局不重复
    – listeners=PLAINTEXT://:9092 #监听的IP地址以及端口号

  • 配置slaver2节点
    1)添加环境变量,见(master节点配置)
    2)修改Kafka配置文件server.properties
    修改一下几处:
    – broker.id=2 #broker id,全局不重复
    – listeners=PLAINTEXT://:9092 #监听的IP地址以及端口号

- 验证Kafka是否安装配置成功
此处启动3个broker,master节点作为生产者发布数据,slaver1和slaver2作为消费者消费数据

  • 启动zookeeper集群
    zkServer.sh start
    zkServer.sh status
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 启动Kafka(三个节点)
    kafka-server-start.sh kafka_2.11-2.1.1/config/server.properties &
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 创建Topic(包含一个分区,三个副本)
    kafka-topics.sh --create --zookeeper master:2181 --replication-factor 3 --partitions 1 --topic test
    在这里插入图片描述
    创建了Topic test,一个partition,三个副本

  • 查询topic的详细描述
    kafka-topics.sh --describe --zookeeper master:2181
    在这里插入图片描述
    Partiton:0 表示分区文件位于broker ID为0的节点
    Leader:0 表示副本的leader位于broker ID为0的节点
    Replicas:0,1,2 表示三个副本分别位于broker ID为0,1,2的节点
    Isr:0,1,2 表示有资格参与leader选举的broker

  • 创建生产者producer,发送数据
    kafka-console-producer.sh --broker-list master:9092 --topic test
    在这里插入图片描述

  • 创建消费者consumer,接收数据
    slaver1:
    kafka-console-consumer.sh --topic test --from-beginning --bootstrap-server localhost:9092
    在这里插入图片描述
    slaver2:
    kafka-console-consumer.sh --topic test --from-beginning --bootstrap-server localhost:9092
    在这里插入图片描述
    实验到此,验证了Kafka集群安装配置成功。


参考资料:
http://kafka.apache.org/intro

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值