pgkv 是一个基于 PostgreSQL UNLOGGED 表构建的高性能键值存储工具,定位是让开发者用 PostgreSQL 获得接近内存缓存的读写速度。
pgkv 的“高性能”来源于 UNLOGGED 表跳过了预写日志(WAL)。代价是牺牲崩溃安全性:数据库异常关闭后,表中的数据会被自动清空。因此它明确适用于缓存、会话、幂等键等可丢失场景。
它提供了相当完整的 Redis 风格 API,包括基础 set/get/delete、TTL 过期管理、批量操作、原子 set_nx 和计数器 increment。
目前主要有两个活跃形态:一是 Rust 的 crate(API 接近 Redis),二是 PostgreSQL 扩展(通过 pgkv.set() 等 SQL 函数调用,数据以 JSONB 存储)。
-
Rust 客户端库 (crate
pgkv)这是最直接的应用层调用方式,适合在 Rust 项目中使用。它直接连接 PostgreSQL,操作的是底层的
UNLOGGED表。use pgkv::{Store, Config}; fn main() -> pgkv::Result<()> { // 连接 PostgreSQL let store = Store::connect("postgresql://localhost/mydb")?; // 基础读写 (值可以是 &[u8] 或 &str) store.set("user:1:name", "Alice")?; if let Some(value) = store.get("user:1:name")? { println!("Name: {}", String::from_utf8_lossy(&value)); } store.delete("user:1:name")?; // 带 TTL 的写入 (3600秒后过期) store.set_ex("session:token", b"data", std::time::Duration::from_secs(3600))?; // 原子操作:仅当 key 不存在时设置 if store.set_nx("lock:resource", b"locked")? { println!("Lock acquired"); } Ok(()) }它还支持批量操作、前缀扫描等,API 设计接近 Redis。
-
PostgreSQL 扩展 (SQL 函数)**
这是另一种形态,作为数据库扩展安装后,直接在 SQL 中调用 Redis 风格的函数。数据以 JSONB 形式存储在
pgkv.store表中。-- 安装扩展 CREATE EXTENSION pgkv; -- 基本 KV 操作 SELECT pgkv.set('user:42', '{"name":"Ada","active":true}'); SELECT pgkv.get('user:42')->>'name'; -- 返回 "Ada" -- 带 TTL 的设置 (60秒后过期) SELECT pgkv.set('session:42', 'active', 60); SELECT pgkv.ttl('session:42'); -- 查看剩余时间 -- 原子计数器 SELECT pgkv.incr('jobs:completed'); -- 自增 1这个版本支持字符串、哈希、列表、集合、有序集合等数据结构,命令覆盖较全。
pgkv vs pg_memcache:性能对比
pgkv 是在 PostgreSQL 内部用 UNLOGGED 表模拟 KV 操作,而 pg_memcache 是让 PostgreSQL去连接外部的 Memcached 服务。因此,它们的调用方式和性能表现差异很大。
结论先行:如果追求极致的低延迟,pg_memcache 通常更快;如果追求架构简洁、避免引入新组件,pgkv 是更务实的选择。
pg_memcache 的性能逻辑:它的本质是“PostgreSQL 作为 Memcached 的客户端”,数据实际存在 Memcached 的内存里,访问延迟是微秒级的。但代价是引入了额外的组件依赖(需单独部署、运维 Memcached 服务)。
pgkv 的性能边界:
- 写入:基于
UNLOGGED表,跳过了 WAL(预写日志),写入速度显著高于普通表。实测显示单次 SET 约 39 µs,而普通表带 WAL 的 SET 约 62 µs(若强制刷新则达 4.3 ms)。 - 读取:受 PostgreSQL B-tree 索引效率影响,点查性能不错,但无法匹敌纯内存的 Memcached。
- 关键局限:数据仍持久化在磁盘(与 Memcached 纯内存不同),但崩溃后会全部丢失(这是
UNLOGGED表的特性),且不会复制到从库,存在单点风险。
pg_memcache 的局限:它不是 PostgreSQL 内部存储,只是“代理”调用。数据完全不持久化,Memcached 重启即全部消失,且无法利用 PostgreSQL 的事务、复制、备份等核心能力。
- 选
pg_memcache:当你已有 Memcached 集群,且只需要一个从 SQL 内部访问缓存的“快捷方式”时。它能让你在数据库函数、触发器中方便地读写 Memcached,但不要把它当作持久化 KV 存储。 - 选
pgkv:当你希望避免引入 Redis/Memcached 等额外组件,愿意用牺牲崩溃安全性(数据可丢)来换取比普通表高得多的写入性能,并且希望充分利用 PostgreSQL 的 SQL 能力(如事务、复杂查询)时。它适合缓存、会话、幂等键等可丢失场景。