1. 安装
docker-compose.yml
version: '3.7'
services:
zookeeper:
image: bitnami/zookeeper:latest ## 镜像
container_name: zookeeper ## 容器名称
restart: always ## 重启策略
ports:
- "2181:2181" ## 对外暴露的端口号
network_mode: 'host' ## 网络模式
environment:
ALLOW_ANONYMOUS_LOGIN: yes
volumes:
- /etc/localtime:/etc/localtime ## 挂载时区(kafka镜像和宿主机器之间时间保持一致)
kafka:
image: bitnami/kafka:latest ## 镜像
container_name: kafka ## 容器名称
ports:
- "9092:9092" ## 对外暴露的端口号
network_mode: 'host' ## 网络模式
environment: ## 环境变量
KAFKA_BROKER_ID: 1
ALLOW_PLAINTEXT_LISTENER: 'yes'
KAFKA_ZOOKEEPER_CONNECT: 47.97.102.116:2181 ## 按实际写入宿主IP
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
KAFKA_ADVERTISED_HOST_NAME: 47.97.102.116
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://47.97.102.116:9092
depends_on: ## 依赖情况
- zookeeper
kafka tool: https://www.kafkatool.com/download.html
2. 简述
- Topic:一组消息数据的标记符;
- Producer:生产者,用于生产数据,可将生产后的消息送入指定的Topic;
- Consumer:消费者,获取数据,可消费指定的Topic;
- Group:消费者组,同一个group可以有多个消费者,一条消息在一个group中,只会被一个消费者获取;
- Partition:分区,为了保证kafka的吞吐量,一个Topic可以设置多个分区。同一分区只能被一个消费者订阅。
3. 命令
# 在较新版本(2.2 及更高版本)的 Kafka 不再需要 ZooKeeper 连接字符串使用Kafka Broker
$ --bootstrap-server localhost:9092 替代- -zookeeper localhost:2181。
# 新建Topic
$ kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 2 --topic topic_name
# 查看当前所有Topic
$ kafka-topics.sh --bootstrap-server localhost:9092 --list
# 消费者消费消息
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topic_name --from-beginning
4. kafka-python
from kafka import KafkaProducer, KafkaConsumer
from kafka.errors import kafka_errors
import traceback
import json
# Master
def producer_demo():
# 假设生产的消息为键值对(不是一定要键值对),且序列化方式为json
producer = KafkaProducer(
bootstrap_servers=['localhost:9092'],
key_serializer=lambda k: json.dumps(k).encode(),
value_serializer=lambda v: json.dumps(v).encode())
# 发送三条消息
for i in range(0, 3):
future = producer.send(
'kafka_demo',
key='count_num', # 同一个key值,会被送至同一个分区
value=str(i),
partition=1) # 向分区1发送消息
print("send {}".format(str(i)))
try:
future.get(timeout=10) # 监控是否发送成功
except kafka_errors: # 发送失败抛出kafka_errors
traceback.format_exc()
# Slave
def consumer_demo():
consumer = KafkaConsumer(
'kafka_demo',
bootstrap_servers=':9092',
group_id='test'
)
for message in consumer:
print("receive, key: {}, value: {}".format(
json.loads(message.key.decode()),
json.loads(message.value.decode())
)
)
参数设置
-
group_id
高并发量,需要多个消费者协作,由group_id统一消费进度。例如:消费者A与消费者B在初始化时使用同一个group_id。当一条消息被A消费后(正确commit),在kafka中会被标记,这条消息不会在被B消费。
-
key_deserializer, value_deserializer
与生产者中的参数一致,自动解析。
-
auto_offset_reset
消费者启动的时刻,消息队列中或许已经有堆积的未消费消息,有时候需求是从上一次未消费的位置开始读(则该参数设置为earliest),有时候的需求为从当前时刻开始读之后产生的,之前产生的数据不再消费(则该参数设置为latest)。
-
enable_auto_commit, auto_commit_interval_ms
是否自动commit,当前消费者消费完该数据后,需要commit,才可以将消费完的信息传回消息队列的控制中心。enable_auto_commit设置为True后,消费者将自动commit,并且两次commit的时间间隔为auto_commit_interval_ms。
手动commit
def consumer_demo(): consumer = KafkaConsumer( 'kafka_demo', bootstrap_servers=':9092', group_id='test', enable_auto_commit=False ) for message in consumer: print("receive, key: {}, value: {}".format( json.loads(message.key.decode()), json.loads(message.value.decode()) ) ) consumer.commit()
-
查看kafka堆积剩余量
在线环境中,需要保证消费者的消费速度大于生产者的生产速度,所以需要检测kafka中的剩余堆积量是在增加还是减小。可以用如下代码,观测队列消息剩余量:
consumer = KafkaConsumer(topic, **kwargs) partitions = [TopicPartition(topic, p) for p in consumer.partitions_for_topic(topic)] print("start to cal offset:") # total toff = consumer.end_offsets(partitions) toff = [(key.partition, toff[key]) for key in toff.keys()] toff.sort() print("total offset: {}".format(str(toff))) # current coff = [(x.partition, consumer.committed(x)) for x in partitions] coff.sort() print("current offset: {}".format(str(coff))) # cal sum and left toff_sum = sum([x[1] for x in toff]) cur_sum = sum([x[1] for x in coff if x[1] is not None]) left_sum = toff_sum - cur_sum print("kafka left: {}".format(left_sum))