Neon 数据库入门指南

Neon 是一个现代化的 Serverless PostgreSQL 数据库服务,提供自动扩缩容、按需计费和分支管理等特性。它将传统 Postgres 的强大功能与云原生架构结合,让开发者能够像使用无服务器函数一样使用数据库。本文将介绍 Neon 的核心概念、使用方法和实际应用场景。

什么是 Neon

Neon 是一个完全托管的 Serverless PostgreSQL 服务,采用存储与计算分离的架构,为开发者提供按需付费、自动扩缩容和分支管理等现代化特性。

核心特性

Serverless 架构

Neon 采用 Serverless 设计,数据库实例可以在无请求时自动暂停,有请求时快速恢复。这种设计大幅降低了空闲时的成本,开发者只需为实际使用的计算资源付费。

typescript 复制代码
// 连接 Neon 数据库,即使实例处于暂停状态
import { Pool } from "@neondatabase/serverless";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL, // Neon 会自动唤醒实例
});

const result = await pool.query("SELECT NOW()");
console.log(result.rows[0]); // 首次查询可能需要几秒钟唤醒

自动扩缩容

Neon 支持根据负载自动调整计算资源。在流量高峰时自动扩容,流量降低时自动缩容,无需手动干预。

分支管理

Neon 支持为数据库创建分支(Branch),类似 Git 分支管理代码。每个分支都是独立的数据库实例,可以用于开发、测试或预览环境。

bash 复制代码
# 使用 Neon CLI 创建分支
neonctl branches create --project-id my-project --name feature-branch

# 每个分支有独立的连接字符串
postgresql://user:pass@feature-branch-ep-xxx.us-east-2.aws.neon.tech/main

技术架构

Neon 采用存储与计算分离(Storage-Compute Separation)架构:

  • 存储层:基于云对象存储,提供持久化和高可用性
  • 计算层:运行 PostgreSQL 实例,负责查询处理
  • 代理层:管理连接、路由请求、实现自动唤醒

这种架构使得计算资源可以独立扩缩容,而存储容量按需增长。

与传统 PostgreSQL 对比

特性 传统 PostgreSQL Neon
部署方式 需要自行管理服务器 完全托管的 Serverless
扩容方式 手动垂直扩容,需停机 自动扩缩容,无停机
成本模式 固定成本,即使空闲也计费 按需计费,空闲时自动暂停
分支管理 需手动备份恢复 内置分支功能,秒级创建
存储容量 受限于磁盘大小 弹性存储,按需增长
兼容性 原生 PostgreSQL 完全兼容 PostgreSQL

快速开始

本章介绍如何快速上手 Neon,从注册账号到执行第一个查询。

创建项目

  1. 访问 Neon Console 并注册账号(支持 GitHub、Google 登录)
  2. 点击 "Create a project" 创建新项目
  3. 选择区域(Region)和 PostgreSQL 版本
  4. 系统会自动创建一个默认数据库 main

获取连接字符串

创建项目后,在项目面板中可以看到连接字符串:

bash 复制代码
# 连接字符串格式
postgresql://username:password@ep-xxx.region.aws.neon.tech/dbname?sslmode=require

连接字符串包含以下信息:

  • username:数据库用户名
  • password:自动生成的密码
  • ep-xxx:Endpoint ID(计算实例标识)
  • region:数据中心区域
  • dbname:数据库名称

连接数据库

使用 Node.js

typescript 复制代码
import { Pool } from "@neondatabase/serverless";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

async function main() {
  const client = await pool.connect();

  try {
    // 创建表
    await client.query(`
      CREATE TABLE IF NOT EXISTS users (
        id SERIAL PRIMARY KEY,
        name VARCHAR(100),
        email VARCHAR(100) UNIQUE,
        created_at TIMESTAMP DEFAULT NOW()
      )
    `);

    // 插入数据
    await client.query("INSERT INTO users (name, email) VALUES ($1, $2)", ["Alice", "alice@example.com"]);

    // 查询数据
    const result = await client.query("SELECT * FROM users");
    console.log(result.rows);
  } finally {
    client.release();
  }
}

main();

使用 psql 命令行

bash 复制代码
# 使用 psql 连接
psql "postgresql://username:password@ep-xxx.region.aws.neon.tech/main?sslmode=require"

# 执行查询
main=> SELECT version();
main=> \dt  -- 列出所有表

使用其他客户端

