EdgeOne Makers KV 存储
KV 存储是 EdgeOne Makers 提供的高性能键值存储服务,专门用来存配置、缓存、会话这类小体积高频访问的数据。全球边缘节点缓存,读取延迟极低,是后端开发最常用的存储之一。这篇讲清楚 KV 的概念、读写操作、数据管理最佳实践。
KV 存储概念与特点
KV 的全称是 Key-Value,就是一个超级大的 Map,通过键存取值。
"user:1" -> {"name": "Alice", "age": 20}
"config:theme" -> "dark"
"counter:visits" -> "1234"
它的核心特性:
| 特性 | 说明 |
|---|---|
| 全球分布 | 数据自动复制到全球所有边缘节点 |
| 读写极快 | 读取由就近节点直接响应,延迟几毫秒 |
| 最终一致性 | 写入后几秒内传播到全球 |
| 支持过期时间 | 键可以设置 TTL,到期自动删除 |
| 单值上限 | 最大 10MB |
KV 最适合读多写少的场景。配置项、功能开关、用户资料缓存、静态内容,这些都是典型用途。
适用场景与注意点
KV 的最终一致性是新手最容易踩的坑。你在某个节点写入数据后,其他地区的节点可能要过几秒才能读到新值。所以它不适合需要强一致性的业务,比如库存扣减、计数器、订单状态。
| 适合 KV | 不适合 KV |
|---|---|
| 站点配置 | 计数累加 |
| 用户资料缓存 | 库存扣减 |
| 静态内容 | 交易记录 |
| 功能开关 | 需要立刻读到最新值的场景 |
创建命名空间
KV 的数据存放在”命名空间”里,每个命名空间是一个独立的数据集合。一个函数可以绑定多个命名空间。
在 EdgeOne Makers 控制台创建:
- 进入”存储” -> “KV”页面
- 点击”创建命名空间”
- 输入名称,比如
my_kv - 确认创建
记下命名空间的 ID,后面绑定要用。
绑定到函数
在函数配置文件里添加 KV 绑定。以 Edge Functions 为例,在 edgeone.json 中配置:
{
"name": "my-function",
"bindings": {
"kv": [
{
"name": "MY_KV",
"namespace_id": "ns_abc123"
}
]
}
}
字段说明:
| 字段 | 作用 |
|---|---|
| name | 代码里访问 KV 的变量名,这里叫 MY_KV |
| namespace_id | 刚创建的命名空间 ID |
配置后,代码里就能通过 env.MY_KV 访问 KV 服务。
基础读写删操作
export default {
async fetch(request, env) {
// 写入一个键值对
await env.MY_KV.put("user:1", JSON.stringify({ name: "Alice", age: 20 }));
// 读取一个键值对
const raw = await env.MY_KV.get("user:1");
const user = raw ? JSON.parse(raw) : null;
// 删除一个键值对
await env.MY_KV.delete("user:1");
return Response.json({ user });
},
};
常用方法一览:
| 方法 | 说明 |
|---|---|
get(key) |
读取值,不存在时返回 null |
put(key, value) |
写入或覆盖 |
delete(key) |
删除 |
list(options) |
按前缀等条件列出键 |
KV 的值只能是字符串。存对象时用 JSON.stringify 序列化,读取时用 JSON.parse 反序列化。
数据过期设置
写入时可以设置过期时间,让 KV 自动清理数据。
// 10 分钟(600 秒)后过期
await env.MY_KV.put("captcha:123", "abcd", { expirationTtl: 600 });
// 指定绝对过期时间戳(秒级)
await env.MY_KV.put("promo", "summer", { expiration: 1790000000 });
expirationTtl 的单位是秒,从写入时刻开始计算。注意 TTL 有最小值限制,具体看官方文档。
按前缀列出键
KV 支持按前缀列出所有键,方便批量管理。
// 列出所有以 "user:" 开头的键
const list = await env.MY_KV.list({ prefix: "user:" });
console.log(list.keys);
// [{ name: "user:1" }, { name: "user:2" }, ...]
常用选项:
| 选项 | 说明 |
|---|---|
| prefix | 按前缀过滤 |
| limit | 最多返回多少条 |
| cursor | 分页游标,从上次结果继续 |
数据管理最佳实践
键命名规范
建议用前缀加分隔符,例如 user:1、config:theme,方便用 list({ prefix: "user:" }) 按类型管理。
| 好的命名 | 不好的命名 |
|---|---|
| user:1001 | u1001 |
| config:site:theme | theme |
| session:abc123 | abc123 |
序列化策略
存对象时统一用 JSON 序列化,读取时反序列化。如果对象很大或结构复杂,考虑用 MessagePack 等二进制格式,体积更小。
缓存失效策略
对于缓存数据,设置合理的 TTL 避免脏数据长期存在。热点数据 TTL 短一些,冷数据 TTL 长一些。
批量操作
KV 没有原子的批量写入接口,需要批量操作时只能循环调用 put。如果要写入大量数据,考虑用 Cloud Functions 在后台处理,避免阻塞边缘请求。
一个完整的 CRUD 示例
把前面讲的组合起来,写一个用户管理的 KV 接口。
export default {
async fetch(request, env) {
const url = new URL(request.url);
const parts = url.pathname.split("/").filter(Boolean);
if (!(parts[0] === "api" && parts[1] === "users")) {
return new Response("页面不存在", { status: 404 });
}
const id = parts[2];
const method = request.method;
// 读取单个用户
if (method === "GET" && id) {
const raw = await env.MY_KV.get(`user:${id}`);
if (!raw) return Response.json({ error: "用户不存在" }, { status: 404 });
return Response.json(JSON.parse(raw));
}
// 新增用户
if (method === "POST") {
const body = await request.json();
const newId = String(Date.now());
await env.MY_KV.put(`user:${newId}`, JSON.stringify(body));
return Response.json({ id: newId, ...body }, { status: 201 });
}
// 删除用户
if (method === "DELETE" && id) {
await env.MY_KV.delete(`user:${id}`);
return Response.json({ ok: true });
}
return Response.json({ error: "请求方式不支持" }, { status: 405 });
},
};
速查卡片
| 要点 | 说明 |
|---|---|
| KV 是什么 | 全球分布式键值存储,读多写少场景 |
| 核心特性 | 极快读取、最终一致性、单值最大 10MB |
| 适合存什么 | 配置、缓存、功能开关、会话 |
| 不适合存什么 | 需要强一致性的计数、库存、交易 |
| 值类型 | 只能是字符串,对象需要 JSON 序列化 |
| 过期时间 | 支持 TTL 和绝对时间戳 |
| 键命名建议 | 用前缀加分隔符,如 user:1、config:theme |
| 批量操作 | 没有原子批量接口,需要循环调用 |