模块安装
1.在使用python调用kafka的时候我选择的模块是confluent_kafka这个模块,首先安装模块
pip install confluent_kafka
模块使用
我们知道kafka是一个消息队列,那么就必须有一个生产者和消费者,生产者负责向kafka队列中放入消息而消费者负责从kafka队列中获取消息,并且执行消息相关任务,所以我们就要基于confluent_kafka有一个生产者和消费者
生产者代码
from confluent_kafka import Producer
producer = Producer({'bootstrap.servers': bootstrap_servers})
producer.produce(topic, key=key_bytes, value=message)
producer.flush()
# 上面是一个生产者实例代码
# 1.从confluent_kafka从该模块中导入我们的生产者类Producer
# 2.我们生产者需要指定我们kafka的IP地址和端口,bootstrap_servers就我们IP+端口,kafka的默认端口
是9092,我们本地这个参数就是"localhost:9092",这样python代码会成功连接我们的kafka
# 3.我们连接kafka之后就要发送消息到kafka中,这个时候就要注意我们需要填写的参数
# topic:kafka的主题,kafka的队列中可以创建多个主题,不同主题可以理解为不同的通道
# key 我们发送消息的key,可以理解为python字典的key,可以做判断
# Value 就是我们发送的消息,我们可以通过key来判断同一个主题中是否是我们需要消费的消息
消费者代码
from confluent_kafka import Consumer
def consume(topic):
c = Consumer({
'bootstrap.servers': bootstrap_servers,
'group.id': '3', # 消费者组ID,不同于消费者2的组ID
'auto.offset.reset': 'earliest' # 从最早的消息开始消费
})
c.subscribe([topic])
while True:
msg = c.poll(timeout=1.0)
if msg is None:
continue
if msg.error():
print("消费错误: {}".format(msg.error()))
continue
print('消费者1接收到消息: {}'.format(msg.value().decode('utf-8')))
key = msg.key().decode()
if key == '127.0.0.1':
print('消费者1接收到消息: {}'.format(msg.value().decode('utf-8')))
# 同样的我们需要导入我们消费者类
# 1.我们消费者对象产生的时候注意几个参数
# bootstrap.servers kafka的IP:端口
# group.id 消费者组IP,在同一个TOPIC中,不同的组id的消费者他们的消费是不会互相影响的
# auto.offset.reset 消费逻辑,earliest代表从最早的消息开始消费,latest表示从最新的开始消 费,这两个可以这么理解,当我们消费者还没有启动的时候,如果我们生产者向队列中生产消息,如果参数是earliest,那么会从生产者丢入的第一个消息开始消费,如果是latest他只会消费他启动以后生产者生产的消息
# 2.c.subscribe([topic]) 就是去消费指定的主题消息
# 3.c.poll(timeout=1.0) 每隔一秒去消费一次,如果没有消费消息会堵塞住,等待队列中有消息
以上是我们的生产者与消费者大概就是这样的,这其中最关键的就是主题,我们不管是生产还是消费的时候都要指定一个主题,当生产者与消费者在同一个主题他们在能真正的完成生产与消费,关于创建主题,我们可以通过kafka自有的命令来创建主题,如下:
kafka自有创建主题
windows系统为例:
创建主题:
首先我们要进入我们kafka的安装目录下使用:
.\bin\windows\kafka-topics.bat --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic test_topic
这个命令的意思是我们使用bat文件启动kafka,使用的配置文件是server.properties这个配置文件,所以我们可以改变这个配置文件来修改我们kafka启动配置,可以看一些文件的参数
kafka的配置文件
server.properties
我们主要看一些关键参数
############################# Socket Server Settings #############################
# The address the socket server listens on. If not configured, the host name will be equal to the value of
# java.net.InetAddress.getCanonicalHostName(), with PLAINTEXT listener name, and port 9092.
# FORMAT:
# listeners = listener_name://host_name:port
# EXAMPLE:
# listeners = PLAINTEXT://your.host.name:9092
#listeners=PLAINTEXT://:9092# Listener name, hostname and port the broker will advertise to clients.
# If not set, it uses the value for "listeners".
#advertised.listeners=PLAINTEXT://your.host.name:9092这一部分表示的是kafka的监听,我们如果想要外部机器访问我们的kafka就需要配置advertised.listeners这个参数为我们服务器的地址,否则我们通过python是无法向kafka生产消息,会直接报错
############################# Log Basics #############################
# A comma separated list of directories under which to store log files
log.dirs=C:\\kafka\\kafka_2.13-3.2.1\\logs# The default number of log partitions per topic. More partitions allow greater
# parallelism for consumption, but this will also result in more files across
# the brokers.
num.partitions=1log.dirs这一部分主要是我们kafka日志的存放位置,我们可以进行修改
num.partitions=1 这一部分主要是我们kafka的默认分区数量,kafka的分区其实可以理解为帮助我们提升消费的速度,当我们分区数量不为1的时候,生产者生产的消息会放入我们该topic下的不同分区,我们可以用多个消费者去消费不同分区的内容,这样可以起到一个并发消费,但是因为分区消费的顺序是没办法控制的,所以只适合无序的生产消费
############################# Internal Topic Settings #############################
# The replication factor for the group metadata internal topics "__consumer_offsets" and "__transaction_state"
# For anything other than development testing, a value greater than 1 is recommended to ensure availability such as 3.
offsets.topic.replication.factor=1这个表示我们每个分区复制的份数
上面大概是一些重要的配置,修改这些参数就可以更改我们kafka启动后的配置
封装代码
kafka支持生产者,消费者,创建主题,那么我们也可以使用confluent_kafka来实现这些
代码如下:
from confluent_kafka import Producer
from confluent_kafka.admin import AdminClient, NewTopic
bootstrap_servers = "127.0.0.1:9092"
class BaseKafka(object):
def __init__(self):
self.producer = Producer({'bootstrap.servers': bootstrap_servers})
self.admin_client = AdminClient({"bootstrap.servers": bootstrap_servers})
def send_message(self, topic, key, message):
key_bytes = key.encode('utf-8')
self.producer.produce(topic, key=key_bytes, value=message)
self.producer.flush()
def create_topic(self, topic,num_partitions=1,replication_factor=1):
"""创建kafka topic"""
# 定义要创建的主题及其配置,主题名,分区数量以及分区复制的份数
new_topic = NewTopic(topic, num_partitions=num_partitions, replication_factor=replication_factor)
# 创建主题
fs = self.admin_client.create_topics([new_topic])
# 等待创建完成
for topic, future in fs.items():
try:
future.result() # 等待直到主题创建完成或抛出异常
except Exception as e:
raise e
def check_topic(self):
# 获取 Kafka 集群中的所有 topic
topics = self.admin_client.list_topics().topics
# 返回所有 topic 名称
topic_list = []
for topic_name in topics:
topic_list.append(topic_name)
return topic_list
docker安装kafka
我们选择使用docker-compose.yml来安装kafka
version: '2.1' services: zoo1: image: zookeeper:3.4.9 hostname: zoo1 ports: - "2181:2181" environment: ZOO_MY_ID: 1 ZOO_PORT: 2181 ZOO_SERVERS: server.1=zoo1:2888:3888 volumes: - ./zk-single-kafka-single/zoo1/data:/data - ./zk-single-kafka-single/zoo1/datalog:/datalog kafka1: image: confluentinc/cp-kafka:5.3.1 hostname: kafka1 ports: - "9092:9092" environment: KAFKA_ADVERTISED_LISTENERS: LISTENER_DOCKER_INTERNAL://kafka1:19092,LISTENER_DOCKER_EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: LISTENER_DOCKER_INTERNAL:PLAINTEXT,LISTENER_DOCKER_EXTERNAL:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: LISTENER_DOCKER_INTERNAL KAFKA_ZOOKEEPER_CONNECT: "zoo1:2181" KAFKA_BROKER_ID: 1 KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO" KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 volumes: - ./zk-single-kafka-single/kafka1/data:/var/lib/kafka/data depends_on: - zoo1# LISTENER_DOCKER_INTERNAL://kafka1:19092,LISTENER_DOCKER_EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092
这个参数是比较重要的,如果我们想要外部访问我们的kafka一定要将这个参数设置为我们服务器的地址