news 2026/9/10 14:36:14

Open Notebook 数据库配置指南:基于 SurrealDB 的环境变量、部署拓扑与多实例隔离

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Open Notebook 数据库配置指南:基于 SurrealDB 的环境变量、部署拓扑与多实例隔离

Open Notebook 数据库配置指南:基于 SurrealDB 的环境变量、部署拓扑与多实例隔离

【免费下载链接】open-notebookAn Open Source implementation of Notebook LM with more flexibility and features项目地址: https://gitcode.com/GitHub_Trending/op/open-notebook

Open Notebook 使用 SurrealDB 作为其唯一的主数据存储,承载笔记、来源、笔记本、凭证等全部业务数据。本文基于 docs/5-CONFIGURATION/database.md 展开,完整覆盖五个SURREAL_*核心变量的语义与默认值、三种主流部署拓扑下的连接串写法、端口暴露的安全边界,以及如何用"同一实例多 Namespace/Database"支持多个独立部署,并延伸到仓库源码层的连接建立与自动迁移机制。

SurrealDB 在 Open Notebook 中的角色

从源码结构看,SurrealDB 是 Open Notebook 的持久化基座,而非可选组件:

  • 全部数据访问都收敛在 open_notebook/database/repository.py 这一层,对外提供repo_queryrepo_createrepo_upsertrepo_relate等通用封装,业务模块通过它们读写 SurrealDB;
  • 数据库结构(表、关系、索引)完全由版本化迁移脚本维护,位于 open_notebook/database/migrations 目录下,以1.surrealql23.surrealql编号排列,每个迁移都配有一个N_down.surrealql回滚脚本;
  • 迁移执行器位于 open_notebook/database/async_migrate.py,版本号记录在_sbl_migrations表中(不存在时视为版本 0,即全新库)。

因此,数据库连接配置是否正确直接决定了 API、Worker 能否启动并完成自动迁移,这是本文将环境变量放在第一优先级讲解的原因。

五个核心环境变量:字段语义与默认值

Open Notebook 通过环境变量定位并认证 SurrealDB,官方文档 docs/5-CONFIGURATION/environment-reference.md 将它们标为"必需"项:

变量必需?默认值说明
SURREAL_URLws://surrealdb:8000/rpcSurrealDB WebSocket 连接地址,路径固定为/rpc(RPC 端点)
SURREAL_USERrootSurrealDB 登录用户名
SURREAL_PASSWORDrootSurrealDB 登录密码
SURREAL_NAMESPACEopen_notebook逻辑命名空间(Namespace)
SURREAL_DATABASEopen_notebookNamespace 下的具体数据库(Database)名

实际代码与文档互为印证:在 open_notebook/database/repository.py 中,连接 URL、密码、Namespace、数据库名均从环境变量读取,其中密码读取SURREAL_PASSWORD、缺失时回退SURREAL_PASS再回退字面量"root",而 Namespace 与数据库名缺省时统一回退"open_notebook"

连接建立的真实调用链

repository.py 中的db_connection()是每次访问数据库都会执行的上下文管理器:

async with db_connection() as connection: # connection 已登录并 use 到目标 Namespace/Database

其内部顺序为:

  1. SURREAL_URL构造AsyncSurreal客户端;
  2. 调用signin(),传入用户名(SURREAL_USER)与密码(见上文回退逻辑);
  3. 调用use(get_database_namespace(), get_database_name())切到目标逻辑空间;
  4. 业务查询结束后自动close()

这解释了为什么五者必须同时正确:仅 URL 正确而SURREAL_USER/SURREAL_PASSWORD与 SurrealDB 启动参数不一致会认证失败;Namespace/Database 与迁移目标不一致则数据会"落错库"。

向后兼容的遗留变量

代码保留了早期命名方式的回退逻辑:未设置SURREAL_URL时,会按SURREAL_ADDRESS(默认localhost)与SURREAL_PORT(默认8000)拼出ws://{address}/rpc:{port}(见 repository.py)。新部署请直接使用规范的SURREAL_URL全量 URL。

三种部署拓扑与推荐配置

官方文档 docs/5-CONFIGURATION/database.md 给出了三个典型场景,区别只在于SURREAL_URL的主机名怎么写——这正是最容易配错的地方。

场景一:SurrealDB 与 Open Notebook 同属一个 docker compose(推荐)

这也是 docs/1-INSTALLATION/docker-compose.md 描述的推荐安装方式。容器之间通过 compose 内部网络通信,主机名直接使用服务名surrealdb

SURREAL_URL="ws://surrealdb:8000/rpc" SURREAL_USER="root" SURREAL_PASSWORD="root" SURREAL_NAMESPACE="open_notebook" SURREAL_DATABASE="open_notebook"

仓库根目录的 docker-compose.yml 即为这一拓扑的标准落地:surrealdb服务以rocksdb:/mydata/mydatabase.db启动、数据卷映射./surreal_data:/mydataopen_notebook服务通过depends_on等待其就绪,两个服务共用同一份SURREAL_USER/SURREAL_PASSWORD(通过${SURREAL_USER:-root}插值,可在.env中一并覆盖,保证两侧始终同步)。

