Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RustBill 运维手册

RustBill 的生产部署与运维参考手册。目标读者:生产环境中的系统管理员。


1. 系统架构概览

RustBill 是基于 Rust 的云服务器分销计费与开通平台,采用 Cargo workspace 多 crate 结构:

Crate职责
rustbill-protoprotobuf 定义 + tonic 代码生成(公共契约)
rustbill-core领域模型 + 全部 trait(插件/存储抽象)
rustbill-store-pgPostgreSQL 存储实现(sqlx)
rustbill-servergRPC 服务端(tonic),插件加载,Session+JWT 双认证,内嵌 Admin SPA
rustbill-cli最高权限 CLI 管理工具(直接 DB 访问),含 TUI 交互模式
rustbill-provider-*服务器资源供应商插件
rustbill-gateway-*支付网关插件
rustbill-notifier-*通知渠道插件

1.1 运行环境依赖

  • Rust 1.80+(编译);运行时仅需 glibc 2.35+(ubuntu-22.04 构建产物兼容绝大多数现代 Linux 发行版)
  • PostgreSQL 16+(数据存储,9 个迁移文件:001_initial009_plugins_table
  • Redis(可选,用于 session 缓存、分布式锁、跨实例速率限制;不可用时自动降级)
  • Node.js 22+ + npm(前端构建;运行时不需要)

1.2 服务端口与协议

端口协议说明
50051gRPC (HTTP/2)tonic 服务端主端口
80/443HTTP/HTTPSCaddy/Nginx 反向代理对外暴露(含 gRPC-Web 路径)
/healthHTTP GET健康检查端点(Circuit-breaker 短路后续所有中间件层,直接返回 200 OK)
/admin/*HTTP GET内嵌 Admin SPA(通过 Tower Layer 嵌入 tonic server,SPA fallback 到 index.html)

1.3 Tower 中间件栈

ConcurrencyLimitLayer(30) → HealthRouteLayer(/health 短路) → RateLimitLayer
→ AdminUiLayer → CorsLayer → SessionAuthLayer → JwtAuthLayer
→ ApiKeyAuthLayer → LogContextLayer → GrpcWebLayer → gRPC services

每个认证中间件只处理自己的认证类型,无凭证时直接放行(pass-through),不做 401 拦截。


2. 配置文件参考

配置文件 config.toml(复制自 config.example.toml),支持 config.local.toml 覆盖(Figment 层叠合并)。数组替换而非追加。

2.1 [server] — 服务器配置

字段类型默认值说明
hoststring"127.0.0.1"gRPC 服务监听地址。生产环境反向代理前置时保持 127.0.0.1
portinteger50051gRPC 服务监听端口
max_concurrencyinteger30入口并发上限,超过排队(FIFO backpressure)
notify_emailstring""系统通知接收邮箱(订单通知等)

2.2 [db] — 数据库配置

字段类型默认值说明
urlstring(必填)PostgreSQL 连接字符串。格式:postgres://user:pass@host:5432/rustbill
max_connectionsinteger20连接池最大连接数
min_connectionsinteger2连接池最小连接数(启动时预建立)
idle_timeout_secsinteger300空闲连接超时秒数
max_lifetime_secsinteger1800连接最大生命秒数(到期后回收重建)
acquire_timeout_secsinteger5获取连接超时秒数
test_before_acquirebooleantrue取连接前执行 SELECT 1 剔除死连接

2.3 [jwt] — JWT 配置(Customer 认证)

字段类型默认值说明
secretstring(必填)JWT 签名密钥。必须 >= 32 字符。为空或为 "change-me-in-production" 时启动拒绝
expiry_hoursinteger24access_token 过期小时数

2.4 [session] — Session 配置(Admin 认证)

字段类型默认值说明
cookie_namestring"rustbill_session"httpOnly Session Cookie 名称
idle_timeout_minutesinteger1440空闲超时分钟数(24 小时)
absolute_timeout_hoursinteger168绝对超时小时数(7 天),无论是否活跃
cookie_securebooleanfalseCookie Secure 标志(生产环境经 HTTPS 代理时设为 true
cookie_same_sitestring"Lax"Cookie SameSite 策略(Strict / Lax / None

2.5 [bootstrap] — 初始管理员配置

字段类型默认值说明
admin_usernamestring"admin"初始管理员用户名
admin_passwordstring(必填)初始管理员密码(bcrypt 哈希存储,无默认值)

2.6 [rate_limit] — 速率限制配置

字段类型默认值说明
enabledbooleantrue是否启用速率限制
login_per_secinteger5每秒登录请求上限
register_per_secinteger1每秒注册请求上限

2.7 [redis] — Redis 配置(可选)

字段类型默认值说明
enabledbooleanfalse是否启用 Redis。启用后提供 Session 缓存 + 分布式锁 + 跨实例速率限制
urlstring"redis://127.0.0.1:6379"Redis 连接 URL
max_connectionsinteger10Redis 连接池大小
prefixstring"rustbill"Redis key 前缀(避免多实例/多环境 key 冲突)

2.8 [plugins] — 插件配置

字段类型默认值说明
plugins_dirstring"./plugins"Rune 脚本插件目录。PluginScanner 扫描此目录下 *.rn 文件并同步到数据库

3. 构建与部署

3.1 从源码构建

# 克隆仓库
git clone https://github.com/zyxisme/rustbill.git
cd rustbill

# 编译服务端(Release,二进制约 15-25MB stripped)
cargo build --release -p rustbill-server

# 编译 CLI 管理工具
cargo build --release -p rustbill-cli

# 跨平台编译(ARM64)
cargo build --release --target aarch64-unknown-linux-gnu

3.2 构建前端

# Admin SPA(内嵌于 rustbill-server)
cd web-admin
npm install
npm run build
# 产物:dist/ → 复制到 rustbill-server/admin-dist/

# Consumer SPA(独立部署)
cd web-consumer
npm install
npm run build
# 产物:dist/ → 部署到 Web 服务器(Caddy/Nginx/Apache)

3.3 Consumer 前端配置

Consumer 运行时配置位于 web-consumer/public/config.json

{
  "grpcEndpoint": "https://your-domain.com",
  "appTitle": "RustBill",
  "adminUrl": "https://admin.your-domain.com"
}
字段说明
grpcEndpointgRPC 服务完整 origin(跨域部署时必填,同源可省略)
appTitle页面标题(浏览器标签页显示)
adminUrl管理后台外部链接(前台 Dashboard 点击跳转)

品牌配置:web-consumer/brand.yaml(品牌名/Logo/强调色/导航/集群节点),npm run buildvite-plugin-brand.ts 将颜色和导航编译进 JS bundle。

3.4 PostgreSQL 准备

# 创建数据库
sudo -u postgres createdb rustbill

# 创建用户
sudo -u postgres psql -c "CREATE USER rustbill WITH PASSWORD 'your-password';"
sudo -u postgres psql -c "GRANT ALL ON DATABASE rustbill TO rustbill;"

# 赋予 schema 权限(迁移由应用启动时自动执行)
sudo -u postgres psql -d rustbill -c "GRANT ALL ON SCHEMA public TO rustbill;"

迁移由应用启动时 leader 实例自动执行,无需手动 sqlx migrate run。单实例部署时该实例即为 leader。

3.5 systemd Service

# /etc/systemd/system/rustbill.service
[Unit]
Description=RustBill gRPC Server
After=network.target postgresql.service redis.service
Wants=postgresql.service

[Service]
Type=simple
User=rustbill
Group=rustbill
WorkingDirectory=/opt/rustbill
ExecStart=/opt/rustbill/rustbill-server
Restart=on-failure
RestartSec=5

# 安全加固
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/rustbill /var/log/rustbill
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

# 资源限制
MemoryHigh=512M
MemoryMax=1G
CPUQuota=200%

# 日志
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rustbill

# 环境变量
Environment="RUST_LOG=info"
Environment="RUST_LOG_FORMAT=json"

[Install]
WantedBy=multi-user.target
# 启用并启动
sudo systemctl daemon-reload
sudo systemctl enable rustbill
sudo systemctl start rustbill
sudo systemctl status rustbill

3.6 日志轮转

# /etc/logrotate.d/rustbill
/var/log/rustbill/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    dateext
    dateformat -%Y%m%d
}

如果使用 systemd journal(StandardOutput=journal),日志由 journald 管理,无需额外 logrotate 配置。

3.7 反向代理 (Caddy)

# /etc/caddy/Caddyfile
your-domain.com {
    # gRPC-Web
    handle /rustbill.* {
        reverse_proxy 127.0.0.1:50051 {
            transport http {
                versions h2c
            }
        }
    }

    # Admin 管理后台(内嵌于 rustbill-server)
    handle /admin* {
        reverse_proxy 127.0.0.1:50051
    }

    # Consumer 前台(独立部署的静态文件)
    handle {
        root * /var/www/rustbill-consumer
        file_server
        try_files {path} /index.html
    }
}

3.8 Docker Compose

# docker-compose.yml
version: '3.8'
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: rustbill
      POSTGRES_USER: rustbill
      POSTGRES_PASSWORD: change-me
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data
    ports:
      - "6379:6379"
    restart: unless-stopped

  rustbill:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "50051:50051"
    volumes:
      - ./config.toml:/opt/rustbill/config.toml:ro
      - ./config.local.toml:/opt/rustbill/config.local.toml:ro
      - ./plugins:/opt/rustbill/plugins
    depends_on:
      - postgres
      - redis
    restart: unless-stopped

volumes:
  pgdata:
  redisdata:

Dockerfile(多阶段构建):

# 构建阶段
FROM rust:1.80-bookworm AS builder
WORKDIR /app
COPY . .
RUN cargo build --release -p rustbill-server

# 运行阶段
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates libssl3 && rm -rf /var/lib/apt/lists/*
WORKDIR /opt/rustbill
COPY --from=builder /app/target/release/rustbill-server .
COPY config.toml .
COPY plugins/ plugins/
EXPOSE 50051
CMD ["./rustbill-server"]

4. 数据库管理

4.1 迁移状态

# CLI 查看迁移状态
cargo run -p rustbill-cli -- db status

# 手动 psql 查看
psql -d rustbill -c "SELECT version, description, installed_on FROM _sqlx_migrations ORDER BY version;"

当前迁移清单(9 个):

迁移文件说明
001_initial.sql初始基线(所有核心表、FK、CHECK 约束、索引)
002_operation_logs.sql操作日志表
003_config_schema.sqlplugin_interfaces 新增 config_schema 列
004_citus_prepare.sqlCitus 兼容准备(customer_id NOT NULL)
005_api_keys.sqlAPI Key 表
006_customer_api_key_flag.sqlcustomer 表 can_create_api_keys 标志
007_instance_detail_sections.sql实例详情自定义段
008_scriptable_plugins.sql脚本化插件系统迁移
009_plugins_table.sql独立 plugins 定义表

4.2 备份

# 完整备份(pg_dump 自定义格式)
pg_dump -Fc -d rustbill -f /backup/rustbill_$(date +%Y%m%d_%H%M%S).dump

# crontab 自动化每日备份(凌晨 2:00)
# crontab -e
0 2 * * * pg_dump -Fc -d rustbill -f /backup/rustbill_$(date +\%Y\%m\%d).dump && find /backup -name 'rustbill_*.dump' -mtime +30 -delete

4.3 恢复

# 停止服务后再恢复
sudo systemctl stop rustbill

# 恢复
pg_restore --clean --if-exists -d rustbill /backup/rustbill_20260526.dump

# 重新启动
sudo systemctl start rustbill

4.4 重建数据库

# 破坏式重建(开发/测试环境)
dropdb rustbill
createdb rustbill
# 启动服务后自动运行迁移

5. CLI 与 TUI 管理

5.1 CLI 命令

# 查看帮助
cargo run -p rustbill-cli -- --help

# 用户管理
cargo run -p rustbill-cli -- user list
cargo run -p rustbill-cli -- user create --username admin2 --password pass123 --role admin

# 插件列表
cargo run -p rustbill-cli -- plugin list

# 数据库状态
cargo run -p rustbill-cli -- db status

5.2 TUI 交互模式

cargo run -p rustbill-cli -- tui

8 个标签页:Dashboard / Admin Users / Cust Users / Customers / Products / Plugins / Instances / DB Status

快捷键功能
q / Esc退出
Tab / Shift+Tab切换标签页
1-8直接跳转到对应标签页
↑↓ / jk列表导航
Enter查看详情
r刷新数据
d删除/终止(确认弹窗)
e / x启用/禁用插件
y / n确认/取消弹窗
Backspace关闭详情面板

TUI 完全复用服务端数据库连接,零额外连接。安全退出保证终端恢复(TerminalGuard Drop guard)。


6. 日常运维操作

所有操作均可通过 Admin UI 或 CLI 完成。以下为 CLI 常用命令及对应 Admin UI 页面。

6.1 商品管理 (Products)

Admin UI: 商品管理 → Products
  • 创建商品:指定名称、描述、所属分组、动态规格(JSONB)、计费周期(monthly/quarterly/yearly)、价格
  • 编辑/删除商品
  • 从上游同步商品(Upstream 页 → 上游商品标签 → 勾选 → ImportUpstreamProducts)
  • 批量定价(Upstream 页 → 定价管理标签 → 按加价比例批量更新售价:cost_price × markup_ratio
  • 商品规格(specs JSONB)支持动态键值对,包括 cpu_cores / memory_gb / disk_gb / bandwidth_mbps / region / os 等

6.2 客户管理 (Customers)

Admin UI: 客户管理 → Customers
  • 创建客户:姓名/联系人/邮箱/电话/信用额度
  • 编辑客户信息
  • 余额管理:充值/扣款(MyBalance 页面可查看交易流水)
  • 启用 API Key 权限(can_create_api_keys 标志)

6.3 订单管理 (Orders)

Admin UI: 交易管理 → Orders

订单状态流转:

pending → paid → provisioning → active
                ├→ cancelled(开通失败退款)
                ├→ suspended
                ├→ refunded
                └→ completed
  • 创建订单:选择客户 + 商品 + 支付网关 + 计费周期
  • 支付订单(余额扣减)
  • 开通实例(自动由 event_worker 处理异步开通)
  • 取消/退款
  • 支付超时(24 小时自动取消)

6.4 实例管理 (Instances)

Admin UI: 基础设施 → Instances

实例状态:provisioning / running / stopped / suspended / terminated / error

  • 启动/停止/重启/终止实例
  • 查看实例详情(含插件自定义 section/iframe)
  • 终止是最终操作,不可恢复

6.5 支付管理 (Payments)

Admin UI: 交易管理 → Payments
  • 查看支付记录
  • 银行转账人工确认
  • 退款(全额/部分)
  • 支付回调幂等性(SELECT FOR UPDATE 原子化)

6.6 工单管理 (Tickets)

Admin UI: 系统管理 → Tickets

工单状态:pendingprocessingresolvedclosed

  • 创建/分配工单
  • 回复(含内部备注 is_internal=true,对客户不可见)
  • 分配处理人变更时自动通知新旧处理人

6.7 发票管理 (Invoices)

Admin UI: 交易管理 → Billing

发票状态:draftissuedpaid / overdue / cancelled

  • 手动创建发票
  • 批量生成(按客户+周期)
  • 标记为已付款

6.8 插件管理 (Plugins)

Admin UI: 系统管理 → Plugins

插件列表页分为两部分:

  1. 已安装插件.rn 定义按 type+id 去重)- 只读列表
  2. 接口实例 — 可创建/启用/禁用/编辑配置 JSON/执行健康检查

当前已实现的 7 个插件:

类型插件 ID说明
Notifiernotifier-webhookWebhook HTTP POST 通知
Notifiernotifier-emailSMTP 邮件通知
Gatewaygateway-banktransfer银行转账(本地逻辑)
Gatewaygateway-yipay易支付聚合支付(HTTP + MD5 签名)
UpstreamProviderprovider-rustbillRustBill 上游分销(gRPC-Web)
FirstPartyProviderprovider-incusIncus 虚拟化(mTLS REST API)

插件脚本存储在数据库 plugin_interfaces.script_source 列中,通过 Admin UI 编辑。修改后由 ScriptEngine.evict() 自动热重载。


7. 日志与监控

7.1 日志格式

RustBill 使用 tracing-subscriber

# 开发环境 — 彩色文本
RUST_LOG=rustbill_server=debug cargo run -p rustbill-server

# 生产环境 — JSON 格式(日志采集)
RUST_LOG=info RUST_LOG_FORMAT=json cargo run -p rustbill-server

# 特定模块调试
RUST_LOG=rustbill_server::plugin_scanner=debug,rustbill_server::services=info

7.2 健康检查

# 基本健康检查
curl -s http://localhost:50051/health
# 预期响应: 200 OK(空 body)

# 就绪检查(含 DB 连接池验证)
curl -s http://localhost:50051/ready
# 200 就绪,503 未就绪

7.3 关键日志事件

事件日志级别说明
服务启动INFO实例身份注册、leader 选举结果、插件扫描完成
Leader 选举INFO当选/续期/释放 leader 角色
数据库迁移INFO迁移执行状态
插件扫描INFO / WARN新增/更新插件定义,文件解析异常
gRPC 请求DEBUG请求路径、耗时、状态码
认证失败WARNsession/JWT/API key 验证失败
支付回调INFO支付网关回调处理
事件消费DEBUGevent_worker 处理订单事件
熔断器WARNCircuitBreaker 开/半开/关状态变更
Redis 降级WARNRedis 不可用时自动降级通知
实例心跳TRACE每 10s 心跳更新(生产环境建议不输出)

7.4 metrics 端点

# OpenTelemetry OTLP 导出(需要配置 OTLP exporter endpoint)
# 导出指标:gRPC 请求计数/延迟、DB 连接池状态、熔断器状态、事件队列深度

8. 升级流程

8.1 标准升级(单实例)

# 1. 拉取最新代码
cd /opt/rustbill
git pull origin main

# 2. 编译新版本
cargo build --release -p rustbill-server

# 3. 构建前端(如有变更)
cd web-admin && npm install && npm run build
cp -r dist ../rustbill-server/admin-dist/

# 4. 停止服务
sudo systemctl stop rustbill

# 5. 替换二进制
cp target/release/rustbill-server /opt/rustbill/

# 6. 启动服务
sudo systemctl start rustbill

# 7. 验证
sudo systemctl status rustbill
curl -s http://localhost:50051/health

8.2 零停机升级(多实例 + 反向代理)

# 前提:多实例部署,反向代理轮询
# 1. 逐个从负载均衡摘除实例 → 升级 → 加回
# 2. Leader 选举自动切换:关闭实例的 leader role 自动过期
# 3. 最后验证所有实例正常

8.3 数据库迁移

迁移在 leader 实例启动时自动运行。如果迁移失败,leader 持有 migration 角色锁阻止其他实例启动。

手动查看迁移状态:

psql -d rustbill -c "SELECT version, description, installed_on, success FROM _sqlx_migrations ORDER BY version;"

9. 故障排查

9.1 数据库连接失败

错误: PoolTimedOut / connection refused
  1. 检查 PostgreSQL 是否运行:sudo systemctl status postgresql
  2. 验证 pg_hba.conf 允许应用用户连接:sudo -u postgres psql -c "SHOW hba_file;"
  3. 使用 config.toml 中的连接参数测试:psql "postgres://rustbill:password@localhost:5432/rustbill" -c "SELECT 1;"
  4. 检查防火墙规则:sudo ufw status
  5. 连接池耗尽:增大 [db].max_connections 或缩短 idle_timeout_secs

9.2 端口被占用

# 查找占用端口的进程
sudo lsof -i :50051
# 或
sudo ss -tlnp | grep 50051

# 停止占用进程
sudo kill -TERM <PID>

9.3 systemd 启动失败

# 查看最近日志
sudo journalctl -u rustbill -n 50 --no-pager

# 持续跟踪
sudo journalctl -u rustbill -f

# 常见原因
# - 配置文件缺失或格式错误(config.toml)
# - JWT secret 未设置或过短(< 32 字符)
# - bootstrap admin_password 未设置
# - 数据库 URL 错误或数据库不存在
# - 端口已被占用

9.4 Admin 管理后台白屏

  1. 硬刷新浏览器(Ctrl+Shift+R
  2. 检查 admin-dist/index.html 是否存在:ls /opt/rustbill/admin-dist/
  3. 检查 Nginx/Caddy 配置:/admin* 路径是否正确代理到 localhost:50051
  4. 检查浏览器控制台是否有 JS 资源 404 错误
  5. 重新构建并部署 admin-dist:cd web-admin && npm run build && cp -r dist /opt/rustbill/rustbill-server/admin-dist/

9.5 插件无法加载

  1. 检查 Admin UI → Plugins 页面中对应接口实例的 enabled 状态
  2. 检查 plugins/ 目录下 .rn 文件是否存在
  3. 检查 plugin_interfaces 表的 script_source 列是否为空
  4. 检查服务器日志中 PluginScanner 的 WARN/ERROR 日志
  5. Rune 脚本语法错误:脚本编译失败但服务器仍可正常运行,错误仅影响对应插件

9.6 HTTPS 证书问题

# Caddy 自动管理证书,确认:
# 1. DNS 解析正确:dig your-domain.com
# 2. 防火墙开放 80/443 端口:sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
# 3. Caddy 日志:sudo journalctl -u caddy -f

9.7 内存使用过高

# 查看当前内存使用
sudo systemctl show rustbill -p MemoryCurrent

# 调整 systemd 资源限制
sudo systemctl edit rustbill

# 添加或修改:
# [Service]
# MemoryHigh=768M
# MemoryMax=1.5G

sudo systemctl daemon-reload
sudo systemctl restart rustbill

9.8 gRPC 调用超时

# 1. 检查服务是否可达
grpcurl -plaintext localhost:50051 list

# 2. 检查请求是否进入(日志级别调整为 debug)
RUST_LOG=rustbill_server=debug cargo run -p rustbill-server

# 3. 检查 ConcurrencyLimit 是否已达上限(默认 30)
# 增大 max_concurrency:在 config.toml [server] 节设置 max_concurrency = 100

# 4. 检查数据库连接池是否耗尽
# 增大 [db].max_connections 或检查慢查询

9.9 gRPC-Web trailers-only 错误

浏览器收到 200 OK 但 grpc-status header 非 0。这是 gRPC 错误的标准传递方式。

  1. 检查 grpc-status header 值(gRPC 状态码)
  2. 检查 grpc-message header 值(错误描述)
  3. 常见原因:认证失败(session 过期/JWT 过期)、参数校验失败、权限不足

9.10 Redis 故障降级

当 Redis 不可用时,系统自动降级:

功能Redis 正常Redis 降级
Session 缓存Redis cache-aside纯 DB 查询
速率限制跨实例共享计数单实例内存计数
分布式锁Redis SET NXPG advisory lock

降级时系统正常运行但跨实例协调能力下降(速率限制不跨实例、锁竞争通过 PG 完成)。日志中会出现 WARN 级别的 Redis 连接失败信息。


10. 环境变量参考

变量说明示例
RUST_LOGtracing 日志级别过滤器info / rustbill_server=debug / warn
RUST_LOG_FORMAT日志输出格式不设置=彩色文本 / json=JSON 格式
DATABASE_URLPostgreSQL 连接(覆盖 config.toml)postgres://user:pass@host/db
CONFIG_FILE主配置文件路径/etc/rustbill/config.toml
LOCAL_CONFIG_FILE本地覆盖配置路径/etc/rustbill/config.local.toml
PROTOCprotoc 二进制路径(编译时需要)/usr/local/bin/protoc
CARGO_BUILD_JOBSCargo 并行编译任务数1(低内存环境限制)

11. 安全检查清单

  • config.toml[jwt].secret 已设置为 >= 32 字符的随机字符串(非 "change-me-in-production"
  • [bootstrap].admin_password 已设置为强密码
  • 生产环境 [session].cookie_secure 已设为 true(经 HTTPS 代理)
  • 生产环境 CorsLayer 已配置 allowed_origins 白名单(非 permissive)
  • 防火墙仅开放必要端口(80/443,禁止 50051 直接暴露公网)
  • systemd 安全加固已启用(NoNewPrivileges=yesProtectSystem=strict
  • 数据库用户密码不为默认值
  • config.tomlconfig.local.toml 文件权限为 600(仅 owner 可读写)
  • 备份 cron 任务已配置并验证
  • .claude/ 目录在 .gitignore 中(防止 Agent worktree 被提交)

12. 常见部署拓扑

12.1 最小部署(单机)

Client → Caddy (:443) → rustbill-server (:50051) → PostgreSQL (:5432)
                         ↓ (Admin SPA 内嵌)
                         ↓ (Consumer SPA 静态文件由 Caddy 直接 serve)

12.2 带 Redis 的中型部署

Client → Caddy (:443) → rustbill-server (:50051) → PostgreSQL (:5432)
                                                   → Redis (:6379)

12.3 多实例高可用部署

                    ┌→ rustbill-server-1 (:50051) ──┐
Client → Caddy LB ─┼→ rustbill-server-2 (:50051) ──┼→ PostgreSQL (Citus 多 coordinator)
                    └→ rustbill-server-3 (:50051) ──┘→ Redis (实例间不共享)

多实例模式下:

  • Leader 选举通过 PG leader_role 表锁进行(迁移/事件消费/计费各独立角色)
  • 支付回调通过 SELECT FOR UPDATE 原子化防重
  • 事件队列通过 FOR UPDATE SKIP LOCKED 并发消费
  • 熔断器按 host 独立维护
  • 速率限制在 Redis 启用时跨实例共享,降级后单实例独立计数

13. 插件脚本热更新

编辑插件脚本后无需重启服务:

  1. Admin UI → Plugins → 接口实例 → 编辑脚本源码
  2. 保存到数据库 plugin_interfaces.script_source
  3. ScriptEngine.evict(key) 自动清除缓存
  4. 下次调用该插件时自动重新编译并执行新版本
# 也可以手动替换 plugins/*.rn 文件
# PluginScanner 每 5 分钟后台任务检测文件变化
# 文件系统版本 > DB 版本时自动更新 plugins 表

14. 金额精度说明

所有金额使用 DECIMAL(12,2) 数据库类型,Rust 端以 rust_decimal::Decimal 承载,序列化始终保留 2 位小数。

涉及金额的 6 张表:

金额列
productsprice
orderstotal_amount
invoicesamountpaid_amount
paymentsamount
customersbalancecredit_limit
balance_transactionsamountbalance_beforebalance_after