Skip to content

Commit 8278905

Browse files
committed
perf: 修复调度器 Redis N+1、补齐数据库索引、消除请求体重复解析等性能问题
- scheduler: 删除每次 RPM 查询的 Redis TIME 命令,改用本地时间 - scheduler: 预获取并缓存 getCurrentLoad 结果,选号 Redis 调用量从 2N 降到 N - schema: apikey 添加 (key_hash) 唯一索引和 (status, created_at) 复合索引 - schema: account 添加 (platform, state) 复合索引 - schema: balancelog 添加 (user_id_snapshot, created_at) 复合索引 - schema: usagelog 添加 (model, created_at) 复合索引 - schema: usersubscription 添加 (status) 索引 - plugin/request: 请求体 JSON 解析从 3 次降到 1 次,缓存 imageToolPayload - plugin/request: buildHeaders 从全量 Clone 改为选择性拷贝,跳过 hop-by-hop 头 - store: ListTrendLogs 和 TrendEntries 添加 LIMIT 50000 防止 OOM - plugin/extension_proxy: 流式写入检测 client disconnect,避免无效资源消耗 - server/dynamic_router: 双重 RLock 合并为单次,减少锁竞争
1 parent e6d24bf commit 8278905

15 files changed

Lines changed: 201 additions & 52 deletions

File tree

backend/ent/migrate/schema.go

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/ent/schema/account.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"entgo.io/ent"
55
"entgo.io/ent/schema/edge"
66
"entgo.io/ent/schema/field"
7+
"entgo.io/ent/schema/index"
78
)
89

910
// Account 上游 AI 账户。
@@ -47,6 +48,12 @@ func (Account) Fields() []ent.Field {
4748
}
4849
}
4950

51+
func (Account) Indexes() []ent.Index {
52+
return []ent.Index{
53+
index.Fields("platform", "state"),
54+
}
55+
}
56+
5057
func (Account) Edges() []ent.Edge {
5158
return []ent.Edge{
5259
edge.To("groups", Group.Type),

backend/ent/schema/apikey.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"entgo.io/ent"
55
"entgo.io/ent/schema/edge"
66
"entgo.io/ent/schema/field"
7+
"entgo.io/ent/schema/index"
78
)
89

910
// APIKey API 密钥
@@ -35,6 +36,13 @@ func (APIKey) Fields() []ent.Field {
3536
}
3637
}
3738

39+
func (APIKey) Indexes() []ent.Index {
40+
return []ent.Index{
41+
index.Fields("key_hash").Unique(),
42+
index.Fields("status", "created_at"),
43+
}
44+
}
45+
3846
func (APIKey) Edges() []ent.Edge {
3947
return []ent.Edge{
4048
edge.From("user", User.Type).Ref("api_keys").Unique().Required(),

backend/ent/schema/balancelog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@ func (BalanceLog) Indexes() []ent.Index {
4343
return []ent.Index{
4444
// Postgres 唯一索引对 NULL 不互斥,仅约束显式提供的幂等键
4545
index.Fields("idempotency_key").Unique(),
46+
index.Fields("user_id_snapshot", "created_at"),
4647
}
4748
}

backend/ent/schema/usagelog.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ func (UsageLog) Indexes() []ent.Index {
107107
StorageKey("usage_log_platform_created_at"),
108108
index.Fields("user_id_snapshot", "created_at").
109109
StorageKey("usage_log_user_snapshot_created_at"),
110+
index.Fields("model", "created_at").
111+
StorageKey("usage_log_model_created_at"),
110112
index.Edges("user").
111113
StorageKey("usage_log_user"),
112114
index.Edges("api_key").

backend/ent/schema/usersubscription.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"entgo.io/ent"
55
"entgo.io/ent/schema/edge"
66
"entgo.io/ent/schema/field"
7+
"entgo.io/ent/schema/index"
78
)
89

910
// UserSubscription 用户订阅
@@ -22,6 +23,12 @@ func (UserSubscription) Fields() []ent.Field {
2223
}
2324
}
2425

26+
func (UserSubscription) Indexes() []ent.Index {
27+
return []ent.Index{
28+
index.Fields("status"),
29+
}
30+
}
31+
2532
func (UserSubscription) Edges() []ent.Edge {
2633
return []ent.Edge{
2734
edge.From("user", User.Type).Ref("subscriptions").Unique().Required(),

backend/internal/infra/store/dashboard_store.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ func (s *DashboardStore) ListTrendLogs(ctx context.Context, startTime, endTime t
9292
preds = append(preds, usageUserPredicate(int64(userID)))
9393
}
9494

95+
const trendLogLimit = 50000
9596
list, err := s.db.UsageLog.Query().
9697
Where(preds...).
9798
Select(
@@ -106,6 +107,8 @@ func (s *DashboardStore) ListTrendLogs(ctx context.Context, startTime, endTime t
106107
entusagelog.FieldTotalCost,
107108
entusagelog.FieldCreatedAt,
108109
).
110+
Order(ent.Desc(entusagelog.FieldCreatedAt)).
111+
Limit(trendLogLimit).
109112
All(ctx)
110113
if err != nil {
111114
return nil, err

backend/internal/infra/store/usage_store.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ func (s *UsageStore) TrendEntries(ctx context.Context, filter appusage.TrendFilt
384384
query = query.Where(entusagelog.CreatedAtGTE(time.Now().Add(-time.Duration(filter.DefaultRecentHours) * time.Hour)))
385385
}
386386

387+
const trendEntryLimit = 50000
387388
logs, err := query.
388389
Select(
389390
entusagelog.FieldInputTokens,
@@ -395,6 +396,8 @@ func (s *UsageStore) TrendEntries(ctx context.Context, filter appusage.TrendFilt
395396
entusagelog.FieldTotalCost,
396397
entusagelog.FieldCreatedAt,
397398
).
399+
Order(ent.Desc(entusagelog.FieldCreatedAt)).
400+
Limit(trendEntryLimit).
398401
All(ctx)
399402
if err != nil {
400403
return nil, err

backend/internal/plugin/extension_proxy.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@ func (ep *ExtensionProxy) handleStream(c *gin.Context, ext *sdkgrpc.ExtensionGRP
239239
}
240240

241241
if len(chunk.Data) > 0 {
242-
_, _ = c.Writer.Write(chunk.Data)
242+
if _, err := c.Writer.Write(chunk.Data); err != nil {
243+
return // 客户端已断开
244+
}
243245
c.Writer.Flush()
244246
}
245247

backend/internal/plugin/forwarder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (f *Forwarder) Forward(c *gin.Context) {
129129
defer releaseClientQuota()
130130

131131
requirements := routing.Requirements{
132-
NeedsImage: requestNeedsImage(f.manager, state.requestPath, state.model, state.body),
132+
NeedsImage: requestNeedsImageCached(f.manager, state),
133133
}
134134
routes := routesForAPIKey(state, requirements)
135135
if len(routes) == 0 {

0 commit comments

Comments
 (0)