Neon 完全兼容 PostgreSQL,可以使用任何支持 PostgreSQL 的客户端工具:

  • GUI 工具:pgAdmin, DBeaver, TablePlus
  • ORM:Prisma, TypeORM, Sequelize, Drizzle
  • 语言驱动pg (Node.js), psycopg2 (Python), pgx (Go)

核心功能

Neon 提供了分支管理、自动扩缩容、自动暂停和时间点恢复等核心功能,让数据库管理更加灵活高效。

分支管理

Neon 的分支(Branch)功能类似 Git,可以为数据库创建多个独立的副本。每个分支都是完整的数据库实例,拥有独立的连接字符串和计算资源。

创建分支

bash 复制代码
# 从主分支创建新分支
neonctl branches create \
  --project-id my-project \
  --name dev-feature-x

# 从指定分支创建
neonctl branches create \
  --project-id my-project \
  --parent main \
  --name staging

使用场景

  • 功能开发:每个功能分支对应一个数据库分支,避免开发环境相互干扰
  • 测试环境:为测试创建独立分支,测试完成后直接删除
  • 数据探索:复制生产数据到分支进行分析,不影响生产环境

创建分支的速度极快(通常几秒钟),因为 Neon 采用写时复制(Copy-on-Write)技术,只在数据修改时才真正复制数据。

自动扩缩容

Neon 支持根据工作负载自动调整计算资源。可以设置最小和最大 CPU 单位(CU),Neon 会在这个范围内动态调整。

typescript 复制代码
// 通过 API 配置自动扩缩容
import { createClient } from "@neondatabase/api-client";

const client = createClient({ apiKey: process.env.NEON_API_KEY });

await client.updateProject({
  projectId: "my-project",
  project: {
    settings: {
      // 设置 0.25 到 2 CU 的自动扩缩容范围
      autoscaling_limit_min_cu: 0.25,
      autoscaling_limit_max_cu: 2,
    },
  },
});

工作机制

  • 流量增加时,Neon 自动增加 CPU 和内存资源
  • 流量降低时,自动缩减资源以节省成本
  • 扩缩容过程对应用透明,不会中断连接

自动暂停

当数据库在配置的时间内没有活动时,Neon 会自动暂停计算实例。暂停后不再计费,但数据仍然保留在存储层。

typescript 复制代码
// 配置自动暂停延迟(单位:秒)
await client.updateProject({
  projectId: "my-project",
  project: {
    settings: {
      suspend_timeout_seconds: 300, // 5 分钟无活动后暂停
    },
  },
});

自动唤醒

当有新的连接请求时,Neon 会自动唤醒暂停的实例:

typescript 复制代码
// 连接暂停的数据库,会触发自动唤醒
const client = await pool.connect();

// 首次查询可能需要几秒钟等待唤醒
const result = await client.query("SELECT NOW()");
// 后续查询正常执行

唤醒时间通常在 1-3 秒,对于大多数应用场景可以接受。

时间点恢复

Neon 支持时间点恢复(Point-in-Time Recovery, PITR),可以将数据库恢复到过去某个时刻的状态。

bash 复制代码
# 恢复到指定时间点(创建新分支)
neonctl branches create \
  --project-id my-project \
  --name recovery-branch \
  --timestamp "2024-12-08T10:30:00Z"

应用场景

  • 误操作恢复:执行了错误的 DELETE 或 UPDATE 操作,可以恢复到操作前的状态
  • 数据审计:查看某个时间点的历史数据
  • 回滚测试:测试环境出问题时,快速回滚到之前的状态

保留期限取决于订阅计划(免费版保留 7 天,付费版可达 30 天)。

使用 API Client

@neondatabase/api-client 是 Neon 官方提供的 TypeScript/JavaScript SDK,用于通过代码管理 Neon 项目、数据库、分支等资源。

安装和配置

安装依赖

bash 复制代码
npm install @neondatabase/api-client
# 或
pnpm add @neondatabase/api-client

获取 API Key

  1. 登录 Neon Console
  2. 进入 "Account settings" → "API keys"
  3. 点击 "Generate new API key" 创建密钥
  4. 保存密钥到环境变量
bash 复制代码
# .env
NEON_API_KEY=your_api_key_here

初始化客户端

typescript 复制代码
import { createClient } from "@neondatabase/api-client";

const client = createClient({
  apiKey: process.env.NEON_API_KEY,
});

常用操作

列出所有项目

