Neon compute GetPage

计算节点(compute)执行 getpage 请求的完整调用栈,从上到下:

1. 从 Postgres 内核入口

text 复制代码
PostgreSQL buffer manager
  └─ bufmgr.c: ReadBufferExtended() / InitBufferPage()
      └─ smgrread() / smgrreadv()   ← 分发到 Neon 的 smgr hook

2. Neon smgr 层

pgxn/neon/pagestore_smgr.c

neon_read() (PG≤16) // 单块读取

neon_readv() (PG≥17) // 向量化读取(批量)

│

├─ 1 communicator_prefetch_pump_state()

│ └─ communicator.c:468

│ 从 TCP 接收缓冲中 drain 已到达的 prefetch 响应

│

├─ 2 communicator_prefetch_lookupv()

│ └─ communicator.c:1049

│ 在 prefetch ring buffer (hash table) 中查找是否已有缓存的页

│ 命中 → memcpy 到 buffer,返回;未命中则继续

│

├─ 3 lfc_read / lfc_readv_select()

│ └─ file_cache.c

│ 查 Local File Cache(本地磁盘缓存)

│ 命中 → memcpy,返回;未命中则继续

│

└─ 4 neon_read_at_lsn() / communicator_read_at_lsnv()

└─ communicator.c:2093

└─ 见下方详细链路

核心请求发送/接收链路

pgxn/neon/communicator.c

communicator_read_at_lsnv()

│

├─ prefetch_register_bufferv() // 注册到 ring buffer

│ └─ prefetch_do_request() // 填充 LSN、构建 NeonGetPageRequest

│ └─ page_server->send() // 发送请求

│ └─ libpagestore.c:1135

│ nm_pack_request() // 序列化(pq_send...)

│ PQputCopyData() // 发到 Pageserver TCP

│

├─ prefetch_wait_for(ring_index) // 阻塞等待响应

│ └─ prefetch_flush_requests() // 如果有未 flush 的请求先 flush

│ └─ prefetch_read(slot) // 从 Pageserver 接收响应

│ └─ page_server->receive()

│ └─ libpagestore.c:1219

│ call_PQgetCopyData() // 异步 read,含超时/断连逻辑

│ nm_unpack_response() // 反序列化

│

└─ 处理响应

├─ T_NeonGetPageResponse → memcpy(page, buffer, BLCKSZ)

├─ T_NeonErrorResponse → ereport(ERROR)

└─ prefetch_set_unused() // 释放 ring slot

Pageserver 端处理

pageserver/src/page_service.rs

PageStream handler (每连接一个线程)

└─ handle_getpage_request()

└─ tenant/timeline::get_page_at_lsn()

├─ 查 in-memory delta / image layer

├─ 查 s3 remote storage(需拉取时)

└─ WAL redo(pageserver 侧 walredo,非 compute 侧)

└─ 对旧版本 page image 应用 WAL diff

关键设计要点

  1. Prefetch Ring Buffer:compute 端维护一个最多 readahead_buffer_size(默认 128)个 slot 的环形缓冲区,支持异步 pipelining。

  2. LSN 语义:请求携带 (request_lsn, not_modified_since) 两个 LSN,primary 端 request_lsn=UINT64_MAX(最新),replica

端=replay_lsn。

  1. 三重缓存:prefetch ring → LFC(Local File Cache,本地磁盘)→ 远程 Pageserver。

  2. 协议:基于 libpq COPY 协议的 pagestream_v3,每个 request 带 reqid 用于匹配响应。

  3. 分片:get_shard_number() 按 relNode + block/stripe_size 哈希到不同 shard(Pageserver)。

相关推荐
ZENERGY-众壹41 分钟前
告警风暴怎么压?100MW 电站监控平台告警引擎架构复盘
数据库·架构·iot·电站监控
zhengfei6112 小时前
Go-fastdfs /reload 未授权访问: 有效PoC
数据库·sql
DevOpenClub2 小时前
高考教育信息问答 API:会话参数、资料引用与流式响应
java·数据库·高考
yuanyuan3342 小时前
2026枣庄带检测报告伸缩门品牌测评|本地服务
大数据·数据库·人工智能·伸缩门
wdyan2972 小时前
带着小白学习-微服务-5 实战:配置中心-数据库连接
数据库·学习·微服务
大维3 小时前
DBX 实测:从 SQLite 查询到 MiniMax-M3 自然语言生成 SQL
数据库·sql·sqlite
玖米GEO运营王总监4 小时前
2026年账号矩阵协同效应怎么量化:三个指标与公式结构
java·大数据·数据库
景煜拾年5 小时前
InnoAI SQL 助手
运维·数据库·笔记·sql
.痞老板.6 小时前
mysql初阶--数据类型
android·数据库·mysql
Risehuxyc6 小时前
MySQL密码插件
数据库·mysql