initdb.tar.zst 的生成时机
bootstrap_timeline() (tenant.rs:5269) 在 timeline 创建时 执行:
cargo neon tenant create / timeline create
│
└── pageserver.bootstrap_timeline()
│
├── NO existing_initdb (新建分支):
│ 1. run_initdb() // 调系统 initdb 命令,生成空 PG 集群
│ 2. upload_initdb() // 压缩上传 →remote storage 的 initdb.tar.zst
│ 3. import_pgdata() // 导入 pageserver 内部 layer 格式
│
└── HAS existing_initdb (从已有分支 fork):
1. 复制/下载已有 timeline 的 initdb.tar.zst
2. 解压 →导入 pageserver
initdb.tar.zst 就是 Postgres initdb 命令的原始输出 —一个空白的数据库模板(template1, template0, postgres 库),不包含任何 neon 相关内容。
后续 basebackup 的构成
compute 请求 basebackup
│
└── pageserver 内部:
├── 起点: initdb 导入时创建的初始 layer (等价于 initdb.tar.zst 的内容)
├── + 后续 WAL 回放产生的 delta layer
├── + checkpoint 产生的 image layer
│
└── 合成 →tar 流 →compute 拿到完整数据库快照
所以 basebackup = 空 initdb 快照 + 所有后续 WAL/checkpoint 增量。
initdb.tar.zst 里到底有没有 neon 扩展?
下表详细说明了 initdb.tar.zst 中包含的内容:
| 内容 | 来源 | 在 initdb.tar.zst 中? |
|---|---|---|
| template1/template0/postgres | initdb 命令 | ✅ 有 |
| neon.so 共享库 | postgresql.conf 配置 | ❌ 没有(运行时加载) |
| neon schema | CREATE SCHEMA neon | ❌ 没有 |
| neon extension (SQL) | CREATE EXTENSION neon | ❌ 没有 |
| 用户角色/数据库 | apply_config() | ❌ 没有 |
initdb.tar.zst 里 只有 initdb 原生的三个空数据库。neon 扩展是后来 apply_config() 通过 SQL 创建的,记录在后续 WAL/layer 中。
验证
如果你用 --update-catalog 创建并启动过一次,可以这样验证:
# 第一次启动后,pageserver 的 remote storage 里会有 initdb.tar.zst
ls .neon/local_fs_remote_storage/pageserver/tenants/<tenant_id>/timelines/<timeline_id>/
# 你会看到:
# initdb.tar.zst ←timeline 创建时生成,不会再变
# layers/ ←后续的增量数据(neon 扩展的变更在这里)
总结:initdb.tar.zst 永远只是 initdb 快照,不包含 neon 扩展。basebackup 在运行时会叠加所有后续 layer,所以计算节点拿到的完整快照包含 neon 扩展。
cargo neon endpoint start
│
▼
compute_ctl (Rust)
│
├─► 1. sync_safekeepers →获取 LSN
│
├─► 2. get_basebackup @LSN ←── pageserver(从 timeline 当前状态生成tar)
│ │
│ └── 数据来源:pageserver 存储的 layer 文件 + WAL
│ (保存在 .neon/pageserver_<id>/ 和
│ local_fs_remote_storage/pageserver/)
│
├─► 3. 解压 basebackup →pgdata/
│
├─► 4. start_postgres
│
└─► 5. configure_as_primary()
│
├── if skip_pg_catalog_updates == false:
│ apply_config() →apply_spec_sql()
│ ├── CreateSchemaNeon →CREATE SCHEMA IF NOT EXISTS neon
│ └── HandleNeonExtension →CREATE EXTENSION neon WITH SCHEMA neon
│
└── post_apply_config() (始终执行,但只做 ALTER EXTENSION neon UPDATE)
关键点:timeline 创建时是空的
当 cargo neon timeline create 时,使用的是 Bootstrap 模式(neon_local.rs:1213-1214):
mode: TimelineCreateRequestMode::Bootstrap {
existing_initdb_timeline_id: None, // 没有模板!
pg_version: Some(args.pg_version),
},
新 timeline 在 pageserver 中是完全空的,没有任何数据库内容。第一次启动时 Postgres 在 pageserver 上层运行出一个空的数据库集群,所有数据(包括 neon
schema/extension)都是在运行时通过 SQL 创建的。