← 返回文档中心

B2B2B 酒店分销平台系统架构文档

版本: v1.0
适用场景: 一人公司 + AI 搭档,技术驱动,几万块启动资金,Demo 驱动融资
目标读者: 创始人/技术负责人、投资人
编写日期: 2025-01


目录


1. 项目概述

1.1 什么是 B2B2B 酒店分销

B2B2B 酒店分销平台连接三方:酒店/批发商(供应商)本平台OTA/旅行社/代理商(采购方)

核心价值: - 聚合供应商:统一接入多个酒店批发商和直签酒店 - 标准化数据:异构房型、价格、库存统一映射 - 智能分发:根据渠道需求匹配最优价格和可用性 - 自动化运营:订单、结算、对账全流程自动化

1.2 核心业务流程

代理商查价 → 平台聚合多供应商报价 → 代理商下单 → 平台向供应商下单 
→ 供应商确认/拒绝 → 订单履约 → 对账结算 → 佣金结算

1.3 关键成功指标

指标 MVP 目标 成熟期目标
接入供应商数 3-5 家 50+ 家
日均查价 QPS 100 10,000+
订单转化率 5% 15%+
查价响应 P99 < 2s < 500ms
订单自动化率 80% 98%+

2. 整体系统架构

flowchart TB
    subgraph Clients["客户端层"]
        A1["代理商API接入
OTA/旅行社"] A2["管理后台Web
运营人员"] A3["供应商对接
API/文件"] end subgraph Gateway["网关层"] G1["API Gateway
Kong/Nginx"] G2["认证鉴权
JWT + API Key"] G3["限流熔断
Sentinel"] G4["日志采集
+ 请求追踪"] end subgraph Services["业务服务层"] S1["酒店基库服务
Hotel Service"] S2["匹配服务
Mapping Service"] S3["查价引擎
Pricing Engine"] S4["订单服务
Order Service"] S5["销售服务
Sales Service"] S6["价格服务
Rate Service"] S7["结算服务
Settlement Service"] S8["库存服务
Inventory Service"] S9["风控服务
Risk Control"] S10["数据智能
Data Intelligence"] end note_left[connection_mode决定服务路由: direct_connect实时查价 direct_procure查本地库存] subgraph Middleware["中间件层"] MQ["消息队列
RabbitMQ"] CACHE["缓存层
Redis Cluster"] CONFIG["配置中心
Nacos"] end subgraph Data["数据层"] DB["PostgreSQL
主库 (业务数据)"] RO["PostgreSQL
只读副本"] CH["ClickHouse
分析库"] ES["Elasticsearch
搜索引擎"] OBJ["MinIO/OSS
对象存储"] end subgraph External["外部对接"] E1["供应商API
Hotelbeds/Expedia等"] E2["支付网关
Stripe/支付宝"] E3["通知服务
Email/SMS"] E4["汇率API
ExchangeRate"] end A1 --> G1 A2 --> G1 A3 --> G1 G1 --> G2 --> G3 --> G4 G1 --> S1 G1 --> S3 G1 --> S4 G1 --> S5 G3 --> S9 S1 <--> S2 S2 --> S3 S3 <--> S6 S3 <--> S8 S4 --> S7 S4 --> S8 S5 --> S7 S6 --> S3 S8 --> S3 S1 <--> MQ S4 <--> MQ S8 <--> MQ S1 --> DB S2 --> DB S3 --> CACHE S3 --> DB S4 --> DB S5 --> DB S6 --> DB S6 --> CACHE S7 --> DB S8 --> DB S8 --> CACHE S10 --> CH S10 --> ES S1 --> ES Services --> External class A1,A2,A3,G1,G2,G3,G4,S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,MQ,CACHE,CONFIG,DB,RO,CH,ES,OBJ,E1,E2,E3,E4 process classDef process fill:#1a2744,stroke:#58a6ff,stroke-width:1px,color:#c9d1d9 classDef decision fill:#3a2a1a,stroke:#f0883e,stroke-width:2px,color:#f0883e classDef done fill:#1a3a2a,stroke:#3fb950,stroke-width:1px,color:#3fb950 classDef error fill:#3a1a1a,stroke:#f85149,stroke-width:2px,color:#f85149 classDef warning fill:#3a2a1a,stroke:#d29922,stroke-width:1px,color:#d29922 classDef skip fill:#21262d,stroke:#484f58,color:#8b949e

3. 技术栈选型及理由

3.1 核心技术栈

层级 技术选型 理由
后端语言 Go (Golang) 高并发性能优异,编译型语言部署简单,标准库丰富,适合一人团队高效开发。goroutine 天然适合大量供应商并发查价场景
Web 框架 Gin / Fiber 轻量高性能,中间件生态完善,社区活跃。Fiber 更快但 Gin 生态更成熟
关系型数据库 PostgreSQL 15+ JSONB 支持灵活 schema(酒店数据异构性强),全文搜索、GIS 地理查询、强事务一致性,开源免费
缓存 Redis 7 (单节点 → Cluster) 查价结果缓存、库存缓存、分布式锁、限流计数。内存型响应快,数据结构丰富
消息队列 RabbitMQ MVP 阶段够用,管理界面友好,routing key 灵活。后期可迁移至 Kafka 处理高吞吐
搜索引擎 Elasticsearch 酒店搜索(地理位置、设施、关键词)、日志分析。倒排索引天然适合搜索
分析数据库 ClickHouse 列式存储,BI 查询快 100 倍+。适合聚合统计、趋势分析、报表
API 网关 Kong (开源版) 插件丰富(限流、鉴权、日志),性能好,开源免费
容器化 Docker + Docker Compose 一人团队首选,环境一致,部署简单。后期迁移 K8s
CI/CD GitHub Actions 免费额度足够,与 GitHub 深度集成,配置即代码
前端 Vue 3 + Element Plus 管理后台首选,组件丰富,上手快。或用 React + Ant Design
监控 Prometheus + Grafana 开源标配,指标采集 + 可视化。AlertManager 告警
日志 Loki (配合 Grafana) 轻量级日志聚合,与 Grafana 统一界面。或用 ELK
对象存储 MinIO (自建) / 阿里云 OSS 存储合同文件、报表、日志归档
定时任务 Asynq (Go) 基于 Redis 的任务队列,比 cron 更可靠,支持重试和延迟

3.2 开发工具链

工具 用途
GoLand / VS Code + Go 插件 开发 IDE
Docker Desktop 本地开发环境
Postman / Bruno API 调试
DBeaver 数据库管理
TablePlus PostgreSQL 客户端
Draw.io / Excalidraw 架构图绘制
Swagger / OpenAPI API 文档
golang-migrate 数据库版本管理
Mockoon 供应商 API Mock

3.3 基础设施

组件 MVP 方案 生产方案
服务器 1-2 台 4C8G 云服务器 (阿里云/腾讯云) K8s 集群 + 弹性伸缩
数据库 与应用同机部署,主从分离 RDS + 只读副本
缓存 同机 Redis 单实例 Redis Cluster / 阿里云 Redis
存储 本地磁盘 + MinIO OSS / S3
域名 1 个 .com 域名 多域名(API/管理/文档)
CDN 不需要 CloudFlare / 阿里云 CDN
SSL Let's Encrypt 免费证书

4. 模块间调用关系图

flowchart LR
    subgraph P0["P0 核心模块"]
        API["API网关"]
        HS["酒店基库"]
        MS["匹配管理"]
        PE["查价引擎"]
        OM["订单管理"]
        AM["管理后台"]
    end

    subgraph P1["P1 增长模块"]
        SM["销售管理"]
        PM["价格管理"]
        BM["库存管理"]
        PAP["进阶定价"]
        ST["结算管理"]
        RC["风控体系"]
    end

    subgraph P2["P2 智能模块"]
        DI["数据智能"]
    end

    API --> PE
    API --> OM
    API --> AM

    HS --> MS
    MS --> PE
    PM --> PE
    PAP["进阶定价"] -.->|"Phase3"| PE
    BM --> PE
    SM -.->|"Phase1"| PE
    RC --> PE
    PE --> OM

    SM --> OM
    SM --> ST
    OM --> ST
    PM --> ST
    BM --> OM

    OM --> DI
    PE --> DI
    SM --> DI
    ST --> DI

    AM --> HS
    AM --> MS
    AM --> SM
    AM --> PM
    AM --> OM
    AM --> ST
    AM --> BM
    AM --> RC
    AM --> DI

    PE -.->|"降级查询"| CACHE["Redis缓存"]
    class API,HS,MS,PE,OM,AM,SM,PM,BM,ST,RC,DI,CACHE,PAP process
    classDef process fill:#1a2744,stroke:#58a6ff,stroke-width:1px,color:#c9d1d9
    classDef decision fill:#3a2a1a,stroke:#f0883e,stroke-width:2px,color:#f0883e
    classDef done fill:#1a3a2a,stroke:#3fb950,stroke-width:1px,color:#3fb950
    classDef error fill:#3a1a1a,stroke:#f85149,stroke-width:2px,color:#f85149
    classDef warning fill:#3a2a1a,stroke:#d29922,stroke-width:1px,color:#d29922
    classDef skip fill:#21262d,stroke:#484f58,color:#8b949e

5. 数据流图

5.1 三阶段业务数据流

查价、试单、下单三条链路均采用三阶段模型,详见各模块设计文档。

flowchart TD
    START(["代理商发起查价请求"]) --> P1_BOX
    subgraph P1["Phase 1: 查价前 Pre-Query"]
        P1_BOX --> GW["Gateway
鉴权+限流"] GW --> CB["熔断检查
供应商/代理商"] CB --> VIS["可见性过滤
白名单/黑名单"] VIS --> CACHE{"L1/L2 缓存
是否有结果?"} CACHE -->|"缓存命中"| RET_CACHE["直接返回
回填L1"] CACHE -->|"未命中"| MAP["匹配服务
供应商映射解析"] MAP --> CH_CFG["渠道配置加载"] end P1_BOX -->|"熔断/无权限"| BLOCKED(["阻断返回"]) CH_CFG --> P2_BOX subgraph P2["Phase 2: 查价 Query"] P2_BOX --> PARA["并发查价
errgroup + 超时"] PARA --> DC["直连供应商
调SA实时API"] PARA --> DP["直采供应商
查本地库存"] DC --> DC_FAIL{"超时/错误?"} DC_FAIL -->|"是"| SKIP["跳过该供应商"] DC_FAIL -->|"否"| DC_OK["原始报价"] DP --> DP_OK["原始报价"] end DC_OK --> P3_BOX DP_OK --> P3_BOX SKIP --> P3_BOX subgraph P3["Phase 3: 查价后 Post-Query"] P3_BOX --> AGG["结果聚合
去重+排序+分页"] AGG --> MKUP["Markup 加价"] MKUP --> DYN["动态定价调整"] DYN --> PROMO["促销匹配"] PROMO -> FX["汇率换算"] FX --> WR_CACHE["写入L2+L1缓存"] WR_CACHE --> LOG_Q["异步写查价日志"] LOG_Q --> RETURN(["返回最终报价"]) end class RET_CACHE,RETURN done class BLOCKED error class START,GW,CB,VIS,CACHE,MAP,CH_CFG,PARA,DC,DP,DC_FAIL,SKIP,DC_OK,DP_OK,AGG,MKUP,DYN,PROMO,FX,WR_CACHE,LOG_Q process classDef process fill:#1a2744,stroke:#58a6ff,stroke-width:1px,color:#c9d1d9 classDef decision fill:#3a2a1a,stroke:#f0883e,stroke-width:2px,color:#f0883e classDef done fill:#1a3a2a,stroke:#3fb950,stroke-width:1px,color:#3fb950 classDef error fill:#3a1a1a,stroke:#f85149,stroke-width:2px,color:#f85149

5.1.2 试单 + 下单链路

flowchart TD
    SEARCH(["查价结果"]) --> V1
    subgraph V1["Verify Phase 1: 试单前"]
        V1 --> V_EXP["报价有效期检查"]
        V_EXP --> V_RISK["风控预检
信用额度"] V_RISK --> V_CB["熔断检查"] end V_CB --> V2 subgraph V2["Verify Phase 2: 试单"] V2 --> V_SUP["供应商实时价格确认"] V_SUP --> V_DEV{"价格偏差
超阈值?"} end V2 --> V3 subgraph V3["Verify Phase 3: 试单后"] V3 --> V_FREEZE["冻结信用额度"] V_FREEZE --> V_TOKEN["生成 verify_token"] V_TOKEN --> V_DONE(["返回确认价格
+ verify_token"]) end V_DONE --> O1 subgraph O1["Order Phase 1: 下单前"] O1 --> O_TOKEN["verify_token 校验"] O_TOKEN --> O_RECHECK["报价二次校验"] O_RECHECK --> O_RISK["风控检查
信用+价格异常"] O_RISK --> O_INV["库存预检
直采模式"] end O1 -->|"阻断"| O_BLOCK(["返回错误"]) O_INV --> O2 subgraph O2["Order Phase 2: 下单"] O2 --> O_CREATE["创建订单 PG事务"] O_CREATE --> O_LOCK["库存预占
Redis DECRBY"] O_LOCK --> O_CREDIT["信用冻结"] O_CREDIT --> O_SUP["调供应商API下单"] O_SUP --> O_RESULT{"供应商响应"} O_RESULT -->|"确认"| PENDING["PENDING_CONFIRM"] O_RESULT -->|"拒绝"| O_REJECT["REJECTED
释放库存+信用"] end PENDING --> O3 subgraph O3["Order Phase 3: 下单后"] O3 --> O_NOTIFY["通知代理商"] O3 --> O_TIMEOUT["设置超时任务"] O3 --> O_LOG["写订单日志"] end PENDING -->|"Webhook确认"| CONFIRMED(["CONFIRMED"]) PENDING -->|"超时"| EXPIRED(["EXPIRED
自动取消"]) class V_DONE,CONFIRMED done class O_BLOCK,O_REJECT,EXPIRED error class SEARCH,V_EXP,V_RISK,V_CB,V_SUP,V_DEV,V_FREEZE,V_TOKEN,O_TOKEN,O_RECHECK,O_RISK,O_INV,O_CREATE,O_LOCK,O_CREDIT,O_SUP,O_RESULT,PENDING,O_NOTIFY,O_TIMEOUT,O_LOG process classDef process fill:#1a2744,stroke:#58a6ff,stroke-width:1px,color:#c9d1d9 classDef decision fill:#3a2a1a,stroke:#f0883e,stroke-width:2px,color:#f0883e classDef done fill:#1a3a2a,stroke:#3fb950,stroke-width:1px,color:#3fb950 classDef error fill:#3a1a1a,stroke:#f85149,stroke-width:2px,color:#f85149

5.2 数据分层

数据类型 存储位置 保留策略
酒店静态数据 PostgreSQL + ES 永久
价格/库存数据 Redis (热) + PG (冷) 热数据 5min,历史数据永久
订单数据 PostgreSQL 永久
查价日志 ClickHouse 6 个月
操作日志 ClickHouse 3 个月
结算数据 PostgreSQL + ClickHouse 永久
合同文件 MinIO/OSS 永久

6. 缓存架构

6.1 三级缓存架构

查价系统采用 L1 本地内存 + L2 Redis + DB/远程 API 的三级缓存架构,逐层穿透:

请求 → L1 本地内存(sync.Map + LRU,10万条,30s TTL)
     → L2 Redis(单节点/集群,5min TTL)
     → DB / 远程 API

6.2 缓存粒度设计

查价原始报价缓存

key = price:raw:{supplier_code}:{supplier_hotel_id}:{check_in}:{check_out}

聚合结果缓存

key = price:agg:{hotel_id}:{check_in}:{check_out}:{adults}:{channel_code}

6.3 缓存失效策略(Tag 清理 + Pub/Sub)

Tag 体系

为不同业务维度定义缓存 Tag,支持按维度批量清理:

Tag 说明 触发场景
markup:all 加价规则 Admin 修改加价规则
pricing:{hotel_id} 动态定价规则 Admin 修改某酒店定价
promo:{hotel_id} 促销活动 Admin 创建/修改/删除促销
rate:{from}_{to} 汇率 定时任务更新汇率
visibility:{agent_code} 可见性规则 Admin 修改代理商可见性
mapping:{supplier_code} 供应商映射 Admin 修改供应商映射关系
circuit:{supplier_code} 熔断状态 熔断器状态变更
credit:{agent_code} 信用额度 Admin 调整代理商额度

Admin CRUD 操作流程

  1. 写入 DB:数据持久化
  2. 调用 cache.TagDelete(tags...):批量清除 L2 Redis 中关联该 Tag 的所有缓存 key
  3. 发布 Redis Pub/Sub 消息:频道 cache:invalidate:{tag},通知所有实例
  4. 所有 QE 实例订阅该 channel:收到消息后清理 L1 本地缓存中关联 key

消息格式

{"tag": "markup:all", "ts": 1713000000}

6.4 热点数据分层 TTL

数据类型 L1 TTL L2 TTL 说明
聚合查价结果 30s 5min 最终兜底缓存
原始供应商报价 10s 60s/30s 直连 60s,直采 30s
Markup 规则 30s 10min 变更时 Tag 清理
动态定价规则 30s 10min 变更时 Tag 清理
促销活动列表 30s 5min 变更时 Tag 清理
汇率 5min 1h 定时任务每小时更新
供应商映射 1min 30min 变更时 Tag 清理
可见性规则 30s 10min 变更时 Tag 清理
信用额度 10s 1min 变更时 Tag 清理
熔断状态 10s 30min 变更时 Tag 清理

6.5 防击穿与防雪崩

singleflight 合并请求

缓存 miss 时使用 singleflight 模式:只放一个请求穿透到下游,其余相同 key 的请求等待结果,避免缓存击穿。

空值缓存

查无结果也缓存(空值标记),TTL = 30s。防止恶意请求或无效查询反复穿透到数据库或供应商 API。

随机 TTL 偏移

所有缓存 TTL 增加 ±10% 随机偏移,避免大量 key 在同一时刻过期导致缓存雪崩。

实际 TTL = 基准 TTL × (0.9 + random() × 0.2)

6.6 多实例一致性