摘要

本文主要介绍了Kafka的架构原理、消息订阅模式以及在金融风控等领域的应用。Kafka作为数据中转站,可同步不同系统数据,支持事件驱动架构,广泛应用于金融支付与风控场景。其架构包括Producer、Broker、Topic、Partition、Replication、Message、Consumer和Consumer Group等组件,依赖Zookeeper保存元信息。Kafka的消息订阅模式包括点对点、发布-订阅、分区级订阅、静态订阅和动态订阅等,每种模式都有其特点和适用场景。此外,还探讨了Kafka与RocketMQ的对比、消息丢失问题及解决方案、消息存储与删除策略等。

1. Kafka原理介绍

1.1. Kafka基本特点

Kafka 是一个分布式发布-订阅消息系统。是大数据领域消息队列中唯一的王者。最初由 linkedin 公司使用 scala 语言开发,在2010年贡献给了Apache基金会并成为顶级开源项目。至今已有十余年,仍然是大数据领域不可或缺的并且是越来越重要的一个组件。Kafka适合离线和在线消息,消息保留在磁盘上,并在集群内复制以防止数据丢失。kafka构建在zookeeper同步服务之上。它与Flink和Spark有非常好的集成,应用于实时流式数据分析。

Kafka特点:

  • 可靠性:具有副本及容错机制。
  • 可扩展性:kafka无需停机即可扩展节点及节点上线。
  • 持久性:数据存储到磁盘上,持久性保存。
  • 性能:kafka具有高吞吐量。达到TB级的数据,也有非常稳定的性能。
  • 速度快:顺序写入和零拷贝技术使得kafka延迟控制在毫秒级。

1.2. Kafka架构应用场景

Kafka 的使用场景其实非常广泛,它本质上是一个 高吞吐、可扩展的分布式消息流处理平台,常用于消息队列(MQ)+ 日志系统 + 流式处理 三类场景。结合实际金融支付、风控和互联网场景,我给你梳理下常见的应用:

1.2.1. 消息解耦与削峰填谷

  • 场景:上下游系统解耦,生产者只需要把消息写入 Kafka,消费者根据自身处理能力来消费。
  • 示例
    • 订单系统下单后,支付系统、库存系统、营销系统都订阅订单消息,异步处理,避免耦合。
    • 双十一、618 秒杀场景,流量洪峰先写入 Kafka,消费者按能力消费,防止系统被压垮。

1.2.2. 日志收集与统一处理

  • 场景:收集分布式系统中的日志,统一存储、分析。
  • 示例
    • 用户行为日志(点击、浏览、下单)发送到 Kafka,再进入 大数据平台(Hadoop、Hive、Spark、Flink) 分析。
    • 风控系统采集交易流水日志,实时分析欺诈行为。

1.2.3. 实时流式计算

  • 场景:Kafka + Flink / Spark Streaming / Storm,做实时数据处理。
  • 示例
    • 实时监控:金融支付中的交易反欺诈系统,实时监控交易特征,秒级拦截可疑交易。
    • 实时推荐:电商网站根据 Kafka 中的用户行为数据实时更新推荐结果。

1.2.4. 数据总线(Data Pipeline)

  • 场景:作为数据中转站,把不同系统的数据可靠地同步到另一个系统。
  • 示例
    • Kafka Connect 将数据库 binlog(MySQL、PostgreSQL) 同步到 ES、HDFS、ClickHouse。
    • Kafka MirrorMaker 实现跨数据中心的数据复制(异地多活)。

1.2.5. 事件驱动架构(EDA)

  • 场景:通过事件驱动系统协作,而不是强耦合调用。
  • 示例
    • 银行风控:用户发起交易 → Kafka 发布事件 → 多个风控模块(黑名单校验、设备指纹校验、额度校验)并行消费。
    • 电商业务:下单事件触发 → 物流系统、优惠券系统、积分系统都能订阅同一个事件。

1.2.6. 金融支付与风控场景

这是你熟悉的领域,可以更贴近实际:

  • 支付交易流水存储:支付核心系统把交易流水写入 Kafka,用于清算、对账、监管报送。
  • 实时风控:交易请求先进入 Kafka,由多个风控服务并行消费,判断风险。
  • 账务/清结算:通过 Kafka 进行账务流水的实时同步,避免单点瓶颈。
  • 监控告警:Kafka 采集交易异常、延时、错误日志,实时触发告警。

1.3. Kafka架构原理

  • Producer:Producer即生产者,消息的产生者,是消息的入口。
  • Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……
  • Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。
  • Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!
  • Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。
  • Message:每一条发送的消息主体。
  • Consumer:消费者,即消息的消费方,是消息的出口。
  • Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!
  • Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。

1.4. Kafka 消息订阅模式

Kafka 的消息订阅模式,其实就是 Consumer 如何订阅 Topic 并消费消息 的方式。不同于传统 MQ(例如 RabbitMQ 的交换机 + 路由模式),Kafka的订阅模式比较简洁,但围绕Topic/Partition/ConsumerGroup 有几种典型方式。

模式

特点

消费次数

典型场景

点对点(Queue-like)

组内消息只给一个 Consumer

每消息 1 次(组内)

负载均衡任务

发布-订阅(Pub/Sub)

多个组可独立消费

每消息 N 次(组数)

事件通知,多系统订阅

分区级订阅

精确分区分配策略

