Kafka :存储、复制与可靠性
本章目标本章从底层解释 Kafka 为什么吞吐高、为什么能容错以及什么配置会影响丢消息和重复消息。Kafka 日志存储模型Kafka 的 partition 本质是追加日志。每个 partition 在磁盘上对应一个目录目录中有多个日志段文件。典型文件00000000000000000000.log 00000000000000000000.index 00000000000000000000.timeindex 00000000000001000000.log 00000000000001000000.index 00000000000001000000.timeindex文件作用.log保存真实消息内容.indexoffset 到物理位置的稀疏索引.timeindex时间戳到 offset 的索引Kafka 高吞吐的核心原因顺序追加写磁盘避免随机写。充分利用 OS page cache。批量发送和批量落盘。sendfile / zero-copy 降低内核态和用户态拷贝。partition 并行分布在多个 broker。Retention 与 CompactionKafka 删除数据不是因为消费者消费了而是因为保留策略。常见配置retention.ms604800000 retention.bytes107374182400 segment.bytes1073741824 segment.ms604800000含义retention.ms保留多久。retention.bytes最多保留多大。segment.bytes单个日志段大小。segment.ms日志段滚动时间。Delete 策略默认策略超过时间或大小后删除旧日志段。适合行为日志。订单事件流水。操作日志。Compact 策略按 key 保留最新值旧值会被压缩清理。适合用户最新状态。配置变更。数据库 CDC 的最新快照。配置示例kafka-configs --bootstrap-server localhost:9092\--entity-type topics\--entity-name user-profile-snapshot\--alter\--add-configcleanup.policycompact副本复制每个 partition 可以有多个 replica。一个 replica 是 leader其余是 follower。Producer 和 Consumer 默认只与 leader 交互follower 从 leader 拉取数据。关键概念概念说明Leader当前处理读写请求的副本Follower从 leader 复制数据的副本ARAssigned Replicas所有分配副本ISRIn-Sync Replicas与 leader 保持同步的副本OSROut-of-Sync Replicas落后太多的副本LEOLog End Offset日志末尾位置HWHigh Watermark消费者可见的最高已提交位置ISR 与 HWKafka 不会把 leader 刚写入但尚未被足够副本确认的消息立即暴露为“稳定数据”。HW 表示已经被 ISR 副本确认的安全位置消费者只能读到 HW 之前的消息。这解决的问题leader 写入一条消息后立刻宕机。follower 没来得及复制。新 leader 不包含那条消息。如果消费者之前已经读到那条消息就会出现“读到的数据后来消失”。Kafka 通过 HW 避免消费者读到未提交数据。Producer 可靠性配置可靠性从 producer 开始acksall enable.idempotencetrue retries2147483647 max.in.flight.requests.per.connection5 delivery.timeout.ms120000 request.timeout.ms30000acks0Producer 发出去就认为成功不等待 broker。吞吐高但可能丢消息。适合可丢弃日志、埋点采样。acks1Leader 写入成功就返回。leader 宕机且 follower 未同步时可能丢消息。适合一般日志但不适合核心交易。acksallLeader 等 ISR 中副本确认后返回。配合min.insync.replicas可以显著降低丢消息风险。生产建议replication.factor3 min.insync.replicas2 acksall unclean.leader.election.enablefalse含义3 副本中至少 2 个同步副本确认才认为写入成功不同步副本不能被选为 leader。幂等生产者幂等生产者解决“发送成功但响应丢失producer 重试导致重复写入”的问题。开启enable.idempotencetrueKafka 为 producer 分配 PID并为每个 partition 维护 sequence number。broker 发现同一 PID、同一 partition 上重复 sequence会去重。边界幂等只保证单 producer session 内、单 partition 上的写入不重复。producer 重启后 PID 变化业务层仍建议有eventId做幂等。Kafka 事务Kafka 事务解决“多条消息要么一起对消费者可见要么一起不可见”的问题。配置transactional.idorder-tx-producer-1 enable.idempotencetrue事务流程beginTransaction send topic A send topic B sendOffsetsToTransaction commitTransaction消费者如果只想读已提交事务数据isolation.levelread_committed适用场景从一个 topic 消费处理后写入另一个 topic同时提交消费 offset。Kafka Streams exactly-once 处理。不适用场景直接保证数据库和 Kafka 的强一致事务。数据库不参与 Kafka 事务。跨外部 HTTP 服务的全局事务。数据库 Kafka 更常用的是 Outbox 模式业务事务写订单表 outbox_event 表 - 后台任务/CDC 发送 Kafka - 标记已发送Consumer 可靠性Consumer 可靠性重点不是 Kafka 能否保存消息而是 offset 提交时机。错误做法poll - commit offset - 业务处理处理失败后消息不会再被消费。推荐做法poll - 业务处理成功 - commit offset如果业务处理成功但提交 offset 失败消息可能重复消费。因此消费者业务必须支持幂等。端到端语义语义条件说明At most once先提交 offset 后处理可能丢不重复At least once处理成功后提交 offset不易丢可能重复Exactly onceKafka 事务 幂等 read_committed只覆盖 Kafka 内链路在业务系统中最常见、最务实的是Kafka 至少一次投递 消费端业务幂等实操可靠性配置检查查看 topic 配置dockercomposeexeckafka kafka-configs\--bootstrap-server localhost:9092\--entity-type topics\--entity-name order-events\--describe创建 3 副本 topic 的生产命令在单 broker demo 中不可用但生产环境应类似kafka-topics --bootstrap-server kafka-1:9092\--create\--topicorder-events\--partitions12\--replication-factor3\--configmin.insync.replicas2检查 ISRkafka-topics --bootstrap-server kafka-1:9092\--describe\--topicorder-events重点看Leader: 1 Replicas: 1,2,3 Isr: 1,2,3如果 ISR 长期少于副本数说明 follower 落后或 broker 异常需要排查网络、磁盘、GC、负载。04 性能调优、压测与容量规划本章目标Kafka 调优不是记一堆参数而是围绕目标吞吐、延迟、可靠性和成本做取舍。本章给出可落地的调优路线Producer 批量、压缩、并发。Broker 磁盘、网络、线程、页缓存。Consumer 拉取、批处理、并发和背压。Topic 分区和容量规划。压测方法与指标解释。性能问题先分类表现可能原因优先排查Producer 发送慢批次太小、网络慢、broker 写入慢producer metrics、request latencyConsumer 堆积消费逻辑慢、分区太少、下游慢lag、处理耗时、线程池Broker CPU 高压缩消耗、请求太多、TLS/SASLCPU、请求队列、网络线程Broker 磁盘忙顺序写压力大、page cache 不足iostat、log flush、磁盘延迟Rebalance 频繁消费者心跳超时、实例波动consumer group logs某分区热点key 分布不均partition bytes in/outProducer 调优批量发送Producer 不是每条消息都立刻发送一个网络请求而是先进入本地缓冲区按 topic-partition 聚合成批次。关键配置linger.ms10 batch.size65536 buffer.memory67108864 compression.typelz4调优思路延迟敏感linger.ms小一些例如 0-5ms。吞吐优先linger.ms适当增大例如 10-50ms。消息较小提高batch.size更容易合批。网络或磁盘压力大开启lz4或zstd压缩。可靠性与吞吐取舍配置吞吐可靠性说明acks0高低不等确认acks1中高中leader 写入即成功acksall中高等 ISR 确认compression.typenoneCPU 低不直接影响网络和磁盘压力高compression.typelz4常见较优不直接影响综合性能好Broker 调优磁盘Kafka 强依赖磁盘顺序 IO。生产建议使用 SSD 或高性能云盘。日志目录分散到多块盘。保留足够 page cache。不要把 broker 和重 IO 服务混部。监控磁盘使用率、IO wait、读写延迟。关键配置log.dirs/data/kafka-logs-1,/data/kafka-logs-2 log.segment.bytes1073741824 log.retention.hours168 num.recovery.threads.per.data.dir2网络线程和 IO 线程num.network.threads8 num.io.threads16 queued.max.requests500 socket.send.buffer.bytes102400 socket.receive.buffer.bytes102400调优原则请求队列积压说明 broker 处理不过来。网络线程不足时 request queue 会升高。IO 线程不足时磁盘相关处理延迟升高。不要盲目调大线程先看 CPU 是否还有余量。Consumer 调优批处理max.poll.records500 fetch.min.bytes1048576 fetch.max.wait.ms500 max.partition.fetch.bytes1048576如果消费逻辑支持批量写库应该尽量批处理poll 500 条 - 批量校验 - 批量写入数据库 - 提交 offset比每条消息一次数据库写入更稳定。背压当下游数据库或 HTTP 服务变慢时消费者继续高速拉取会导致内存和线程池堆积。策略降低max.poll.records。暂停对应 partitionconsumer.pause(partitions)。下游恢复后再resume。对非核心业务使用限流和降级。对核心业务保留堆积容量和告警阈值。容量规划输入指标容量规划至少需要这些数字指标示例用途峰值 TPS30,000 msg/s估算请求量平均消息大小1 KB估算带宽和磁盘保留时间7 天估算存储副本数3存储乘数压缩比0.5修正存储和网络目标峰值利用率60%保留冗余存储估算公式每日原始数据量 TPS * 消息大小 * 86400 实际存储 每日原始数据量 * 保留天数 * 副本数 * 压缩比 / 磁盘目标利用率示例TPS 30000 消息大小 1KB 保留 7天 副本 3 压缩比 0.5 磁盘目标利用率 0.7 每日原始数据 30000 * 1KB * 86400 2471 GB 实际存储 2471 * 7 * 3 * 0.5 / 0.7 37065 GB大约需要 36 TB 可用磁盘容量。Partition 估算如果单 partition 写入能力按 10 MB/s峰值写入约30000 msg/s * 1KB 30 MB/s写入角度至少 3 个 partition。但消费角度如果需要 24 个消费者并行处理则 topic 至少要 24 个 partition。建议partition max(写入吞吐所需, 消费并行度所需) * 未来增长系数压测工具Kafka 自带压测脚本Producer 压测kafka-producer-perf-test\--topicperf-test\--num-records1000000\--record-size1024\--throughput-1\--producer-propsbootstrap.serverslocalhost:9092acksallcompression.typelz4Consumer 压测kafka-consumer-perf-test\--bootstrap-server localhost:9092\--topicperf-test\--messages1000000\--groupperf-test-group看结果时重点关注records/secMB/secavg latencyp95/p99 latencyproducer error rateconsumer lag热点分区治理热点分区常见原因key 分布不均例如大量消息 key 都是system。某个大客户、热门商品、热门直播间流量过高。分区数量不足。治理方法方法示例代价key 打散userId randomBucket牺牲严格顺序大客户单独 topicvip-order-eventstopic 增多增加 partition12 - 24key 映射变化分业务拆 topic订单、支付、履约分离架构调整如果必须保证单订单顺序可以按orderId分区如果只需要用户级聚合可以按userId分区如果更关注吞吐可以使用更细粒度散列 key。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2577475.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!