MongoDB-非关系型数据库-文档数据库(三) Kafka测试MongoDB性能

一、Kafka 简介与核心概念

1.1 什么是 Kafka?

Apache Kafka 是一个分布式消息队列系统,由 LinkedIn 开发,后捐给 Apache 基金会。它的核心作用是解耦数据生产者和消费者 ,就像现实生活中的邮局

  • 生产者:寄信的人(你的Java程序)
  • Kafka:邮局(暂存、分类、转发信件)
  • 消费者:收信的人(MongoDB写入程序)

1.2 Kafka 的核心作用

作用 说明 比喻
缓冲 生产者和消费者速度不匹配时暂存数据 邮局的信件暂存架
解耦 生产者和消费者互不感知对方存在 寄信人不需要知道谁收信
削峰填谷 应对突发流量,防止系统崩溃 双十一快递先堆在邮局
持久化 数据可保存一段时间,消费者随时来取 信件保存7天,随时可取

1.3 Kafka 核心术语

术语 解释 类比
Topic(主题) 消息的分类,类似数据库的表 不同类型的信件(平信、挂号信)
Partition(分区) Topic 的分片,提高并行度 多个分拣口同时处理信件
Producer(生产者) 发送消息的程序 寄信人
Consumer(消费者) 接收消息的程序 收信人
Broker(代理) Kafka 服务器节点 邮局的分局
Offset(偏移量) 消息在分区中的唯一编号 信件的邮政编码+流水号

二、ZooKeeper 简介与原理

2.1 什么是 ZooKeeper?

Apache ZooKeeper 是一个分布式协调服务,用来管理集群状态。如果把 Kafka 比作邮局,ZooKeeper 就是邮局的管理系统

  • 记录哪个邮局分局(Broker)在运行
  • 记录哪个分局负责哪个片区的信件(Leader选举)
  • 通知大家谁出故障了

2.2 ZooKeeper 的核心原理

ZooKeeper 采用 ZAB 协议(ZooKeeper Atomic Broadcast),保证数据一致性:

text

