目录
安装的话直接第三步即可
一.基本概念
- 一个典型的kafka体系架构包括若干producer、若干broker、若干consumer,以及一个zookeeper集群,其中zookeeper是kafka用来负责集群元数据的管理、控制器的选举等操作的。producer将消息发送到broker,broker负责将收到的消息存储到磁盘中,而consumer负责从broker订阅并消费消息。
二.术语介绍
-
producer:生产者,也就是发送消息的一方。生产者负责创建消息,然后将其投递到kafka中。
-
consumer:消费者,也就是接收消息的一方。消费者连接到kafka上并接收消息,进而进行相应的业务逻辑处理。
-
broker:服务代理节点。对于kafka而言,broker可以简单地看作一个独立的kafka服务节点或kafka服务实例。大多数情况下 也可以将broker看作一台kafka服务器,前提是这台服务器上只部署了一个kafka实例。一个或多个broker组成了一个kafka集群。
-
还有两个特别重要的概念——topic(主题)和partition(分区),kafka中的消息以topic为单位进行归类,生产者负责将消息发送到特定的主题(发送到kafka集群中的每一条消息都是指定一个主题),而消费者负责订阅主题并进行消费。
-
topic是一个逻辑上的概念,它还可以细分为多个partition,一个分区只属于单个topic,很多时候也把分区称为topic-partition(主题分区)。同一topic下的不同partition包含的消息是不同的,partition在存储层面可以看作一个可追加的log(日志)文件,消息在被追加到分区log文件的时候都会分配一个特定的offset(偏移量)。
-
offset是消息在分区中的唯一标识,kafka通过它来保证消息在分区类的顺序性,不过offset并不跨越分区,也就是说,kafka保证的是partition有序而不是topic有序!!
-
-
如上图所示,topic有四个partition,消息被顺序追加到每个partition的log文件的尾部。kafka的partition可以分布在不同的broker上,也就是说,一个topic可以横跨多个broker,以此来提供比单个broker更强大的性能。
-
每一条消息被发送到broker之前,会根据分区规则训着存储到那个具体的partition。如果partition规则设定得合理,所有的消息都可以均匀分配到不同的partition中。如果一个topic只对应一个文件,那么这个文件所在的机器I/O将会成为这个topic的性能瓶颈,二partition解决了这个问题,在创建topic的时候可以通过制定的参数来设置partition的个数,当然也可以在topic创建完成之后去修改partition的数量,通过增加partition的数量可以实现水平拓展。
-
-
kafka为partition引入了replica(多副本)机制,通过增加replica数量可以提升容灾能力。同一partition的不同replica中保存的是相同的消息(在同一时刻,replica之间并非完全一样),replica之间是“一主多从”的关系,其中leader副本负责处理读写请求,follower副本只负责与leader副本的消息同步。replica处于不同的broker中,当leader副本出现故障时,从follower副本中重新 选举新的leader副本对外提供服务。kafka通过多replica机制实现了故障的自动转移,当kafka集群中某个broker失效时仍然能保证服务可用。
-
如上图,kafka集群中有4个broker,某个topic中有三个partition,且副本因子(副本个数)也为3,如此每个分区中便有1个leader副本和2个follower副本。生产者和消费者只与leader副本进行交互,而follower副本只负责消息的同步,很多时候follower副本中的消息相对leader副本而言会有一定的滞后。
-
kafka消费端也具备一定的容灾能力。consumer使用pull(拉)模式从服务端拉取消息,并且保存消费的具体位置,当消费者宕机后恢复上线时可以根据之前保存的消费位置重新拉取需要的消息进行消费,这样就不会造成消息丢失。
-
分区中所有的副本统称为AR(Assigned Replica)。所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成ISR(In-Sync Replica),消息会先发送到leader副本,然后follower副本才能从leader副本中拉群消息同步,同步期内follower副本相对于leader副本会有一定程度的滞后(可以忍受的范围,可以通过参数进行配置)。滞后过多的副本(不包括leader副本)组成OSR(Out-of-Sync Replicas),由此可见 AR=ISR+OSR。正常情况下,所有follower副本都应该与leader副本保持一定程度的同步,即AR=ISR。OSR集合为空。
-
leader副本负责维护和跟踪ISR集合中所有follower副本的滞后状态,当follower副本落后太多或失效时,leader副本会把它从ISR集合中剔除。如果OSR集合中有follower副本“追上”了leader副本,那么leader副本会把它从OSR集合转移至ISR集合。默认情况下,当leader副本发生故障时,只有在ISR集合中的副本才有资格被选举为新的leader,而在OSR集合中的副本则没有任何机会(不过这个原则也可以通过修改相应的参数配置来改变)。
-
ISR与HW(High Watermark:高水位)和LEO(Log End Offset)也有紧密的关系。
-
HW标识了一个特定的消息offset,消费者只能拉群到这个offset之前的消息。
-
-
如上图所示,它代表一个文件,这个日志文件有9条消息,第一条消息的offset(LogStartOffset)为0,最后一条消息的offset为8,offset为9的消息用虚线框表示,代表下一条待写入的消息。日志文件的HW为6,表示消费者只能拉取到offset在0-5之间的消息,而offset为6的消息对消费者而言是不可见的。
-
LEO标识了当前log文件中下一条待写入消息的offset。上图中offset为9的位置即为当前日志文件的LEO,LEO的大小相当于当前日志分区中最后一条消息的offset值加1。分区ISR集合中的每个副本都会维护自身的LEO,而ISR集合中最小的LEO即为分区的HW,对消费者而言只能消费HW之前的消息。
-
为了更好的理解ISR集合,以及HW和LEO之间的关系,下面通过一个简单的实例来进行相关的说明。
如上图所示,假设某个分区的ISR集合中有3个副本,即一个leader副本和2个follower副本,此时分区的LEO和HW都为3 。
消息3和消息4从生产者发出之后会被先存入leader副本,如下图所示。
在同步过程中,不同的follower副本的同步效率也不尽相同,如下图所示,在某一时刻follower1完全跟上了leader副本而follower2只同步了消息3,如此leader副本的LEO为5,follower1的LEO为5,follower2的LEO为4,那么当前分区的HW取最小值4,此时消费者可以消费到offset为0-3之间的消息。
写入消息,如下图所示,所有的副本都成功写入了消息3和消息4,整个分区的HW和LEO都变为5,因此消费者可以消费道offset为4的消息了。
由此可见,Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。事实上,同步复制要求所有能工作的follower副本都复制完,这条消息才会被确认为成功提交,这种复制方式极大地影响了性能。而在异步复制方式下,follower副本异步地从leader副本中复制数据,数据只要被leader副本写入就被认为已经提交成功。在这种情况下,如果follower副本都没有完成复制而落后于leader副本,突然leader副本宕机,则会造成数据丢失。Kafka使用的这种ISR的方式则有效地权衡了数据可靠性和性能之间的关系。
-
-
搭建kafka运行环境需要涉及zookeeper,而kafka和zookeeper都是运行在JVM之上的服务,所以需要安装JDK。kafka从2.0.0版本就不在支持JDK7及以下版本,此处以JDK8为例。并且操作目录都在/opt目录下。
三.安装与配置
- JDK的安装与配置;(本次搭建需要3台机器)
- 下载JDK安装包(jdk-8u162-linux-x64.tar.gz),可以去oracle官网,然后下载上传到服务器/opt目录下(可点这里下载全部,提取码5uf0)
- 进入/opt目录解压;
tar xzvf jdk-8u162-linux-x64.tar.gz
mv jdk1.8.0_162 jdk
#/opt/jdk 就是当前JDK8的安装目录 - 配置JDK环境变量;
[root@postfix ~]# vim /etc/profile #在尾部追加下面代码 export JAVA_HOME=/opt/jdk1.8.0_45 export JRE_HOIME=$JAVA_HOME/jre export PATH=$PATH:$JAVA_HOME/bin export CLASSPATH=./://$JAVA_HOME/lib:$JRE_HOME/lib
- 配置生效;
[root@postfix ~]# source /etc/profile
- 验证;
[root@postfix ~]# java -version java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
其余两台机器也需配好JDK环境
-
zookeeper的安装与配置
-
zookeeper是安装kafka集群的必要组件,kafka通过zookeeper来实施对元数据信息的管理,包括集群、broker、主题、分区等内容。
-
zookeeper是一个开源的分布式协调服务,是Google Chubby的一个开源实现。分布式应用程序可以基于zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、master选举、配置维护等功能。在zookeeper中共有三个角色:leader、follower和observer,同一时刻,zookeeper集群中只会有一个leader,其他的都是follower和observer。observer不参与投票,默认情况下zookeeper中只有leader和follower两个角色。更多知识可以查阅zookeeper官方网站来获得。
-
下载zookeeper(zookeeper-3.4.14.tar.gz)安装包上传到/opt目录;http://archive.apache.org/dist/zookeeper/
-
cd /opt
tar xzvf zookeeper-3.4.14.tar.gz
mv zookeeper-3.4.14 zookeeper -
配置变量;(配置jdk已配置过)
[root@postfix ~]# vim /etc/profile #在尾部追加 export ZK_HOME=/opt/zookeeper export PATH=$PATH:$ZK_HOME/bin [root@postfix ~]# source /etc/profile
- 修改zookeeper的配置文件;
[root@postfix conf]# cd /opt/zookeeper/conf [root@postfix conf]# cp zoo_sample.cfg zoo.cfg [root@postfix conf]# cat zoo.cfg #zookeeper服务器心跳时间,单位为ms tickTime=2000 #允许follower连接并同步到leader的初始化连接时间,以tickTime的倍数表示 initLimit=10 #leader与follower心跳检测最大容忍时间,响应超过syncLimit*tickTime,leader认为 #follower“死掉”,从服务器列表中删除follower syncLimit=5 #数据目录 dataDir=/opt/zookeeper/data #日志目录 dataLogDir=/opt/zookeeper/log #zookeeper对外服务端口 clientPort=2181 #集群配置 server.0=192.168.1.116:2888:3888 server.1=192.168.1.117:2888:3888 server.2=192.168.1.118:2888:3888
默认情况下没有data和log两个目录,需要手动创建
-
mkdir -pv /opt/zookeeper/{data,log}
-
关于集群配置,示例:server.A=B:C:D,其中A是一个数字,代表服务器的编号,也就是myid文件的值。集群中每台服务器的编号都必须唯一,所以要保证每台服务器中的myid文件中的值不同。B代表服务器的IP地址。C表示服务器与集群中的leader服务器交换信息的端口。D表示选举时服务器相互通信的端口。
-
-
添加myid文件;
根据集群配置的A和B的值对应添加myid-
111机器:echo 0 > /opt/zookeeper/data/myid
-
112机器:echo 1 > /opt/zookeeper/data/myid
-
113机器:echo 2 > /opt/zookeeper/data/myid
-
- 启动集群;
cd /opt/zookeeper/bin ./zkServer.sh start
- 检测集群状态;
cd /opt/zookeeper/bin ./zkServer.sh status #可以用jps -l查看java的进程 [root@postfix bin]# jps -l 1858 sun.tools.jps.Jps 1733 org.apache.zookeeper.server.quorum.QuorumPeerMain
-
-
kafka的安装与配置
-
下载kafka(kafka_2.12-2.1.0.tgz)安装包上传到/opt目录;https://archive.apache.org/dist/kafka/
cd /opt tar xzvf kafka_2.12-2.1.0.tgz mv kafka_2.12-2.1.0 kafka
-
配置变量;
[root@postfix conf]# vim /etc/profile #在尾部追加 export KK_HOME=/opt/kafka export PATH=$PATH:$KK_HOME/bin [root@postfix conf]# source /etc/profile
- 修改broker配置文件;
以111机器为例
确保集群中每个 broker的broker.id配置参数不一样,以及listeners配置参数也需要修改为broker对应的IP地址或域名,之后就各自启动服务,且确保需要连接的zookeeper集群以及正确启动。cd /opt/kafka/config cat server.properties #broker的编号,如果集群中有多个broker,则每个broker的编号需要设置得不同 broker.id=0 #broker对外提供的服务入口地址 listeners=PLAINTEXT://192.168.1.111:9092 #存放消息日志文件的地址 log.dirs=/opt/kafka/logs #kafka所需的zookeeper的集群地址,用,隔开zookeeper集群 zookeeper.connect=192.168.1.111:2181,192.168.1.112:2181,192.168.1.113:2181 #配置信息有点少,大家可以做响应的调整
- 启动
cd /opt/kafka mkdir -v logs bin/kafka-server-start.sh config/server.properties 后台运行: bin/kafka-server-start.sh -daemon config/server.properties 或者 nohup bin/kafka-server-start.sh config/server.properties & 或者 bin/kafka-server-start.sh /config/server.properties >>kafka.log 2>&1 & #如果报错,看看报错的是什么,楼主这边内存报错了, [root@postfix kafka]# bin/kafka-server-start.sh config/server.properties Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c0000000, 1073741824, 0) failed; error='Cannot allocate memory' (errno=12) # # There is insufficient memory for the Java Runtime Environment to continue. # Native memory allocation (mmap) failed to map 1073741824 bytes for committing reserved memory. # An error report file with more information is saved as: # /opt/kafka/hs_err_pid1922.log 于是加2个G的虚拟内存 [root@postfix kafka]# free -m total used free shared buff/cache available Mem: 972 307 95 8 569 512 Swap: 0 0 0 [root@postfix kafka]# dd if=/dev/zero of=/tmp/big_swap bs=1M count=2048 记录了2048+0 的读入 记录了2048+0 的写出 2147483648字节(2.1 GB)已复制,6.84442 秒,314 MB/秒 [root@postfix kafka]# du -sh /tmp/big_swap 2.0G /tmp/big_swap [root@postfix kafka]# mkswap /tmp/big_swap 正在设置交换空间版本 1,大小 = 2097148 KiB 无标签,UUID=af730916-f855-4cb7-bd70-dd8c574c2f62 [root@postfix kafka]# swapon /tmp/big_swap swapon: /tmp/big_swap:不安全的权限 0644,建议使用 0600。 [root@postfix kafka]# free -m total used free shared buff/cache available Mem: 972 300 76 8 596 520 Swap: 2047 0 2047 在fstab加入/root/swapfile swap swap defaults 0 0 如果要关闭某个分区,可以swapon 路径,比如上面那个 [root@postfix kafka]# swapon /tmp/big_swap swapon: /tmp/big_swap:不安全的权限 0644,建议使用 0600。 [root@postfix kafka]# free -m total used free shared buff/cache available Mem: 972 300 76 8 596 520 Swap: 2047 0 2047
- 检测启动状态
-
四.测试
生产者将消息发送至kafka的主题中(准确说是主题的分区中),而消费者也是通过订阅主题从而消费消息的。在演示生产与消费之前,需要创建一个topic作为消息的载体。
- 创建topic;
cd /opt/kafka/bin ./kafka-topics.sh --create --zookeeper 192.168.1.111:2181,192.168.1.112:2181,192.168.1.113:2181 --topic test --partitions 3 --replication-factor 1 !!--topic 指定了所要创建主题的名称 !!--partitions 指定了分区个数 !!--replication-factor 指定了副本因子 !!--create 创建主题动作命令
#查看所有topic ./kafka-topics.sh --list --zookeeper 192.168.1.111:2181,192.168.1.112:2181,192.168.1.113:2181
#查看指定topic详情 ./kafka-topics.sh --describe --zookeeper 192.168.1.111:2181,192.168.1.112:2181,192.168.1.113:2181 --topic test
- 生产数据;
111机器操作./kafka-console-producer.sh --broker-list 192.168.1.111:9092,192.168.1.112:9092,192.168.1.113:9092 --topic test !!--broker-list 指定了kafka集群地址
- 消费数据
112机器或者113机器操作./kafka-console-consumer.sh --bootstrap-server 192.168.1.113:9092 --topic test !!--bootstrap-server #指定kafka集群(全部或指定一台或随意搭配)
- 演示
在111机器输入 Welcome to Kafka!!!
在113机器查看全部