与分区数量相关

顺序消费、流量均衡

静态订阅

手动指定分区

可控

用户交易顺序处理

动态订阅

订阅整个 Topic

自动分配

常见业务消费

1.4.1. 点对点(Queue-like 模式)

机制:多个 Consumer 组成一个 Consumer Group每条消息只会被组内一个 Consumer 消费一次;Partition 会被分配给组内某个 Consumer。类似于传统 MQ 的“队列模式”。

应用场景:下游服务需要做 负载均衡,如支付流水入账任务,多个实例分摊任务量。

点对点模式通常是基于拉取或者轮询的消息传送模型,这个模型的特点是发送到队列的消息被一个且只有一个消费者进行处理。生产者将消息放入消息队列后,由消费者主动的去拉取消息进行消费。点对点模型的的优点是消费者拉取消息的频率可以由自己控制。但是消息队列是否有消息需要消费,在消费者端无法感知,所以在消费者端需要额外的线程去监控。

1.4.2. 发布-订阅(Pub/Sub 模式)

机制:一个Topic可以被多个Consumer Group 订阅;不同组的消费者都能收到完整的消息副本;Broker不会为单个消息维护“已消费状态”,只管存消息。类似于传统 MQ 的“广播模式”。

应用场景:订单事件同时通知 库存系统、营销系统、风控系统。支付交易流水同时写入 清算系统、风控系统、监控系统

发布订阅模式是一个基于消息送的消息传送模型,发布订阅模型一个消息可以有多种不同的订阅者同时消费。生产者将消息放入消息队列后,队列会将消息推送给订阅过该类消息的消费者。由于是消费者被动接收推送,所以无需感知消息队列是否有待消费的消息!但是consumer1、consumer2、consumer3由于机器性能不一样,所以处理消息的能力也会不一样,但消息队列却无法感知消费者消费的速度!所以推送的速度成了发布订阅模模式的一个问题!假设三个消费者处理速度分别是8M/s、5M/s、2M/s,如果队列推送的速度为5M/s,则consumer3无法承受!如果队列推送的速度为2M/s,则consumer1、consumer2会出现资源的极大浪费!

1.4.3. 分区级订阅(Partition Assignment)

Kafka中,Topic → Partition → Consumer 的绑定方式,有几种策略:

  • Range(范围分配)按照分区号顺序分配给消费者(可能导致负载不均)。
  • RoundRobin(轮询分配)轮流分配分区,更均匀。
  • Sticky(粘性分配,推荐)保证分区尽可能稳定地分配给同一个 Consumer,减少 rebalance 开销。

1.4.4. 静态订阅 vs 动态订阅

  • 静态订阅(Assign 模式):Consumer 手动指定订阅的 Topic 和 Partition。适合严格顺序消费的场景,比如一个用户的交易记录必须按顺序处理。
  • 动态订阅(Subscribe 模式):Consumer 订阅整个 Topic,具体分区由 Kafka 自动分配。常见于一般业务消费,扩展性更好。

1.4.5. 多播/单播对比

  • 单播(Unicast):同一个 Consumer Group 内,消息只会被其中一个 Consumer 消费。
  • 多播(Multicast):不同 Consumer Group 都能消费相同的消息,各自独立。

2. kafka实战开发经验总结

2.1. 什么时候使用Kafka、MQ中间件

Kafka和传统消息队列(RabbitMQ、ActiveMQ、RocketMQ 等)虽然都是消息中间件,但定位、架构和适用场景不一样,所以“什么时候用 Kafka、什么时候用 MQ”主要取决于你的业务需求、性能要求和系统架构

2.1.1. 核心定位对比

特性

Kafka

MQ(RabbitMQ / RocketMQ / ActiveMQ 等)

设计目标

高吞吐、分布式日志存储、流处理

可靠消息传递、业务解耦、事件驱动

消费模式

发布-订阅(Pub/Sub),支持多消费组,消息可重复消费

队列(Queue)+ 发布订阅,通常一次消费即删除

消息存储

长期存储(按时间/大小保留),可回溯消费

消费后一般删除(RocketMQ 可配置保留)

性能

百万级 TPS

一般万级 TPS(RocketMQ 高性能除外)

顺序性

分区内有序

队列内有序

事务支持

基本事务(Kafka 0.11+),但弱于 MQ

较完善的事务消息(RocketMQ 事务消息较成熟)

2.1.2. Kafka、MQ使用场景对比?

场景类型

典型需求

Kafka 适合

MQ 适合(RabbitMQ / RocketMQ)

高吞吐日志采集

每秒百万级日志/埋点采集,写入存储或分析系统

✅(ELK、ClickHouse、Hadoop 等)

❌(吞吐不够)

实时流计算

需要实时处理数据流,窗口聚合、风控计算

✅(Kafka Streams、Flink、Spark Streaming)

❌(延迟较大)

大数据中间总线

系统间批量传输数据到数据湖、仓库

消息回溯 / 重放

消费端需反复读取历史数据

✅(可配置保留期)

❌(消费后删除)

系统解耦

系统间异步调用,降低耦合

⚠️(可做但功能简单)

✅(队列 + 订阅模式)

事务一致性

确保消息与数据库操作同时成功

⚠️(Kafka事务弱)

✅(RocketMQ事务消息成熟)

延迟/定时任务

定时发消息、延迟队列

