Open-Source Wikis

/

Neon

/

Services

/

Page service

neondatabase/neon

Page service

The page service is the pageserver's read-side network surface. It accepts GetPage@LSN requests and a few related commands from compute nodes, looks up the right layers, runs WAL-redo if needed, and writes the resulting page back. It speaks two protocols today: the original libpq replication-stream protocol and a newer gRPC variant.

Two protocols, one implementation

libpq protocol (original)

Implemented in pageserver/src/page_service.rs (≈4.7k lines). When a compute opens a connection, the pageserver hands the socket to a per-connection task. The wire framing reuses Postgres's libpq replication protocol — specifically, the BasebackupRequest, PagestreamRequest, and copy-mode messages — but the semantics are Neon's.

Message types (defined in libs/pageserver_api/src/models.rs):

Request Response
PagestreamGetPageRequest { tenant, timeline, key, lsn } PagestreamGetPageResponse { page_image }
PagestreamExistsRequest { rel, lsn } PagestreamExistsResponse { exists }
PagestreamNblocksRequest { rel, lsn } PagestreamNblocksResponse { nblocks }
PagestreamGetSlruSegmentRequest PagestreamGetSlruSegmentResponse
PagestreamDbSizeRequest PagestreamDbSizeResponse

The compute also uses the same channel to request a basebackup (pageserver/src/basebackup.rs) when it boots — a tarball of the files Postgres needs to start up at a given LSN. This avoids any per-page initialization round trips for cold starts.

gRPC protocol (newer)

Defined in pageserver/page_api/proto/. The same logical operations are exposed as a tonic-based gRPC service. The reasons for adding gRPC:

  • Easier for non-Postgres clients to consume (e.g. lambda-style serverless functions).
  • Better support for streaming and cancellation primitives.
  • Compatible with HTTP/2 connection pooling, which simplifies multiplexing many compute connections through fewer TCP sockets.

The gRPC service is implemented in pageserver/src/page_service_grpc.rs (in newer commits) and uses the same per-tenant timeline lookup and Timeline::get_at_lsn() call as the libpq variant. Sharded routing in the gRPC client lives in pageserver/client_grpc/.

pageserver/page_api/ is the standalone crate exposing the protobuf definitions and a low-level client builder. pageserver/client/ is the libpq-flavored client; pageserver/client_grpc/ is the gRPC one.

Request lifecycle

sequenceDiagram
    participant C as Compute
    participant Net as page_service.rs
    participant TL as Timeline
    participant LM as LayerMap
    participant Redo as WAL-redo
    C->>Net: PagestreamGetPage(key, lsn)
    Net->>TL: get_at_lsn(key, lsn)
    TL->>LM: search(key, lsn)
    LM-->>TL: layers covering (key, lsn)
    alt layer not local
        TL->>RemoteStorage: download(layer)
    end
    TL->>TL: read base image + delta records
    TL->>Redo: request_redo(base, [records])
    Redo-->>TL: materialized page
    TL-->>Net: page bytes
    Net-->>C: PagestreamGetPageResponse(page)

Per-connection tasks log a span at info (the request_id field is propagated from the compute side) so operators can trace a single request from compute through to layer-map lookup to redo.

Authentication

The page service authenticates compute nodes using JWTs. The token signing key is a per-tenant key that the compute receives from the control plane at boot time; the pageserver verifies tokens with a public key configured at startup.

See pageserver/src/auth.rs and libs/utils/src/auth.rs. The same JWT machinery is reused by the safekeeper and the proxy.

Throttling and cancellation

  • Per-tenant throttling. pageserver/src/tenant/throttle.rs rate-limits expensive operations per tenant when a tenant is misbehaving (e.g. asking for many cold pages).
  • Cancellation. Each request is bound to a CancellationToken; when the compute disconnects or the timeline is detached, the in-flight request is cancelled before it expensively reaches WAL-redo.
  • Backpressure. If the WAL receiver is far behind the requested LSN, the page service can either wait for the WAL to be ingested or return a "not yet" status. The latter is exposed via the PagestreamGetPageRequest's not_modified_since field.

Basebackup

pageserver/src/basebackup.rs builds a tar stream containing every file a Postgres needs to start: pg_control, pg_xlog/000…, the relation files for the system catalog, etc. It also writes a small neon.signal and zenith.signal file to mark the data directory as Neon-managed.

A basebackup_cache (pageserver/src/basebackup_cache.rs) memoizes recent basebackups so that "warm" cold starts (compute restarts within a short window) can replay an existing tarball instead of regenerating it.

Metrics

Look for pageserver_smgr_query_seconds_* (per-message-type histograms), pageserver_smgr_*_request_total, and pageserver_request_in_flight_count. These are the key SLOs for the page service.

Key source files

File Purpose
pageserver/src/page_service.rs libpq replication-flavored connection handler.
pageserver/src/basebackup.rs Tar stream generator for compute bootstrap.
pageserver/src/basebackup_cache.rs Memoization layer for basebackups.
pageserver/page_api/proto/ gRPC service definitions.
pageserver/client/ libpq client (used by neon_local, tests, the compute side).
pageserver/client_grpc/ gRPC client (used by newer compute builds).
libs/pageserver_api/src/models.rs Request/response types shared between client and server.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Page service – Neon wiki | Factory