- 数据库
- 后端
【免费下载链接】convex-backend
The open-source reactive database for app developers
导读
Convex 是一个开源响应式数据库后端,默认以 SQLite 作为本地持久化存储;但对于需要高可用与托管运维的生产环境,官方推荐将后端连接到托管式 Postgres 或 MySQL 服务。本文基于仓库 self-hosted/advanced/postgres_or_mysql.md 展开,完整讲解POSTGRES_URL、MYSQL_URL、INSTANCE_NAME、DO_NOT_REQUIRE_SSL等环境变量的用法与数据库命名规则,并结合仓库源码(如 crates/db_connection/src/lib.rs、crates/clusters/src/lib.rs、self-hosted/docker-build/run_backend.sh)剖析后端如何解析连接串、派生数据库名、注入 SSL 参数,让读者既能照着文档完成 Neon/PlanetScale/本地 Postgres/MySQL 的接入,也能理解底层实现原理。
一、为什么生产环境要考虑 Postgres 或 MySQL
Convex 后端本身被设计为同时兼容 SQLite、Postgres 与 MySQL 三种数据库。默认情况下,self-hosted/docker/docker-compose.yml 中的 Docker 镜像使用本地 SQLite 存储(数据存放在 Docker volumedata:/convex/data中)。
- SQLite 方案适合本地开发与快速起步,是官方推荐的入门配置(详见 self-hosted/README.md);
- 如果运行的是需要保证可用性(guaranteed uptime)的生产负载,则应优先选择托管式 Postgres 或 MySQL 服务,例如 Neon(Postgres)或 PlanetScale(MySQL/Vitess);
- 官方测试确认 Convex 后端可与Postgres v17和MySQL v8协同工作,其他版本也可能兼容,但未做验证。
需要特别注意一个硬性约束:后端必须与数据库托管在同一区域,且网络距离尽可能近。后端与数据库之间的任何额外延迟都会直接拖累查询性能,这一点在 postgres_or_mysql.md 中被反复强调。
1.1 迁移前先导出数据
在不同数据库提供方之间迁移时,务必先使用官方 CLI 导出数据:
npx convex export该命令会将当前部署的数据导出为文件,随后再在新数据库环境上执行npx convex deploy重新部署 Convex 函数(详见下文“部署后的重部署”说明)。
二、环境变量速查表
以下变量在接入外部数据库时最常用,全部在 docker-compose.yml 的environment段中透传,并由容器入口脚本 self-hosted/docker-build/run_backend.sh 消费:
| 环境变量 | 作用 | 取值要点 |
|---|---|---|
POSTGRES_URL | 指定 Postgres 连接串,优先级最高 | 不含数据库名与查询参数,形如postgresql://user@host:5432 |
MYSQL_URL | 指定 MySQL 连接串 | 不含数据库名,形如mysql://user:pass@host:3306 |
DATABASE_URL | 已弃用,兼容旧行为,等价于 Postgres 连接 | 设置时会打印弃用警告 |
DO_NOT_REQUIRE_SSL | 关闭对数据库连接的 SSL 强制要求 | 仅建议本地开发使用;设置后若存在 SSL 仍会优先使用 |
INSTANCE_NAME | 指定实例名,间接决定数据库名 | 默认convex-self-hosted,连字符会被替换为下划线 |
INSTANCE_SECRET | 实例密钥,与INSTANCE_NAME配对 | 后端启动必需 |
从 run_backend.sh 的入口逻辑可以看出完整的优先级链:
if [ -n "$POSTGRES_URL" ]; then DB_SPEC="$POSTGRES_URL" DB_FLAGS=("${POSTGRES_DB_FLAGS[@]}") # --db postgres-v5 elif [ -n "$MYSQL_URL" ]; then DB_SPEC="$MYSQL_URL" DB_FLAGS=("${MYSQL_DB_FLAGS[@]}") # --db mysql-v5 elif [ -n "$DATABASE_URL" ]; then # 弃用警告,按 Postgres 处理以保持向后兼容 else DB_SPEC="$SQLITE_DB" # 回退到 SQLite fi即:POSTGRES_URL>MYSQL_URL>DATABASE_URL(弃用)> SQLite 回退。最终这些参数被拼装为convex-local-backend的命令行参数--db postgres-v5 <DB_SPEC>或--db mysql-v5 <DB_SPEC>(postgres-v5/mysql-v5对应 crates/clusters/src/db_driver_tag.rs 中的DbDriverTag枚举值),同时--instance-name "$INSTANCE_NAME"、${DO_NOT_REQUIRE_SSL:+--do-not-require-ssl}等参数也会一并传入。
三、连接 Neon 上的托管 Postgres(生产场景)
3.1 获取连接串并建库
从 Neon 控制台复制连接字符串,并创建后端专用的数据库:
export DATABASE_CONNECTION='<connection string>' psql $DATABASE_CONNECTION -c "CREATE DATABASE convex_self_hosted"3.2 构造 POSTGRES_URL
POSTGRES_URL是不含数据库名和查询参数的连接串。以 Neon 为例,其结尾应为neon.tech。文档给出了用sed剥掉路径与查询串的做法:
export POSTGRES_URL=$(echo $DATABASE_CONNECTION | sed -E 's/\/[^/]+(\?.*)?$//')该正则将形如postgresql://user:pass@ep-xxx.neon.tech/convex_self_hosted?sslmode=require的完整连接串中的/convex_self_hosted?sslmode=require部分剥离,得到postgresql://user:pass@ep-xxx.neon.tech。
3.3 在托管平台上注册环境变量
- 若运行在 Fly.io 等平台,通过平台命令注册密钥:
fly secrets set POSTGRES_URL=$POSTGRES_URL- 若在本机运行,直接重启后端容器即可让环境变量生效(
POSTGRES_URL已在 docker-compose.yml 的environment中声明透传)。
3.4 验证连接并重部署函数
启动后端后检查日志,应能看到类似Connected to Postgres的行。这一日志来自 crates/db_connection/src/lib.rs:
tracing::info!("Connected to Postgres database: {}", deployment_name);另外,切换到新数据库后,必须重新部署已有的 Convex 函数:
npx convex deploy3.5 为什么 URL 中不能带数据库名:源码剖析
在 crates/clusters/src/lib.rs 中,Postgres 分支会校验连接串路径必须为空或/,否则直接报错:
anyhow::ensure!( cluster_url.path() == "" || cluster_url.path() == "/", "cluster url already contains db name: {}", cluster_url.path() );随后后端依据deployment_name(即实例名)自动拼接数据库名:
let db_name = deployment_name.replace('-', "_"); cluster_url.set_path(&db_name);这正是“不要在POSTGRES_URL中包含数据库名”的根本原因——数据库名由后端根据实例名自动计算并写入连接串路径。
四、本地连接 Postgres(开发场景)
本地已有 Postgres 实例时:
psql postgres -c "CREATE DATABASE convex_self_hosted"然后设置连接串并关闭 SSL 强制要求:
export POSTGRES_URL='postgresql://<your-username>@host.docker.internal:5432' export DO_NOT_REQUIRE_SSL=1 docker compose up要点说明:
host.docker.internal用于从 Docker 容器内访问宿主机上的 Postgres;- 同样不要在
POSTGRES_URL中包含数据库名; DO_NOT_REQUIRE_SSL对应后端--do-not-require-ssl参数。其语义在 crates/local_backend/src/config.rs 中有明确注释:关闭后不强制要求数据库连接使用 SSL,但如果数据库支持 SSL,仍会优先使用;官方注释强调该选项“只应在测试中设置”。
4.1 SSL 参数如何注入:源码验证
在 crates/clusters/src/lib.rs 中,adjust_postgres_url会根据require_ssl与require_leader标志向连接串追加查询参数:
if require_ssl { cluster_url .query_pairs_mut() .append_pair("sslmode", "require"); } if require_leader { cluster_url .query_pairs_mut() .append_pair("target_session_attrs", "read-write"); }因此设置了DO_NOT_REQUIRE_SSL时不会注入sslmode=require;而在 Neon 等托管场景(默认强制 SSL),后端会注入sslmode=require,并对会话附加target_session_attrs=read-write(要求连接到可写的 leader 节点,见 crates/db_connection/src/lib.rs 的TargetSessionAttrs::ReadWrite)。
五、本地连接 MySQL(开发场景)
mysql -e "CREATE DATABASE convex_self_hosted;" export MYSQL_URL=mysql://<your-username>@host.docker.internal:3306 export DO_NOT_REQUIRE_SSL=1 docker compose up与 Postgres 一致:数据库名由后端推导,URL 中不要带库名。
六、连接 PlanetScale 上的 MySQL(生产场景)
在 PlanetScale 创建数据库,必须命名为convex_self_hosted,然后:
export MYSQL_URL=mysql://<your-username>:<your-password>@aws.connect.psdb.cloud docker compose up6.1 MySQL 分支的源码行为
从 crates/clusters/src/lib.rs 可以看出 MySQL 分支与 Postgres 的关键差异:后端不会把数据库名写入连接串路径,而是保持无库连接、在持久化层按需USE对应的库:
// NOTE: We do not set any database so we can reuse connections between // database. The persistence layer will select the correct database. if require_ssl { cluster_url .query_pairs_mut() .append_pair("require_ssl", "true") .append_pair("verify_ca", "true"); } let db_name = deployment_name.replace('-', "_");即:db_name同样由实例名推导(-替换为_),但以独立字段PersistenceArgs::MySql { url, db_name, ... }传递,供 crates/db_connection/src/lib.rs 中ConvexMySqlPool连接后选择数据库。MySQL 路径还要求连接串用户名非空(crates/clusters/src/lib.rs),若缺失会报cluster url username must be set且不打印完整 URL 以防泄露密码。
七、数据库命名规则与 INSTANCE_NAME
后端使用的持久化数据库名 = 实例名(instance name)中-替换为_后的结果:
| 实例名 | 实际连接的数据库 |
|---|---|
convex-self-hosted(默认) | convex_self_hosted |
your-instance-name | your_instance_name |
在 Docker 容器中通过INSTANCE_NAME环境变量设置实例名。例如使用 Postgres:
export POSTGRES_URL='<connection string>' export INSTANCE_NAME='your-instance-name' psql $POSTGRES_URL -c "CREATE DATABASE your_instance_name;"源码侧,LocalConfig::name()(crates/local_backend/src/config.rs)在未设置INSTANCE_NAME时回退到DEV_INSTANCE_NAME:
pub fn name(&self) -> String { self.instance_name .clone() .unwrap_or(DEV_INSTANCE_NAME.to_owned()) }而DEV_INSTANCE_NAME定义于 crates/keybroker/src/lib.rs,取自常量文件 crates/keybroker/dev/instance_name.txt(内容为carnitas),用于本地开发;Docker 镜像的入口脚本 run_backend.sh 则始终透传--instance-name "$INSTANCE_NAME",因此容器内默认实例名由镜像默认值决定(即文档所述convex-self-hosted)。随后deployment_name.replace('-', "_")即产生convex_self_hosted,这与前文所有建库命令中的库名完全对应。
八、连接流程全景:从环境变量到持久化层
综合 run_backend.sh、crates/db_connection/src/lib.rs 与 crates/clusters/src/lib.rs,一条完整调用链如下:
- 容器入口脚本读取
POSTGRES_URL/MYSQL_URL(或回退 SQLite),组装--db postgres-v5/--db mysql-v5与--do-not-require-ssl、--instance-name等参数; convex-local-backend解析参数(LocalConfig),得到DbDriverTag、db_spec(连接串)、实例名;persistence_seed/connect_persistence(crates/db_connection/src/lib.rs)调用persistence_args_from_cluster_url(crates/clusters/src/lib.rs):- 校验用户名非空、路径不含库名;
- Postgres:路径写入推导出的库名,按需注入
sslmode=require与target_session_attrs=read-write; - MySQL:保持无库连接,注入
require_ssl=true&verify_ca=true,库名单独传递;
- 创建连接池(
PostgresPersistence::create_pool/ConvexMySqlPool::new),初始化持久化层; - 日志分别输出
Connected to Postgres database: {deployment_name}或Connected to MySQL database: {db_name}(crates/db_connection/src/lib.rs 与 crates/db_connection/src/lib.rs)。
九、常见问题与注意事项
- 连接串必须可被 URL 解析:后端使用 Rust
url库解析连接串,Postgres 路径带库名会直接报错;用户名缺失会报cluster url username must be set。 - SSL 策略:托管服务(Neon、PlanetScale)默认强制 SSL;本地开发可用
DO_NOT_REQUIRE_SSL=1关闭强制要求,但官方建议仅测试环境使用。 - 数据库需预先创建:后端不会自动建库,所有示例都先用
psql/mysql客户端显式CREATE DATABASE。 - 迁移数据与函数:切换数据库提供方前先
npx convex export导出数据;切换后需npx convex deploy重新部署函数。 - 延迟敏感:后端与数据库必须在同一区域就近部署,否则查询性能会显著下降。
DATABASE_URL已弃用:旧配置中若使用DATABASE_URL,启动日志会打印弃用警告,并仍按 Postgres 语义处理以保持向后兼容(见 run_backend.sh)。
十、扩展阅读
- self-hosted/README.md:自托管总览,包含 Docker 启动、admin key 生成与前端对接;
- self-hosted/docker/docker-compose.yml:完整环境变量清单;
- self-hosted/advanced/hosting_on_own_infra.md:自有基础设施托管方案;
- self-hosted/advanced/fly/README.md:Fly.io 托管方案(含 secrets 配置);
- self-hosted/advanced/railway/README.md:Railway 托管方案;
- self-hosted/advanced/upgrading.md:版本升级指南;
- crates/db_connection/src/lib.rs 与 crates/clusters/src/lib.rs:持久化连接与连接串解析的实现源码。
- 数据库
- 后端
【免费下载链接】convex-backend
The open-source reactive database for app developers
相关推荐
使用 Redis 作为 sccache 缓存后端:环境变量、连接协议与源码级配置指南
使用 Redis 作为 sccache 缓存后端:环境变量、连接协议与源码级配置指南 导读 本文以 sccache 官方文档 docs/Redis.md htt
开发工具构建工具OpenMetadata Prefect 管道连接器配置指南:从 Prefect Cloud 到自托管 Server 的接入与实现原理
OpenMetadata Prefect 管道连接器配置指南:从 Prefect Cloud 到自托管 Server 的接入与实现原理 本篇技术指南以 Open
数据目录数据血缘数据治理后端MCP 服务Prisma 1.13 自托管服务器与数据库连接器完全指南:Docker 部署、认证与 MySQL/Postgres 配置
Prisma 1.13 自托管服务器与数据库连接器完全指南:Docker 部署、认证与 MySQL/Postgres 配置 Prisma API 运行在 Pri
后端数据库GraphQL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考