zhongminma/kafka-incident-response
GitHub: zhongminma/kafka-incident-response
一个基于 Kafka 的事件流平台可靠性练习项目,通过模拟和诊断常见故障场景帮助开发者掌握分布式系统的可观测性与容错处理能力。
Stars: 0 | Forks: 0
# Kafka 可靠性与事件流平台
本项目模拟了一个 Kafka 到数据库的事件流平台,并将常见的 Kafka 故障转化为可重复、可观测的练习。
我们的目标不是一次性构建所有内容。本项目将通过小步快跑的方式逐步实现。每一步必须完成一个功能或一个目标,并且每次 GitHub commit 或 pull request 在提交前都需要明确的批准。
## 项目目标
- 构建本地 Kafka 到数据库的 pipeline。
- 模拟并诊断 consumer lag 的增长。
- 模拟 broker 故障并观察服务行为。
- 模拟重复消息并实现幂等数据库写入。
- 模拟 poison message 并安全路由失败记录。
- 通过 Prometheus、Grafana 和 OpenTelemetry 添加可观测性。
- 在本地 Docker 工作流稳定后提供 Kubernetes manifest。
- 保持每个实施步骤小巧、易于审查且易于回滚。
## 技术栈
- Kafka 用于事件流。
- Node.js 用于 producer、consumer 和控制 API 服务。
- 数据库,最初使用 PostgreSQL,用于持久化事件存储。
- Docker Compose 用于首个本地环境。
- Kubernetes 用于可部署的平台版本。
- Prometheus 用于指标收集。
- Grafana 用于仪表板。
- OpenTelemetry 用于 trace 和服务埋点。
## 高层架构
```
flowchart LR
Producer["Node.js Producer"] --> OrdersTopic["Kafka Topic: orders.events"]
OrdersTopic --> Consumer["Node.js Consumer"]
Consumer --> Database["PostgreSQL"]
Consumer --> DLQ["Kafka Topic: orders.dlq"]
ControlAPI["Node.js Control API"] --> Producer
ControlAPI --> Consumer
ControlAPI --> Kafka["Kafka Broker"]
Producer --> OTel["OpenTelemetry Collector"]
Consumer --> OTel
ControlAPI --> OTel
OTel --> Prometheus["Prometheus"]
Prometheus --> Grafana["Grafana"]
```
## 核心服务
| 服务 | 用途 |
| --- | --- |
| Producer | 生成业务事件并将其发布到 Kafka。 |
| Consumer | 读取 Kafka 事件、验证 payload 并将记录写入数据库。 |
| Control API | 暴露场景开关,如慢 consumer 模式、重复发布、poison message 发布和健康检查。 |
| Database | 存储已消费的事件并支持幂等性检查。 |
| Kafka | 提供事件流主干。 |
| Prometheus | 抓取服务、Kafka 和数据库的指标。 |
| Grafana | 可视化 lag、吞吐量、故障、重试和数据库写入。 |
| OpenTelemetry Collector | 接收来自 Node.js 服务的 trace 和指标。 |
## 故障场景
### 1. Consumer Lag 持续增加
Producer 发送消息的速度超过了 Consumer 的处理速度。
预期学习目标:
- 理解 consumer group lag。
- 比较 producer 速率、consumer 吞吐量和数据库写入延迟。
- 观察 lag 何时增长、稳定或排空。
- 练习扩展或调优 consumer。
可能的控制方式:
- 提高 producer 事件发送速率。
- 增加人为的 consumer 处理延迟。
- 增加人为的数据库写入延迟。
- 降低 consumer 并发数。
重要指标:
- Kafka consumer group lag。
- 每秒生产的消息数。
- 每秒消费的消息数。
- 数据库写入延迟。
- Consumer 错误率。
### 2. Broker 故障
Kafka 暂时不可用或停止了其中一个 broker。
预期学习目标:
- 理解 producer 的重试行为。
- 理解 consumer 的重连行为。
- 观察在 broker 恢复可用后的消息投递恢复情况。
- 区分服务故障与依赖项故障。
可能的控制方式:
- 停止 Kafka broker 容器。
- 重启 Kafka broker 容器。
- 在 Kubernetes 中,删除一个 broker pod 并观察恢复过程。
重要指标:
- Producer 发布失败。
- Consumer 断开连接与重新连接。
- Kafka broker 可用性。
- 事件吞吐量的下降与恢复。
- 应用程序健康与就绪状态。
### 3. 重复消息
相同的逻辑事件被发布或消费多次。
预期学习目标:
- 理解至少一次投递。
- 使用事件 ID 和数据库约束实现幂等性。
- 跟踪重复消息且不破坏业务状态。
可能的控制方式:
- 多次发布同一个事件 ID。
- 在成功写入数据库之后、但在提交 offset 之前强制触发 consumer 重试。
重要指标:
- 重复事件数。
- 数据库冲突数。
- Consumer 重试次数。
- 存储的事件数与消费的消息数对比。
### 4. Poison Message(毒消息)
格式错误或无效的消息会阻碍正常处理,除非对其进行安全处理。
预期学习目标:
- 在写入数据库前验证消息。
- 避免无限重试循环。
- 将无效记录路由至死信队列。
- 保留足够的上下文以供后续调查。
可能的控制方式:
- 发布无效的 JSON。
- 发布缺少必填字段的有效 JSON 记录。
- 发布故意无法通过业务验证的记录。
重要指标:
- 验证失败次数。
- 死信队列消息数。
- Consumer 重试次数。
- Consumer 处理延迟。
## 逐步交付计划
每一步都应足够小,以便独立审查。只有当某一步具备文档、验证命令或检查清单并获得提交批准时,该步骤才算完成。
| 步骤 | 目标 | 功能范围 | 预期交付物 |
| --- | --- | --- | --- |
| 1 | 定义架构 | 包含目标、系统设计、场景和交付规则的 README | `README.md` |
| 2 | 添加本地项目骨架 | 仅包含最简目录和包元数据 | 空的服务文件夹、根包元数据,无运行时行为 |
| 3 | 启动本地依赖 | 用于 Kafka 和 PostgreSQL 的 Docker Compose | `docker-compose.yml` 以及设置文档 |
| 4 | 创建 Kafka topic 设置 | 为主 topic 和 DLQ topic 进行可重复的 topic 创建 | 用于 `orders.events` 和 `orders.dlq` 的脚本或容器命令 |
| 5 | 构建 producer MVP | Producer 以固定速率发布有效事件 | 带有基本日志的 Node.js producer |
| 6 | 构建 consumer MVP | Consumer 读取事件并写入数据库 | 包含数据库插入操作的 Node.js consumer |
| 7 | 添加数据库 schema | 具有唯一事件 ID 的持久化事件表 | 迁移或初始化 SQL |
| 8 | 添加控制 API | 用于健康检查和场景切换的基本 endpoint | Node.js API 服务 |
| 9 | 模拟不断增加的 lag | Producer 速率或 consumer 延迟控制 | 可重现的 lag 场景 |
| 10 | 添加 lag 指标 | 暴露 consumer 吞吐量和 lag 相关指标 | Prometheus 指标 endpoint |
| 11 | 模拟 broker 故障 | 已成文的 broker 停止/重启工作流 | Runbook 章节和验证检查清单 |
| 12 | 处理重复消息 | 使用事件 ID 进行幂等数据库写入 | 重复场景和指标 |
| 13 | 处理 poison message | 验证以及死信队列路由 | DLQ 流程和调查文档 |
| 14 | 添加 OpenTelemetry trace | 追踪 producer、consumer、API 和数据库操作 | OTel collector 配置和 trace span |
| 15 | 添加 Prometheus | 抓取 Node.js 服务和基础设施指标 | Prometheus 配置 |
| 16 | 添加 Grafana 仪表板 | 用于吞吐量、lag、错误和 DLQ 的仪表板 | Grafana 仪表板 JSON |
| 17 | 添加 Kubernetes manifest | 部署 Kafka、数据库、服务和可观测性组件 | `k8s/` 下的 Kubernetes YAML |
| 18 | 添加故障 Runbook | 针对每种故障模式的操作指南 | 用于检测、诊断、缓解、恢复的文档 |
| 19 | 添加测试 | 针对关键行为的单元或集成测试 | 针对幂等性、验证和健康检查的测试 |
| 20 | 最终审查 | 完善文档、验证所有场景、准备演示流程 | 完整的演示检查清单 |
## GitHub 批准规则
禁止自动执行任何 commit、branch push、pull request 或 GitHub issue 更新。
每一步的工作流:
1. 精确实施或记录一个步骤。
2. 展示更改的文件并总结结果。
3. 在适用时运行该步骤的验证检查清单。
4. 在进行任何 Git commit 之前请求批准。
5. 在进行任何 push 或 pull request 之前再次请求批准。
## 初始本地开发策略
推荐的顺序是本地优先:
1. 构建 Docker Compose 环境。
2. 在本地验证 Kafka 到数据库的投递。
3. 逐一添加故障切换开关。
4. 添加指标和仪表板。
5. 将稳定版本迁移至 Kubernetes。
这使得早期的调试保持快速,并避免了将应用程序行为问题与 Kubernetes 部署问题混为一谈。
## 仓库布局
该仓库以一个小的 Node.js 工作区起步。运行时代码将在后续步骤中添加。
```
docker-compose.yml Root Compose entrypoint for local dependencies.
apps/
producer/ Kafka event producer service.
consumer/ Kafka-to-database consumer service.
control-api/ Scenario control and health API.
packages/
shared/ Shared event contracts and helper utilities.
infra/
docker/ Docker Compose and local dependency configuration.
kubernetes/ Kubernetes manifests.
observability/ Prometheus, Grafana, and OpenTelemetry configuration.
docs/ Incident runbooks and verification notes.
scripts/ Local setup and maintenance scripts.
```
步骤 2 验证:
- `git status --short` 仅显示供审查的骨架文件。
- `find . -maxdepth 3 -type f | sort` 仅显示工作区元数据和占位文件。
- 未添加任何应用程序运行时代码。
步骤 3 验证:
- `docker compose config` 解析根 Compose 入口点。
- Kafka 被配置为端口 `9092` 上的本地单节点 broker。
- PostgreSQL 配置在端口 `5432` 上,数据库为 `event_stream`。
步骤 4 验证:
- `sh -n scripts/setup-topics.sh` 验证 topic 设置脚本的语法。
- `docker compose config` 确认脚本使用的 Docker Compose 服务名称。
- 当 Kafka 运行时,`./scripts/setup-topics.sh` 会以幂等方式创建 `orders.events` 和 `orders.dlq`。
步骤 5 验证:
- `npm run check -w apps/producer` 验证 producer 的 JavaScript 语法。
- `npm run test` 验证工作区测试脚本仍能正常解析。
- 当 Kafka 运行时,`npm run start -w apps/producer` 会向 `orders.events` 发布正常的 `order.created` 事件。
步骤 6 验证:
- `npm run check -w apps/consumer` 验证 consumer 的 JavaScript 语法。
- `npm run test` 验证工作区测试脚本仍能正常解析。
- `docker compose config` 确认 PostgreSQL 初始化 schema 的挂载能正确解析。
- 当 Kafka 和 PostgreSQL 运行时,consumer 会将正常的 `order.created` 事件存储到 `consumed_events` 中。
步骤 7 验证:
- `sh -n scripts/db-summary.sh` 验证数据库摘要脚本的语法。
- 当 PostgreSQL 运行时,`npm run db:summary` 会检查本地数据库。
- `docker compose config` 确认 PostgreSQL 初始化 schema 的挂载仍能正确解析。
步骤 8 验证:
- `npm run check -w apps/control-api` 验证控制 API 的 JavaScript 语法。
- `npm run test` 验证工作区测试脚本仍能正常解析。
- 在本地运行时,`GET /health` 返回服务健康状况,而 `GET /scenarios` 返回场景状态。
步骤 9 验证:
- `npm run check -w apps/consumer` 验证人为处理延迟控制。
- `npm run check -w apps/producer` 验证 producer 的 interval 配置。
- `docs/consumer-lag.md` 记录了如何创建和恢复不断增加的 lag。
步骤 10 验证:
- `npm run check -w apps/producer` 验证 producer 的指标 endpoint 代码。
- `npm run check -w apps/consumer` 验证 consumer 的指标 endpoint 代码。
- `docs/metrics.md` 列出了 producer 和 consumer 的 Prometheus 指标。
步骤 11 验证:
- `sh -n scripts/kafka-status.sh` 验证 Kafka 状态脚本的语法。
- `docker compose config` 确认 Kafka 服务仍然可解析。
- `docs/broker-failure.md` 记录了停止、观察、恢复和清理的步骤。
步骤 12 验证:
- `npm run check -w apps/producer` 验证重复发布控制。
- `npm run check -w apps/consumer` 验证幂等 consumer 写入。
- `docker compose config` 确认更新后的 schema 仍然处于挂载状态。
- `docs/duplicate-messages.md` 记录了重复注入和验证过程。
步骤 13 验证:
- `npm run check -w apps/producer` 验证 poison message 发布控制。
- `npm run check -w apps/consumer` 验证消息验证和 DLQ 路由。
- `docker compose config` 确认 DLQ topic 仍可通过 Kafka 设置访问。
- `docs/poison-message.md` 记录了 poison message 注入和 DLQ 验证过程。
## 定义
| 术语 | 含义 |
| --- | --- |
| Consumer lag | Kafka 最新 offset 与 consumer group 已处理 offset 之间的差值。 |
| Broker 故障 | 由于停止、重启或删除 broker 实例导致的 Kafka broker 不可用。 |
| 重复消息 | 代表同一个逻辑业务事件的多个 Kafka 消息。 |
| Poison message | 由于其 payload 或业务含义无效而反复导致处理失败的消息。 |
| 死信队列 | 用于存储无法成功处理的消息的 Kafka topic。 |
| 幂等性 | 多次处理同一个逻辑事件而不会错误地改变最终结果的能力。 |
## 当前状态
- 步骤 1 已完成。
- 步骤 2 已。
- 步骤 3 已完成。
- 步骤 4 已完成。
- 步骤 5 已完成。
- 步骤 6 已完成。
- 步骤 7 已完成。
- 步骤 8 已完成。
- 步骤 9 已完成。
- 步骤 10 已完成。
- 步骤 11 已完成。
- 步骤 12 已完成。
- 可以通过幂等数据库写入模拟并跳过重复消息。
- 步骤 13 已起草并等待审查。
- Poison message 可以被路由到 `orders.dlq` 而不会阻塞 consumer。
- 步骤 13 尚未进行 commit 或 push。
标签:API集成, GNU通用公共许可证, Kafka, MITM代理, Node.js, PostgreSQL, SonarQube插件, 事件流处理, 可观测性, 子域名突变, 测试用例, 消息队列, 版权保护, 用户代理, 自定义脚本, 自定义请求头