Neon Pageserver Storage Shard 扩容分析
Neon pageserver 的扩容通过 Storage Shard 机制实现。这不是传统意义上对单个 pageserver 水平扩展而是两层扩容策略1. Tenant Sharding分片 —将租户数据打散到多个 pageserver 节点上2. Node Scale-out节点伸缩 —增减 pageserver 物理节点两者由 storage controller 统一管理。---一、架构总览架构总览Neon Storage Shard 架构概览用户/控制面neon_local CLI / storcon_cli / REST API↓ HTTP callsStorage Controller (Rust)Scheduler(AZ感知)Reconciler(执行差异)TenantShard(Intent/Observed)DB: PostgreSQL (tenant_shards, nodes 表)↓ gRPC/HTTPPageserver(shard 0)Pageserver(shard 1)Pageserver(shard N)关键角色组件位置职责Storage Controllerstorage_controller/src/service.rs (~10K行)核心编排器管理所有 shard placement、split、migrationPageserverpageserver/数据平面存储实际 data layersTenant Managerpageserver/src/tenant/mgr.rs管理本地 shard 集合DBstorage_controller/migrations/持久化 tenant_shards nodes---二、Shard 概念模型核心类型定义在 libs/utils/src/shard.rs 和 libs/pageserver_api/src/shard.rs┌────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────┐│ 类型 │ 说明 │├────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┤│ TenantShardId {tenant_id, shard_number, shard_count} │ 全局唯一标识 │├────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┤│ ShardCount (u8) │ 总分片数0unsharded │├────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┤│ ShardNumber (u8) │ 0-based 索引最多 255 │├────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┤│ ShardStripeSize │ 默认 4096 页16 MiB决定连续 block 同放一个 shard │├────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┤│ ShardIdentity │ {number, count, stripe_size, layout} —包含 key→shard映射 │└────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┘Key 到 Shard 的映射用 MurmurHash32与 Postgres smgr 兼容hash murmurhash32(rel_node) murmurhash32(block_num / stripe_size)shard_number hash % shard_count数据分三类- local —只存一个 shard- global —存所有 shard如 rel_size- disposable —split 后可丢弃不属于本 shard 的数据---三、三种扩容操作1. Tenant Shard Split租户分片拆分将租户从一个 shard 拆成多个 shards分布到更多 pageserver 上。API: PUT /control/v1/tenant/:tenant_id/shard_split触发方式:# CLIstorcon_cli tenant-shard-split --tenant-idid --new-shard-countN# APIcurl -X PUT http://controller:PORT/control/v1/tenant/tid/shard_split \-d {new_shard_count: N}执行流程 (service.rs →tenant_shard_split()):1. 标记父 shard 为 Splitting数据库锁2. 创建 child shard 行继承 generation3. 对每个 pageserver 上的 parent shard 调用 PUT /v1/tenant/id/shard_split4. Pageserver 侧执行 (mgr.rs →do_shard_split()):- Phase 1: Prepare —下载 index_part.json上传到各 child remote path- Phase 2: Hardlink —硬链接 resident layer files零拷贝冷分片- Phase 3: Spawn children —创建 child location- Phase 4: WAL catch-up —等 children 追平 WAL- Phase 5: Shutdown parent —关闭 parent shard- Phase 6: Release lock —清理 splitting flag5. 完成 —DB 中删除 parent 行child 行 splitting06. 后台 warmup —child shard 在 secondary mode 下预热限制:- 只能 2 的幂次扩展1→2,2→4,4→8...- stripe_size 只在第一次 split (1→N)时能设之后不可改2. Node Drain/Fill/Delete节点级别伸缩Drain —把所有 shard 从一个 pageserver 迁出curl -X PUT http://controller:PORT/control/v1/node/node_id/drain- 最多并发 64 个 reconcile- 优先用 warm secondary 做 cutover零停机迁移- 用于维护/退役节点Fill —把 shard 迁回到新节点curl -X PUT http://controller:PORT/control/v1/node/node_id/fill反向操作配合 drain 用于滚动升级Delete —物理删除节点curl -X DELETE http://controller:PORT/control/v1/node/node_id/delete先 drain 完再 delete3. Single Shard Migrate单 shard 迁移手动指定某个 shard 迁到特定 pageservercurl -X PUT http://controller:PORT/control/v1/tenant/shard_id/migrate \-d {node_id: target}---四、自动扩缩容HSCC (Hyper Scalable Compute Controller) 利用以下指标驱动 autoscalingsql_exporter_autoscaling 暴露的指标端口 9499从 neon_collector_autoscaling.jsonnet 引入全部跟 LFC 相关┌────────────────────────────────────────────────────────────┬────────────────────────────────────────────┐│ 指标名 │ 说明 │├────────────────────────────────────────────────────────────┼────────────────────────────────────────────┤│ lfc_approximate_working_set_size_seconds{duration_seconds} │ 过去 1~60 分钟每个窗口的工作集大小核心 │├────────────────────────────────────────────────────────────┼────────────────────────────────────────────┤│ lfc_cache_size_limit │ LFC 缓存上限 │├────────────────────────────────────────────────────────────┼────────────────────────────────────────────┤│ lfc_hits / lfc_misses │ 缓存命中/未命中计数 │├────────────────────────────────────────────────────────────┼────────────────────────────────────────────┤│ lfc_used / lfc_writes │ 缓存使用量和写入量 │└────────────────────────────────────────────────────────────┴────────────────────────────────────────────┘其中 lfc_approximate_working_set_size_windows 是最关键的 —看历史 working set 趋势来判断是否需要 split。Auto-Split 机制见 test_runner/performance/test_sharding_autosplit.py —storage controller 监控 tenant size / working set超过阈值时自动触发 split。---五、关键文件清单┌──────────────────────────────────────────────────────┬──────────────────────────────────────────────────┐│ 文件 │ 内容 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/service.rs │ 核心编排split/migrate/drain/fill/reconcile_all │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/tenant_shard.rs │ TenantShard 状态机 (Intent/Observed/Policy) │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/scheduler.rs │ 节点打分/AZ感知调度 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/reconciler.rs │ 将 intent diff 转化为 pageserver API 调用 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/http.rs │ REST API 端点注册 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/background_node_operations.rs │ Drain/Fill/Delete │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/persistence.rs │ DB CRUD (tenant_shards/nodes 表) │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/src/schema.rs │ Diesel table definitions │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ storage_controller/migrations/* │ DB schema evolution │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ libs/utils/src/shard.rs │ ShardCount/ShardNumber/TenantShardId │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ libs/pageserver_api/src/shard.rs │ ShardIdentity/key_to_shard_number │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ pageserver/src/tenant/mgr.rs │ do_shard_split() —pageserver 侧 split 逻辑 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ pageserver/src/http/routes.rs │ pageserver API endpoint │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ control_plane/storcon_cli/src/main.rs │ CLI 入口 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ compute/vm-image-spec-bookworm.yaml │ VM 中 sql_exporter 启动配置 │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ docs/rfcs/2025-02-14-storage-controller.md │ Storage Controller RFC │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ docs/rfcs/028-pageserver-migration.md │ Zero-downtime migration procedure │├──────────────────────────────────────────────────────┼──────────────────────────────────────────────────┤│ test_runner/regress/test_sharding.py │ 分片功能测试 │└──────────────────────────────────────────────────────┴──────────────────────────────────────────────────┘---六、验证方案1. 查看当前 shard 分布: curl http://controller:PORT/debug/v1/tenant/tenant_id2. 定位 shard 在哪台 pageserver: curl http://controller:PORT/debug/v1/tenant/tid/locate3. 手动 split: 用 storcon_cli tenant-shard-split 或 HTTP API4. 观察 reconciliation: 看 /debug/v1/tenant/tid/shards 的 intent vs observed5. 跑 test_sharding.py 确认 split 后数据正确性

