这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
《Java 消息中间件·可靠消息与消费治理》8.3 Schema Registry 的取舍
集中式 schema 管理能给你版本查找、兼容性门禁和跨语言契约,代价是多一个服务、多一次依赖和一套客户端耦合。本篇不引入任何第三方 registry 客户端,只用消息头、schema 文件和 CI 脚本,搭一个能跑的最小自管方案,并给出该不该上 registry 的判定表。
posts
这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
集中式 schema 管理能给你版本查找、兼容性门禁和跨语言契约,代价是多一个服务、多一次依赖和一套客户端耦合。本篇不引入任何第三方 registry 客户端,只用消息头、schema 文件和 CI 脚本,搭一个能跑的最小自管方案,并给出该不该上 registry 的判定表。
加字段、删字段、改类型、改字段名,四种变更分别能不能兼容?本篇用同一份 JSON payload,让老消费者读新消息、新消费者读旧消息,八个方向逐个跑,贴出 ClassCastException 与 NullPointerException 的原文,并给出双写双读的发布顺序、回滚判据与七条上线前检查清单。
事件是已经发生的事实,不是请求也不是状态快照。本篇先划清事件体该放什么、不该放什么,再给出 libraryd 六个事件的 record 定义,逐字段说明它为什么存在、缺了会怎样;最后用一次本机实测说明事件 ID 与增量字段如何决定重放是否可重复。
只存当前状态,你能回答「现在是什么」,回答不了「为什么变成这样」。事件溯源把状态变更本身作为唯一事实来源,状态由重放推导。本篇用纯 JDK 实现最小事件存储,追加 8 个库存事件后从 0 重放得到 stock=9、reserved=12,再用 version=4 的快照加 4 条增量重放,两条路径结果逐字段相等;并实测乐观并发与重复 eventId 两种拒绝。
日志挖掘读数据库的变更日志,查询轮询读一张带水位列的表,两者在 op 语义、删除可见性和业务侵入上完全不同。本篇手写轮询版 CDC 实测 c/u/d 三种变更,用同一毫秒的两行证明单列时间水位会漏数据,再用快照前取水位与快照后取水位两种顺序,说明衔接为什么只有前者能得到一致状态;Debezium 仅做架构对照并标注未在本机执行。
先写库再发消息,会在进程崩溃时留下「有业务行、无事件」的孤儿数据。本篇用同库同事务的 outbox 表消除这个窗口,给出轮询发布器的完整实现,并在本机用嵌入式数据库真实 kill -9:写入 5 笔后崩溃、发送 3 条未标记就崩溃,重启补发后业务行 5、outbox 行 5、Kafka 8 条记录 5 个事件 ID,逐条对上。
把卷三涉及交易、营销、增长与开放平台的合规与风控要求整理成可勾选的清单:主体资质、价格与促销、支付与发票、隐私与数据、未成年人保护、消费者权益、交易监测、风控维度、处置动作、申诉与审计,并给出上线前、活动中、事后复盘三阶段的检查项与常见失败案例。
毒消息不是「处理失败」,而是每次都以同样方式失败、无法自愈的消息。本篇在本机让一条坏消息把整个分区卡住 30 秒:消费位移停在 2,LAG 从 4 涨到 9;再演示转入隔离主题、提交位移、分区恢复消费,并用 libraryd 的退货事件给出人工修复后回灌必须满足的幂等前提。
原地重试会占住分区,进程一崩还会丢掉等待中的重试。本篇用三级重试主题把等待外置,实测一条消息从主主题到 DLT 的完整时间轨迹(5 秒、15 秒、45 秒三档退避),量化重试带来的记录放大:100 条业务消息产生 140 条记录,并给出可落地的参数与观测判据。
死信队列不是失败消息的垃圾桶,而是一份可回放的失败证据。本篇给出进入死信的判据、必须随消息搬运的元信息清单,并在 Kafka 4.3.0 上跑通完整链路:九条消息中一条重试耗尽进入 DLT,贴出死信头原文,再把修复后的消息回灌原主题,最后给出可验收的判据与反模式清单。
下游只有每秒 870 条的能力,消费者硬拉会怎样?实测不限速时 3.7 秒把 3 万条全拉进 JVM,队列峰值 29783,客户端内 p99 滞留 29.7 秒;用 pause/resume 把队列压到 1995,p99 降到 1.9 秒。附一份可运行的背压实现与 AIMD 限速器。
积压处置的第一步不是扩容,而是算清楚「追得上还是追不上」。本篇用 9 万条真实积压,分别走加消费者、提高批量和跳过三条路径,记录每秒采样的 LAG 曲线:3 个消费者只快 1.4 倍、批量放大 10 倍只快 13%、跳过 7.2 万条要先等组变空。
同一时刻同一分区,kafka-consumer-groups.sh 报 LAG=800,客户端 records-lag-max 显示 900,手算 LEO−position 是 600。三个数都不是 bug,而是三种口径。本篇用一次真实取数把这三种口径拆开,附源码依据与 70 秒空转后指标变 NaN 的实测。
扩容一个消费者会触发整组再平衡,停机的姿势决定了消息是重复、丢失还是要等会话超时。本篇给出一份完整可运行的优雅停止代码,用 1200 条消息实测 SIGTERM 后零重复零丢失;再让一个消费者停 poll 25 秒,贴出 max.poll.interval.ms 踢出的原始 WARN 日志,并数清 1212 次投递里的重复。
7 个分区、2 到 3 个消费者,range、round-robin、sticky、cooperative-sticky 四种策略各跑一遍:谁撤销了全部分区,谁只撤销搬走的那几个,谁多花一轮协议,谁把 8 个分区分成 4-2-2。本篇把分配结果、迁移分区数、再平衡耗时与倾斜成因放进同一组实测数据,并给出观测与选型方法。
消费组不是一个进程列表,而是一份职责加一套位移。本篇用 600 条消息、两个快慢不同的消费者和三个订阅同一主题的组,量出「同组能力必须一致」与「多组订阅的复制成本」,再给出按业务域、按处理职责、按分区手工分配三种方案的对照,以及组 ID 命名、空组回收与选择清单。
事务不是免费的:多一次协调器往返、多一个状态主题、多一段 LSO 阻塞,还要为 abort 的数据付磁盘钱。本篇用 broker 请求日志数出每个事务多发了哪些 RPC,用两组单次运行对比事务与非事务的发送耗时,并给出判断「什么时候不该用事务」的工程判据。
把卷三反复出现的指标与实验口径集中成一份可查的表:流量、转化、留存、交易、退款、履约、增长与实验各自的分子分母、时间窗口、去重规则与常见误读,再给出样本量估算公式、显著性判读顺序、多重比较校正、归因口径、指标字典模板、报表一致性、实验复盘记录与口径变更流程。
事务不会永远开着:transaction.timeout.ms 到期后由协调器主动中止,客户端下一次提交只会收到一个致命错误。本篇实测超时事务的 abort 时点与数据形态,再用两个同 transactional.id 的生产者复现 fencing,说明僵尸写入为什么会被拒绝。
事务生产者把多条消息与消费位移放进一个原子单元。本篇跑通 transactional.id、initTransactions、begin/commit/abort 全流程,用同一份数据分别喂给 read_committed 与 read_uncommitted 消费者,对照提交与中止的可见性,并解释 LSO 为什么会挡住事务之后的消息。