场景二:SurrealDB 跑在宿主机、Open Notebook 跑在 Docker

此时容器内无法使用surrealdb服务名,需要指向宿主机 IP 或 Docker 提供的特殊域名host.docker.internal

SURREAL_URL="ws://your-machine-ip:8000/rpc" # 或 host.docker.internal SURREAL_USER="root" SURREAL_PASSWORD="root" SURREAL_NAMESPACE="open_notebook" SURREAL_DATABASE="open_notebook"

重要安全提示(原文档强调):如果 SurrealDB 容器按文档默认只把端口发布到127.0.0.1,那么宿主机 IP 上其实是连不通的。若确实需要从宿主机侧访问,请有意识地重新发布端口——参考仓库根目录的 docker-compose.override.yml.example,并且务必放到防火墙或 SSH 隧道之后,同时把SURREAL_USER/SURREAL_PASSWORD换成真实强凭证。

场景三:SurrealDB 与 Open Notebook 跑在同一台机器

适用于两者都直接跑在宿主机本地的场景,或者已弃用的单容器方案(见 docs/1-INSTALLATION/single-container.md,v2 将移除,仓库中仍有示例 examples/docker-compose-single.yml,其内部以ws://localhost:8000/rpc覆盖连接):

SURREAL_URL="ws://localhost:8000/rpc" SURREAL_USER="root" SURREAL_PASSWORD="root" SURREAL_NAMESPACE="open_notebook" SURREAL_DATABASE="open_notebook"

三种场景仅替换第一行主机名,其余四行保持一致,这正是 Open Notebook 支持"换库不换逻辑"的设计体现。

端口暴露边界:默认只绑 127.0.0.1 的用意

仓库根目录 docker-compose.yml 对 SurrealDB 端口做了刻意约束:

ports: # Bound to localhost only: the open_notebook service reaches this over # the internal compose network regardless, so the host port is purely # for local debugging (e.g. Surrealist, `surreal sql`). - "127.0.0.1:8000:8000"

注释写得很清楚:Open Notebook 容器走 compose 内部网络,根本不需要宿主机把 8000 端口暴露给外部;宿主机的端口仅用于本地调试(如用 Surrealist 可视化工具或surreal sql命令行)。若改成0.0.0.0,任何能触达宿主机的人都可以用默认的root:root以管理员身份连接数据库。

若确实需要跨机器访问(例如在笔记本上用 Surrealist 连开发机),官方提供了 docker-compose.override.yml.example:

services: surrealdb: ports: !override - "8000:8000"

注意其中的关键细节:必须使用!override语法替换而非合并 ports(Docker Compose 需 v2.24.4+),否则新旧两条端口规则共存会报 "port is already allocated"。更稳妥的做法是:先通过 SSH 隧道或防火墙限定访问来源,再以真实凭证启动 SurrealDB(把SURREAL_USER/SURREAL_PASSWORD写入.env,两个服务会自动同步读取,见 docker-compose.yml 的注释说明,密码含空格时以 exec 列表形式传参避免被 shell 拆分)。

启动期的自动迁移:为什么"连上库"还不够

正确配置好五个环境变量后,启动流程还有一个与数据库直接相关的环节:自动执行迁移

在 api/main.py 中,_run_database_migrations()会在 FastAPI 的lifespan里被调用:

  1. 先执行_wait_for_database()做只读的就绪探测——ping()会真实发起一次连接并查询_sbl_migrations版本,但对连接失败采用指数退避重试(不重试迁移本身,避免掩盖真正的 schema 错误),从而容忍 compose 环境下 API 比数据库先起的时序问题;
  2. 对比当前版本与内置迁移列表长度(needs_migration()),有未应用迁移时逐条执行N.surrealql
  3. 成功后在_sbl_migrations表写入新版本号;失败则快速失败(fail fast),拒绝用过期 schema 启动 API。

迁移脚本的加载逻辑见 open_notebook/database/async_migrate.py:up_migrations列表按序注册了open_notebook/database/migrations/1.surrealql23.surrealqldown_migrations对应每个N_down.surrealql,支持单步回滚。对应测试可参考 tests/test_startup_migration_retry.py。

实践意义:如果你"新建"了一套带自定义 Namespace/Database 的库却忘了在其中执行迁移,API 会启动失败或报 schema 缺失——因为迁移只对代码默认与连接目标指向的那套逻辑空间自动执行。这也是为什么文档建议保持默认的open_notebook值或确保每个新库都经过一次正常启动。

写入重试与网络代理两个隐藏配置

除了五个核心变量,数据库行为还受两组环境变量影响,均记录在 docs/5-CONFIGURATION/environment-reference.md:

命令级重试(数据库写入的容错)

变量默认值说明
SURREAL_COMMANDS_RETRY_ENABLEDtrue是否启用失败重试
SURREAL_COMMANDS_RETRY_MAX_ATTEMPTS3最大重试次数
SURREAL_COMMANDS_RETRY_WAIT_STRATEGYexponential_jitter退避策略:exponential_jitter/exponential/fixed/random
SURREAL_COMMANDS_RETRY_WAIT_MIN1单次最小等待(秒)
SURREAL_COMMANDS_RETRY_WAIT_MAX30单次最大等待(秒)

在多人写入或事务冲突(repository 对可重试冲突仅以 debug 级别记录日志,见 repository.py)的场景下,合理调低MAX_ATTEMPTS、收紧等待区间,可以让失败更早暴露。

NO_PROXY:WebSocket 代理陷阱

Open Notebook 的 SurrealDB SDK 通过 WebSocket 通信,而较新版本的websockets库会把ws://连接也塞进已配置的 HTTP 代理,导致内部数据库主机被代理以 HTTP 403 拒绝,API 与 Worker 双双无法启动。因此NO_PROXY必须显式包含内部主机host.docker.internal(Docker 宿主机场景)与surrealdb(compose 服务名)。

Open Notebook 在 open_notebook/utils/proxy.py 的ensure_internal_no_proxy()中会自动host.docker.internal,surrealdb,localhost,127.0.0.1合并进no_proxy/NO_PROXY作为安全网,但官方文档仍建议用户自行显式设置,例如:

NO_PROXY=localhost,127.0.0.1,host.docker.internal,surrealdb,.local

注意该模块在 repository.py 导入时就执行(API 与 Worker 两条进程路径都会触发),可见这是数据库连通性的前置保障。

多实例共库:一个 SurrealDB 跑多套 Open Notebook

SurrealDB 的逻辑隔离分两层:Namespace(命名空间)之下可以有多个Database(数据库)。Open Notebook 官方文档明确说明:想为不同用户部署多套 Open Notebook,无需部署多个 SurrealDB 实例,只需复用同一实例并用不同的 Namespace/Database 对即可。

结合本文前面的机制,落地方式如下:

  1. 每套 Open Notebook 部署使用各自唯一的SURREAL_NAMESPACESURREAL_DATABASE(例如SURREAL_NAMESPACE=tenant_a+SURREAL_DATABASE=open_notebook,另一套用tenant_b);
  2. 每套部署首次正常启动时会自动把迁移执行到自己的 Namespace/Database 中,数据彼此物理隔离;
  3. 所有套共享同一个 SurrealDB 连接端点与认证账号(也可在 SurrealDB 侧按用户权限做更细的账号拆分,但 Open Notebook 侧只需关注这五个变量)。

需要提醒的是:凭证数据在库内经OPEN_NOTEBOOK_ENCRYPTION_KEY加密存储(见 docs/5-CONFIGURATION/environment-reference.md 与 docker-compose.yml),多租户共库时每套部署务必使用不同的加密密钥,避免一处泄漏殃及全部。

常见问题排查速查

结合 docs/1-INSTALLATION/docker-compose.md 与 docs/6-TROUBLESHOOTING/connection-issues.md 的思路,把排查项收敛为三条:

  1. 启动即失败、日志含认证错误:核对SURREAL_USER/SURREAL_PASSWORD是否与 surrealdb 容器启动参数(--user/--pass)一致。默认双root,生产必须改;
  2. 迁移报错或表缺失:确认SURREAL_NAMESPACE/SURREAL_DATABASE与首次初始化时一致,且该 Namespace/Database 确实存在(SurrealDB 通常会在首次use时自动创建,但若你手动建库需保证迁移曾成功执行);
  3. 容器间连不通:Docker 内请用服务名surrealdb(同 compose)或host.docker.internal(宿主机),不要写localhost;同时确认端口未被防火墙拦截、NO_PROXY已放行内部主机。

全部变量总表与按场景组合的.env示例(Minimal / Production / Corporate 等)可直接查阅 docs/5-CONFIGURATION/environment-reference.md,它与本文共同构成 Open Notebook 数据库配置的完整参考。

【免费下载链接】open-notebookAn Open Source implementation of Notebook LM with more flexibility and features项目地址: https://gitcode.com/GitHub_Trending/op/open-notebook

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:30:00

YOLOv5+ArcFace人脸检测与特征提取工程闭环实践

简介:本资源是一套基于YOLOv5与ArcFace的人脸检测与识别完整实现方案,面向计算机视觉初学者及AI项目开发者,解决从人脸定位到特征匹配的一体化技术落地问题,适用于安防监控、门禁系统、身份核验等实际场景。压缩包共54个文件&…

作者头像 李华
网站建设 2026/9/10 14:25:50

Spring Boot拦截器中获取requestBody的最佳实践

1. 为什么需要获取requestBody? 在Spring Boot开发中,拦截器(Interceptor)是处理HTTP请求的重要组件。但很多开发者都遇到过这样的困境:在拦截器的preHandle方法中,无法直接获取到请求体(requestBody)的内容。这主要是因为Servlet…

作者头像 李华