Files
tiku-backend.net/docs/operations.md
xiong 603bc24c26
Some checks are pending
ci / release-gate (push) Waiting to run
feat(cache): adopt FusionCache for business caching
2026-08-05 09:30:48 +08:00

211 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 配置与后台任务
本文列出 API、Worker 和 DbMigrator 当前实际读取的配置。敏感值应通过环境变量、Secret Manager 或部署平台密钥注入,不能提交到仓库。
## 进程与依赖
| 进程 | PostgreSQL | Redis | 说明 |
| --- | --- | --- | --- |
| `Tiku.Api` | 必需 | Development 可选Production 必需 | 提供 HTTP API、认证、授权、FusionCache L1/L2 和 Output Cache |
| `Tiku.Worker` | 必需 | Development 可选Production 必需 | 承载周期任务、业务缓存 Backplane 和授权缓存失效重试 |
| `Tiku.DbMigrator` | 必需 | 不需要 | 执行 Migration、内置目录 seed 和管理员引导FusionCache 仅使用本地 L1 |
Development 未配置 Redis 时,业务 FusionCache 只使用进程内 L1安全服务使用进程内/数据库防线。Production 不允许 Redis 降级;后台任务在所有环境统一使用 PostgreSQL。
## 数据库
解析顺序:
1. `ConnectionStrings:Database`
2. `DATABASE_URL`
3. 仅 Development`Host=localhost;Database=tiku;Username=<当前系统用户>`
DbMigrator 命令:
```bash
dotnet run --project Tiku.DbMigrator
dotnet ef migrations script \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator
dotnet ef migrations has-pending-model-changes \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator
```
Production 首次创建平台管理员必须显式执行:
```bash
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_EMAIL='admin@example.com'
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_PASSWORD='use-a-strong-temporary-password'
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_NAME='Platform Administrator'
dotnet run --project Tiku.DbMigrator -- --bootstrap-platform-admin
```
该命令只允许在不存在平台角色用户绑定时执行。管理员首次登录后必须改密。
## Redis
连接串读取 `ConnectionStrings:Redis``REDIS_URL`。当前用途:
- 密码、短信发送和短信校验的安全窗口计数;
- `TikuBusiness` FusionCache 的租户目录、Feature 快照和运行时配置 L2
- FusionCache Backplane用于跨 API/Worker 节点驱逐业务 L1
- 可选的 Session、安全状态和版本化权限快照缓存
- Production 的 ASP.NET Core Output Cache。
业务缓存 key 和 Backplane channel 使用 `tiku:<environment>:business:v2` 前缀;配置解析会强制 `AbortOnConnectFail=false`。FusionCache 复用现有 `IConnectionMultiplexer`,不创建额外 Redis 连接。业务缓存禁用 fail-safe 与后台分布式写入Redis 异常时回退 PostgreSQLRedis 不是用户、Session、权限、套餐或用量的权威数据源。
`TikuBusiness` 的 TTL 和安全边界见[认证、授权与租户隔离](architecture/security-and-tenancy.md#fusioncache-业务缓存)。FusionCache、授权缓存与 Output Cache 是三套不同语义:业务读模型使用 FusionCache安全状态保留版本化专用实现HTTP 响应继续由 ASP.NET Core Output Cache 管理。
授权缓存由 `Security:AuthorizationCache` 配置,默认 `Mode``Disabled`。切换为 `Shadow``Active` 前,应先确认 API 与 Worker 使用同一 Redis 和 PostgreSQL并观察 `Tiku.Security.AuthorizationCache` 的 mismatch、fallback 与 Redis 延迟指标。回滚只需切回 `Disabled`,不应回退授权版本或失效事件相关数据库结构。详细故障语义见[认证、授权与租户隔离](architecture/security-and-tenancy.md#redis-授权缓存模式)。
## Worker 与后台处理配置
```json
{
"Worker": {
"Enabled": true,
"JobPollSeconds": 2,
"JobParallelism": 4,
"JobBatchSize": 5
},
"TenantDomains": {
"Enabled": true,
"PollSeconds": 60,
"BatchSize": 50,
"DnsJsonEndpoint": "https://cloudflare-dns.com/dns-query",
"VerificationRecordPrefix": "_tiku-verification",
"AllowedCnameTargets": [],
"GatewayBaseUrl": null,
"GatewayApiKey": null
},
"TenantProvisioning": {
"DefaultBaseOfferingCode": "starter",
"DefaultTrialDays": 14,
"OwnerActivationMinutes": 30
},
"SaasSubscriptions": {
"Enabled": true,
"BatchSize": 100,
"PastDueGraceDays": 7
},
"FeatureUsageReconciliation": {
"Enabled": true,
"BatchSize": 100,
"IntervalMinutes": 60
},
"CommercialBilling": {
"Enabled": true,
"BatchSize": 100,
"AllowedWebhookHosts": []
}
}
```
域名只有在 `AllowedCnameTargets`、DNS JSON endpoint、Gateway URL 和 API key 配置完成后,才可能从 Pending/Failed 进入 Active。仅 DNS 验证成功不代表 TLS 已就绪。
`TenantProvisioning:DefaultBaseOfferingCode` 必须指向 Active 基础套餐的有效 Published 版本。Production 启动与租户开通事务都会校验,缺失时返回 `default_offering_unavailable`。完整流程见[空数据库到租户建站验收](tenant-provisioning.md)。
后台任务状态和 `RunAfter` 存在 PostgreSQL。`BackgroundJobsWorker` 使用 `FOR UPDATE SKIP LOCKED`、五分钟租约和有限重试,允许多个 Worker 实例并行消费;其他周期处理器使用 PostgreSQL advisory lock 防止重复执行。通用任务由模块注册的 `IBackgroundJobHandler` 处理Jobs 模块负责查找、租约、重试和失败补偿。七个循环处理域名、订阅、Feature 用量、通用任务、授权缓存失效、商业账务和平台审批执行。`Worker:Enabled=false` 会关闭全部循环。
API 和 Worker 必须使用同一 PostgreSQL 数据库与一致的对象存储配置。迁移必须在两者启动前由 `Tiku.DbMigrator` 单独执行。
容器镜像从仓库根目录构建:
```bash
docker build -f Tiku.Api/Dockerfile -t tiku-api .
docker build -f Tiku.Worker/Dockerfile -t tiku-worker .
```
API 和 Worker 应独立设置副本数与资源限制。发布顺序固定为 `Tiku.DbMigrator``Tiku.Worker``Tiku.Api``Tiku.PlatformAdmin.Web`;不要在容器入口自动执行 Migration。
## 发布门禁、备份恢复和告警
`.gitea/workflows/ci.yaml` 执行 restore、build、完整测试、format、EF 模型漂移、幂等 Migration SQL、平台前端检查、OpenAPI 生成漂移、API/Worker 镜像构建和 `git diff --check`。本地发布前应执行相同检查。
PostgreSQL 恢复演练使用标准 `PGHOST``PGPORT``PGUSER``PGPASSWORD` 环境变量,并通过 `TIKU_BACKUP_SOURCE_DATABASE` 指定源数据库:
```bash
TIKU_BACKUP_SOURCE_DATABASE=tiku scripts/rehearse-postgres-restore.sh
```
脚本只创建并删除名称受限的 `tiku_restore_drill_*` 临时数据库,校验 Migration 历史与租户表后自动清理。生产演练仍应在隔离实例上执行,并把耗时、备份大小和恢复点记录到变更单。
`deploy/monitoring/postgres-exporter-queries.yaml` 提供 Worker stale、最老 Pending Job、支付回调失败、逾期应收和催缴死信指标`deploy/monitoring/commercial-alerts.yaml` 提供对应 Prometheus 告警。部署时必须让 PostgreSQL exporter 使用只读监控账号,并先在预发布验证规则名称与采集前缀。
## 安全与网络配置
Production 启动至少需要核对:
| 配置 | 作用 |
| --- | --- |
| `Security:Jwt` | issuer、audience、当前 key ID、RSA 私钥和验证公钥 |
| `Security:DataProtection` | application name、X509 证书路径和密码 |
| `Security:TenantSecrets` | key ID 和 Base64 编码的 32 字节 master key |
| `Authentication:Sms` | 至少 32 字符的验证码 pepper 和频控阈值 |
| `Tenancy:Resolution` | 正式平台 Host、可信代理、tenant code 允许路径 |
| `AllowedHosts` | 非通配 Host allowlist |
| `Cors` | 明确的 Origin、Header、Method 和凭据策略 |
| `BrowserAuth:AllowedOrigins` | 允许使用 Browser Auth 的 HTTP(S) Origin |
| `RateLimiting` | 全局和认证端点限流 |
可用环境变量覆盖包括:
- `TIKU_DATA_PROTECTION_APPLICATION_NAME`
- `TIKU_DATA_PROTECTION_CERTIFICATE_PATH`
- `TIKU_DATA_PROTECTION_CERTIFICATE_PASSWORD`
- `TIKU_TENANT_SECRET_KEY_ID`
- `TIKU_TENANT_SECRET_MASTER_KEY`
- `TIKU_SMS_CODE_PEPPER`
不要在命令输出、文档、Git diff 或错误报告中粘贴这些值。
## 对象存储与外部 Provider
对象存储读取 `Storage``Storage:AliyunOss``Storage:S3Compatible`。API 与 Worker 支持 `STORAGE_*``ALIYUN_OSS_*` 以及 `S3_ENDPOINT``S3_ACCESS_KEY``S3_SECRET_KEY``S3_REGION``S3_SECURE` 环境变量。Production 默认并强制使用已配置的阿里云 OSS非 Production 没有完整 OSS 凭据时回退到 `local_dev`,该 Provider 使用 S3 兼容存储,快速部署环境由 MinIO 提供。所有托管 Provider 都强制租户 key 前缀、上传大小和 MIME allowlist。租户导出使用 `application/gzip`,该类型不能从 allowlist 删除。
## ClamAV 资源安全扫描
API 和 Worker 都读取 `Security:ClamAV`
```json
{
"Security": {
"ClamAV": {
"Host": "clamav",
"Port": 3310,
"TimeoutSeconds": 30,
"ChunkBytes": 65536,
"StreamMaxLength": 524288000
}
}
}
```
Worker 使用 ClamAV `INSTREAM` 协议,不在本地落盘待扫描对象。启动校验要求 `StreamMaxLength >= Storage:MaxUploadBytes`;同时必须把 clamd 自身的 `StreamMaxLength` 配到相同或更高值。扫描结果为 FOUND 时资源标记为 Failed 并记录病毒签名ClamAV 超时或不可用时任务保留 Pending 并退避重试。只有 `Passed` 或系统明确标记为可信的 `NotRequired` 资源可以签发访问地址。
身份、短信、支付、通知和 AI 的租户配置由业务后台写入 `TenantExternalProvider`;敏感值写入加密的 `TenantSecret`。全局默认配置不能绕过租户 Provider 状态和 Secret 边界。
## 健康检查与观测
- `GET /api/system/health`:轻量 liveness只说明 API 进程可响应。
- `GET /api/system/health/ready`:检查 PostgreSQL 和已配置 Redis依赖未就绪时返回 503匿名响应只包含总体状态和检查时间。
- `GET /api/platform/operations/health`:需要 `platform:operations:view`,返回 PostgreSQL、Redis、Worker heartbeat、ClamAV 和对象存储配置状态。
- `GET /api/platform/operations/workers`:查询 Worker 心跳、周期循环和 stale 状态。
- `GET /api/platform/operations/job-metrics`:查询队列状态、最老 Pending 任务与过期租约。
- 设置 `OpenTelemetry:OtlpEndpoint` 后导出 ASP.NET Core、HTTP client、数据库和 FusionCache 的 hit/miss、L1/L2、工厂、Backplane 指标与 trace。
- Serilog 输出结构化请求日志;数据库性能拦截器记录慢查询指标。
Readiness 为绿色不等于认证授权、跨租户隔离或后台任务恢复演练已通过,发布仍需执行对应集成测试。
## 租户归档与导出发布门禁
- 租户归档是逻辑归档,禁止硬删除。
- 归档前必须存在 24 小时内成功完成的租户导出,且不能有 Processing 后台任务。
- 导出包是 `tar.gz`,包含 manifest、租户、成员、域名和资源元数据明确排除密码哈希、令牌、密钥明文、Data Protection keys 和全局平台数据。
- 归档会撤销该租户授权域 Session、禁用域名并失效运行时缓存恢复后租户为 `Suspended`,域名为 `Pending`,必须重新审核后再激活。
- Owner 转移目标必须是已有 Active 成员,并在同一事务内同步成员角色和后台角色绑定。
- 发布前至少演练一次导出可下载、归档阻断条件、归档、恢复和 Owner 转移。