相关新闻

Kimi K3 vs Fable 5 最新资讯

Kimi K3 vs Fable 5 最新资讯

最近AI圈两大顶级模型持续上演对标大戏,国产开源代表Kimi K3、海外闭源标杆Fable 5,短短几天接连爆出重磅消息,不管是做开发、AI内容创作、本地部署,还是选择API服务,这些动态直接影响选型。今天把两边最新事件一次性梳…

2026/10/16 0:47:27 阅读更多 →
AI如何学习知识?与人类学习的本质差异

AI如何学习知识?与人类学习的本质差异

如今,AI已深度融入生活,能识字作画、解题编程、对话答疑,看似拥有和人类相似的学习能力。但事实上,AI的“学习”与人类的学习只是表象相似,底层逻辑、认知方式、成长逻辑有着天壤之别。AI的学习是算法驱动的数据拟合&a…

2026/10/16 18:45:05 阅读更多 →
MySQL中文乱码全链路解决方案与最佳实践

MySQL中文乱码全链路解决方案与最佳实践

1. 乱码问题的本质与常见场景 当MySQL、phpMyAdmin和PHP三者之间出现中文乱码时,本质上都是字符编码不一致导致的。这种情况在Web开发中极为常见,特别是当系统涉及多语言环境或不同组件混用时。我处理过最典型的一个案例是:phpMyAdmin中显示正…