✅(RocketMQ 原生延迟,RabbitMQ TTL)

复杂路由

消息根据规则路由到不同队列

✅(RabbitMQ交换机灵活)

轻量异步任务

低并发的任务调度,如发邮件/短信

❌(过重)

✅(RabbitMQ / RocketMQ)

多消费者独立消费

多个系统独立消费同一份消息

✅(多消费组独立)

⚠️(需额外配置)

2.1.3. Kafka、MQ选型建议

需求

推荐

高吞吐(百万级 TPS)、实时流、可回溯

Kafka

分布式事务、消息必达

RocketMQ

复杂路由、轻量级消息通信

RabbitMQ

实时流 + 事务一致性

Kafka + 事务补偿 / RocketMQ

大数据日志采集

Kafka

延迟消息 / 定时任务

RocketMQ / RabbitMQ(TTL)

2.2. 点对点(Queue-like 模式) 中消息是否标记为已经消费?

在 Kafka 的点对点模式(Consumer Group 内单消费)下:消息不会被标记已消费;Broker 只管存消息,消费状态由 Consumer Group 的 offset 记录;

2.2.1. Kafka的设计和传统 MQ 不一样

在 RabbitMQ、ActiveMQ 等传统 MQ 里,Broker 会记录消息是否已经被某个消费者确认(ACK),已消费的消息就会被标记或删除。但在 Kafka 中:Broker 不关心消费状态,只负责存储消息。Consumer 自己维护消费进度(offset)

2.2.2. 消费进度的管理方式

每个Consumer Group在Kafka里会有一个 offset,指向该组在某个 Partition 中的消费进度(即下一个要消费的消息位置)。这个 offset 默认存储在 __consumer_offsets 内置主题中,而不是存在消息本身。所以消息不会有“已消费标记”,只是有“消费到哪里了”的进度信息。

2.2.3. 结果表现

消息被消费后,仍然会在 Broker 的日志文件里保留(直到达到过期时间或超过配置的存储大小才删除)。如果 Consumer 提交 offset 出错:可能会 重复消费(offset 没提交成功,下次还会读到同一条消息)。或者消息丢失(offset 提交过早,但实际还没处理完)。

2.3.  Kafka的消息保证不重复消费是依赖于消费者来实现?

Kafka本身的 设计哲学就是:Broker 只负责存储和分发消息,不保证“只消费一次”,消息是否会被重复消费,要靠 Consumer(消费者端)自己来保证。

2.3.1. 为什么Kafka不能天然保证不重复消费?

  1. Offset提交机制决定的
    1. 消费者在拉取消息后,通常会在处理完成后提交offset。
    2. 如果处理成功但 offset 提交失败 → 下次重启会从旧 offset 继续消费 → 重复消费
    3. 如果offset 提交成功但处理失败 → 消息“跳过”了 → 消息丢失。
  1. Kafka Broker 不维护消费状态
    • Broker不记录某个消息是否已被消费。它只维护partition 的日志文件 + 保留策略。

2.3.2. Kafka 官方给出的消费语义有三种:

  1. At most once(至多一次):offset 先提交,再处理消息。风险:消息可能丢失,但绝不会重复。
  2. At least once(至少一次)(默认):先处理消息,再提交 offset。风险:可能重复消费,但不会丢
  3. Exactly once(恰好一次):Kafka 0.11 引入的特性,需要 幂等 Producer + 事务性写入 配合,在特定场景(Kafka → Kafka,Kafka → 支持事务的存储系统)可以实现。对 Consumer 来说,仍需保证幂等(例如业务处理可重试)。

2.3.3. 费端保证不重复消费的常见手段

  1. 幂等性处理:业务层面保证,即使同一条消息被重复处理,结果也是一样。例如:数据库 INSERT ... ON DUPLICATE KEY UPDATE,支付扣款时先判断“订单是否已扣款”。
  2. 唯一键去重:给每条消息一个全局唯一 ID(如订单号、流水号、事务 ID)。Consumer 处理前先检查该 ID 是否已经处理过。
  3. 事务:Kafka 提供 read-process-write 的事务性 API,确保消费和结果写入要么都成功,要么都失败。

2.4. 金融风控场景中什么场景使用kafka什么时候使用RocketMQ?

2.4.1. 金融风控中Kafka的典型使用场景

Kafka 的强项是 高吞吐、低延迟、可回溯的流数据处理,在风控里更多用于 数据实时流转和大数据计算总结:Kafka 在风控中是 数据总线,负责把交易、埋点、外部数据等实时送到决策引擎、大数据平台,强调吞吐、实时、可回溯

场景

说明

为什么用 Kafka

实时交易数据流

实时获取交易流水、支付请求、账户变动信息,推送到风控计算引擎

高吞吐(百万级 TPS),延迟低,可多消费组并行处理

用户行为埋点 & 反欺诈

埋点收集登录、设备指纹、IP 地址、地理位置、操作行为等

可与 Flink / Spark Streaming 做实时风险评分

外部数据接入

接入黑名单、征信、第三方风控数据,汇聚到数据湖

数据量大,可持久化保存并回放

实时监控 & 预警

将风控决策事件推送到监控系统(如 Grafana、Prometheus)

多消费者订阅同一数据流,不互相影响

批量模型重算 / 回测

保存历史交易数据,用于风控模型回测和调优

