Kafka是LinkedIn开源的,属于Apache顶级项目,最初用于日志收集和传输。消费者使用Pull拉取消息,追求高吞吐量,不支持事务,对消息的重复、丢失、错误没有严格要求,适用大量数据的收集。也可以做到消息不丢失,但性能大大减低。
分布式:具有分布式特性,支持消息分区的概念,其核心的概念就是partition, 一个topic下可以有很多个partition,而partition与consumer是一一对应的。
跨平台:具有跨平台的特性,支持不同语言的客户端,比如Java,PHP,Python等
实时性:具有很强的实时性,支持实时处理和离线处理,即使kafka存在大量的数据堆积,只有存储没有问题,它不会影响kafka的性能。
伸缩性:它支持水平扩展
1、高效读写,Page Cache(空中接力,高效读写):顺序写磁盘,可以提高磁盘的利用率,比如consumer通过offset顺序的去消费这些数据,而不删除已经消费过的数据,从而避免磁盘的随机写。一般MQ设计都要做到顺序写磁盘,而不会允许删除消息。借助linux内核的page cache概念,不显式用内存,重启kafka也不会丢失。
2、高性能、高吞吐:初衷,日志收集。
3、后台异步、主动Flush:好多异步级别的scheduler,将连续的小块组成一个大块的物理文件。文件按顺序排好,减少磁盘移动时间,充分利用空闲的内存。
4、预读策略、IO调度、zoreCopy
page cacge是操作系统级别实现的一种主要的磁盘缓存策略,目的减少对磁盘IO的操作,如果频繁的进行IO操作,会影响磁盘的性能,其实就是把磁盘的数据缓存到内存中,把对磁盘的访问转移到对内存的访问,减少磁盘IO操作,用空间换时间。
举个例子,这个思想有点像我们平时开发高并发的互联网项目一样,最开始都是读写关系型数据库如MySQL,压力大时会做分库分表,再后面会考虑使用非关系型数据库如MongoDB,或者远程缓存如Redis,当压力达到Redis都扛不住时会考虑用本地内存缓存。
我们从磁盘读取一个文件,操作系统先到内存中检查文件是否存在,如果存在就直接返回。如果不存在会对磁盘进行一次读操作,读到的数据并不是直接返回给进程,而是先写入到内存中再返回,下一次访问同一个文件时候就比较快。现在越来越多的系统和架构都利用了cache策略。
举个例子,我们查数据库时候,第一次查会慢一点,当第二次重复再执行这条语句时,数据库立马执行完并返回结果,这也是利用了数据库的缓存策略。
当我们要写入一个文件时,操作系统先把数据写入对应的到缓存页中, 如果这个页不存在,就会在缓存页中添加相应的页,将数据写入页中,被修改的这个页就成了“脏页”,等待合适的时机,操作系统会把这个数据刷回到磁盘中。
应用程序把一个磁盘文件读到内存里,再写入到另外一个进程,需要经历四次IO,分别是:磁盘文件->①内核读取缓冲区->②用户缓冲区->③内核空间缓存区->④socket缓存区->网卡接口,这是一种传统的文件读写。
下图展示了通过transferTo实现数据传输的路径
使用了Zero-Copy技术之后,整个过程如下:
这显然是一个伟大的进步:这里把上下文的切换次数从4次减少到2次,同时也把数据copy的次数从4次降低到了3次。
真正的zeroCopy,在内核为2.4或者以上版本的linux系统上,socket缓冲区描述符将被用来满足这个需求。这个方式不仅减少了内核用户态间的切换,而且也省去了那次需要cpu参与的复制过程。
从用户角度来看依旧是调用transferTo()方法,但是其本质发生了变化:
1、调用transferTo方法后数据被DMA从文件复制到了内核的一个缓冲区中。
2、数据不再被复制到socket关联的缓冲区中了,仅仅是将一个描述符(包含了数据的位置和长度等信息)追加到socket关联的缓冲区中。DMA直接将内核中的缓冲区中的数据传输给协议引擎,消除了仅剩的一次需要cpu周期的数据复制。
3、省去cpu参与的复制过程。
Kafka使用了zeroCopy技术,把四次IO减少到一次IO,从磁盘文件拷贝到内核读取缓冲区后,DMA直接把数据发送到网卡接口,给消费者使用,避免了重复复制的操作,应用程序上下文不做任何copy。
如果有10个消费者,使用传统文件读写需要10*4次IO拷贝,而使用zore copy只需要1+10次。
如果生产者和消费者的速度相当的时候,那么消息直接从内存中(page cache)读取就可以了,甚至完全用不到磁盘,磁盘相当于一个异步备份而已。
Kafka不保证100%可靠性,但一定会有可靠性考量。内存级别副本replicate,相同的消息在存在多份(多个节点)。
如果要实现Kafka消息不丢也是可以配置的,但性能会有所下降。
Zookeeper是一个类似Linux、hdfs的树形文件结构,Zookeeper可以用来保证数据在集群之间的数据的事务一致性,Zookeeper强调CAP理论(强一致性)
1. 准备工作:
## 准备3个节点,要求配置好主机名称,服务器之间系统时间保持一致
## 注意 /etc/hostname 和 /etc/hosts 配置主机名称(在这个里我准备bhz125,bhz126,bhz127三节点)
## 特别注意 以下操作3个节点要同时进行操作哦!
2. 上传zk到三台服务器节点
## 注意我这里解压到/usr/local下
2.1 进行解压: tar zookeeper-3.4.6.tar.gz
2.2 重命名: mv zookeeper-3.4.6 zookeeper
2.3 修改环境变量: vim /etc/profile
## 这里要添加zookeeper的全局变量
export ZOOKEEPER_HOME=/usr/local/zookeeper
export PATH=.:$ZOOKEEPER_HOME/bin
2.4 刷新环境变量: source /etc/profile
2.5 到zookeeper下修改配置文件:
2.5.1 首先到指定目录: cd /usr/local/zookeeper/conf
2.5.2 然后复制zoo_sample.cfg文件,复制后为zoo.cfg: mv zoo_sample.cfg zoo.cfg
2.5.3 然后修改两处地方, 最后保存退出:
(1) 修改数据的dir
dataDir=/usr/local/zookeeper/data
(2) 修改集群地址
server.0=bhz125:2888:3888
server.1=bhz126:2888:3888
server.2=bhz127:2888:3888
2.6 增加服务器标识配置,需要2步骤,第一是创建文件夹和文件,第二是添加配置内容:
(1) 创建文件夹: mkdir /usr/local/zookeeper/data
(2) 创建文件myid 路径应该创建在/usr/local/zookeeper/data下面,如下:
vim /usr/local/zookeeper/data/myid
注意这里每一台服务器的myid文件内容不同,分别修改里面的值为0,1,2;与我们之前的zoo.cfg配置文 件里:server.0,server.1,server.2 顺序相对应,然后保存退出;
2.7 到此为止,Zookeeper集群环境大功告成!启动zookeeper命令
启动路径:/usr/local/zookeeper/bin(也可在任意目录,因为配置了环境变量)
执行命令:zkServer.sh start (注意这里3台机器都要进行启动,启动之后可以查看状态)
查看状态:zkServer.sh status (在三个节点上检验zk的mode, 会看到一个leader和俩个follower)
具体Zookeeper集群搭建
## kafka 环境安装
下载地址: http://kafka.apache.org/downloads.html
kafka安装要依赖Zookeeper,构建kafka broker
## 解压命令:
tar -zxvf kafka_2.12-2.1.0.tgz -C /usr/local/
## 改名命令:
mv kafka_2.12-2.1.0/ kafka_2.12
## 进入解压后的目录,修改server.properties文件:
vim /usr/local/kafka_2.12/config/server.properties
## 修改配置:
broker.id=0
port=9092
host.name=192.168.11.51
advertised.host.name=192.168.11.51
log.dirs=/usr/local/kafka_2.12/kafka-logs
num.partitions=2
zookeeper.connect=192.168.11.111:2181,192.168.11.112:2181,192.168.11.113:2181
## 建立日志文件夹:
mkdir /usr/local/kafka_2.12/kafka-logs
##启动kafka:
/usr/local/kafka_2.12/bin/kafka-server-start.sh /usr/local/kafka_2.12/config/server.properties &
## 简单操作:
#(1)创建topic主题命令:(创建名为test的topic, 1个分区分别存放数据,数据备份总共1份)
kafka-topics.sh --zookeeper 192.168.11.111:2181 --create --topic topic1 --partitions 1 --replication-factor 1
## --zookeeper 为zookeeper服务列表地址配置项,这里任意指定zookeeper其中一个服务列表地址即可
## --create 命令后 --topic 为创建topic 并指定 topic name
## --partitions 为指定分区数量配置项
## --replication-factor 为指定副本集数量配置项
#(2)查看topic列表命令:
kafka-topics.sh --zookeeper 192.168.11.111:2181 --list
#(3)kafka命令发送数据:(然后我们就可以编写数据发送出去了)
kafka-console-producer.sh --broker-list 192.168.11.51:9092 --topic topic1
## --brokerlist kafka服务的broker节点列表
#(4)kafka命令接受数据:(然后我们就可以看到消费的信息了)
kafka-console-consumer.sh --bootstrap-server 192.168.11.51:9092 --topic topic1 --from-beginning
#(5)删除topic命令:
kafka-topics.sh --zookeeper 192.168.11.111:2181 --delete --topic topic1
#(6)kafka查看消费进度:(当我们需要查看一个消费者组的消费进度时,则使用下面的命令)
kafka-consumer-groups.sh --bootstrap-server 192.168.11.51:9092 --describe --group group1
## --describe --group 为订阅组, 后面指定 group name