typescript 复制代码
async function listProjects() {
  const response = await client.listProjects();

  response.projects.forEach((project) => {
    console.log(`ID: ${project.id}`);
    console.log(`Name: ${project.name}`);
    console.log(`Region: ${project.region_id}`);
  });
}

创建新项目

typescript 复制代码
async function createProject() {
  const project = await client.createProject({
    project: {
      name: "my-new-project",
      region_id: "aws-us-east-2", // 选择区域
      pg_version: 16, // PostgreSQL 版本
    },
  });

  console.log("Project created:", project.id);
  console.log("Connection string:", project.connection_uris[0].connection_uri);
}

管理分支

typescript 复制代码
async function manageBranches(projectId: string) {
  // 列出所有分支
  const branches = await client.listProjectBranches({ projectId });

  // 创建新分支
  const newBranch = await client.createProjectBranch({
    projectId,
    branch: {
      name: "feature-branch",
      parent_id: branches.branches[0].id, // 从主分支创建
    },
  });

  console.log("Branch created:", newBranch.branch.id);

  // 删除分支
  await client.deleteProjectBranch({
    projectId,
    branchId: newBranch.branch.id,
  });
}

获取项目详情

typescript 复制代码
async function getProjectInfo(projectId: string) {
  const project = await client.getProject({ projectId });

  console.log("Project info:", {
    name: project.project.name,
    region: project.project.region_id,
    createdAt: project.project.created_at,
    settings: project.project.settings,
  });
}

管理 Endpoints

Endpoint 是 Neon 中的计算实例,每个分支可以有多个 Endpoint。

typescript 复制代码
async function manageEndpoints(projectId: string, branchId: string) {
  // 列出分支的所有 Endpoints
  const endpoints = await client.listProjectBranchEndpoints({
    projectId,
    branchId,
  });

  // 更新 Endpoint 配置
  await client.updateProjectEndpoint({
    projectId,
    endpointId: endpoints.endpoints[0].id,
    endpoint: {
      autoscaling_limit_min_cu: 0.25,
      autoscaling_limit_max_cu: 2,
      suspend_timeout_seconds: 300,
    },
  });
}

实际应用场景

Neon 的 Serverless 特性和分支管理功能,使其在多种场景下都能发挥独特优势。

开发环境:独立数据库分支

传统开发中,多个开发者共享同一个开发数据库容易产生冲突。使用 Neon,可以为每个开发者创建独立的数据库分支。

typescript 复制代码
// 脚本:为开发者创建个人分支
import { createClient } from "@neondatabase/api-client";

async function setupDeveloperBranch(developerName: string) {
  const client = createClient({
    apiKey: process.env.NEON_API_KEY!,
  });

  // 从主分支创建开发者分支
  const branch = await client.createProjectBranch({
    projectId: process.env.NEON_PROJECT_ID!,
    branch: {
      name: `dev-${developerName}`,
      parent_id: mainBranchId,
    },
  });

  console.log(`Branch for ${developerName}:`, branch.endpoints[0].host);
  return branch;
}

// 开发者 Alice 获得独立分支
await setupDeveloperBranch("alice");

优势

  • 每个开发者有独立的数据库环境,互不干扰
  • 可以自由修改 schema 和数据,不影响他人
  • 创建和删除分支成本极低

预览部署:PR 临时数据库

在 CI/CD 流程中,为每个 Pull Request 创建临时数据库分支,实现真正的预览环境。

typescript 复制代码
// GitHub Actions 工作流示例
// .github/workflows/preview.yml

async function handlePullRequest(prNumber: number, action: "opened" | "closed") {
  const client = createClient({ apiKey: process.env.NEON_API_KEY! });

  if (action === "opened") {
    // PR 创建时,创建数据库分支
    const branch = await client.createProjectBranch({
      projectId: process.env.NEON_PROJECT_ID!,
      branch: {
        name: `pr-${prNumber}`,
        parent_id: mainBranchId,
      },
    });

    // 将连接字符串注入到预览部署
    const connectionString = branch.connection_uris[0].connection_uri;
    await deployPreview(prNumber, connectionString);

    // 在 PR 中添加评论
    await addCommentToPR(prNumber, `Preview deployed with database branch: ${branch.id}`);
  } else if (action === "closed") {
    // PR 合并或关闭时,删除分支
    const branches = await client.listProjectBranches({
      projectId: process.env.NEON_PROJECT_ID!,
    });

    const prBranch = branches.branches.find((b) => b.name === `pr-${prNumber}`);
    if (prBranch) {
      await client.deleteProjectBranch({
        projectId: process.env.NEON_PROJECT_ID!,
        branchId: prBranch.id,
      });
    }
  }
}