客户端\] → \[Leader节点\] → \[Follower节点1

↘ [Follower节点2]

↘ [Follower节点3]

  • Leader:处理所有写请求,广播给其他节点
  • Follower:处理读请求,参与Leader选举
  • 奇数节点:必须奇数个(3、5、7),才能选举出多数派

2.3 ZooKeeper 在 Kafka 中的作用

作用 存储内容 类比
Broker注册 记录哪些Kafka服务器活着 邮局分局名录
Topic元数据 主题有哪些分区,副本在哪 信件分拣规则表
Leader选举 选出一个分区的主副本 谁负责这个片区的信件
消费进度 记录消费者组读到哪里了 谁读到哪封信了

三、Kafka 配置方案

3.1 方案一:Standalone 模式(无 ZooKeeper,Kafka 3.x+)

这是 Kafka 3.0 引入的 KRaft (Kafka Raft)模式 ,不需要 ZooKeeper,适合开发测试

3.1.1 配置步骤

server.properties(单节点KRaft模式)

properties

# 必须配置 process.roles

process.roles=broker,controller # 同时充当broker和控制器

# 节点ID

node.id=1

# 控制器监听器

controller.listener.names=CONTROLLER

# 监听器配置

listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093

advertised.listeners=PLAINTEXT://localhost:9092

# 控制器选举配置(单节点)

controller.quorum.voters=1@localhost:9093

# 数据目录

log.dirs=/tmp/kafka-logs

# 基本配置

num.partitions=3

default.replication.factor=1

offsets.topic.replication.factor=1

3.1.2 初始化与启动

bash

# 1. 生成集群ID

./bin/kafka-storage.sh random-uuid

# 输出类似:fRg4QvF8T8mUz0kL1nX2pQ

# 2. 格式化存储目录(使用 --standalone 参数)

./bin/kafka-storage.sh format -t fRg4QvF8T8mUz0kL1nX2pQ \

-c config/server.properties --standalone

# 3. 启动Kafka

./bin/kafka-server-start.sh config/server.properties

3.1.3 优缺点

优点 缺点
配置简单,无需维护ZooKeeper 无高可用,单点故障
资源占用少 不能水平扩展
适合开发测试 生产环境不推荐

3.2 方案二:ZooKeeper 模式(传统集群)

这是 Kafka 经典模式,需要独立 ZooKeeper 集群,适合生产环境

3.2.1 集群规划(以3节点为例)

节点 IP Kafka Broker ID ZooKeeper 角色
node1 192.168.1.101 1 Leader/Follower
node2 192.168.1.102 2 Leader/Follower
node3 192.168.1.103 3 Leader/Follower

3.2.2 ZooKeeper 配置

在每个节点上:

bash

# 创建数据目录

mkdir -p /data/zookeeper

zookeeper.properties

properties

tickTime=2000

dataDir=/data/zookeeper

clientPort=2181

initLimit=10

syncLimit=5

# 集群节点配置

server.1=192.168.1.101:2888:3888

server.2=192.168.1.102:2888:3888

server.3=192.168.1.103:2888:3888

# 自动清理

autopurge.snapRetainCount=3

autopurge.purgeInterval=1

创建 myid 文件(各节点不同)

bash

# node1

echo "1" > /data/zookeeper/myid

# node2

echo "2" > /data/zookeeper/myid

# node3

echo "3" > /data/zookeeper/myid

启动 ZooKeeper

bash

# 所有节点执行

./bin/zookeeper-server-start.sh -daemon config/zookeeper.properties

# 查看状态

./bin/zookeeper-shell.sh localhost:2181 stat

3.2.3 Kafka Broker 配置

server.properties(以node1为例)

properties

# Broker唯一ID(集群内唯一)

broker.id=1

# 监听地址

listeners=PLAINTEXT://192.168.1.101:9092

advertised.listeners=PLAINTEXT://192.168.1.101:9092

# 日志目录

log.dirs=/data/kafka-logs

# ZooKeeper 连接

zookeeper.connect=192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181

# 主题配置(高可用设置)

default.replication.factor=3 # 副本数=节点数

min.insync.replicas=2 # 最小同步副本

num.partitions=6 # 分区数

# 内部主题配置

offsets.topic.replication.factor=3

transaction.state.log.replication.factor=3

transaction.state.log.min.isr=2

# 网络线程(根据CPU调整)

num.network.threads=8

num.io.threads=8

其他节点只需修改 broker.id 和 listeners 中的 IP。

启动 Kafka

bash

# 所有节点执行

./bin/kafka-server-start.sh -daemon config/server.properties

3.2.4 验证集群

bash

# 查看Broker列表

./bin/zookeeper-shell.sh localhost:2181 ls /brokers/ids

# 输出:[1,2,3]

# 创建测试主题

./bin/kafka-topics.sh --bootstrap-server 192.168.1.101:9092 \

--create --topic test-cluster \

--partitions 3 --replication-factor 3

# 查看主题详情

./bin/kafka-topics.sh --bootstrap-server 192.168.1.101:9092 \

--describe --topic test-cluster

# 输出示例:

# Topic: test-cluster Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3

# Topic: test-cluster Partition: 1 Leader: 2 Replicas: 2,3,1 Isr: 2,3,1

# Topic: test-cluster Partition: 2 Leader: 3 Replicas: 3,1,2 Isr: 3,1,2

Isr (In-Sync Replicas) 等于 Replicas 说明集群健康。


四、Kafka 与 MongoDB 集成

4.1 整体架构

text

Java Producer\] → \[Kafka Topic\] → \[Java Consumer\] → \[MongoDB

↑ ↓

生成数据 批量写入

4.2 配置参数详解

关键配置文件 conf.properties说明

properties

# Kafka 连接配置

kafka.bootstrap.servers=192.168.1.101:9092,192.168.1.102:9092

kafka.topic=pm.mo.update # 主题名,类似数据库表名

# 生产者性能配置

kafka.producer.hasKey=false # 无key:轮询发到各分区,性能最好

# true:相同key发同分区,保证顺序

kafka.producer.acks=1 # 确认机制:1(leader确认),all(所有副本确认)

kafka.producer.batch.size=65536 # 批次大小(字节),攒够一批才发

kafka.producer.linger.ms=10 # 等待时间(ms),攒批提高吞吐

kafka.producer.compression=snappy # 压缩:snappy/lz4 提高网络效率

# 消费者性能配置

kafka.consumer.max.poll.records=2000 # 一次拉取最大条数

kafka.consumer.fetch.max.bytes=52428800 # 一次拉取最大字节(50MB)

# MongoDB 连接配置

mongodb.hosts=192.168.1.201:27017 # MongoDB地址

mongodb.database=iot_data # 数据库名

mongodb.collection=sensor_data # 集合名

mongodb.batch.size=1000 # 批量写入条数

4.3 参数对性能的影响

参数 配置建议 性能影响
hasKey=false ✅ 最优 无哈希计算,负载均衡最好
batch.size 65536 (64KB) 越大吞吐越高,但延迟增加
linger.ms 5-10ms 等待攒批,可提升30%+吞吐
compression snappy 减少网络传输,CPU换带宽
max.poll.records 2000-5000 一次处理更多,减少网络往返
mongodb.batch.size 1000 批量写入,可提升5-10倍性能

4.4 消费者代码优化示例

java

// 消费者主循环 - 批量写入MongoDB

while (true) {

// 从Kafka拉取一批消息

ConsumerRecords<String, byte[]> records = consumer.poll(100);

// 攒批写入MongoDB

List<Document> docs = new ArrayList<>();

for (ConsumerRecord<String, byte[]> record : records) {

// 反序列化为MongoDB Document

Document doc = Document.parse(new String(record.value()));

docs.add(doc);

// 攒够一批就写入

if (docs.size() >= batchSize) { // batchSize=1000

collection.insertMany(docs);

docs.clear();

}

}

// 写入最后剩余的一批

if (!docs.isEmpty()) {

collection.insertMany(docs);

}

// 手动提交offset(确保至少一次处理)

consumer.commitSync();

}

4.5 性能基准对比

测试场景 TPS (docs/sec) 说明
YSCB (C++直接写MongoDB) 30万+ C++极致优化,无中间件
Kafka Producer (无消费者) 14-15万 Kafka自身吞吐能力
Java Consumer (纯计数) 12-13万 消费者代码本身效率
Java Consumer + MongoDB 10-12万 完整链路,含反序列化和写入
集群模式 + 多消费者 20-30万 多节点并行,需要MongoDB分片

4.6 常见性能瓶颈排查

bash

# 1. 检查Kafka生产者性能

./bin/kafka-producer-perf-test.sh \

--topic test-perf --num-records 1000000 \

--record-size 1024 --throughput -1 \

--producer-props bootstrap.servers=localhost:9092

# 2. 检查消费者纯读性能(注释掉MongoDB写入)

# 修改代码,只计数不写入,重新编译测试

# 3. 检查磁盘IO

iostat -x 1

# 查看 await 和 %util,如果 >20ms 或 >80% 说明磁盘慢

# 4. 检查MongoDB写入性能

mongostat --host your-mongodb-host

# 查看 insert 列,看实际写入速度

4.7 调优总结

问题现象 可能原因 解决方案
生产者TPS低 批次太小/未压缩 增大batch.size,启用compression
消费者TPS低 单条写入 改为insertMany批量写入
MongoDB写入慢 索引太多/磁盘慢 优化索引,换SSD
整体TPS不达标 单节点瓶颈 上集群,多消费者并行

五、方案选型建议

5.1 环境选择

场景 推荐方案 理由
开发测试 Standalone (KRaft) 配置简单,资源占用少
小型生产 3节点ZooKeeper + 3节点Kafka 高可用,可容忍单节点故障
大型生产 5节点ZooKeeper + N节点Kafka 更高可用,可水平扩展

5.2 性能预期

配置 预期TPS 适用场景
Standalone + 单消费者 10-12万 开发测试,小型项目
3节点集群 + 3消费者 20-30万 中型生产,IoT数据
集群 + MongoDB分片 50万+ 大型互联网,实时分析

六、常见问题解答

Q1: Standalone 模式和集群模式性能差多少?

A: 集群模式因数据复制,生产者TPS会降低5-10%,但消费者TPS可通过多消费者提升。

Q2: ZooKeeper 一定要奇数节点吗?

A: 是的,奇数节点(3、5、7)才能选出多数派Leader,偶数节点(如2个)无法容错。

Q3: 为什么我的TPS只有5万?

A: 检查是否每条都写MongoDB,改为批量写入可提升5-10倍;检查acks=all是否导致性能下降。

Q4: hasKey=false 和 true 怎么选?

A: 不需要保证顺序就用false(性能最好);需要相同key顺序处理用true。

Q5: 消费者如何做到至少一次处理?

A: 处理完数据后再commitSync(),确保处理成功才提交offset。


七、文档总结

本文档从零开始介绍了:

  1. Kafka:分布式消息队列,起缓冲解耦作用
  2. ZooKeeper:分布式协调服务,管理Kafka集群状态
  3. 两种配置方案
    • Standalone模式(无ZK,适合开发)
    • ZooKeeper集群模式(生产环境)
  4. 与MongoDB集成:Java消费者批量写入MongoDB
  5. 性能调优:关键参数解释和优化建议

通过本配置,可以实现:

  • 数据生产:Java程序发送消息到Kafka
  • 缓冲解耦:Kafka暂存消息,削峰填谷
  • 数据消费:消费者从Kafka拉取数据,批量写入MongoDB
  • 性能可达:10-30万 TPS(取决于硬件和配置)

最终目标:构建一个高吞吐、可扩展的实时数据处理管道。

相关推荐
m0_678485452 小时前
c++如何提取系统环境变量并直接保存到txt日志中_getenv与ofstream【实战】
jvm·数据库·python
lKWO OMET2 小时前
查看 nginx 是否已经启动
运维·数据库·nginx
qq_342295822 小时前
Go语言怎么嵌入静态文件_Go语言embed嵌入文件教程【秒懂】
jvm·数据库·python
qq_206901392 小时前
如何在Linux上源码编译安装MySQL_CMake配置与依赖包安装
jvm·数据库·python
2401_871696522 小时前
CSS如何解决Flex布局在老版本安卓机兼容性_使用autoprefixer工具
jvm·数据库·python
qq_206901392 小时前
c++怎么把多个变量一次性写入二进制文件_结构体对齐与write【实战】
jvm·数据库·python
weixin_580614002 小时前
golang如何给图片添加水印_golang图片添加水印解析
jvm·数据库·python
Shorasul2 小时前
mysql如何进行表空间传输恢复_mysql transport tablespace实战
jvm·数据库·python
解救女汉子2 小时前
golang如何实现群聊功能_golang群聊功能实现策略
jvm·数据库·python