基于 Go 与 go-zero 的票务业务总线项目,当前采用 Gateway -> API -> RPC 分层,面向高并发下单、自动分座、模拟支付与智能客服联调场景。
当前项目采用三层职责划分:
Gateway:统一 HTTP 入口与路由汇聚点,负责统一鉴权接入、路由转发与观测接入。对应services/gateway-api/。API:HTTP 适配与协议层,负责 handler/middleware、参数解析、上下文提取、外部响应模型与轻量聚合;不承载核心业务规则。对应services/*-api/。RPC:服务契约与主要业务逻辑承载层,负责领域规则、状态流转、数据访问、缓存、消息队列与内部服务协作。对应services/*-rpc/。
主调用链路:
client -> gateway-api -> xxx-api -> xxx-rpc
user:注册、登录、资料维护、观演人管理program:节目、场次、票档、座位、预下单信息、系统自动分座冻结order:下单、查单、取消、支付检查、退款、超时关单pay:模拟支付、支付单查询、模拟退款gateway:统一外部 HTTP 入口agents:根级 Python 组件,提供基于Python 3.12 + LangGraph 1.1.6 + MCP + Redis + MySQL的Thread / Message / RunAPI
当前明确约束:
program不支持用户手动选座,但保留系统分配座位能力pay不接真实支付通道,仅提供模拟支付与模拟退款
livepass/
├── README.md
├── AGENTS.md
├── docs/
├── deploy/
├── jobs/
├── pkg/
├── scripts/
├── services/
│ ├── gateway-api/
│ ├── user-api/ user-rpc/
│ ├── program-api/ program-rpc/
│ ├── order-api/ order-rpc/
│ └── pay-api/ pay-rpc/
├── sql/
├── tests/
└── agents/
目录约定:
services/*-api/:HTTP 服务services/*-rpc/:gRPC 服务jobs/*/:后台任务与补偿任务pkg/:通用基础能力,禁止承载具体业务规则agents/:独立 Python 组件,不纳入 go-zero 服务目录规范
user:注册、登录、用户资料与观演人链路program:分类、首页、分页、详情、票档、预下单详情、自动分座冻结order/pay:下单、查单、取消、模拟支付、退款、超时关单gateway/agents:统一 HTTP 入口与Thread / Message / Run联调
推荐直接使用一键启动脚本:
bash scripts/deploy/start_backend.sh该脚本会自动完成:
- 拉起 MySQL、Redis、etcd、Kafka 基础设施
- 检测业务库是否为空;若为空则自动导入 schema 与 seed
- 启动全部 Go RPC / API / Job
- 启动
order-mcp、program-mcp - 启动
agents - 最后启动
gateway-api - 默认以前台 supervisor 模式保活;若直接在受控执行环境中启动,脚本不退出时可避免其子进程被宿主清理
常用变体:
# 强制重新导入 SQL
bash scripts/deploy/start_backend.sh --import-sql
# 强制重启已运行服务后再启动(会重置对应服务日志)
bash scripts/deploy/start_backend.sh --force-restart
# 只启动后端主链路,跳过 MCP 和 agents
bash scripts/deploy/start_backend.sh --skip-agents
# 只启动 agents 相关链路(user/program/order-rpc + MCP + agents)
bash scripts/deploy/start_backend.sh --only-agents
# 启动完成后立即退出,保留旧的“只拉起进程不保活脚本”行为
bash scripts/deploy/start_backend.sh --detach
# 使用压测配置启动已有 perf 配置的 Go 服务
bash scripts/deploy/start_backend.sh --perf --force-restart如需重建运行数据,请使用独立脚本:
bash scripts/deploy/rebuild_databases.sh该脚本会:
- 删除并重建
user/program/order/pay/agentsMySQL 业务库 - 重新导入全部 schema 与 seed
- 清空 Redis DB
0 - 删除并重建 Kafka 业务 Topic(默认
ticketing.attempt.command.v1)
本地初始化后会预置一个普通测试用户:
- 手机号:
13800000000 - 密码:
123456
默认基础设施为:
- MySQL
- Redis
- etcd
- Kafka
如果只想手动拉起基础设施:
docker compose -f deploy/docker-compose/docker-compose.infrastructure.yml up -d如果需要模拟 order-db-0 + order-db-1 分片库:
docker compose -f deploy/mysql/docker-compose.sharding.yml up -d对应端口:
order-db-0:127.0.0.1:3317order-db-1:127.0.0.1:3318
如需单独导入 SQL:
bash scripts/import_sql.sh
IMPORT_DOMAINS=program bash scripts/import_sql.sh
IMPORT_DOMAINS=agents bash scripts/import_sql.sh
MYSQL_CONTAINER=docker-compose-mysql-1 MYSQL_PASSWORD=123456 bash scripts/import_sql.sh如需覆盖数据库名:
MYSQL_DB_USER=livepass_user \
MYSQL_DB_PROGRAM=livepass_program \
MYSQL_DB_ORDER=livepass_order \
MYSQL_DB_PAY=livepass_pay \
MYSQL_DB_AGENTS=livepass_agents \
bash scripts/import_sql.sh其中 sql/order 目录约定为:
sql/order/sharding/:仅存放真正按表后缀分表的 schema,例如d_order_*、d_order_ticket_user_*sql/order/:存放未分表、但随订单分片库一并部署的 schema,例如d_order_user_guard、d_order_viewer_guard、d_order_seat_guard、d_delay_task_outbox
Go 服务与作业:
go test ./...agents 组件测试:
cd agents
uv run pytest -v如需跳过一键脚本、手动排查链路,可按下面方式启动:
go run services/user-rpc/user.go -f services/user-rpc/etc/user.yaml
go run services/program-rpc/program.go -f services/program-rpc/etc/program.yaml
go run services/pay-rpc/pay.go -f services/pay-rpc/etc/pay.yaml
go run services/order-rpc/order.go -f services/order-rpc/etc/order.yaml
go run jobs/order-close/cmd/worker/main.go -f jobs/order-close/etc/order-close-worker.yaml
go run jobs/order-close/cmd/dispatcher/main.go -f jobs/order-close/etc/order-close-dispatcher.yaml
go run services/user-api/user.go -f services/user-api/etc/user-api.yaml
go run services/program-api/program.go -f services/program-api/etc/program-api.yaml
go run services/order-api/order.go -f services/order-api/etc/order-api.yaml
go run services/pay-api/pay.go -f services/pay-api/etc/pay-api.yaml
go run services/order-rpc/cmd/order_mcp_server/main.go -f services/order-rpc/etc/order-mcp.yaml
go run services/program-rpc/cmd/program_mcp_server/main.go -f services/program-rpc/etc/program-mcp.yaml
go run services/gateway-api/gateway.go -f services/gateway-api/etc/gateway-api.yamluser-rpc:8080gateway-api:8081order-rpc:8082program-rpc:8083pay-rpc:8084user-api:8888program-api:8889order-api:8890agents:8891pay-api:8892order-mcp:9082program-mcp:9083
user-rpc、program-rpc、order-rpc、pay-rpc默认注册到本地etcdgateway-api是统一外部入口,负责把 HTTP 请求转发到各域 API 或agentsagents的运行态支持GET /agent/runs/{runId}/events?after=回放 run 事件,并对resume/cancel重试保持接口级幂等/order/create采用accept + async模式:Redis admission 成功后立即返回orderNumber;Kafka 由进程内异步任务发送,producer 失败只通过PENDING -> FAILEDCAS 尝试回补/order/poll在 TTL 期间优先读取 Redis attempt;attempt miss 时查 MySQL byorderNumber,DB 有单为成功,DB 无单为失败jobs/order-close/cmd/worker负责消费 Asynq 延迟任务,并调用order-rpc.CloseExpiredOrder推进超时关单jobs/order-close/cmd/dispatcher负责扫描d_delay_task_outbox(order.close_timeout),补发延迟任务到 Asynq;真正的业务关闭仍只走order-rpc.CloseExpiredOrderorder.close_timeout与program.rush_inventory_preheat共用 outbox 生命周期:pending(0) -> published(1) -> processed(3),失败进入failed(4)后可由 dispatcher 补投publish_attempts表示投递总次数,首次投递和补投都会递增;日志通过is_republish区分首次投递与补投consume_attempts表示 worker 实际消费尝试次数;成功收敛和失败记录都会递增,用于定位 DB 事实是否已经完成order.close_timeout以订单库为事实源:先在订单库事务内关闭订单、删除 guard 并把 outbox 标记为processed,提交后再 best-effort 释放座位冻结program.rush_inventory_preheat以运行态预热完成为前置条件:先执行PrimeRushRuntime和PrimeSeatLedger,再在节目库事务内写预热完成态并把 outbox 标记为processedgateway-api已启用Telemetry;若要得到完整链路,需要给下游 API/RPC 同步补齐Telemetry
推荐优先使用仓库内现成脚本与文档:
- 下单主路径:
docs/api/order-checkout-acceptance.md - 下单失败分支:
docs/api/order-checkout-failure-acceptance.md - 退款主路径:
docs/api/order-refund-acceptance.md - 智能客服联调:
scripts/acceptance/agent_threads.sh
当前仓库已补充“从 create order 起压”的压测准备与执行脚本,默认面向:
- 单
showTimeId - 单
ticketCategoryId - 每用户随机
1-3张 - 超卖竞争模型
压测模式通过一键启动脚本的 --perf 参数开启,会将已有 *.perf.yaml 的 Go 服务统一切到压测配置;当前包括 gateway/user/program/order/pay 的 API/RPC 服务。未提供 perf 配置的 Job、MCP 与 agents 继续使用默认配置。
bash scripts/deploy/start_backend.sh --perf --force-restart默认会:
- 重建目标票档座位
- 批量插入压测用户与观演人
- 预热 rush runtime 与 seat ledger
- 批量申请
purchase token - 导出
users.json/users.csv/meta.json
示例:
BASE_URL=http://127.0.0.1:8081 \
SHOW_TIME_ID=30001 \
TICKET_CATEGORY_ID=40001 \
USER_COUNT=5000 \
SEAT_COUNT=5000 \
ROW_COUNT=50 \
COL_COUNT=100 \
PERF_SECRET=livepass-perf-secret-0001 \
bash scripts/perf/prepare_rush_perf_dataset.sh输出目录默认位于:
tmp/perf/<dataset-id>/其中:
users.json:给 k6 直接读取users.csv:人工查看meta.json:记录参数与生成时间
k6 run \
-e DATASET_PATH=tmp/perf/<dataset-id>/users.json \
-e BASE_URL=http://127.0.0.1:8081 \
-e PERF_SECRET=livepass-perf-secret-0001 \
tests/perf/rush_create_order.jsSHOW_TIME_ID=30001 \
TICKET_CATEGORY_ID=40001 \
bash scripts/perf/verify_rush_perf_result.sh校验脚本会输出:
- 票档总库存
- 票档剩余库存
seat_status = 3的已售座位数d_order_seat_guard数量d_order_ticket_user*聚合数量
可执行脚本:
bash scripts/acceptance/order_checkout.sh
bash scripts/acceptance/order_checkout_failures.sh
bash scripts/acceptance/order_refund.sh
JWT=<user-jwt> bash scripts/acceptance/agent_threads.shagents 至少需要确认以下配置:
REDIS_URL=redis://127.0.0.1:6379/0USER_RPC_TARGET=127.0.0.1:8080PROGRAM_RPC_TARGET=127.0.0.1:8083ORDER_RPC_TARGET=127.0.0.1:8082
- 核心业务规则进入
RPC API保持薄层,避免回流核心业务逻辑Gateway只做入口、路由与横切能力,不承载业务规则- 新增 go-zero 服务时,遵循
services/*-api/与services/*-rpc/的目录规范
• 最新这组直压 gRPC CreateOrder 的接口指标是:
- avg = 217.0165 ms,见 tmp/perf/results/rush-rpc-2000-20260419132812/summary.json:12
- p95 = 403 ms,见 tmp/perf/results/rush-rpc-2000-20260419132812/summary.json:10
- p99 = 419.03 ms,见 tmp/perf/results/rush-rpc-2000-20260419132812/summary.json:11
- client_request_window_qps = 6349.2063,见 tmp/perf/results/rush-rpc-2000-20260420103837/client_request_window_qps.json:1