Kafka消息中间件
一、为什么使用Kafka
1.1 什么是Kafka
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 这种动作(网页浏览、搜索和其他用户的行动)是在现代网络上的许多功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息。
1.2 特性
Kafka 是一种高吞吐量的分布式发布订阅消息系统,有如下特性:
- 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。
- 高吞吐量,即使是非常普通的硬件Kafka也可以支持每秒数百万 [2] 的消息。
- 支持通过Kafka服务器和消费机集群来分区消息。
- 支持Hadoop并行数据加载。
1.3 术语
-
Broker
Kafka集群包含一个或多个服务器,这种服务器被称为broker [5]
-
Topic
每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)
-
Partition
Partition是物理上的概念,每个Topic包含一个或多个Partition.
-
Producer
负责发布消息到Kafka broker
-
Consumer
消息消费者,向Kafka broker读取消息的客户端。
-
Consumer Group
每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。
1.4 比较RabbitMQ
RabbitMQ是一个分布式系统,存在以下抽象概念:
- broker:每个节点运行的服务程序,功能为维护该节点的队列的增删以及转发队列操作请求。
- master queue:每个队列都分为一个主队列和若干个镜像队列。
- mirror queue:镜像队列,作为master queue的备份。在master queue所在节点挂掉之后,系统把mirror queue提升为master queue,负责处理客户端队列操作请求。注意,mirror queue只做镜像,设计目的不是为了承担客户端读写压力。
如上图所示,集群中有两个节点,每个节点上有一个broker,每个broker负责本机上队列的维护,并且borker之间可以互相通信。集群中有两个队列A和B,每个队列都分为master queue和mirror queue(备份)。那么队列上的生产消费怎么实现的呢?
1) 队列消费
如上图有两个consumer消费队列A,这两个consumer连在了集群的不同机器上。RabbitMQ集群中的任何一个节点都拥有集群上所有队列的元信息,所以连接到集群中的任何一个节点都可以,主要区别在于有的consumer连在master queue所在节点,有的连在非master queue节点上。
因为mirror queue要和master queue保持一致,故需要同步机制,正因为一致性的限制,导致所有的读写操作都必须都操作在master queue上(想想,为啥读也要从master queue中读?和数据库读写分离是不一样的。),然后由master节点同步操作到mirror queue所在的节点。即使consumer连接到了非master queue节点,该consumer的操作也会被路由到master queue所在的节点上,这样才能进行消费。
2) 队列生产
原理和消费一样,如果连接到非 master queue 节点,则路由过去。
所以,到这里小伙伴们就可以看到 RabbitMQ的不足:由于master queue单节点,导致性能瓶颈,吞吐量受限。虽然为了提高性能,内部使用了Erlang这个语言实现,但是终究摆脱不了架构设计上的致命缺陷。
3)Kafka优势
说实话,Kafka我觉得就是看到了RabbitMQ这个缺陷才设计出的一个改进版,改进的点就是:把一个队列的单一master变成多个master,即一台机器扛不住QPS(每秒查询率),那么我就用多台机器扛QPS,把一个队列的流量均匀分散在多台机器上不就可以了么?注意,多个master之间的数据没有交集,即一条消息要么发送到这个master queue,要么发送到另外一个master queue。
这里面的每个master queue 在Kafka中叫做Partition,即一个分片。一个队列有多个主分片,每个主分片又有若干副分片做备份,同步机制类似于RabbitMQ。
如上图,我们省略了不同的queue,假设集群上只有一个queue(Kafka中叫Topic)。每个生产者随机把消息发送到主分片上,之后主分片再同步给副分片。
队列读取的时候虚拟出一个Group的概念,一个Topic内部的消息,只会路由到同Group内的一个consumer上,同一个Group中的consumer消费的消息是不一样的;Group之间共享一个Topic,看起来就是一个队列的多个拷贝。所以,为了达到多个Group共享一个Topic数据,Kafka并不会像RabbitMQ那样消息消费完毕立马删除,而是必须在后台配置保存日期,即只保存最近一段时间的消息,超过这个时间的消息就会从磁盘删除,这样就保证了在一个时间段内,Topic数据对所有Group可见(这个特性使得Kafka非常适合做一个公司的数据总线)。队列读同样是读主分片,并且为了优化性能,消费者与主分片有一一的对应关系,如果消费者数目大于分片数,则存在某些消费者得不到消息。
由此可见,Kafka绝对是为了高吞吐量设计的,比如设置分片数为100,那么就有100台机器去扛一个Topic的流量,当然比RabbitMQ的单机性能好。
二、部署Kafka
因为Kafka需要Zookeeper(Google Chubby)实现分布式应用程序协调服务,所以先安装配置好Zookeeper。
2.1 下载镜像
docker pull wurstmeister/zookeeper
docker pull wurstmeister/kafka
2.2 编写Docker-compose文件
关于Docker-Compose.yml文件的编写规则请参考:Docker Compose 详解
编写docker-compose.yml文件,内容如下:
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
ports:
- "2181:2181"
container_name: zookeeper
kafka:
image: wurstmeister/kafka
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_HOST_NAME: localhost
KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181"
KAFKA_BROKER_ID: 1
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_CREATE_TOPICS: "stream-in:1:1,stream-out:1:1"
volumns:
- /data/kafka/docker.sock:/var/run/docker.sock
container_name: kafka
version:指定 docker-compose.yml 文件的写法格式
services:多个容器集合
KAFKA参数说明
-
**KAFKA_ZOOKEEPER_CONNECT: ** 连接zookeeper的字符描述
-
KAFKA_CREATE_TOPICS: Kafka运行后自动创建的topics(话题), stream-in是topic的名称, :1:1是表示partitions的数量(分区)及备份(ReplicationFactor)的数量
container_name: 容器名称
2.3 编排工具安装
apt install docker-compose -y
查看帮助的命令
docker-compose -h
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file (default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name (default: directory name)
--verbose Show more output
--no-ansi Do not print ANSI control characters
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the name specified
in the client certificate (for example if your docker host
is an IP address)
--project-directory PATH Specify an alternate working directory
(default: the path of the Compose file)
Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information
2.4 编排构建
在 docker-compose.yml 文件所在目录下,执行如下命令:
root@llserver:~/kafka# docker-compose build
zookeeper uses an image, skipping
kafka uses an image, skipping
2.5 运行服务
docker-compose up -d
up命令是创建并启动容器
-d 是后台运行
2.6 查看服务
查看kafka和zookeeper是否启动
docker-compose ps
查看kafka启动的日志信息
docker-compose logs kafka
三、Kafka的应用
3.1 Kafka官方文档
官方文档: http://kafka.apache.org/documentation/
另外,关于Kafka的partition和topic的关系描述,请参考: https://www.jianshu.com/p/cdfc3df9e4c6
3.2 创建话题Topic
进入到kafka容器中
docker exec -it kafka bash
创建话题 my_topic
$KAFKA_HOME/bin/kafka-topics.sh --create --topic my-topic --partitions 4 --zookeeper zookeeper:2181 --replication-factor 1
查看话题
$KAFKA_HOME/bin/kafka-topics.sh --zookeeper zookeeper:2181 --describe --topic my-topic
命令的结果:
Topic:my_topic PartitionCount:4 ReplicationFactor:1 Configs:
Topic: my_topic Partition: 0 Leader: 1 Replicas: 1 Isr: 1
Topic: my_topic Partition: 1 Leader: 1 Replicas: 1 Isr: 1
Topic: my_topic Partition: 2 Leader: 1 Replicas: 1 Isr: 1
Topic: my_topic Partition: 3 Leader: 1 Replicas: 1 Isr: 1
查看所有话题
$KAFKA_HOME/bin/kafka-topics.sh --zookeeper zookeeper:2181 --list
【扩展】查看所有Kafka的brokers
docker exec zookeeper bin/zkCli.sh ls /brokers/ids
3.3 发布消息
$KAFKA_HOME/bin/kafka-console-producer.sh --topic my_topic --broker-list kafka:9092
>
按Ctrl+C退出编写消息。
3.4 接收消息
$KAFKA_HOME/bin/kafka-console-consumer.sh --bootstrap-server kafka:9092 --from-beginning --topic my_topic
开始接收my_topic的消息。
四、Python交互
参考: https://pypi.org/project/kafka-python/
4.1 安装环境
pip install kafka-python==1.4.7
参考: https://blog.youkuaiyun.com/luanpeng825485697/article/details/81036028
五、集群管理
拉镜像
docker pull sheepkiller/kafka-manager
启动服务
docker run -itd --name kafka-manager -p 9000:9000 -e ZK_HOSTS="localhost:2181" sheepkiller/kafka-manager
ZK_HOSTS 是zookeeper的路径。
访问
http://localhost:9000/