docs: design better auth performance optimization
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
# Better Auth 接口响应时间优化设计
|
||||
|
||||
## 背景
|
||||
|
||||
`cfw-auth` 运行在 Cloudflare Worker 上,使用 Better Auth 和 Cloudflare D1 提供认证能力。当前项目已经接入账号中心相关插件,包括 username、phone-number、organization、api-key、expo、email OTP、two-factor、passkey、captcha 等。
|
||||
|
||||
本设计关注 Better Auth 接口响应时间优化,目标是在不重写 Better Auth adapter、不更换数据库、不改变客户端体验的前提下,先降低认证热路径延迟,并建立可观测的性能闭环。
|
||||
|
||||
## 范围
|
||||
|
||||
纳入范围:
|
||||
|
||||
- `/api/auth/get-session`
|
||||
- 邮箱、用户名、手机号登录注册路径
|
||||
- `/phone-number/send-otp`
|
||||
- `/phone-number/verify`
|
||||
- organization 邀请和接受邀请相关路径
|
||||
- `/api-key/verify`
|
||||
- Worker 层认证接口耗时观测
|
||||
- Better Auth session 和 API key 插件的低风险性能配置
|
||||
|
||||
不纳入范围:
|
||||
|
||||
- 更换 D1 或重写 Better Auth database adapter
|
||||
- 引入全新的缓存基础设施
|
||||
- 改客户端 UI 或 Expo 客户端实现
|
||||
- 改 Better Auth 认证语义
|
||||
- 将 OTP 发送异步化
|
||||
- 生产环境强制启用 Smart Placement 或 D1 read replication
|
||||
|
||||
## 成功标准
|
||||
|
||||
- 支持 session cookie cache,以减少 session 读取路径对 D1 的重复访问。
|
||||
- 支持 API key 非关键更新延迟执行,以减少 API key 验证路径的同步写入成本。
|
||||
- `/api/auth/*` 请求有结构化耗时日志,且不记录 token、cookie、API key、邮箱、手机号或请求体。
|
||||
- 性能配置都能通过配置关闭或调低。
|
||||
- 本地 `pnpm db:check`、`pnpm typecheck`、`pnpm test` 通过。
|
||||
- 纯性能配置不应产生无关 D1 migration SQL 变化。
|
||||
|
||||
## 方案选择
|
||||
|
||||
### 推荐方案:低风险热路径优化 + 观测闭环
|
||||
|
||||
第一阶段只做三件事:
|
||||
|
||||
- 启用 Better Auth `session.cookieCache`。
|
||||
- 给 `/api/auth/*` 增加轻量结构化耗时日志。
|
||||
- 给 `@better-auth/api-key` 配置 `deferUpdates`,复用现有 Better Auth `advanced.backgroundTasks.handler` 和 Worker `executionCtx.waitUntil`。
|
||||
|
||||
这个方案改动小,能直接覆盖最可能的热路径瓶颈,也能为后续更重的 Cloudflare 平台优化提供证据。
|
||||
|
||||
### 备选方案:平台定位优化
|
||||
|
||||
开启 Cloudflare `observability` 和生产环境 `placement.mode = "smart"`,通过线上 p50、p95、p99 对比验证 Worker 与 D1、外部 provider 的距离是否是主要瓶颈。
|
||||
|
||||
该方案保留为第二阶段,因为如果当前瓶颈是 session 查询、API key 写入或外部短信/邮件,仍需要第一阶段先拆清楚路径。
|
||||
|
||||
### 暂缓方案:存储层重构
|
||||
|
||||
引入 secondary storage、D1 read replication/Sessions API 或专门缓存层。该方向潜在收益高,但会增加一致性、安全和 adapter 适配复杂度。本次只记录决策门槛,不实施。
|
||||
|
||||
## 架构设计
|
||||
|
||||
保留现有三层架构。
|
||||
|
||||
第一层是 Worker/Hono 入口,由 `src/index.ts` 负责:
|
||||
|
||||
- CORS
|
||||
- `/api/auth/*` 路由挂载
|
||||
- 把 `executionCtx.waitUntil` 传给 Better Auth
|
||||
- 追加认证接口观测包装
|
||||
|
||||
第二层是 Better Auth 配置,由 `src/auth.ts` 负责:
|
||||
|
||||
- `database: env.DB`
|
||||
- `secret`
|
||||
- `baseURL`
|
||||
- `trustedOrigins`
|
||||
- email/password 配置
|
||||
- session 性能配置
|
||||
- `advanced.backgroundTasks.handler`
|
||||
- 插件列表
|
||||
|
||||
第三层是插件和外部服务适配,由 `src/plugins.ts`、`src/email.ts`、`src/sms.ts` 负责:
|
||||
|
||||
- Better Auth plugin 配置
|
||||
- 邮件 provider
|
||||
- SMS provider
|
||||
- API key 性能配置
|
||||
|
||||
新增一个小型观测边界,例如 `src/observability.ts`。它只负责记录请求耗时,不参与认证语义,不改写 Better Auth 响应。
|
||||
|
||||
## 数据流
|
||||
|
||||
### Session 读取路径
|
||||
|
||||
请求进入 Worker 后仍交给 Better Auth。启用 `session.cookieCache` 后,短 TTL 内的 session 数据可以从签名 cookie cache 读取,从而减少 D1 session 查询。
|
||||
|
||||
建议默认:
|
||||
|
||||
```ts
|
||||
session: {
|
||||
cookieCache: {
|
||||
enabled: true,
|
||||
maxAge: 300,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
TTL 可以通过 env 配置。若安全策略要求更高,可以降到 `60` 秒或关闭。
|
||||
|
||||
### OTP、邮件和短信路径
|
||||
|
||||
短信 OTP、验证邮件、密码重置邮件默认保持同步 `await`。这些路径的外部发送动作是用户感知成功的一部分,不能为了接口更快而提前返回成功。
|
||||
|
||||
后续可以异步化的仅限:
|
||||
|
||||
- 非关键通知
|
||||
- 审计日志
|
||||
- 分析事件
|
||||
- 不影响用户下一步操作的后台同步
|
||||
|
||||
### API key 验证路径
|
||||
|
||||
API key 的验证结果必须同步返回。请求计数、`lastRequest`、`remaining` 等非关键更新可以延迟执行。
|
||||
|
||||
`@better-auth/api-key` 提供 `deferUpdates`,并要求主 Better Auth 配置存在 `advanced.backgroundTasks.handler`。当前项目已经通过 Worker `waitUntil` 提供该 handler,因此可以将 `deferUpdates` 作为默认开启的性能配置。
|
||||
|
||||
## 一致性边界
|
||||
|
||||
### 可接受的短暂陈旧
|
||||
|
||||
`session.cookieCache` 可能导致 session 撤销、封禁、角色变化等状态在 TTL 内不立即反映。默认 TTL 不能过长,建议 `300` 秒起步,并允许配置为更短。
|
||||
|
||||
### 可接受的 eventual consistency
|
||||
|
||||
API key 计数和时间戳更新可以接受 eventual consistency。API key 是否有效、是否匹配、是否过期等核心判断仍必须同步完成。
|
||||
|
||||
### 不接受的提前成功
|
||||
|
||||
OTP 发送、验证邮件、密码重置邮件不应在 provider 未完成时提前返回成功。否则用户可能收到成功响应却拿不到验证码或链接。
|
||||
|
||||
## 配置策略
|
||||
|
||||
建议新增或使用以下配置:
|
||||
|
||||
- `BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE`
|
||||
- 默认:`300`
|
||||
- 用途:控制 Better Auth session cookie cache TTL。
|
||||
|
||||
- `API_KEY_DEFER_UPDATES`
|
||||
- 默认:`true`
|
||||
- 用途:控制 API key 非关键更新是否延迟执行。
|
||||
|
||||
- Cloudflare `observability`
|
||||
- 建议写入 `wrangler.jsonc`
|
||||
- 初始 `head_sampling_rate` 使用低采样,例如 `0.1`
|
||||
|
||||
- Cloudflare `placement.mode = "smart"`
|
||||
- 不作为本次强制配置
|
||||
- 作为生产验证选项记录
|
||||
|
||||
非法配置处理:
|
||||
|
||||
- session cache TTL 非数字或小于等于 0 时使用默认值。
|
||||
- `API_KEY_DEFER_UPDATES=false` 时关闭延迟更新;其他值按默认开启处理。
|
||||
|
||||
## 观测设计
|
||||
|
||||
结构化日志字段:
|
||||
|
||||
- `event`: 固定为 `auth_request`
|
||||
- `method`
|
||||
- `path` 或归一化后的 endpoint
|
||||
- `status`
|
||||
- `durationMs`
|
||||
- `colo`,来自 `request.cf?.colo`
|
||||
- `cfRay`,来自请求头 `cf-ray`
|
||||
|
||||
不得记录:
|
||||
|
||||
- `Authorization`
|
||||
- `Cookie`
|
||||
- API key
|
||||
- session token
|
||||
- 请求体
|
||||
- 邮箱
|
||||
- 手机号
|
||||
- OTP code
|
||||
|
||||
观测层失败时必须静默降级,不影响 Better Auth 响应。
|
||||
|
||||
## 错误处理
|
||||
|
||||
- Better Auth 业务错误保持原样返回。
|
||||
- 观测层不能改写响应体、状态码或 header。
|
||||
- 后台任务失败只记录错误,不回滚已经返回给客户端的响应。
|
||||
- `waitUntil` 接收的 promise 必须捕获并记录错误,避免隐藏失败。
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 配置单元测试
|
||||
|
||||
扩展现有 `tests/auth-config.test.ts`:
|
||||
|
||||
- 默认 session cookie cache TTL 是 `300`。
|
||||
- env 可覆盖 TTL。
|
||||
- 非法 TTL 使用默认值。
|
||||
- API key defer 默认开启。
|
||||
- `API_KEY_DEFER_UPDATES=false` 可以关闭。
|
||||
|
||||
### Worker 行为测试
|
||||
|
||||
扩展现有 `tests/auth-worker.test.ts`:
|
||||
|
||||
- `/api/auth/*` 请求仍能正常返回。
|
||||
- 观测包装不改写 Better Auth 响应。
|
||||
- 日志包含 `durationMs`、`method`、`status`。
|
||||
- 日志不包含 `cookie`、`authorization`、手机号、邮箱、API key 等敏感信息。
|
||||
|
||||
### 本地验收
|
||||
|
||||
必须通过:
|
||||
|
||||
```bash
|
||||
pnpm db:check
|
||||
pnpm typecheck
|
||||
pnpm test
|
||||
```
|
||||
|
||||
如果本地 Worker 可运行,补充烟测:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:8788/api/auth/get-session
|
||||
curl -i http://localhost:8788/api/auth/reference
|
||||
```
|
||||
|
||||
## 生产验证策略
|
||||
|
||||
本次不要求完成生产验证,但部署后应对比:
|
||||
|
||||
- `get-session` p50、p95、p99
|
||||
- `api-key/verify` p50、p95、p99
|
||||
- OTP 发送路径 p95
|
||||
- organization invitation 路径 p95
|
||||
- Worker colo 分布
|
||||
- D1 或外部 provider 是否主导尾延迟
|
||||
|
||||
只有当观测显示主要延迟来自远端等待时,再评估开启 Smart Placement。只有当 D1 读延迟明确成为瓶颈时,再评估 D1 read replication、Sessions API 或 secondary storage。
|
||||
|
||||
## 后续决策门槛
|
||||
|
||||
进入平台定位优化的门槛:
|
||||
|
||||
- 第一阶段上线后,p95 仍不能接受;
|
||||
- 日志显示延迟主要来自 D1 或外部 provider;
|
||||
- 多地域请求有明显延迟差异。
|
||||
|
||||
进入存储层重构的门槛:
|
||||
|
||||
- `get-session` 或 organization 读路径被证明确实受 D1 读延迟限制;
|
||||
- session cookie cache 无法满足安全或一致性要求;
|
||||
- API key rate counter 写入仍是高频瓶颈;
|
||||
- 有明确的强一致、弱一致、撤销语义设计。
|
||||
|
||||
## 风险
|
||||
|
||||
- session cookie cache 会引入短 TTL 内的撤销延迟。
|
||||
- API key `deferUpdates` 会让计数类字段 eventual consistent。
|
||||
- 观测日志若设计不当可能泄露敏感信息。
|
||||
- 过早引入 secondary storage 会增加一致性复杂度。
|
||||
- Smart Placement 可能改善后端等待,也可能对当前瓶颈帮助有限,必须用数据验证。
|
||||
|
||||
## 实施顺序
|
||||
|
||||
1. 抽出性能配置解析函数。
|
||||
2. 在 `src/auth.ts` 启用 session cookie cache。
|
||||
3. 在 `src/plugins.ts` 为 API key 配置 `deferUpdates`。
|
||||
4. 增加 `/api/auth/*` 观测包装。
|
||||
5. 增加配置和 Worker 行为测试。
|
||||
6. 更新 operations 文档。
|
||||
7. 运行本地验证。
|
||||
|
||||
## 自检结论
|
||||
|
||||
- 无未完成标记或空白段落。
|
||||
- 范围限定在第一阶段低风险优化,没有混入存储层重构。
|
||||
- 架构、数据流、一致性、配置和测试互相一致。
|
||||
- 每个可能引入安全或一致性变化的优化都有关闭或调低路径。
|
||||
Reference in New Issue
Block a user