Kafka 可按时间窗口读取历史消息

2.4.2. 金融风控中RocketMQ的典型使用场景

RocketMQ在风控里更多用于可靠事务消息、事件驱动和任务调度,强调可靠性和一致性

场景

说明

为什么用 RocketMQ

风控决策结果落库

决策结果(放行、拦截、人工复核)与交易落库保持事务一致

事务消息保证数据库与消息一致提交

反欺诈补救动作

如冻结账户、拦截支付、通知客服,这些动作必须可靠执行

消息必达,支持重试机制

延迟风控处理

某些规则需要延迟检查(如 24 小时内重复提现)

原生延迟消息支持

风控事件驱动

触发下游系统(反洗钱 AML 系统、合规审核)执行任务

可靠投递保证事件不会丢失

批量风险任务调度

夜间批量跑风控规则、信用评估任务

结合延迟消息 / 定时任务执行

2.4.3. 对比总结表

需求

Kafka

RocketMQ

高吞吐交易流采集

用户行为埋点

实时流计算(Flink)

历史数据回放

决策结果落库事务一致

延迟/定时风控规则

风控处置任务必达

⚠️(需自己实现)

异步事件驱动

⚠️

2.5. kafka消息可能丢失呢?

是的,Kafka 消息是可能丢失的,而且丢失的原因和环节都比较多,尤其在金融风控这种高可靠场景下,需要特别注意。

2.5.1. 生产端(Producer)丢消息的原因

原因

说明

解决方式

acks=0 / acks=1

- acks=0:Producer 发送完就算成功,不管 Broker 是否收到(高性能低可靠)

- acks=1:Leader 收到即返回 ack,如果 Leader 崩溃、Follower 没同步,就丢了

生产环境用 acks=all(等待所有副本同步)

未处理发送异常

发送时网络异常/超时,应用没做 send().get()或回调检查

对 send() 结果做异常处理或重试

未开启重试机制

Producer 默认 retries=0,发送失败就丢

设置 retries > 0,并配合 enable.idempotence=true 保证幂等性

缓冲区未刷盘

Producer 进程挂了,缓冲区里的数据没发出去

开启 linger.ms= + 定时 flush,或者减少缓冲区

2.5.2. Kafka Broker丢消息的原因

原因

说明

解决方式

ISR(同步副本集合)不完整

Leader 崩溃时,Follower 未完全同步数据,被选为 Leader 后数据丢

开启 min.insync.replicas

(比如 2),配合 acks=all

日志未落盘

Kafka 默认批量刷盘(log.flush.interval.messages / log.flush.interval.ms),Broker 崩溃会丢内存数据

关键主题可调低刷盘间隔(会降低性能)

unclean.leader.election.enable=true

允许不完整副本选为 Leader,会导致数据丢失

生产环境设为 false

磁盘损坏/数据目录丢失

物理损坏、磁盘满等异常

监控磁盘、配 RAID / 云存储快照

2.5.3. 消费端(Consumer)丢消息的原因

原因

说明

解决方式

自动提交 offset(enable.auto.commit=true)

Kafka 默认 5s 自动提交 offset,如果消费未完成就宕机,下次会跳过未处理的消息

改为手动提交 offset(commitSync/commitAsync)在处理完成后提交

先提交 offset 后处理

提交成功但处理失败,消息丢失

先处理,再提交 offset

批量消费未处理完

一批数据部分成功部分失败,但 offset 已提交到最大位置

使用精细化 offset 控制或单条提交

消费端丢弃异常消息

消费代码中 try-catch 后直接忽略异常数据

对异常消息入死信队列(DLQ)

2.5.4. Kafka 可靠性最佳实践(防止丢消息)

如果你在金融风控系统中用 Kafka,建议这样配置:

2.5.4.1. 生产端(Producer)
acks=all
retries=Integer.MAX_VALUE
enable.idempotence=true
max.in.flight.requests.per.connection=1
2.5.4.2. Broker
min.insync.replicas=2
unclean.leader.election.enable=false
2.5.4.3. 消费端(Consumer)
enable.auto.commit=false
# 业务处理完成后手动 commit

并且:

  • 对关键消息使用 多副本 + 事务消息(Kafka 0.11+)
  • 对异常消息使用 死信队列(Dead Letter Queue)
  • 定期做 Kafka 数据校验和对账

2.6. kafka 只负责存储消息,消息存储后怎么删除?

Kafka 的设计理念就是 Broker 只负责存储消息,不管消费状态,所以消息是否被“消费”跟消息删除没有关系。Kafka 删除消息主要依赖 保留策略(Retention Policy) 来决定。Kafka 的消息删除机制与消费无关,主要靠 保留策略 来实现:

  1. 基于时间(默认 7 天)
  2. 基于大小(超过磁盘上限)
  3. 按 segment 文件批量删除(不是逐条删除)
  4. 日志压缩(compact):保留每个 key 的最新值

👉 所以 Kafka 可以保证消息存储高效,同时也能灵活应对“短期日志存储”和“长期状态存储”两类需求。

2.6.1. 基于时间的保留(Log Retention by Time)

  • 配置log.retention.hours(默认 168 小时 = 7 天)也可以用 log.retention.minuteslog.retention.ms 精确控制
  • 含义:超过指定时间的消息会被删除(底层是删除旧的 segment 文件)。
  • 应用场景:日志采集场景,保留最近 7 天的日志即可。