2026/10/16 1:19:31 阅读更多 →

最新新闻

Typora 1.14.x 最新破解方法!亲测可用

Typora 1.14.x 最新破解方法!亲测可用

经常用Markdown的伙伴们肯定知道,Typora是一款“所见即所得”的Markdown语言编辑器,深受大家喜爱。不过,这款编辑器是以89人人民币/次/3台设备进行一次性费用收取的。作为一名资深白嫖党,在经过一周多的研究后,我成功找…

2026/10/18 7:31:04 阅读更多 →
2026年国内API聚合平台综合评测:版本时效、协议兼容与企业治理避坑指南

2026年国内API聚合平台综合评测:版本时效、协议兼容与企业治理避坑指南

很多开发者选API聚合平台时,眼睛盯着价格,实际踩坑最多的却是另外三件事:模型版本滞后、协议兼容性不过关、企业治理能力缺位。这三件事平日不起眼,一旦进入生产环境就会集中爆发。本文围绕模型覆盖广度、协议支持完整度、稳定性、…

2026/10/18 7:31:04 阅读更多 →
2026年国内Claude聚合平台实测:安全合规与稳定调用深度解析

2026年国内Claude聚合平台实测:安全合规与稳定调用深度解析

Claude 系列模型在国内开发者群体中的热度持续走高,Opus、Sonnet、Haiku 全系都被大量用于代码生成、文档处理与企业知识库场景。本次横评覆盖国内多家主流 Claude 聚合平台,验证场景包括国内网络直连、接口兼容与数据隐私等真实生产环境,从稳…

2026/10/18 7:31:04 阅读更多 →
复试机试二刷复盘:从错题到决策规则,把刷题经验变成提分能力

复试机试二刷复盘:从错题到决策规则,把刷题经验变成提分能力

临近复试的那几周,我几乎把所有空余时间都砸在了 OJ 上。要说最煎熬的,不是第一轮刷题时对着题目发呆的茫然,而是第二轮重刷时发现——当初 AC 过的题,现在连思路都想不起来。这篇复盘笔记,就是在这种被打击感里攒出来…

2026/10/18 7:31:04 阅读更多 →
AI可复现性挑战:原因、排查与实操流程

AI可复现性挑战:原因、排查与实操流程

做AI这行时间久了,会发现一个特别让人崩溃的现象:你照着论文的框架把代码写下来,跑出来的结果却跟论文里漂亮到不行的曲线差了十万八千里。这不是因为你太菜,而是因为AI研究的可复现性挑战,本身就是目前整个行业最头疼…

2026/10/18 7:31:04 阅读更多 →
ESP32分区表完全指南:从partitions.csv到OTA与Flash规划

ESP32分区表完全指南:从partitions.csv到OTA与Flash规划

第一次打开ESP32工程目录,看到partitions.csv这个文件时,我压根没当回事,以为就是个自动生成的临时配置。直到有一次编译报错提醒我“app partition is too small”,我才被迫去搞懂它。搞懂之后回头看,分区表几乎决定了…

2026/10/18 7:30:04 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →