Kafka-生产者(Producer)

0 阅读1分钟

作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。

我们上一章介绍了中间件:Zookeeper,本章将介绍另外一个中间件:Kafka。目前这2个中间件都是基于JAVA语言的。

我们上前面介绍了Topic的基本概念和涉及到Topic核心的分区和副本概念,但是我们还得往里面写入数据才行,然后数据写进入以后我们还得把里面的数据读出来,我们今天首先介绍的负责向Kafka写入消息角色:生产者(Producer)。

生产者(Producer)

将数据(消息)发布到 Kafka 的 Topic 中的Leader分区里面。生产者可以发送带有或不带有键的消息,并且可以选择这些消息应该被发送到哪个分区。下面是几个关于消息的核心特性。

消息路由

  • 轮询(Round Robin):当消息没有指定 key 时,生产者会采用轮询的方式均匀地将消息分布到所有的分区上。

  • 哈希(Key-based):如果消息包含了一个 key,那么生产者会根据这个 key 的哈希值选择一个分区。默认情况下,Kafka 使用 murmur2 算法计算哈希值,然后对分区总数取模以确定具体的分区。

  • 自定义分区策略:实现 Partitioner 接口自定义逻辑。

生产者首先需要连接到 Kafka 集群中的一个或多个 Broker,并获取关于目标 Topic 的元数据信息,包括该 Topic 所有分区及其对应的Leader Broker。根据上述的路由策略,生产者会选择合适的目标分区,并直接与该分区所在的 Leader Broker 建立连接,将消息发送出去。也就是链接Broker和发送的Topic所在Broker并没有直接关系。

可靠性保证

  • acks=0:生产者不会等待任何来自服务器的确认。这意味着如果发送过程中发生错误(例如网络故障),则消息可能会丢失。

  • acks=1:生产者会等待 Leader 副本确认收到消息后才认为发送成功。

    这种模式下,只要 leader 副本写入成功,即使后续副本同步失败也不会影响消息的确认状态,但是存在 leader 宕机且未完成副本同步的风险,可能导致数据丢失

  • acks=all:生产者会等待 ISR 中的所有副本都确认收到了消息后才认为发送成功。提供了最高的可靠性保障,但同时也可能增加消息发送的延迟。

重试机制

生产者可以通过配置 retries 参数启用自动重试机制。当遇到临时性的发送失败(如网络抖动)时,生产者可以尝试重新发送消息。结合 retry.backoff.ms 参数,可以设置每次重试前的等待时间,避免过于频繁地重试造成更大的压力。

高性能优化

  • 批处理(Batching):生产者将多条消息合并为一批发送,减少网络开销(通过 linger.msbatch.size 控制)。

  • 压缩(Compression):支持 gzipsnappylz4 等压缩算法减少网络传输量。这里需要注意,生产者和消费者必须同时支持相同的算法,并不需要服务端支持。gzip 压缩率高,但 CPU 开销大,可能增加生产者和消费者的延迟。lz4/snappy 压缩速度快,适合高吞吐低延迟场景。

发送消息

#或者可以多次发送不同或者相同的内容 
echo "hello world" | ./bin/kafka-console-producer.sh \
  --topic my-topic \
  --bootstrap-server 192.168.31.143:9092

也可以进入交互模式再输入内容。

# 启动控制台生产者(带 Key 支持)
./bin/kafka-console-producer.sh \
  --topic my-topic \
  --bootstrap-server 192.168.31.143:9092 \
  --property "parse.key=true" \
  --property "key.separator=:"
# 进入交互模式后,输入以下消息(按回车发送):
> user1:Hello Kafka
> order123:{"id": 123, "status": "created"}
> sensor01:25.5

下面是使用程序代码发送。

#python3代码 需要下安装 kafka模块 
#pip3 install kafka  -i https://mirrors.aliyun.com/pypi/simple/
import time
import json
from datetime import datetime
from kafka import KafkaProducer
from kafka.errors import KafkaError

# 配置 Kafka 生产者
producer = KafkaProducer(
    bootstrap_servers=['192.168.31.143:9092','192.168.31.144:9092','192.168.31.145:9092'],  # Kafka 服务器地址
    value_serializer=lambda v: json.dumps(v).encode('utf-8')  # 将消息序列化为 JSON
)

topic = 'my-topic1'  # 目标 Topic

try:
    count = 0
    while True:
        # 生成消息内容(示例:包含时间戳和计数)
        message = {
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "count": count,
            "data": f"Message-{count}"
        }

        # 发送消息(异步)
        future = producer.send(topic, value=message)

        # 可选:等待消息发送完成(同步确认)
        # record_metadata = future.get(timeout=10)
        # print(f"发送成功 → 分区: {record_metadata.partition}, 偏移量: {record_metadata.offset}")

        print(f"已发送: {message}")
        count += 1
        time.sleep(1)  # 每秒发送一次

except KafkaError as e:
    print(f"Kafka 错误: {e}")
except KeyboardInterrupt:
    print("用户终止程序")
finally:
    producer.close()  # 关闭生产者

如果系统不存在这个Topic,它将自动创建,默认只有1个分区和1个副本,这2个参数我们前面也讲过。

#副本数量,默认是1,参数默认不存在,如果要修改配置需要手工添加 
default.replication.factor  

#分区数量,默认是1,参数默认存在
num.partitions 

#如果生产者向不存在的Topic发送消息,
#默认是true,就是允许创建Topic
#参数默认不存在
auto.create.topics.enable 

通过下面的命令可以查看到各个分区里面有多少数据。

#查看topic的消息数量,一般不会用,这里为了方便统计才使用 
./bin/kafka-run-class.sh \
kafka.tools.GetOffsetShell \
--broker-list 192.168.31.143:9092 
--topic my-topic123 \
--time -1

[root@localhost kafka_2.13-2.8.2]# ./bin/kafka-run-class.sh kafka.tools.GetOffsetShell   --broker-list 192.168.31.143:9092   --topic my-topic123   --time -1
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
my-topic123:0:0
my-topic123:1:0
my-topic123:2:0

运维小路

一个不会开发的运维!一个要学开发的运维!一个学不会开发的运维!欢迎大家骚扰的运维!

关注微信公众号《运维小路》获取更多内容。