• 首页

  • 写作

  • 文章归档

  • 照片

  • 友情链接

  • 旅行

  • 读书

  • 日志

  • 随记

  • 人文历史

  • linux

  • 前端
b l o g
b l o g

admin

lzp

05月
09
cloudflare

durable object 替代 kv D1 数据库并实现访问加速

发表于 2025-05-09 • 字数统计 7642 • 被 5 人看爆

durable object 替代 kv D1 数据库并实现访问加速

下面这两篇博客很清楚地解释了 durable object的相关概念,包括输出门,内建的缓存,原子性,竞态条件的处理以及 sqlite 作为存储端。
https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/
https://blog.cloudflare.com/sqlite-in-durable-objects/

为什么要使用 durable object

为了加速cloudflare-memoflow的访问速度,通过测试发现瓶颈在 kv 键值的访问速度,而 D1 数据库则比较快,我可以使用 D1 数据库来替代 kv 存储。但是我还发现更好的方式 Durable Object (持久性存储)

简而言之,你应该将 D1 视为一个更“管理型”的数据库产品,而 SQLite-in-DO 则更像是低级别的“存储与计算”构建块。

持久化对象需要更多努力,但作为回报,赋予你更多权力。使用 DO,你拥有两段在不同地方运行的代码:一个前端 Worker,它将来自互联网的请求路由到正确的 DO,以及 DO 本身,它在与 SQLite 数据库相同的机器上运行。你可能需要仔细考虑哪些代码在哪里运行,你可能需要构建一些 D1 中现成的工具。但因为你完全控制,你可以根据应用程序的需求定制解决方案,并可能实现更多

因为代码与sqlite 数据库在一块所以,与数据库相关的增删改查的代码可以不考虑网络延迟,代码会更简洁。

cloudflare memoflow 添加 durable object 的 commit 记录

page 调用 durable 的代码
add durable call
https://github.com/qyzhizi/hono-auth-test-app-D1-func/commit/3a75eab60efaa358bb6dface566a8ed7df4807ee
https://github.com/qyzhizi/hono-auth-test-app-D1-func/commit/01ac8014d19a6ae6078dcc0e0790e4cc216e1c8d

worker durable 的代码
https://github.com/qyzhizi/hono-auth-test-app-D1/commit/0bac45b584f0337b90bb252e0459e0ab3b9d0e49

wrangler types 生成 types 文件

"generate-types": "wrangler types", 记录 Cloudflare 的类型文件生成, wrangler types 会生成 types 文件:worker-configuration.d.ts

package.json

"wrangler": "^4.13.2"

"wrangler": "^4.13.2" 生成的 worker-configuration.d.ts 包含了更多的东西,需要卸载之前的安装的包:"@cloudflare/workers-types"

"wrangler": "^3.60.3" 的配置:
package.json

  "devDependencies": {
    "@cloudflare/workers-types": "^4.20240925.0",
    "typescript": "^5.5.2",
    "wrangler": "^3.60.3"
  }

生成 worker-configuration.d.ts 后还需要配置文件 tsconfig.json的 types 字段,否则会报错。

 "types": ["./worker-configuration.d.ts", "node"],

下面这个命名是指定了 生成的文件名:env.d.ts

wrangler types --env-interface CloudflareEnv env.d.ts

这个命令生成的 env.d.ts文件不需要配置 tsconfig.json的 types 字段,似乎 ts 编译器可以自动读取 env.d.ts 文件

Cloudflare durable object 迁移配置在迁移完成后,配置是否可以去掉旧的 tag

简短答案:可以
参考:https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/
Cloudflare durable object 迁移配置 :

