Kafka使用入门

a distributed streaming platform.
参考 kafka-python官方文档

Kafka简介

  Kafka是一种消息队列,主要用来处理大量数据状态下的消息队列,一般用来做日志的处理。既然是消息队列,那么Kafka也就拥有消息队列的相应的特性了。

  • 消息队列的好处
    • 解藕
    • 异步处理
    • 削峰平谷

Kafka的消费模式

  • 一对一模式
      消息生产者发布消息到Queue队列中,通知消费者从队列中拉取消息进行消费。消息被消费之后则删除,Queue支持多个消费者,但对于一条消息而言,只有一个消费者可以消费,即一条消息只能被一个消费者消费
  • 一对多模式
      这种模式也称为发布/订阅模式,即利用Topic存储消息,消息生产者将消息发布到Topic中,同时有多个消费者订阅此Topic,消费者可以从中消费消息,注意发布到Topic中的消息会被多个消费者消费,消费者消费数据之后,数据不会被清除,Kafka会默认保留一段时间,然后再删除。

Kafka的基础架构

  Kafka像其他MQ一样,也有自己的基础架构,主要存在生产者Producer、Kafka集群Broker、消费者Consumer、注册消息Zookeeper。

  • Producer:消息生产者,向Kafka中发布消息的角色。
  • Consumer:消息消费者,即从Kafka中拉取消息消费的客户端。
  • Consumer Group:消费者组,消费者组则是一组中存在多个消费者,消费者消费Broker中当前Topic的不同分区中的消息,消费者组之间互不影响,所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。某一个分区中的消息只能够一个消费者组中的一个消费者所消费
  • Broker:经纪人,一台Kafka服务器就是一个Broker,一个集群由多个Broker组成,一个Broker可以容纳多个Topic。
  • Topic:主题,可以理解为一个队列,生产者和消费者都是面向一个Topic
  • Partition:分区,为了实现扩展性,一个非常大的Topic可以分布到多个Broker上,一个Topic可以分为多个Partition,每个Partition是一个有序的队列(分区有序,不能保证全局有序)
  • Replica:副本Replication,为保证集群中某个节点发生故障,节点上的Partition数据不丢失,Kafka可以正常的工作,Kafka提供了副本机制,一个Topic的每个分区有若干个副本,一个Leader和多个Follower
  • Leader:每个分区多个副本的主角色,生产者发送数据的对象,以及消费者消费数据的对象都是Leader。
  • Follower:每个分区多个副本的从角色,实时的从Leader中同步数据,保持和Leader数据的同步,Leader发生故障的时候,某个Follower会成为新的Leader。

  上述一个Topic会产生多个分区Partition,分区中分为Leader和Follower,消息一般发送到Leader,Follower通过数据的同步与Leader保持同步,消费的话也是在Leader中发生消费,如果多个消费者,则分别消费Leader和各个Follower中的消息,当Leader发生故障的时候,某个Follower会成为主节点,此时会对齐消息的偏移量。
在这里插入图片描述

利用Docker容器快速构建Kafka环境

kafka需要zookeeper管理,所以需要先安装zookeeper

⚾️ 安装zookeeper和kafka

docker pull wurstmeister/zookeeper
docker pull wurstmeister/kafka

⚾️ 启动zookeeper

# 端口映射到本地的2181
docker run -d --name zookeeper -p 2181:2181 -t wurstmeister/zookeeper

⚾️ 启动kafka

# 本机IP使用ifconfig命令查看
docker run -d --name kafka \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=本机ip:2181 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://本机ip:9092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 wurstmeister/kafka

# 启动示例
docker run -d --name kafka \
-p 9092:9092 \
-e KAFKA_BROKER_ID=0 \
-e KAFKA_ZOOKEEPER_CONNECT=10.31.154.242:2181 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://10.31.154.242:9092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 wurstmeister/kafka

⚾️ 消息测试

🔧kafka自带了终端工具,可以在终端测试

# 进入容器
docker exec -it {container-id} bash

