Deno KV ベータ版発表！cloudflare KVとcloudflare D1のいいとこ取り？

2023年4月29日、Deno KVのベータ版が発表されました！

https://twitter.com/deno_land/status/1651972190965837825

現在はベータ期間中のため、deno deployからKVを使用するには[waitlist](https://dash.deno.com/kv)から登録する必要があります。
後述しますが、ローカルで試す場合はコマンドラインフラグに`--unstable`を付けることで実行できます。

この記事では、競合製品であるcloudflare workers KVとの比較を行いつつDeno KVの特徴を挙げていきたいと思います。

# 特徴1：ローカルとdeno deployの両方で動作

**Deno KVは[deno deploy](https://deno.com/deploy)から使用することができる分散データベースです**。deno deploy自体が世界各地の「エッジ」でサーバーを実行するサービスなのですが、Deno KVのデータベースも分散配置されているため、最寄りのデータベースに高速にアクセスすることができます。内部実装では[Foundation DB](https://www.foundationdb.org/)が使用されているそうです。

また、**Deno KVはローカル環境のDeno CLIでも動作します**。この場合、データの保存先はローカルのSQLiteになります。

```ts:以下はローカルとdeno deployの両方で動作する
// ローカルとdeno deployの両方で動作する
const kv = await Deno.openKv("./tmp.sqlite");

// path/to/keyにデータを設定
await kv.set(["path", "to", "key"], data);

// path/to/keyのデータを取得
const res = await kv.get(["path", "to", "key"]);

// キーがpath/to始まりのデータを列挙する
for await (const data of kv.list({ prefix: ["path", "to"] })) {
  console.log(data);
}
```

上記のコードを見るとわかる通り、`.env`を使って環境変数を設定したり、データベースを手動で立ち上げたり、ローカル開発用のDBを用意したりといった手間が必要ありません。設定ゼロで開発を始めることができます。
GitHub上からdeno deployを使用して開発する際は、「mainブランチから使用される本番用のDB」と「その他のブランチから使用される開発用DB」の2つが自動で作成されるとのこと。

# 特徴2：高速でスケーラブルな分散DB

先述の通り、deno deploy自体がサーバーを分散実行するサービスになっています。そして、Deno KVのデータベースも複数のデータセンターに分散配置されています。
また、データベースは自動でスケールするようになっています。

公式サイトによると、それぞれのリージョンからデータを取得するのにかかる時間の実測値は以下の通りです。

リージョン|レイテンシ (結果整合)|レイテンシ (強整合)
--|--|--
us-east4|7ms|7ms
europe-west3|7ms|94ms
europe-west4|13ms|95ms
us-west2|72ms|72ms
asia-east2|42ms|194ms

us-east4（北バージニア）からは7msという超高速な接続が可能なようです。
手元で計測してみたところ、日本からは70ms～80msのレイテンシでデータが取得可能でした。（詳細は後述）

# 特徴3：結果整合と強整合を選択可能

Deno KVのget操作は、結果整合で読み取るか強整合で読み取るかを選択できるようになっています。

```ts
// 結果整合（速いが、データが常に最新とは限らない）
await kv.get(key, { consistency: "eventual" });

// 強整合（結果整合よりは遅いが、常に最新のデータが返ってくる）
await kv.get(key, { consistency: "strong" });
```

ドキュメントによると、Deno KVのデータ保存先は、内部的に「プライマリリージョン」と「レプリカリージョン」の2つに分かれているようです。更に、「[get操作は強整合モードと結果整合モードを選択できる](https://deno.com/kv#:~:text=()%3B-,Customizable%20consistency,-Find%20the%20right)」「[set操作は常に強整合モードで実行される](https://deno.com/manual@v1.33.0/runtime/kv/operations#:~:text=Set%20operations%20are%20always%20performed%20in%20strong%20consistency%20mode.)」という記述もあることから、KVのシステム構成は以下のようになっているのではないかと考えられます。**（※筆者の想像です）**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/cfba524a-5578-3e94-9aa6-6685aed51cb1.png)

※プライマリも複数あるのかどうかはドキュメントからは不明

おそらく各操作では

- set操作はプライマリDBに書き込み
- `consistency: "strong"`を指定したget操作はプライマリDBに書き込み
- `consistency: "eventual"`を指定したget操作はレプリカDBに書き込み
- プライマリDBのデータはレプリカDBに定期的にコピーされる

という形で読み取り/書き込みが実行されているものと推察されます。

(2023/5/14追記)

東京リージョンからのget操作の速度を計測してみました。(20回計測し平均)

リージョン|レイテンシ (結果整合)|レイテンシ (強整合)
--|--|--
asia-northeast1|77.9ms|154ms

結果整合のほうが2倍ほど高速に読み取れようです。
レプリカDBがどのリージョンに存在するのかわかりませんが、今後レプリカリージョンが増加すればもっと速くなる可能性もあります。


# 特徴4：トランザクションが書ける

Deno KVでは楽観ロックを使用したトランザクションを書くことができます。

Deno KVのそれぞれのレコードには`versionstamp`という概念があります。この値はレコードが更新される度に増加していく数値です。この値を使用すると以下のようにトランザクションを書くことができます。

```ts
while (true) {
  const { value, versionstamp } = await kv.get(["path", "to", "key"]);
  const newValue = value + 1;
  const res = await kv.atomic()
    // versionstampをチェックする
    // get~set間でデータが更新されていた場合、ここでチェックが失敗する
    .check({ key: ["path", "to", "key"], versionstamp})
    // チェックが成功した場合はset
    .set(["path", "to", "key"], newValue)
    .commit();

  // 成功するまで繰り返す
  if (res.ok) {
    break;
  }
}
```

`kv.atomic()`には上記のようなset操作以外にも、数値に対する`sum`, `max`, `min`操作が用意されています。

https://deno.land/api@v1.33.1?s=Deno.AtomicOperation&unstable=

# 特徴5：どんなオブジェクトでも保存可能

Deno KVに格納可能な値は数値や文字列だけではありません。以下のような**オブジェクトをそのまま値として保存することができます**。

- `undefined`
- `null`
- `boolean`
- `number`
- `string`
- `bigint`
- `Uint8Array`
- `Array`
- `Object`
- `Map`
- `Set`
- `Date`
- `RegExp`

通常のKVSではこれらの値を一旦JSONにシリアライズして保存する必要があるのですが、Deno KVではそのままsetしてgetできます。

なぜこれが可能なのか調べてみたところ、V8のシリアライズAPI（[Node.jsのv8.serialize()](https://nodejs.org/api/v8.html#v8serializevalue)と同じもの）を使用して、内部的にシリアライズしているようです。
（参考：[denoland/deno ext/kv/01_db.ts#L104](https://github.com/denoland/deno/blob/10ae5ee26557107b22524b1a84ebb56ed7d23fb4/ext/kv/01_db.ts#L104)）

# Deno KV は cloudflare KV と cloudflare D1のいいとこ取り？

ここまで見てきた特徴からわかる通り、cloudflare KVの操作感はそのままに、cloudflare D1の機能を足して更に使いやすくしたものがDeno KVと言ってよさそうです。

cloudflare KV や cloudflare D1 と Deno KV を比較したものが以下の表になります。

| |Cloudflare Workers KV|Cloudflare D1|Deno KV|
--|--|--|--
操作方法|JS|SQL|JS / TS
強整合読み取り|❌|⭕(readレプリカがある場合❌)[^1]|⭕
結果整合読み取り|⭕|❌(readレプリカがある場合⭕)[^1]|⭕
トランザクション|❌|⭕|⭕(楽観的ロック)
JSオブジェクトの保存|JSON化すれば可能|JSON化すれば可能|⭕
ローカル開発|miniflare / wrangler|miniflare / wrangler|Deno CLI

[^1]: https://news.ycombinator.com/item?id=31340942

:::note
DB操作がSQLではなくJS / TSからの操作になっている点は、評価が分かれるところかもしれません。
ただ、Web SQLのようにランタイムから直接SQLiteを叩けるようにしてしまうと、[ランタイムのアップデート周期とSQLite側の破壊的変更の周期がかみ合わず後方互換性問題が生じ](https://developer.chrome.com/blog/deprecating-web-sql/#sustainability-and-security-concerns)、将来的に破綻する可能性があります。
それを考えると、Deno KVやcloudflare KVのようにJS/TSレイヤーまでAPIが抽象化されている方が、Web SQLの二の舞を避けることができるので安心して使えると筆者は感じました。
:::



DB単体の性能や使いやすさとしては完全にDeno KVが上回っているように見えます。ただし、既存のDBからの移行を考えている場合やDB以外のサービスと連携したい場合は、まだまだcloudflare製品の出番もあるかもしれません。

# まとめ

Deno KVのクローズドベータが開始されました。

https://deno.com/kv

Deno KVは以下のような特徴を持ちます。

- ローカルとdeno deployの両方で動作
- 高速、スケーラブルでCDN Edgeからの利用に最適化されている
- 結果整合と強整合を選択可能
- トランザクションが書ける
- `Map`や`Set`や`Date`など、どんなオブジェクトでも保存可能
- cloudflare KV と cloudflare D1のいいとこ取り

またDeno KVのAPIに関してはuki00aさんの記事や公式マニュアルも参考になります。当記事で紹介できなかった他の操作方法についても詳しく解説されています。

https://zenn.dev/uki00a/articles/kv-store-introduced-in-deno-v1-32

https://deno.land/manual@v1.33.1/runtime/kv

https://deno.com/deploy/docs/kv

またDeno KVの使用例となるコードも公開されています。

- [TODOリスト](https://github.com/denoland/showcase_todo)
- [ピクセルアート](https://github.com/denoland/pixelpage)
- [三目並べ](https://github.com/denoland/tic-tac-toe)

## おまけ：誰が作ったのか

Deno KVを主に作っているのは[losfair](https://github.com/losfair)さんという方のようです。

> - Cloudflare D1はSQLite互換でDurable Objectsに突っ込む形で、これはあまり望ましくない性質だった
>   - この性質を避けようと実装した
> - 実装者はByteDanceにいた方
> - ByteDanceにはデータベースオタクがグループを作っていて、論文を書いたりと切磋琢磨している
>
> https://denobata-monthly-report.deno.dev/report/18

Deno KVの作成にあたってはCloudflare D1も意識されているようです。
機能的にも「オタクの夢を全部詰め込みました」みたいなデータベースになっている感じがするので、今後の機能追加にも期待していきたいと思います！！

waitlistにはこちらから登録することができます！↓↓↓

https://dash.deno.com/kv