按性能分析逐项落地,实测对比(16 并发、mock 上游零延迟、SQLite): - 每请求 SQL 10 → 2:模型/渠道目录(模型行、绑定、渠道行)进程内缓存 10s, 运行期状态(冷却、健康)仍每次实时判定;管理端写操作经中间件、 健康状态变化经回调立即失效。新增 TestProxyRequestSQLBudget 钉住预算。 - 端到端 p50 1.3–1.6ms → 0.66–0.70ms,RPS 3.5–8.9k → 16–18k。 - 流式正文累积:字符串 += 改 strings.Builder(原为 O(n²)), 逐行 JSON 提取改字节快路径,并加廉价的子串预过滤、拿到输出 usage 后停累积。 500 块:949µs/7.9MB 分配 → 83µs/136KB。 - 请求体定点改写:模型映射从整包 unmarshal/marshal 改为顶层字段替换 (100KB:585µs → 29µs),stream_options 注入同理;requestText 改为 只在「上游没报用量」时按需提取,亲和键改用原始体前缀。 - 渠道满载背压:新增 Acquire 有界排队(OT_PROXY_CHANNEL_ACQUIRE_WAIT, 默认 150ms);排队仍满时返回 503 + Retry-After 而不是 502。 实测渠道上限 4、16 并发:无排队 81 次 503;排队 150ms 后 400/400 成功。 - 记账按批聚合:同批同用户一次扣款、流水批量插入、日表按 (user,model,日期) 聚合,替代每行 5 条语句;幂等仍靠 ref_id 唯一索引兜底。 - gorm 开启 PrepareStmt(SQL 解析此前占 CPU 15%);tiktoken 编码器按模型复用。 - 管理端用量列表不再返回原始请求/响应体(可能几十 MB), 改为 has_raw 标记 + GET /admin/usage/:id 按需拉取,前端弹窗打开时取。 验证:go vet、go test ./...、go test -race(proxy/channel/usage/tokenizer)、 vue-tsc、eslint、vite build 全绿;本地起 mock 上游实测列表/详情接口与 管理页弹窗按需加载。
87 lines
4.1 KiB
Bash
87 lines
4.1 KiB
Bash
# openteam 服务配置示例 —— 复制为 .env 后修改
|
||
# 所有项均可用环境变量 OT_<KEY> 覆盖(点号转下划线,如 db.driver → OT_DB_DRIVER)
|
||
|
||
# 运行环境 development | production(仅这两个值;生产启动会做密钥断言,见下)
|
||
OT_ENV=development
|
||
OT_PORT=8080
|
||
|
||
# 数据库(开发默认 SQLite;生产切 postgres)
|
||
OT_DB_DRIVER=sqlite
|
||
OT_DB_DSN=data/openteam.db
|
||
# OT_DB_DRIVER=postgres
|
||
# OT_DB_DSN=host=localhost user=openteam password=openteam dbname=openteam port=5432 sslmode=disable
|
||
|
||
# JWT(生产必须更换为随机长字符串;OT_ENV=production 时本文件里的占位值会被启动校验拒绝)
|
||
OT_JWT_SECRET=change-me-to-a-long-random-string
|
||
OT_JWT_ACCESS_TTL=2h
|
||
OT_JWT_REFRESH_TTL=168h
|
||
# 生产必须为 true(refresh cookie 走 HTTPS;反代终止 TLS 时也要置 true)
|
||
OT_JWT_COOKIE_SECURE=false
|
||
|
||
# 注册策略:open(开放)| invite(邀请码)
|
||
OT_AUTH_REGISTRATION_MODE=open
|
||
|
||
# 渠道密钥加密主密钥(生产必须设置,32 字节以上)
|
||
OT_MASTER_KEY=change-me-master-key
|
||
|
||
# 默认上游渠道(首次启动自动创建 OpenAI 渠道)
|
||
OT_PROXY_UPSTREAM_KEY=
|
||
OT_PROXY_UPSTREAM_BASE_URL=https://api.openai.com
|
||
OT_PROXY_DEFAULT_MODEL=gpt-4o-mini
|
||
# 上游超时兜底值(渠道 timeout_ms 优先):
|
||
# 非流式 = 整段请求上限;流式 = 只约束首包,正文不限时长
|
||
OT_PROXY_TIMEOUT=300s
|
||
|
||
# /v1 请求体上限(MB):超限按客户端协议返回 413
|
||
OT_PROXY_MAX_BODY_MB=32
|
||
|
||
# 故障转移给"第二个及以后的渠道"留的时间预算(0=不限)。
|
||
# 首个渠道不受它约束——长回答本就要跑几分钟,但不能让坏渠道把客户端拖到 N×timeout。
|
||
OT_PROXY_FAILOVER_BUDGET=30s
|
||
# 流式空闲多久补一行 SSE 注释心跳(0=关闭)。挂在 nginx/Cloudflare 后面时,
|
||
# 上游长时间不出字(长思考)会被对端的空闲超时掐掉,心跳用来续住这条流。
|
||
OT_PROXY_STREAM_HEARTBEAT=15s
|
||
# 流式在放行给客户端之前最多等内容多久(0=不限):超时未出内容就取消本次尝试、
|
||
# 换下一个渠道。上游挂起(连接正常但一直不吐字)时的兜底。
|
||
OT_PROXY_FIRST_TOKEN_WAIT=0s
|
||
# 会话亲和 TTL(0=关闭,默认 5m):同一会话粘住上次应答的渠道,命中上游的提示词
|
||
# 缓存(整段上下文每轮重发),而不是被加权随机打散后全价重算。
|
||
OT_PROXY_AFFINITY_TTL=5m
|
||
# 渠道并发满载时每个候选渠道最多排队多久(0=立刻跳过)。上游 LLM 请求本来就慢,
|
||
# 短暂排队远好于把 502 直接甩给 agent;排队仍拿不到槽时返回 503 + Retry-After。
|
||
OT_PROXY_CHANNEL_ACQUIRE_WAIT=150ms
|
||
|
||
# 渠道健康检查
|
||
OT_PROXY_HEALTH_INTERVAL=60s
|
||
OT_PROXY_HEALTH_FAIL_THRESHOLD=2
|
||
|
||
# 调试:记录管理员的原始请求与响应到请求明细(默认关闭;流式记录全部事件)
|
||
OT_PROXY_LOG_RAW=false
|
||
|
||
# 限流(内存计数,Redis 后置):用户级每秒请求数上限(0=不限制)
|
||
OT_RATELIMIT_USER_RPS=20
|
||
# 认证端点限速(每分钟,0=不限制):登录是密码爆破面,注册是批量建号面
|
||
OT_RATELIMIT_LOGIN_IP_PER_MIN=30
|
||
OT_RATELIMIT_LOGIN_USER_PER_MIN=10
|
||
OT_RATELIMIT_REGISTER_IP_PER_MIN=5
|
||
|
||
# 跨域白名单(逗号分隔 origin)。留空 = 不输出任何 CORS 头:
|
||
# 网关自托管 web/dist 时前后端同源、vite dev 走 proxy,都不需要跨域。
|
||
# 只有把 web/ 单独部署到别的域名时才需要配。
|
||
OT_CORS_ALLOW_ORIGINS=
|
||
# 反向代理(CIDR 或 IP,逗号分隔)。配置后 gin 才信任 X-Forwarded-For 取客户端 IP,
|
||
# 上面的认证限速依赖它;直连部署留空(此时按连接源地址计数,伪造头无效)。
|
||
OT_SERVER_TRUSTED_PROXIES=
|
||
|
||
# Passkey(WebAuthn):RPID 为域名,RPOrigin 为前端来源(需 HTTPS 或 localhost)
|
||
OT_WEBAUTHN_RP_ID=localhost
|
||
OT_WEBAUTHN_RP_ORIGIN=http://localhost:5173
|
||
OT_WEBAUTHN_RP_NAME=openteam
|
||
|
||
# 初始管理员(仅首次创建生效)。非 development 环境未显式设置 OT_ADMIN_PASSWORD
|
||
# 时拒绝播种管理员;admin123 是公开默认值,生产启动校验也会拒绝它。
|
||
OT_ADMIN_USERNAME=admin
|
||
OT_ADMIN_EMAIL=admin@localhost
|
||
OT_ADMIN_PASSWORD=admin123
|
||
|