优势

  • 每个 PR 都有独立的预览环境和数据库
  • 自动化创建和清理,无需手动管理
  • 数据隔离,测试互不影响

生产环境:弹性应对流量波动

对于流量有明显峰谷的应用,Neon 的自动扩缩容可以显著降低成本。

typescript 复制代码
// 配置生产环境的自动扩缩容
async function configureProduction() {
  const client = createClient({ apiKey: process.env.NEON_API_KEY! });

  await client.updateProjectEndpoint({
    projectId: process.env.NEON_PROJECT_ID!,
    endpointId: productionEndpointId,
    endpoint: {
      // 低流量时使用 0.5 CU
      autoscaling_limit_min_cu: 0.5,
      // 高峰时最多扩展到 4 CU
      autoscaling_limit_max_cu: 4,
      // 30 分钟无活动后暂停(适用于非 24/7 应用)
      suspend_timeout_seconds: 1800,
    },
  });
}

适用场景

  • 内部工具:工作时间访问频繁,下班后自动暂停
  • 营销活动:活动期间流量激增,自动扩容应对
  • 定时任务:只在特定时间运行,其他时间暂停节省成本

测试环境:快速复制生产数据

使用时间点恢复功能,快速复制生产数据到测试环境进行调试和验证。

bash 复制代码
# 从生产分支的最新状态创建测试分支
neonctl branches create \
  --project-id my-project \
  --parent production \
  --name test-reproduce-bug

# 从昨天的数据创建分支,用于复现历史问题
neonctl branches create \
  --project-id my-project \
  --parent production \
  --timestamp "2024-12-07T10:00:00Z" \
  --name test-yesterday-data

使用场景

  • Bug 复现:使用生产数据在测试环境中复现问题
  • 性能测试:使用真实数据规模测试查询性能
  • 数据迁移:在测试分支上验证迁移脚本,确认无误后应用到生产

安全提示

如果生产数据包含敏感信息,应在测试分支上进行脱敏处理:

sql 复制代码
-- 在测试分支上脱敏用户数据
UPDATE users
SET email = CONCAT('user', id, '@example.com'),
    phone = NULL,
    address = 'Test Address';

多区域部署

Neon 支持在多个云区域创建项目,实现地理分布式部署。

typescript 复制代码
// 为不同地区的用户创建区域化数据库
async function createRegionalProjects() {
  const client = createClient({ apiKey: process.env.NEON_API_KEY! });

  const regions = [
    { name: "us-east", region_id: "aws-us-east-2" },
    { name: "eu-west", region_id: "aws-eu-west-1" },
    { name: "ap-south", region_id: "aws-ap-southeast-1" },
  ];

  for (const region of regions) {
    await client.createProject({
      project: {
        name: `myapp-${region.name}`,
        region_id: region.region_id,
        pg_version: 16,
      },
    });
  }
}

优势

  • 降低延迟,用户连接到最近的数据中心
  • 满足数据合规要求(如 GDPR 要求数据存储在欧盟)
  • 提高可用性,某个区域故障时可切换到其他区域
相关推荐
踏浪无痕2 小时前
MySQL 脏读、不可重复读、幻读?一张表+3个例子彻底讲清!
后端·面试·架构
中国胖子风清扬2 小时前
Spring AI 深度实践:在 Java 项目中统一 Chat、RAG、Tools 与 MCP 能力
java·人工智能·spring boot·后端·spring·spring cloud·ai
零一科技2 小时前
Spring AOP 底层实现:JDK 动态代理与 CGLIB 代理的那点事儿
java·后端·spring
用户69371750013842 小时前
27.Kotlin 空安全:安全转换 (as?) 与非空断言 (!!)
android·后端·kotlin
3秒一个大2 小时前
从后端模板到响应式驱动:界面开发的演进之路
前端·后端
是阿漂啊2 小时前
vscode运行springboot项目
java·spring boot·后端
ghfdgbg2 小时前
13. 配置优先级 + Bean的管理 + SpringBoot核心原理
java·spring boot·后端
Moe4882 小时前
Elasticsearch 8.1 Java API Client 客户端使用指南(索引、文档操作篇)
java·后端·面试
温宇飞3 小时前
SQL 语法基础指南
后端