2.6.2. 基于大小的保留(Log Retention by Size)

  • 配置log.retention.bytes,每个 partition 保留的最大数据量。
  • 含义:超过大小后,旧数据被删除。
  • 应用场景:磁盘资源有限时,通过大小控制日志量。

2.6.3. 基于日志段(Log Segment)的删除

  • Kafka 底层不是一条条删除,而是按 segment 文件 删除:每个 partition 的日志会被切分成多个 segment 文件(默认 1GB 或 log.segment.bytes 配置)。当一个 segment 文件中的数据都过期后,整个文件会被删除。
  • 好处:批量删除,效率高。避免逐条消息管理,保持简单高效。

2.6.4. 基于日志压缩(Log Compaction)

除了“保留多久/多大”,Kafka 还支持 Log Compaction(日志压缩)

  • 配置cleanup.policy=compact
  • 含义:只保留每个 key 的最新一条记录,旧的记录会被清理。
  • 应用场景:适合保存状态类数据,比如“用户的最新余额”“账户状态”。

对比:

  • delete 策略:过期消息整体删除(常用)。
  • compact 策略:按 key 只保留最新值(状态存储用)。
  • 也可以同时启用:cleanup.policy=delete,compact

2.6.5. 手动删除(不常用)

  • 可以通过 管理工具 删除整个 Topic 或 Partition:
kafka-topics.sh --delete --topic test --zookeeper zk1:2181
  • 或者修改 Topic 配置,强制缩短保留时间,然后触发清理。

2.7. RockMQ存在消息丢失的情况吗?

是的,RocketMQ 也可能丢消息,只是它的设计在可靠性上比 Kafka强一些(尤其是事务消息、消息必达机制),但是如果配置不当或使用不正确,依然会丢。

2.7.1. 生产端(Producer)丢消息的原因

RocketMQ 的 Producer 如果配置不合理,丢消息概率也不低。

原因

说明

解决方式

发送失败未重试

网络抖动、Broker 不可用时,Producer send() 报错,应用没处理异常

开启 sendRetryTimes(默认 2,可调高)并捕获异常重试

单向发送(Oneway)

sendOneway() 不等待 Broker 返回确认,适合日志但会丢

金融风控禁止用单向发送

异步发送没回调检查

异步模式下 onException没做补偿

异步发送要有失败重试逻辑

事务消息回查失败

事务半消息未提交且回查失败,消息被丢弃

保证事务回查逻辑可用且幂等

2.7.2. Broker(服务端)丢消息的原因

RocketMQ 在 Broker 存储阶段,如果磁盘或刷盘机制配置不当,也可能丢。

原因

说明

解决方式

刷盘方式为异步(ASYNC_FLUSH)

Broker 先写内存,稍后刷盘,宕机前的数据会丢

对金融交易/风控类主题用 SYNC_FLUSH

主从复制为异步(ASYNC_MASTER)

主节点宕机时,未同步到从节点的数据丢失

金融场景用 SYNC_MASTER

(同步双写)

磁盘损坏

物理损坏、文件系统异常

RAID、云存储快照、磁盘监控

Broker 崩溃导致 CommitLog 未落盘

异步刷盘下,崩溃会丢部分消息

关键业务同步刷盘

2.7.3. 消费端(Consumer)丢消息的原因

RocketMQ 消费模式是“至少一次”(At-Least-Once),所以不会无故丢消息,但如果 offset 管理不当,也会丢。

原因

说明

解决方式

自动提交 offset

消费端默认自动提交,如果提交后处理失败,消息会被“认为已消费”而丢失

金融场景用手动 ACK,处理完成后再提交

消费失败但未重试

默认会重试,但如果配置了 consumeRetryTimes=0,会直接丢弃

确保开启重试,并配置死信队列(DLQ)

顺序消息消费阻塞

顺序消费模式下,长时间阻塞会导致 Broker 认为消费成功

在业务超时前主动返回 RECONSUME_LATER

消息被丢到 DLQ

重试超过限制次数会进入死信队列,不被正常消费

定期扫描并人工处理 DLQ

2.7.4. RocketMQ 防丢最佳实践(金融风控场景)

如果是风控、交易、清算等强一致性场景,建议这样配置:

2.7.4.1. 生产端
producer.setRetryTimesWhenSendFailed(5);
producer.setRetryTimesWhenSendAsyncFailed(5);
# 避免 Oneway 模式
2.7.4.2. Broker
properties复制编辑
flushDiskType=SYNC_FLUSH
brokerRole=SYNC_MASTER
2.7.4.3. 消费端
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
consumer.setMaxReconsumeTimes(16); // 超过进入DLQ
consumer.setMessageModel(MessageModel.CLUSTERING); // 集群模式

并且:

  • 对异常消息统一进入死信队列(DLQ),人工或自动补偿。
  • 对事务消息保证回查逻辑幂等且可用。
  • 对关键主题开启消息轨迹(Message Trace)方便排查丢失点。

2.8. RocketMQ 中记录消息被消费吗?

2.8.1. RocketMQ与Kafka的区别

  • Kafka:Broker 不关心消息是否消费,只存消息;offset 在 Consumer Group 端维护,存储在 __consumer_offsets 主题中;所以消息不会有“消费标记”。
  • RocketMQ:Broker 会记录消费进度(消费队列 + 消费进度);通过 ConsumeQueue + Offset 机制来追踪消息是否被消费。

