企业订单参考工程:构建、部署、幂等与故障验收
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
本篇提供实际 API(应用程序接口)、异步 worker、PostgreSQL 迁移、Helm Chart 和自动验收。业务为隔离合成租户的订单与记账,不会调用支付或发货。账本是数据库中的真实持久化副作用,不把 HTTP 200 当业务成功。
1. 获取工程与理解边界#
在本站源码仓库执行:
cp -R static/examples/enterprise-orders /tmp/orders-work
cd /tmp/orders-work工程也可从文件清单下载;目录结构必须保留。app.py 校验租户与幂等键,worker.py 使用 PostgreSQL FOR UPDATE SKIP LOCKED 领取事务队列,订单、账本、投影与确认同事务提交。进程崩溃时事务回滚,锁自动释放,无另设可见性超时。数据库瞬断使用指数退避;账本金额冲突等业务错误每 30 秒重试,5 次后保留在 outbox 死信集合,orders_dead_letters 可监控。先修复并对账,再以当前站点 worker 维护身份按指定 order_id 重置 attempts/available_at;禁止批量清空或跳过错误标记完成。
| 契约 | 实现 |
|---|---|
| POST /orders | Bearer token 绑定租户;Idempotency-Key 在租户内唯一;同键不同正文返回 409 |
| GET /orders/{id} | 只能查 token 所属租户;返回状态、账本金额与查询投影 |
| /healthz、/readyz | 分别检查进程、数据库和当前写入代次;数据库失联不接新业务 |
| /metrics | 请求率、错误率、延迟、未完成任务与最老任务年龄;仅监控网络可访问 |
| 写入隔离 | 数据库登录角色绑定站点,触发器校验单写者与递增 epoch(代次);运行角色不能修改控制表 |
这是 PostgreSQL 事务队列路径,不与原 SQS/Pub/Sub 示例混称。外部支付或其他数据库副作用需额外实现幂等调用、outbox(事务发件箱)投递与对账;本工程不承诺外部系统 exactly-once(恰好一次)。
2. 本地真实依赖验收#
需要 Docker Compose、Python 3。本地使用单 PostgreSQL 验证业务正确性,不声称单机具备高可用。选择当前受支持补丁、扫描后固定 digest(镜像摘要);以下命令将选中的镜像解析为摘要:
export PYTHON_TAG=python:3.12-alpine
export POSTGRES_TAG=postgres:17
# 首次拉取后审查版本、漏洞,批准后才继续;后续使用记录的 digest。
docker pull "$PYTHON_TAG"
docker pull "$POSTGRES_TAG"
export BASE_IMAGE=$(docker image inspect "$PYTHON_TAG" --format '{{index .RepoDigests 0}}')
export POSTGRES_IMAGE=$(docker image inspect "$POSTGRES_TAG" --format '{{index .RepoDigests 0}}')
python3 init_local.py
docker compose up --build -d
curl --fail http://127.0.0.1:8088/readyz
OTHER_TOKEN_FILE=secrets/other-token python3 tests/acceptance.py自动验收:16 次并发同键只有一个新订单;不同正文 409;越权租户 403/404;错误 token 401;worker 完成后订单、账本、投影金额一致。secrets/ 不得提交、归档或复制进镜像。requirements.txt 已锁定传递依赖和哈希,Docker 构建强制 –require-hashes;升级 requirements.in 后重新生成锁文件、扫描并重跑业务验收。
3. 崩溃与恢复#
在该独立 Compose 项目执行:
docker compose stop worker
# 开启一次性 worker,故意在账本写入后、提交前退出。
docker compose run --rm -e FAULT_BEFORE_COMMIT=1 worker &
# 此测试会创建订单,并等待异步完成;另开终端执行。
python3 tests/acceptance.py
# 看到故障 worker 退出 42 后,在 60 秒验收窗口内恢复正常 worker:
docker compose start worker核对测试通过,账本主键保证每订单一条,不能只看 worker 重启成功。数据库暂时停止时 API 应返回 503、worker 退避;恢复后积压完成。停止依赖不要超过验收窗口后再声称测试成功,应重新执行并保存真实耗时。
4. 部署到三节点预生产集群#
前置:独立 orders namespace、支持 NetworkPolicy 的网络插件、私有 PostgreSQL(见生产恢复演练)、受控入口和镜像仓库。命令须在已确认的预生产 context 执行。
- 以 owner 身份在独立迁移 Job 执行
python migrate.py,注入 owner DATABASE_URL 和四个站点/角色初始密码。迁移脚本用事务及 advisory lock(建议锁)防止并发,不在 API 启动时自动迁移。首次创建角色后再次执行不会偷偷轮换密码。 - 企业密钥系统创建
orders-runtime、orders-worker-runtime,只含对应最小权限角色的 DATABASE_URL;使用sslmode=verify-full与可信 CA,数据库主机名必须匹配证书。创建orders-auth的auth.json(token SHA-256 到租户的映射)。迁移身份不授予业务 Pod。创建orders-db-caConfigMap 的 ca.pem,DSN 设置 sslrootcert=/run/dbca/ca.pem;Chart 会挂载证书。迁移 Job 配套见 migration.yaml,注入 orders-migration Secret 后 apply、等待 complete,失败禁止发布,完成后撤销迁移 Secret。 - 构建并推送镜像,扫描、签名、解析 digest 后写入环境 values。不要将示例摘要当可拉取镜像。
export IMAGE='REPLACE_REGISTRY/orders@sha256:REPLACE_APPROVED_DIGEST'
export DB_CIDR='REPLACE_PRIVATE_DB_IP/32'
# 前置密钥需存在;不要在终端输出其值。
kubectl -n orders get secret orders-runtime orders-worker-runtime orders-auth
kubectl -n orders get configmap orders-db-ca
helm lint charts/orders --strict --set image="$IMAGE" --set dbCidr="$DB_CIDR"
helm template orders charts/orders -n orders --set image="$IMAGE" --set dbCidr="$DB_CIDR" > rendered.yaml
kubectl apply --dry-run=server -f rendered.yaml
helm upgrade --install orders charts/orders -n orders --set image="$IMAGE" --set dbCidr="$DB_CIDR" --atomic --wait --timeout 10m
kubectl -n orders rollout status deployment/orders-api
kubectl -n orders rollout status deployment/orders-workerChart 包含三副本、探针、只读根目录、非 root、资源限额、跨节点分散、PDB(Pod 中断预算)、关闭 ServiceAccount 自动 token、默认限制入口和数据库出口。DB_CIDR 仅支持 IPv4;集群内部数据库建议按其 namespace/Pod selector 修改网络规则,不能放通整个公网。NodeLocal DNS 环境须加入实际 DNS 地址的 53 端口规则,否则启动前先修复 DNS。
入口只公开 /orders 路径与业务需要的端点,不公开 /metrics;Gateway 保留 TLS 与身份边界。通过真实 HTTPS 入口设置 BASE_URL/TOKEN_FILE 运行同一验收脚本。API 每 Pod 最多 8 个处理线程;3 API + 3 worker 基线约 27 个并发数据库连接,扩容、surge、迁移和监控另预留,不能让 HPA(水平扩缩容)无限扩展连接数。
可用 Kustomize 替代 Helm:执行 python3 render_kustomize.py "$IMAGE" "$DB_CIDR" 从同一 Chart 生成本地 base,然后 kubectl kustomize kustomize/overlays/staging。两种工具二选一管理相同资源;生成后的 base 与 overlay 一起提交部署仓库。
5. 企业验收与发布#
- 保持业务测试循环运行,逐个重建一个 API/worker Pod;确认无重复账本,错误率与恢复耗时在变更单阈值内。PDB 不保护主动 delete pod,也不能弥补容量不足。
- 使用发布隔离基线生成稳定/候选 API,先验证原 Service 不选候选 Pod;业务错误、指标缺失或权限越界即停止提升。
- 用单写者切换验证旧站点角色不能写;用SRE 闭环验证积压与错误告警。
- 版本变更先扩展兼容 schema,再迁移数据,最后另一次变更删除旧字段。回退镜像前确认旧镜像仍兼容 schema;数据库迁移不随 Helm rollback 自动撤销。
6. 清理#
先停止合成流量,再停止 worker,核对 outbox 未完成数为零并保存脱敏验收报告。云上保留批准的备份,删除本次 release 和专属授权,禁止删除共享数据库。只有本地可丢弃数据时才执行 docker compose down --volumes;该命令会删除本项目卷。