LiteLLM 控制台与 MySQL 兼容性问题排查及双数据库架构改造记录

发布时间:2026/8/30 20:30:13
LiteLLM 控制台与 MySQL 兼容性问题排查及双数据库架构改造记录 LiteLLM 控制台与 MySQL 兼容性问题排查及双数据库架构改造记录1. 问题背景在 LiteLLM Proxy 的日常维护中我们通过自定义的CustomLogger基于 SQLAlchemy 2.0 Core将所有 API 请求的审计流水、Token 消耗以及折算后的人民币费用异步写入 OCI MySQLlitellm_db.llm_request_logs。这套数据面落库方案运行稳定。但在尝试启用 LiteLLM 官方 Admin Web 控制台/ui时遇到了无法正常使用的问题。访问/ui并提交管理员密钥登录时接口返回400 Bad Request{error:Authentication Error, Not connected to DB!}2. 根因排查为什么 LiteLLM UI 无法直接使用 MySQL阅读 LiteLLM 源码后发现LiteLLM 的架构中存在两个不同层次的数据需求数据面Data Plane请求转发、流式 Token 聚合、日志审计与费用核算。这一层可以通过 LiteLLM 的 Custom Callback 机制灵活对接任何数据库如 MySQL、ClickHouse、DynamoDB。控制面Control Plane官方 Next.js Web 控制台的用户认证、JWT 会话维护、Virtual Key虚拟子密钥生成与团队配额管理。控制面强依赖 Python 版本的 Prisma ORMprisma-client-py。查看 LiteLLM 内置的litellm/proxy/schema.prisma定义model LiteLLM_VerificationToken { token String id key_name String? key_alias String? models String[] // PostgreSQL 标量数组 spend Float default(0.0) max_budget Float? permissions Json? // ... }在 Prisma 的类型系统中models String[]被定义为标量数组Scalar Array。PostgreSQL 原生支持标量数组类型。MySQL 原生不支持标量数组只有 JSON 或字符串。Prisma 编译器强制要求如果数据源配置为provider mysql则 schema 中严禁出现标量数组语法。由于 LiteLLM 官方 schema 将models等核心字段强行声明为String[]直接将DATABASE_URL指向 MySQL 会在启动初始化prisma generate/prisma migrate时直接抛错导致官方 UI 无法在 MySQL 环境下运行。此外没有控制面数据库还会带来权限管理上的问题缺少 Virtual Key 生成机制所有调用方只能共用全局LITELLM_MASTER_KEY。审计日志中无法按调用方如不同的应用或开发团队记录api_key_alias难以进行多租户维度的用量与财务分账。3. 架构方案控制面与数据面解耦为了在保留现有 MySQL 审计体系的同时启用官方 UI我们采用了双数据库解耦方案客户端 / 浏览器 │ ▼ Kong Gateway Ingress (KIC) - API 路由: /litellm/v1/... (strip-path: true) - UI 路由: /ui, /_next, /login, /v2, /key 等 (透传) │ ▼ LiteLLM Proxy Service (:4000) ┌───────────────────────────┐ │ Uvicorn / FastAPI Runtime │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ ▼ ▼ [控制面 Control Plane] [数据面 Data Plane] Neon Serverless PostgreSQL OCI MySQL HeatWave - Admin Web UI 登录会话 - 全量 API 异步审计日志 - Virtual Keys 虚拟子密钥 - Token 消耗精确计量 - 团队预算与模型白名单 - 实时汇率折算与人民币结算各组件分工如下控制面Neon PostgreSQL选用 Neon Serverless PostgreSQLAWS 新加坡 region同城直连 OCI 新加坡 ARM 节点网络延迟实测约 10.95ms。仅用于存储控制台元数据与虚拟 Key不承载高频日志写入。数据面OCI MySQL HeatWave继续承载全部对话的异步审计流水落库完全由自研的logging_hook.py接管与控制面隔离。缓存层RedisK3s 集群内网 Redis承载响应缓存与日频汇率二级缓存。4. 实施过程与踩坑记录4.1 Neon 连接池PgBouncer与 DDL 迁移冲突Neon 默认生成的连接串包含-pooler后缀即通过 PgBouncer 代理。LiteLLM 在初次连接空数据库时会自动执行prisma migrate deploy或prisma db push创建十几张元数据表。但 PgBouncer 在 Transaction 模式下不支持预编译语句Prepared Statements和部分 DDL 操作导致容器启动时报错退出Prepared statements not supported in transaction mode处理方式在配置DATABASE_URL时去除主机名中的-pooler关键字直连 5432 端口并附带?sslmoderequire参数postgresql://neondb_owner:PASSWORDep-bitter-sky-azfg5i09.c-3.ap-southeast-1.aws.neon.tech:5432/neondb?sslmoderequire4.2 ARM64 镜像构建中 Prisma CLI 依赖缺失在pyproject.toml中引入prisma0.15.0并构建 Docker 镜像时GitHub Actions 在执行多架构构建linux/amd64,linux/arm64过程中抛出异常subprocess.CalledProcessError: Command [/root/.cache/prisma-python/nodeenv/bin/npm, install, prisma5.17.0] returned non-zero exit status 127.原因分析python:3.12-slim基础镜像未安装 Node.js 与 npm。Python 的prisma包在找不到系统 Node.js 时会尝试用nodeenv在缓存目录下载并执行预编译的 Node 二进制而在精简镜像中缺少对应依赖导致执行失败退出码 127。处理方式在 Dockerfile 中通过系统包管理器安装nodejs、npm、openssl和ca-certificates。设置环境变量PRISMA_USE_GLOBAL_NODEtrue强制 Prisma 直接使用系统的 Node.js。为非 root 用户UID65532预创建可写缓存目录/tmp/prisma-cache并设置PRISMA_HOME_DIR/tmp/prisma-cache。调整后的 Dockerfile 关键部分如下FROM python:3.12-slim ENV PYTHONDONTWRITEBYTECODE1 \ PYTHONUNBUFFERED1 \ PYTHONPATH/app \ PATH/app/.venv/bin:$PATH \ PRISMA_HOME_DIR/tmp/prisma-cache \ PRISMA_USE_GLOBAL_NODEtrue WORKDIR /app RUN apt-get update apt-get install -y --no-install-recommends \ ca-certificates \ openssl \ nodejs \ npm \ rm -rf /var/lib/apt/lists/* COPY pyproject.toml uv.lock README.md ./ RUN pip install --no-cache-dir uv \ uv sync --frozen --no-dev --no-install-project \ mkdir -p /tmp/prisma-cache \ PRISMA_HOME_DIR/tmp/prisma-cache uv run prisma generate --schema/app/.venv/lib/python3.12/site-packages/litellm/proxy/schema.prisma \ chmod -R 777 /tmp/prisma-cache \ rm -rf /root/.cache COPY config.yaml ./config.yaml COPY app ./app USER 65532:65532 EXPOSE 4000 ENTRYPOINT [litellm] CMD [--config, /app/config.yaml, --host, 0.0.0.0, --port, 4000]4.3 密钥管理与 GitOps 编排数据库连接串通过 OCI Vault 托管禁止硬编码在清单或代码中在 OCI Vaultlitellm-prodcompartment中登记 Secretlitellm-database-url。在my-argocd-manifests/argocd-apps/litellm-svc-app.yaml中配置 ExternalSecretexternalSecret:enabled:truesecretStoreRef:name:oci-litellm-vault-storekind:SecretStoretarget:name:litellm-secretsdata:-secretKey:DATABASE_URLremoteRef:key:litellm-database-url-secretKey:MYSQL_PASSWORDremoteRef:key:litellm-mysql-password代码推送到my-litellm-service仓库后GitHub Actions 触发多架构构建并通过repository_dispatch远程更新 ArgoCD 清单中的image.digest实现全自动平滑更新。4.4 Kong Ingress Controller 路由配置LiteLLM 的 Admin 控制台基于 Next.js 开发除了/ui入口路径外前端还会请求大量静态资源/_next/static/...、/litellm-asset-prefix/...以及管理接口/login、/key、/user、/models等。在 ArgoCD Application 的 Helm values 中添加extraRoutes.ui-route确保相关路径正常透传至 LiteLLM PodextraRoutes:ui-route:parentGateway:kong-main-gatewayparentGatewayNamespace:defaultrules:-matches:-path:/ui-path:/litellm-asset-prefix-path:/_next-path:/fallback-path:/swagger-path:/get_favicon-path:/get_logo_url-path:/favicon.ico-matches:-path:/login-path:/v2-path:/v3-path:/auth-path:/sso-path:/onboarding-path:/invitation-matches:-path:/key-path:/user-path:/team-path:/spend-path:/budget-matches:-path:/models-path:/model-path:/routes-path:/config-path:/settings-matches:-path:/health-path:/cache-path:/alerting5. 端到端功能验证5.1 启动与建表验证观察 Pod 日志确认 Prisma 自动连接 Neon PostgreSQL 完成表结构初始化All migrations have been successfully applied. 2026-08-30 08:54:21,253 - litellm_proxy_extras - INFO - prisma migrate deploy completed 2026-08-30 08:54:50,896 - litellm_proxy_extras - INFO - Migration diff applied successfully 2026-08-30 08:54:50,896 - litellm_proxy_extras - INFO - Post-migration sanity check completed INFO: Application startup complete. Uvicorn running on http://0.0.0.0:40005.2 控制台登录与虚拟 Key 创建访问https://gw.jppwl.asia/ui使用管理员 Master Key 登录成功控制台正常展示各模块概览。调用/key/generate接口或通过 UI 页面创建具有额度限制的虚拟 Keycurl-XPOSThttp://gw.jpgcp.cloud:31850/key/generate\-HAuthorization: Bearer$LITELLM_MASTER_KEY\-HContent-Type: application/json\-d{ key_alias: team-test-key, models: [gemini-3.7-flash], max_budget: 10.0 }返回生成的新 Keysk-fnhh6MRvMu-sZ3FElYhaOg。5.3 携带虚拟 Key 发起调用与 MySQL 审计验证使用新生成的子 Key 发送请求curl-XPOSThttp://gw.jpgcp.cloud:31850/litellm/v1/chat/completions\-HAuthorization: Bearer sk-fnhh6MRvMu-sZ3FElYhaOg\-HContent-Type: application/json\-d{ model: gemini-3.7-flash, messages: [{role: user, content: hello}], max_tokens: 10 }接口正常返回响应并在响应头中返回该 Key 的预算消耗数据HTTP/1.1 200 OK X-Litellm-Key-Max-Budget: 10.0 X-Litellm-Key-Spend: 0.000032直连 OCI MySQL 查询litellm_db.llm_request_logsSELECTrequest_id,api_key_alias,model_requested,total_tokens,cost_usd,cost_cny,fx_rateFROMllm_request_logsORDERBYidDESCLIMIT1;查询结果显示该笔调用的 Token 数量、实时汇率以及人民币费用已精确入库且api_key_alias正确记录为team-test-key。6. 总结通过控制面PostgreSQL与数据面MySQL解耦的方式我们解决了 LiteLLM 官方 UI 对 PostgreSQL 标量数组强依赖导致的兼容性问题。改造后的架构具备以下特点职责分离控制面负责用户认证、虚拟 Key 生成和配额管控数据面负责高并发请求的异步落库与人民币计费互不影响。故障隔离控制面数据库的偶尔抖动或冷启动不会阻塞核心 API 的转发流程和 MySQL 审计日志写入保障了线上调用链路的高可用。零额外成本利用 Neon Serverless PostgreSQL 的免费额度搭配现有 OCI MySQL 与 K3s 集群在不新增服务器资源的前提下完成了全套功能的搭建。