"migrations": [
  {
    "tag": "v1",
    "new_sqlite_classes": [
      "MyDurableObject"
    ]
  },
  {
    "tag": "v2",
    "renamed_classes": [
      {
        "from": "MyDurableObject",
        "to": "MemoflowDurableObject"
      }
    ],

迁移完成后,配置是可以去掉 tag v1

  // —— 迁移配置 ——  
  "migrations": [
    // {
    //   "tag": "v1",
    //   "new_sqlite_classes": [
    //     "MyDurableObject"
    //   ]
    // },
    {
      "tag": "v2",
      "renamed_classes": [
        {
          "from": "MyDurableObject",
          "to": "MemoflowDurableObject"
        }
      ],
      // "deleted_classes": [
      //   "MyDurableObject"
      // ]
    }
  ],
  "durable_objects": {
    "bindings": [
      {
        "class_name": "MemoflowDurableObject",
        "name": "MemoFlow_DURABLE_OBJECT"
      }
    ]
  },
  "observability": {
    "enabled": true
  }

cloudflare 官方博客 对 Durable Object 的介绍,比较详细,重点解释了如何处理竞态条件与加速访问

https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/

cloudflare debug page and worker in a single Miniflare instance #cloudflare #durable

在一个 Miniflare 中同时启动一个 page 与一个worker

npx wrangler pages dev -c wrangler.jsonc -c /Users/qy/Documents/git_rep/cloudflare_project/2025-03-05-hono-github-login-db/hono-auth-test-app-D1/wrangler.jsonc

这个命令表示先启动 当前目录的 page, 配置文件是 wrangler.jsonc , 接着 -c /Users/qy/Documents/git_rep/cloudflare_project/2025-03-05-hono-github-login-db/hono-auth-test-app-D1/wrangler.jsonc 表示附加启动另一个 worker -c 接另一个 worker 的目录,这样的好处是 在同一个 Miniflare 实例中同时同时启动 一个 page 和一个 worker,使得 page 可以访问另一个 worker 中的 Durable object。如果在命令行中分别启动 page 与 worker,page 则会显示无法访问 durable object。

分别启动

npx wrangler pages dev -c wrangler.jsonc
npx wrangler dev -c wrangler.jsonc

参考:
https://github.com/cloudflare/workers-sdk/pull/7251
https://github.com/cloudflare/workers-sdk/pull/7098

durable object starter 网站

https://developers.cloudflare.com/durable-objects/get-started/?utm_source=chatgpt.com#3-instantiate-and-communicate-with-a-durable-object
部署的网站:
https://durable-object-starter.l2830942138.workers.dev

Cloudflare pages 不能创建 Durable object

You must create a Durable Object Worker and bind it to your Pages project using the Cloudflare dashboard or your Pages project's Wrangler configuration file. You cannot create and deploy a Durable Object within a Pages project.

DO 只是接收 来自 Worker 或者 另一个 DO 的请求

https://developers.cloudflare.com/durable-objects/get-started/#3-instantiate-and-communicate-with-a-durable-object

Durable Objects do not receive requests directly from the Internet. Durable Objects receive requests from Workers or other Durable Objects.

记录 durable object 存放数据失败的原因,数据校验出错,自己给自己设置绊脚石

错误的代码:

private isTaskPayload(data: any): data is Partial<Task> {
    // 你的校验逻辑,比如检查 commitMessage/content 类型
    return (
      typeof data === 'object' &&
      (data.id === undefined || data.id === 'string') &&
      (data.commitMessage === undefined || typeof data.commitMessage === 'string') &&
      (data.content === undefined || typeof data.content === 'string') &&
      (data.completed === undefined || typeof data.completed === 'boolean')
    )
  }

更改后:

private isTaskPayload(data: any): data is Partial<Task> {
    // 你的校验逻辑,比如检查 commitMessage/content 类型
    return (
      typeof data === 'object' &&
      (data.id === undefined || typeof data.id === 'string') &&
      (data.commitMessage === undefined || typeof data.commitMessage === 'string') &&
      (data.content === undefined || typeof data.content === 'string') &&
      (data.completed === undefined || typeof data.completed === 'boolean')
    )
  }

改动:
data.id === 'string' -> typeof data.id === 'string'

类型校验报错的地方:!this.isTaskPayload(data)

async createTask(data: Task): Promise<Task> {
    if (!this.isTaskPayload(data)) {
        throw new ValidationError('Invalid payload');
    }

    // const id = crypto.randomUUID();
    const task: Task = {
        id: data.id ,
        commitMessage: data.commitMessage ?? '',
        completed: false,
        createdAt: new Date().toISOString(),
        content: data.content ?? '',
        filePath: data.filePath ?? ''
    };

    await this.state.storage.put(data.id, task);
    return task;
}

我一开始 Invalid payload 以为是第三方的报错,由于是 AI 写的,没想到是自己写的代码的错误信息
我怀疑是 durable object 本身的问题,后来经过本地调试,发送调用 另一个 durablehello的函数就没有问题,最终找到这个错误的位置

durable 删除任务 是没有返回值的,之前在这里犯了这个错误 #durable

export const durableDeleteTask = async (c: Context, id: String): Promise<Task> => {
  const doId = c.env.MemoFlow_DURABLE_OBJECT.idFromName('MemoflowDO')
  const stub = c.env.MemoFlow_DURABLE_OBJECT.get(doId)
  console.log("delete task, id: ", id)
  const task: Task = await stub.deleteTask(id)
  if (!task) {
  throw new NotFoundError(`durableDeleteTask with id=${id} failed`)
  }
  return task
}

上面的代码及时删除成功也会抛出错误,就是因为 task 原本就是 null 值,改为下面的代码,通过捕获错误来判断是否执行成功

export const durableDeleteTask = async (c: Context, id: string): Promise<void> => {
  const doId = c.env.MemoFlow_DURABLE_OBJECT.idFromName('MemoflowDO');
  const stub = c.env.MemoFlow_DURABLE_OBJECT.get(doId);
  
  try {
    await stub.deleteTask(id);
  } catch (error) {
    // 如果 Durable Object 内部已经抛出 NotFoundError,这里可以捕捉再处理或继续抛出
    if (error instanceof NotFoundError) {
      throw error;
    }
    console.error("Unexpected error during deleteTask:", error);
    throw new Error(`Failed to delete task with id=${id}`);
  }
};

A worker how to access another worker durable object

https://community.cloudflare.com/t/durable-objects-access-from-different-workers/316511/2?utm_source=chatgpt.com

wrangler.toml 配置文件

The Durable Objects docs mention using script_name (the name of the script where the Durable Object class was defined, exported and published) to access a Durable Object class from another script.

[durable_objects]
bindings = [{name = "EXAMPLE_CLASS", class_name = "DurableObjectExample", script_name = "example-name"}]

page wrangler.jsonc 配置文件

// 1. Durable Object 绑定
"durable_objects": {
  "bindings": [
    {
      "class_name": "MemoflowDurableObject",
      "name": "MemoFlow_DURABLE_OBJECT",
      "script_name": "memoflow_worker"
    }
  ]
},

https://community.cloudflare.com/t/sharing-durable-objects-between-workers-locally/503413

分享到:
网站分享,适合电脑浏览器打开
博客 博主分享
  • 文章目录
  • 站点概览
admin

! lzp

hello

Github Twitter QQ Email Telegram RSS
看爆 Top5
  • 历史与人文 视频链接 189次看爆
  • 2022日志随笔 175次看爆
  • 我的青海湖骑行 164次看爆
  • 读书随笔 124次看爆
  • rs2 设置教程 97次看爆

站点已萌萌哒运行 00 天 00 小时 00 分 00 秒(●'◡'●)ノ♥

Copyright © 2025 admin

由 Halo 强力驱动 · Theme by Sagiri · 站点地图