2.8.2. RocketMQ 的消费队列(ConsumeQueue)

RocketMQ 的存储模型:

  • CommitLog:存储所有原始消息(顺序写入,类似 Kafka 的 log)。
  • ConsumeQueue:存储消费队列(索引文件),记录消息在 CommitLog 中的位置 + 消息 Tag 等。
  • ConsumerOffset:存储消费者组消费到哪条消息。

所以 RocketMQ Broker 能知道:某个消息被投递给哪些消费者组。某个消费者组消费到了哪条消息(offset)。

2.8.3. RocketMQ消费确认(ACK)

消息队列

offset 存储位置

维度

说明

Kafka

Broker 内部主题 __consumer_offsets

Consumer Group

由消费者提交,Kafka 统一管理

RocketMQ (集群模式)

Broker (ConsumerOffsetManager)

Consumer Group + Queue

由 Broker 统一管理

RocketMQ (广播模式)

Consumer 本地文件

Consumer 实例

每个消费者独立维护

  • RocketMQ 默认是“至少一次(At least once)”语义:Consumer 拉取消息 → 成功处理 → 返回 ACK 给 Broker;Broker更新该 Consumer Group的offset。
  • 如果处理失败:消息会被重新投递(支持延时重试 / 死信队列 DLQ)。

这意味着RocketMQ确实在 Broker层面知道一条消息有没有被消费确认

