一、引言
Serverless 函数的无状态特性,把数据层推到了「函数之外」——数据库成为唯一有状态的部分。而边缘计算又把问题加剧:你的函数在东京跑,数据库却在弗吉尼亚,一次查询就是 200ms 光速往返。Serverless 数据层选型的本质是:延迟、一致性、成本与「边缘近度」的权衡。
本文系统讲 Serverless 数据层:先对比边缘 SQLite(D1/Turso)与托管 PostgreSQL(Neon/Supabase)两条主线,再讲 KV/Redis(Upstash/Cloudflare KV)、向量库与对象存储;接着覆盖连接管理与冷启动影响、延迟优化与数据架构设计,最后给出完整的选型矩阵。
关联:https://plumephp.com/tools-serverless-cold-start/(函数形态)、https://plumephp.com/tools-edge-cache-cdn-strategy/(缓存)、https://plumephp.com/cloudflare-d1-fullstack-guide/(D1 实战)、https://plumephp.com/vercel-nextjs-postgres-saas/(Vercel Postgres)。
二、两大主线:边缘 SQLite vs 托管 PostgreSQL
2.1 边缘 SQLite(D1 / Turso)
D1 :Cloudflare 的分布式 SQLite,绑定 Workers,edge 就近
Turso:libSQL(SQLite 分支),多地域副本,HTTP API
共同点:
1. SQLite 内核 → 轻量、零配置
2. 数据副本部署到边缘 → 就近读
3. 写需要协调(单主或多主)→ 写延迟高于读
| 维度 | D1 | Turso |
|---|---|---|
| 运行时绑定 | Cloudflare Workers | 任意(HTTP/SDK) |
| 地域 | Cloudflare 网络 | 多地域副本 |
| 写模型 | 单主 + 备份 | 多主/单主可选 |
| 生态 | wrangler、Drizzle/Prisma | libSQL、Turso CLI |
| 适用 | Cloudflare 全家桶 | 多平台边缘 |
2.2 托管 PostgreSQL(Neon / Supabase)
Neon :Serverless Postgres,按需冷启动、分支管理、存储计算分离
Supabase:Postgres + Auth + Storage + Realtime 一体
共同点:
1. 完整 Postgres 功能(事务/复杂查询/扩展)
2. 自动休眠/唤醒(serverless 计费)
3. 连接是「有状态」的 → 需要连接池/HTTP 接口
| 维度 | Neon | Supabase |
|---|---|---|
| 核心 | 存储计算分离、分支 | Postgres + BaaS 全家桶 |
| 连接 | 连接池 + 自动缩放 | 连接池 + HTTP API |
| 额外服务 | 纯数据库 | Auth/Storage/Realtime |
| 适用 | 纯数据层 | 快速全栈 MVP |
2.3 怎么选
需要低延迟边缘读 + 简单数据模型 → D1 / Turso
需要完整 SQL/事务/复杂查询 → Neon / Supabase
边缘读为主、写少 → 边缘 SQLite
写多、强一致、跨区域 → 托管 Postgres
一句话总结:边缘 SQLite 主打「数据到边缘、就近读」,托管 Postgres 主打「完整能力、云上中心化」——延迟敏感且模型简单选前者,能力需求高选后者。
三、KV 与 Redis:快速键值层
3.1 Cloudflare KV vs Upstash Redis
Cloudflare KV:
全局复制的键值存储,最终一致
适合:配置、会话元数据、静态映射、缓存
Upstash Redis:
云 Redis,通过 HTTP/REST 访问(无 TCP 连接占用)
适合:计数器、排行榜、实时数据、Pub/Sub、TTL 缓存
// Cloudflare KV
await env.KV.put('config:feature-x', 'true', { expirationTtl: 3600 })
const v = await env.KV.get('config:feature-x')
// Upstash Redis(HTTP)
import { Redis } from '@upstash/redis'
const redis = new Redis(env.UPSTASH_REDIS_REST_URL, env.UPSTASH_REDIS_REST_TOKEN)
await redis.incr('counter:orders') // 原子自增
await redis.zadd('leaderboard', { score: 95, member: 'user1' })
3.2 KV vs Redis 选型
| 维度 | KV | Redis |
|---|---|---|
| 一致性 | 最终一致 | 强一致 |
| 写入吞吐 | 高(异步复制) | 高(同步) |
| 数据结构 | 字符串 | 字符串/哈希/列表/集合/有序集合 |
| 原子操作 | 部分 | 丰富(INCR/PEXPIRE/Lua) |
| 适用 | 配置/缓存/会话 | 计数器/队列/实时数据 |
3.3 Durable Objects(Cloudflare)
KV 最终一致无法保证「强一致状态」
DO:边缘上的有状态单实例 → 强一致、可做状态机
适合:WebSocket 状态、协调器、强一致计数器
一句话总结:KV 快但最终一致,Redis 有丰富数据结构与原子操作——配置/会话用 KV,计数器/排行榜/实时用 Redis,强一致状态用 Durable Objects。
四、连接管理与冷启动影响
4.1 连接是 Serverless 的「稀缺资源」
问题:每个函数实例都想连数据库,但 Postgres 连接数有限
函数冷启动 + 建连 = 双重延迟
方案:
1. 连接池(Neon/Supabase pooler / PgBouncer)
2. 函数级复用:模块级全局连接(不每次请求新建)
3. HTTP 接口(Supabase REST / Turso HTTP)免连接池
// 模块级连接复用(Serverless 最佳实践)
// lib/db.ts
const pool = new Pool({ connectionString: DATABASE_URL }) // 模块级 → 实例内复用
export async function query(sql: string, params?: any[]) {
return pool.query(sql, params)
}
// 注意:每次冷启动会重新建池 → 用连接池 + 预热减轻
4.2 冷启动中的数据延迟
三层延迟:
① 函数冷启动(运行时拉起)
② 数据库建连(TCP+TLS 握手)
③ 跨区域网络往返(边缘到数据库所在地)
优化:
① 预热 + 轻运行时
② 连接池/HTTP 免握手
③ 数据放边缘(D1/Turso)或 CDN 缓存
4.3 连接数上限的治理
1. 应用层限流:并发控制(并发池)
2. 数据库层:连接池 / max_connections 配置
3. 架构层:读走副本、写走主库
一句话总结:Serverless 数据库延迟 = 冷启动 + 建连 + 跨区往返——连接池/HTTP 免握手、模块级复用、数据放边缘,三管齐下压延迟。
五、SQLite vs PostgreSQL vs NoSQL 选型矩阵
| 维度 | SQLite(D1/Turso) | PostgreSQL(Neon/Supabase) | Redis/KV |
|---|---|---|---|
| 延迟(边缘) | 低(数据在边缘) | 中(需网络往返) | 极低 |
| 一致性 | 单写强一致 | 强一致 | KV 最终/Redis 强 |
| 事务 | 支持 | 完备 | 有限 |
| 复杂查询 | 基础 | 完备 | 无 |
| 写吞吐 | 单主受限 | 高(可扩展) | 极高 |
| 数据量 | 中 | 大 | 内存受限 |
| 适合 | 边缘读多、简单模型 | 复杂业务核心 | 缓存/实时/计数器 |
组合架构(推荐):
核心业务数据 → Neon/Supabase(Postgres,事务与复杂查询)
边缘高频读 → D1/Turso(就近)或 CDN 缓存
实时/计数器 → Upstash Redis
会话/配置 → Cloudflare KV
文件/图片 → R2/S3 对象存储
向量检索 → 向量库(Pinecone/Weaviate 或 Postgres pgvector)
一句话总结:选型不是「选一个」,而是分层组合——Postgres 管核心、边缘 SQLite 管就近读、Redis 管实时、KV 管会话、R2 管对象、向量库管语义检索。
六、边缘向量库与对象存储
6.1 向量检索(AI 应用数据层)
方案:
pgvector(Postgres 扩展)→ 与业务数据同库,简化架构
独立向量库(Pinecone/Weaviate/Cloudflare Vectorize)→ 规模大
Turso/D1 暂不适合大规模向量
-- pgvector 示例
CREATE EXTENSION vector;
ALTER TABLE products ADD COLUMN embedding vector(384);
SELECT id FROM products ORDER BY embedding <-> $1 LIMIT 10; -- 余弦距离
6.2 对象存储(文件/图片)
R2/S3:静态资源、图片、上传文件
配合 CDN:边缘缓存、免出口流量(R2 特色)
图片处理:Cloudflare Images / Vercel Image 服务
6.3 AI 数据层的分层
结构化业务数据 → Postgres
向量/语义 → pgvector / 向量库
文件/模型权重 → R2/S3
Prompt/会话 → KV/Redis
一句话总结:AI 数据层 = Postgres 管业务、pgvector/向量库管语义、R2 管文件、KV 管会话——向量检索与业务数据同库能显著简化架构。
七、数据架构设计要点
7.1 读写模式决定部署
读多写少(内容站/推荐) → 边缘副本 + CDN 缓存
写多读少(订单/日志) → 中心主库 + 队列削峰
实时数据(排行榜/计数) → Redis
时序数据(监控/事件) → 时序库 / Redis 聚合
7.2 一致性需求分级
强一致(金额/库存) → Postgres 事务
弱一致(阅读数/热度) → KV/Redis + 异步回写
最终一致(社交时间线) → 边缘 SQLite 副本 + 同步
7.3 数据分层示例
请求 → 边缘 KV/缓存(命中即回)→ 边缘 SQLite 副本(就近读)
→ 中心 Postgres(权威写)→ Redis(实时/计数)→ 对象存储(文件)
一句话总结:架构设计先定读写模式与一致性分级——强一致进 Postgres 事务、弱一致进缓存异步回写,再用边缘副本与 CDN 把高频读压到最近处。
八、成本与配额
8.1 计费模式对比
| 服务 | 计费维度 | 免费额度 | 注意 |
|---|---|---|---|
| D1 | 读/写请求 | 5M 读/天 | 写请求贵 |
| Turso | 副本数+请求 | 每库 250M 读 | 多副本加钱 |
| Neon | 计算时间+存储 | 按需休眠 | 唤醒计费 |
| Supabase | 存储+带宽 | 500MB DB | 无服务器级 |
| Upstash | 命令数+存储 | 高频免费层 | 命令计费 |
| Cloudflare KV | 读写+存储 | 免费层大 | 写一致性弱 |
8.2 成本优化要点
1. 高频读用缓存(KV/CDN)→ 省数据库请求
2. 写密集用批处理/队列合并
3. 边缘 SQLite 减少跨区网络费
4. Postgres 用 Neon 休眠省计算时间
5. 监控请求量级,设预算告警
一句话总结:成本优化 = 读走缓存、写走批处理、就近部署省网络、按需休眠省计算——每个服务都有免费额度,关键是别让高频读打到贵路径。
九、生产架构落地示例
场景:SaaS 应用(用户/订单/内容/实时)
数据分层:
┌─ Cloudflare KV ── 会话/配置/特性开关(最终一致可接受)
├─ Upstash Redis ── 排行榜/计数器/PubSub(实时强一致)
├─ D1/Turso ────── 内容/帖子(读多写少,边缘就近)
├─ Neon/Supabase ─ 订单/用户/权限(强一致,事务核心)
├─ R2/S3 ───────── 图片/文件(对象存储 + CDN)
└─ pgvector ────── 向量检索(AI 搜索/推荐)
写路径:函数 → Postgres(事务)/ 队列削峰
读路径:边缘缓存 → 边缘 SQLite → Postgres
一句话总结:生产 Serverless 数据层是「六层分工」——KV 会话、Redis 实时、SQLite 边缘内容、Postgres 核心事务、R2 对象、向量库语义,读写路径分层直达最合适的存储。
十、速查表
| 需求 | 选型 |
|---|---|
| 边缘低延迟读 | D1 / Turso |
| 完整 SQL/事务 | Neon / Supabase |
| 实时/计数器/队列 | Upstash Redis |
| 会话/配置/特性开关 | Cloudflare KV |
| 强一致状态 | Durable Objects |
| 文件/图片 | R2 / S3 |
| 向量检索 | pgvector / 向量库 |
| 复杂查询 | Postgres |
| 连接治理 | 连接池 / HTTP API |
| 成本优化 | 缓存 + 批处理 + 就近 |
一句话记忆:Serverless 数据层按「延迟、一致性、成本」分层——边缘 SQLite(D1/Turso)就近读、托管 Postgres(Neon/Supabase)管事务、KV 管会话、Redis 管实时、R2 管对象、pgvector 管向量;延迟瓶颈是冷启动+建连+跨区往返,用连接池/HTTP 免握手、模块级复用、数据放边缘解决;没有万能数据库,只有合适的分层。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。