一、当Kafka集群开始"喊饿"时

做运维的朋友们都知道,Kafka就像个贪吃的小孩,数据量一大就开始嚷嚷"磁盘不够用了"。上周我就遇到了这个情况:凌晨三点收到报警,某个业务集群的磁盘使用率已经突破90%,消息积压量像坐火箭一样往上窜。

这种情况其实很常见,特别是在业务快速增长期。比如我们有个电商平台,大促期间订单消息量突然暴增5倍,原本能撑3个月的磁盘空间,2周就被塞得满满当当。这时候就需要我们像老中医一样,既要治标(快速扩容),又要治本(合理清理)。

二、紧急扩容:给Kafka"加餐"

当磁盘空间告急时,最直接的解决方案就是扩容。这里我以AWS环境为例,演示如何给Kafka broker节点动态添加EBS卷。

# 技术栈:AWS CLI + Linux
# 首先查看当前磁盘情况
df -h | grep /kafka_data  # 假设Kafka数据目录挂载在/kafka_data下

# 在AWS控制台创建新的EBS卷后,附加到EC2实例
aws ec2 attach-volume \
    --volume-id vol-1234567890abcdef0 \
    --instance-id i-0123456789abcdef \
    --device /dev/sdf

# 在实例上格式化新磁盘(注意:这会清空磁盘数据!)
sudo mkfs -t xfs /dev/nvme1n1  # 根据实际设备名调整

# 创建挂载点并更新fstab
echo "/dev/nvme1n1 /kafka_data2 xfs defaults,nofail 0 2" | sudo tee -a /etc/fstab
sudo mkdir /kafka_data2
sudo mount -a

# 修改Kafka配置,添加新的日志目录
vim /etc/kafka/server.properties
# 找到log.dirs参数,添加新路径(多个路径用逗号分隔)
log.dirs=/kafka_data,/kafka_data2

# 滚动重启Kafka broker
sudo systemctl restart kafka

注意事项

  1. 生产环境建议在业务低峰期操作
  2. XFS文件系统对Kafka性能更友好
  3. 确保新磁盘的IOPS配置足够高
  4. 记得更新监控系统的磁盘告警阈值

三、数据清理:给Kafka"瘦身"

扩容只是权宜之计,合理的清理策略才是长久之道。Kafka提供了多种数据清理机制,我们来详细看看。

3.1 基于时间的保留策略

# Kafka配置示例
log.retention.hours=168    # 保留7天数据
log.segment.bytes=1073741824  # 每个日志段1GB
log.cleanup.policy=delete   # 删除过期数据

这个配置表示:

  • 消息保存7天(168小时)
  • 每个日志文件达到1GB就会切分新文件
  • 采用删除策略而非压缩

3.2 基于大小的保留策略

log.retention.bytes=53687091200  # 每个分区保留50GB

实用技巧:可以通过kafka-topics.sh动态调整已有topic的配置:

bin/kafka-configs.sh --zookeeper localhost:2181 \
    --entity-type topics --entity-name order_events \
    --alter --add-config retention.bytes=107374182400  # 设置为100GB

3.3 手动清理大法

有时候自动清理不够及时,我们可以手动删除旧数据:

# 首先找出需要清理的topic分区
ls -lh /kafka_data/order_events-*/ | sort -rh

# 使用kafka-delete-records.sh删除旧偏移量之前的数据
cat << EOF > offsets.json
{
    "partitions": [
        {
            "topic": "order_events",
            "partition": 0,
            "offset": 15234500
        }
    ],
    "version": 1
}
EOF

bin/kafka-delete-records.sh \
    --bootstrap-server localhost:9092 \
    --offset-json-file offsets.json

四、进阶优化:让Kafka"吃得更健康"

4.1 分区再平衡

当添加新磁盘后,可以使用kafka-reassign-partitions.sh工具将部分分区迁移到新磁盘:

// reassign.json
{
    "version": 1,
    "partitions": [
        {"topic": "order_events", "partition": 0, "replicas": [1,2], "log_dirs": ["/kafka_data","/kafka_data2"]},
        {"topic": "payment_events", "partition": 3, "replicas": [2,3], "log_dirs": ["/kafka_data2","/kafka_data"]}
    ]
}

执行命令:

bin/kafka-reassign-partitions.sh \
    --bootstrap-server localhost:9092 \
    --reassignment-json-file reassign.json \
    --execute

4.2 监控与告警配置

建议监控以下关键指标:

  • 磁盘使用增长率
  • 消息保留时间与实际业务需求差距
  • 清理线程是否正常工作
# 示例Prometheus告警规则
- alert: KafkaDiskUsageCritical
  expr: kafka_log_log_size / kafka_log_log_size_limit > 0.8
  for: 30m
  labels:
    severity: critical
  annotations:
    summary: "Kafka disk usage high on {{ $labels.instance }}"
    description: "Disk usage is {{ $value }}% for topic {{ $labels.topic }}"

五、实战经验分享

去年我们遇到过一个典型案例:某金融系统Kafka集群每天产生2TB数据,但业务要求必须保留30天。直接扩容成本太高,我们最终采用的方案是:

  1. 热数据(7天内):保留在性能型SSD上
  2. 温数据(8-15天):迁移到标准云盘
  3. 冷数据(16-30天):压缩后转存到对象存储

实现这个方案的关键配置:

# 分层存储配置
log.dirs=/ssd_data,/hdd_data
log.retention.hours=360
log.retention.check.interval.ms=300000
log.segment.bytes=536870912  # 512MB分段更利于冷数据迁移

六、避坑指南

  1. 不要直接删除磁盘文件:这会导致消息位移错乱,应该通过Kafka内置机制清理
  2. 注意副本同步:扩容时要确保新磁盘的副本同步不会拖慢整个集群
  3. 监控清理线程:我们曾遇到cleaner线程卡死导致磁盘爆满的情况
  4. 考虑Zookeeper影响:大规模分区重新分配会给ZK带来压力

七、总结与展望

处理Kafka磁盘问题就像管理一个不断膨胀的仓库:既要及时扩建货架,又要定期清理滞销品。随着Kafka 3.0+版本的推出,分层存储功能越来越成熟,未来我们可以更灵活地在性能和成本之间取得平衡。

最后提醒大家,每个业务场景都是独特的,文中的方案需要根据实际情况调整。比如物联网设备日志和金融交易消息的保留策略就截然不同。记住:没有最好的方案,只有最适合的方案。