2.8.4. RocketMQ消息删除

  • 与 Kafka 类似,RocketMQ 也不会因为“消息被消费”就删除消息。
  • 消息删除仍然依赖 过期时间(默认 3 天,可配置 fileReservedTime
  • 所以历史消息依然会在磁盘上保留一段时间,方便回溯。

2.9. 防止消息丢失解决方案有哪些?

防止消息丢失的方案可以分为 端到端三个环节:生产端 → 消息中间件 → 消费端。不同环节丢失的原因不一样,解决方案也不同。

2.9.1. 1️⃣ 生产端防丢

方法

作用

适用 MQ

可靠 ACK 机制acks=all / SYNC_FLUSH

确保消息写入多个副本后才算成功

Kafka / RocketMQ

幂等发送enable.idempotence=true

避免重试导致重复数据

Kafka

发送异常处理与重试

网络异常、超时必须重发

所有 MQ

事务消息

与数据库操作原子性一致

Kafka / RocketMQ

Outbox + CDC

数据库先落地消息,再异步投递 MQ

所有 MQ

批量 flush 控制

防止 Producer 崩溃时缓冲区数据丢失

Kafka / RocketMQ

2.9.2. 2️⃣ 消息中间件防丢

方法

作用

MQ 特性

多副本存储replication.factor>=2

避免单点故障丢消息

Kafka / RocketMQ

同步刷盘SYNC_FLUSH

避免 Broker 崩溃时丢内存数据

RocketMQ

ISR 同步策略min.insync.replicas

仅在副本足够时才确认消息

Kafka

禁止 Unclean Leader 选举

避免落后副本当 Leader 导致丢数据

Kafka

磁盘健康监控

防止物理故障丢消息

所有 MQ

延迟队列 + DLQ

遇到处理异常可暂存或丢到死信队列

所有 MQ

2.9.3. 3️⃣ 消费端防丢

方法

作用

MQ 特性

手动 ACK / 手动提交 offset

确保消费成功后才确认

Kafka / RocketMQ

先处理,再提交 offset

防止处理失败但 offset 已提交

Kafka

消费重试机制

消费失败可重新投递

所有 MQ

死信队列(DLQ)

多次失败的消息单独存储

所有 MQ

幂等消费

防止重试导致重复处理

所有 MQ

消费进度持久化

确保宕机恢复后能从上次位置继续

Kafka / RocketMQ

2.9.4. 4️⃣ 端到端防丢组合方案

根据业务重要性选择:

  • 高一致性(金融交易、风控决策)
    • RocketMQ 事务消息 / Kafka 事务 + 幂等发送
    • 消费端手动 ACK + 幂等消费
    • Broker 多副本 + 同步刷盘
  • 高吞吐实时流(埋点、日志分析)
    • Kafka acks=all + ISR 策略
    • 消费端自动提交 offset + 异步批量处理(可容忍极少丢失)
  • 可补偿业务(异步任务、通知)
    • 先写数据库 + 定时补偿任务
    • 或 Outbox + CDC

一句话总结:防丢必须从生产端可靠发送MQ 高可用存储消费端可靠确认 三方面同时保障,单靠“先写数据库再发 MQ”并不是唯一解。

2.10. Outbox + CDC 是什么方案?

Outbox + CDC 是一种业界常用的防止消息丢失 & 保证数据库与消息一致性的架构模式,尤其在金融、支付、风控等对一致性要求高的系统里很常见。

2.10.1. 为什么会有 Outbox + CDC

在普通架构里,常见有两种做法:

  1. 先写数据库,再发 MQ → 如果发 MQ 失败,需要补偿逻辑,否则不一致。
  2. 先发MQ,再写数据库 → 如果写库失败,就会产生无效消息。

这两个都不是完美方案,尤其金融风控场景下,数据和消息必须100%一致。于是出现了 Outbox(发件箱)模式 + CDC(变更数据捕获) 的组合。

2.10.2. Outbox 模式

核心思想

  • 在业务数据库中增加一个消息表(outbox table)
  • 同一个本地事务中同时写入:
    • 业务数据(比如风控结果、交易流水)
    • 消息数据(写入消息表)

这样,业务数据和消息数据要么一起成功,要么一起失败,天然一致。

例子:

BEGIN;
INSERT INTO risk_decision (id, user_id, decision) VALUES (123, 456, 'REJECT');
INSERT INTO outbox (id, topic, payload, status) VALUES (999, 'risk_event', '{...}', 'NEW');
COMMIT;

2.10.3. CDC(Change Data Capture)

核心思想

  • 用一个独立的消息发送服务(或中间件)实时监听 outbox 表变化
  • 通过读取数据库 binlog(如 MySQL binlog、PostgreSQL WAL)来捕获新插入的消息
  • 把消息发送到 MQ(Kafka / RocketMQ)
  • 发送成功后更新 outbox 表的状态(比如 status=PROCESSED

常用的 CDC 工具:

  • Debezium(最常用,支持 Kafka、Pulsar、RabbitMQ)
  • Canal(阿里开源)
  • Maxwell

2.10.4. 方案优缺点

优点

缺点

强一致:数据库和 MQ 消息一定一致

增加一张 outbox 表,额外占用数据库存储

无分布式事务:只用本地事务

需要部署 CDC 服务,运维复杂度增加

可重放:消息表是天然的“重发记录”

消息延迟略高(取决于 CDC 频率)

可审计:可以追踪每条消息的生命周期

适合异步业务,不适合极低延迟场景

2.10.5. 在金融风控中的典型用法

  • 风控结果写库 + 发消息:确保风控决策落库成功才发消息给下游(冻结、人工复核、黑名单同步等)
  • 交易流水落库 + 事件广播:先保证交易落库,再异步广播到风控、账务、营销等系统
  • 反欺诈事件记录 + 数据分析:确保反欺诈事件既能写库留痕,也能推送到 Kafka 做实时分析

2.10.6. 流程图

[业务服务]|  本地事务写两份数据|----------------------------| 业务表 + Outbox 消息表↓
[数据库]↓  CDC监听 binlog
[CDC 服务 (Debezium/Canal)]↓
[MQ (Kafka/RocketMQ)]↓
[下游消费者]

💡 总结
Outbox + CDC 本质是:

  • Outbox:保证业务数据和消息的原子性
  • CDC:负责异步、可靠地把消息送到 MQ
    这样既避免了分布式事务的复杂性,又能保证数据与消息强一致,是金融风控里非常稳妥的方案。

博文参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96350.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96350.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/96350.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[特殊字符] GitHub 热门开源项目速览(2025/09/09)

今天为大家整理了近期 GitHub 上热度较高的开源项目,涵盖 AI Agent、加密计算、操作系统、机器人、PDF 工具 等多个方向。让我们一起看看都有哪些值得关注的项目吧! 🔹 AI Agents & 开发者工具 parlant (⭐ 10.9k | ⬆️ 117…

OpenHarmony之USB Manager 架构深度解析

1. 整体架构 OpenHarmony USB管理器采用三层架构设计: USB API:提供USB的基础API,主要包含查询USB设备的列表、设备插拔通知、USB HOST/DEVICE 功能切换、批量数据传输、控制命令传输、USB设备打开的权限控制及USB device模式下的function功能切换等。 USB Service:主要实…

java面试中经常会问到的mysql问题有哪些(基础版)

文章目录一、基础概念与存储引擎二、索引设计与优化(高频重点)三、事务与锁(核心原理)四、SQL性能优化与问题排查五、高可用与数据安全六、其他高频细节问题在Java面试中,MySQL作为最常用的关系型数据库,是…

Tess-two - Tess-two 文字识别(Tess-two 概述、Tess-two 文字识别、补充情况)

一、Tess-two 概述Tess-two 是 Tesseract OCR 引擎在 Android 平台上的一个封装库,用于实现离线文字识别Tess-two 的 GitHub 官网:https://github.com/rmtheis/tess-two二、Tess-two 文字识别 1、演示 (1)Dependencies 模块级 bui…

八、Win/Linux/macOS全平台彻底卸载Docker的操作指南

八、Win/Linux/macOS全平台彻底卸载Docker的操作指南 系列文章目录 1. 卸载前准备工作(可忽略) 1.1 数据备份 1.2 停止Docker服务 2. 不同操作系统卸载步骤 2.1 Linux系统 2.2 macOS系统 2.3 Windows系统 3. 残留文件深度清理 3.1 Linux系统 3.2 macOS系统 3.3 Windows系统 4…

强化学习-CH9 策略梯度方法

强化学习-CH9 策略梯度方法 当策略被表示为函数时,通过优化目标函数可以得到最优策略。 这种方法称为策略梯度。策略梯度方法是基于策略的,而之前介绍的方法都是基于值的。其本质区别在于基于策略的方法是直接优化关于策略参数的目标函数。 9.1 策略表示…

[玩转GoLang] 5分钟整合Gin / Gorm框架入门

方法 / 步骤 一: Gin框架 1.1 : 环境 & 项目配置 1, GoLand创建项目 创建main.go package mainimport ("github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"message": "…

【项目复现】MOOSE-Chem 用于重新发现未见化学科学假说的大型语言模型

项目地址 ZonglinY/MOOSE-Chem: [ICLR 2025] --- ZonglinY/MOOSE-Chem: [ICLR 2025] https://github.com/ZonglinY/MOOSE-Chem git代码同步&#xff1a; 同步地址如下&#xff1a;QianPengfei1/MOOSE-Chem: [ICLR 2025] <MOOSE-Chem: Large Language Models for Rediscove…

深入解析TCP核心机制:连接管理、流量与拥塞控制

目录 一、三次握手与四次挥手&#xff1a;可靠连接的建立与终止 1. 三次握手 - 建立连接 为什么是三次&#xff1f; 2. 四次挥手 - 终止连接 为什么需要TIME_WAIT状态&#xff1f; 二、流量控制与滑动窗口&#xff1a;解决收发速度不匹配 核心机制&#xff1a;滑动窗口协…

如何在 DevOps 管道中实现 AI?

对于许多寻求提升效率、优化性能并缩短上市时间的组织而言,将人工智能 (AI) 集成到 DevOps 流水线中已成为一项战略举措。AI 与 DevOps 的结合,有时被称为 AIOps(面向 IT 运营的人工智能),正在重塑开发和运营团队构建、测试、发布和维护软件应用程序的方式。本文将引导您了…

【Agent】DeerFlow Planner:执行流程与架构设计(基于真实 Trace 深度解析)

本文档系统阐述 DeerFlow 中 Planner 的职责边界、端到端执行流程、关键节点设计、数据结构、容错与人审机制&#xff0c;以及与研究/编码子代理的协同方式。面向开发与运维读者&#xff0c;帮助快速理解与调优 Planner 相关链路。 时序图&#xff08;Sequence Diagram&#xf…

后端接口防止XSS漏洞攻击

有这样一个场景&#xff0c;首先构建一个docx文件并插入超链接&#xff08;恶意的链接&#xff09;&#xff0c;上传到文件服务器后获取对应的文件filekey。现在我们提供一个预览接口&#xff0c;通过filekey便可以预览&#xff0c;在根据filekey转html文档返回给页面的时候由于…

4.1Vue基本使用

1.使用Vue-引入 Vue 的本质,就是一个 JavaScript 的库: 刚开始我们不需要把它想象的非常复杂; 我们就把它理解成一个已经帮我们封装好的库; 在项目中可以引入并且使用它即可。 那么安装和使用 Vue 这个 JavaScript 库有哪些方式呢? 方式一:在页面中通过 CDN 的方式来引…

CAD绘图:杂项

一、样式标注管理器 新建CAD图纸的样式标注是定死的,需要手动去改变合适的大小 1)命令行中直接输入“D”,打开样式标注管理器 2)点击“修改”,可以改变其颜色,线条样式以及文字大小、颜色、字体等 3)若想添加字体: a)在网上下载需要的字体 b)右键Auto CAD图标(…

Git上有更新而本地无更新时的解决方案

问题分析 分支名称不匹配&#xff1a;你尝试推送到 main 分支&#xff0c;但你当前在 master 分支上远程仓库有新内容&#xff1a;远程仓库包含你本地没有的提交&#xff0c;需要先拉取 解决方案 方法1&#xff1a;继续使用 master 分支 # 1. 先拉取远程更改 git pull origin m…

用于骨盆骨折复位与固定自动术前手术规划的基于几何的端到端流水线|文献速递-最新医学人工智能文献

Title题目An End-to-End Geometry-Based Pipeline forAutomatic Preoperative Surgical Planning ofPelvic Fracture Reduction and Fixation用于骨盆骨折复位与固定自动术前手术规划的基于几何的端到端流水线01文献速递介绍骨盆骨折及其术前规划相关研究背景与本文方法 骨盆骨…

【导航】OS复习

【OS】操作系统概述-CSDN博客 【OS】PV-CSDN博客 【OS】进程与线程-CSDN博客 【OS】文件管理-CSDN博客 【OS】IO_检查用户io请求的合法性-CSDN博客

Google Nano-banana AI模型图像生成能力实证分析:基于47个案例的系统化技术验证

Google Nano-banana AI模型官方示例库&#xff08;Awesome-Nano-Banana&#x1f34c;-images&#xff09;&#xff0c;通过系统化分析47个技术案例&#xff0c;实证验证其在图像生成、编辑与转换任务中的核心能力。所有测试基于Apache 2.0开源许可的公开案例数据集&#xff0c;…

MySQL 多表操作与复杂查询:深入理解多表关系和高级查询

大家好&#xff01;今天我们要深入探讨 MySQL 中两个非常重要的主题——多表操作 和 复杂查询。一. 多表操作什么是多表操作&#xff1f;在实际应用中&#xff0c;数据通常分布在多个表中&#xff0c;需要通过多表操作来获取完整信息。比如&#xff0c;一个学生表和一个课程表之…

Java入门级教程7——eclipse新建Maven项目,创建和连接数据库,创建数据库表

目录 1.若没有Maven项目&#xff0c;可以选择新建 2.添加Maven依赖 3.数据库的创建 3.1 新建连接 --> 创建数据库 3.2 创建数据库表 4.连接数据库 1.若没有Maven项目&#xff0c;可以选择新建 步骤一&#xff1a;点击 File --> New --> Project 步骤二&#xf…