# 进入kafka安装目录
cd cd opt/kafka_2.13-2.8.1/bin/

# 创建一个叫test的topic
./kafka-console-producer.sh --broker-list localhost:9092 --topic "test"

# 输入一个消息后确认,然后运行consumer查看是否有消息
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic "test" --from-beginning

# 终端输出刚才输入的内容即为构建成功

在Python中使用kafka

参考文档:Kafka-Python Api

⚾️ 构建producer

每一秒向Topic发一条消息


import json
import time
from datetime import datetime

from kafka import KafkaConsumer, KafkaAdminClient, KafkaProducer
from kafka.admin import NewTopic
from kafka.errors import KafkaError


class KafkaApi:
    """ kafka utils
		SERVER = '127.0.0.1:9092'    TOPIC = 'test'
    """

    def __init__(self, broker=""):
        self.brokers = broker
        self.producer = KafkaProducer(
            bootstrap_servers=self.brokers,
            key_serializer=lambda item: json.dumps(item).encode(),
            value_serializer=lambda item: json.dumps(item).encode()
        )

    def create_topic(self, topic, num_partitions=1, replication_factor=1):
        """创建topic"""

        if self.is_exists(topic):
            raise Exception("topic 已存在")

        client = KafkaAdminClient(bootstrap_servers=self.brokers)
        topic_list = [NewTopic(
            name=topic,
            num_partitions=num_partitions,
            replication_factor=replication_factor
        )]
        client.create_topics(new_topics=topic_list)

    def is_exists(self, topic):
        topics = self.get_all_topics()
        return topic in topics

    def get_all_topics(self):
        """获取所有topic"""
        consumer = KafkaConsumer(bootstrap_servers=self.brokers)
        return consumer.topics()

    def send(self, topic, value, key=None):
        if value is None:
            raise 'content 不能为空'

        try:
            if key:
                self.producer.send(topic, value=value, key=key)
            else:
                self.producer.send(topic, value=value)
        except KafkaError as _:
            self.producer.close()


class KafkaService:
    """
    外发信息服务
    """

    def __init__(self):
        self.api = KafkaApi()
        self.topics = []

    def send_kafka(self, topic, content, key=None):

        if content is None:
            raise '发送内容不能为空'

        # 判断topic是否存在,不存在则创建一个
        if topic not in self.topics:
            if not self.api.is_exists(topic):
                self.api.create_topic(topic)
            self.topics.append(topic)

        try:
            self.api.send(topic, content, key)
            print("入kafka成功")
        except KafkaError as error:
            # 如果遇到发送失败,则再重试3次
            retry = 0
            while retry < 3:
                # 暂停0.1秒
                time.sleep(0.1)
                try:
                    self.api.send(topic, content)
                except KafkaError as _:
                    retry += 1
                    continue
                break


if __name__ == '__main__':
    s = KafkaService()

    while 1:
        data = {'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "msg": "成功"}
        s.send_kafka("ichpan", "下午好, 安同学!")
        time.sleep(0.2)

⚾️ 构建consumer

# consumer.py

import json

from kafka import KafkaConsumer
# 第一个参数为topic的名称
# bootstrap_servers: 指定kafka服务器
# group_id : 指定此消费者实例属于的组名,可以不指定
# auto.offset.reset关乎kafka数据的读取,是一个非常重要的设置。常用的二个值是latest和earliest,默认是latest。
# - earliest 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
# - latest 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
consumer = KafkaConsumer(
    "ichpan",
    bootstrap_servers='',
)

for msg in consumer:
    print(msg.key, json.loads(msg.value), dir(msg))

⚾️ 效果展示

在这里插入图片描述

总结

  这就是一个完整运行Kafka消息队列的全过程,原理和redis发布者订阅者模式差不多,可以理解就是基于Channel的,在使用中我们可以查看容器的log来排除错误信息,也是非常方便的。同时也封装了kafka如何创建topic等操作,还是要对照文档来研发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楼下安同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值