👌

Cloudflare Hyperdrive を試してみる

2023/11/10に公開

今日は先日の Birthday Week で発表された Cloudflare Hyperdrive を試してみます。

その前に Cloudflare Workers Connect

今年行われた Developer Week で Workers が Workers Connect という機能アップデートをリリースしています。

従来 Workers はアウトバウンド通信としてHTTPのGETPOST等に対応していましたが、このアップデートでアウトバウンドTCP通信が行えるようになりました。
様々な利用用途が想定されるアップデートですが、その中でもやはりデータベースへの接続が一番利用用途としては多いでしょう。

Cloudflare Hyperdrive とは

Workersは300都市を超えるエッジロケーションで動作します。それぞれのエッジには勿論複数のインスタンスが存在します。また、ステートレスで動作するため、コネクションは都度張られます。このため、 Workers Connect を用いてクラウドなどに存在している中央のデータベースに一斉にアクセスが発生するとデータベースはクエリを処理するよりも、そのコネクション要求の処理や維持で大量のリソースを消費してしまうことになります。
Hyperdrive は Cloudflare 側でそのコネクションをプーリングします。
通常Databaseへの接続は合計7回の折り返し通信が発生いたしますが、Hyperdrive ではそれを削減させます。

また Hyperdrive 経由で実行されたSelect等読み込み系クエリの結果を一定時間キャッシュさせることで、応答をエッジのみでクライアントに返す機能が備わっており、同じクエリの実行結果を高速化させます。
Hyperdrive は Postgres 系データベースに対応しており、Workers から利用可能なサービスです。これは前述の Workers Connect が Postgres に先行して対応しており、mySQL系は開発中であることと連携しています。また、Workers は有償バージョンである必要があります。

やってみる

CloudflareのドキュメントではNeonをお勧めしていますので、まずはNeonでデータベースを起動します。この記事ではNeonの起動方法は割愛しますが以下の記事が参考になるかもしれません。
https://qiita.com/mikecaat/items/f7aea72dd610c7a04171
https://zenn.dev/collabostyle/articles/d0e27b6f918621

起動する際にはあえて遠いリージョンをしておきます。

起動が完了すると以下の文字列が出力されますのでメモしておきます。

postgresql://harunobu:xxxxxxxxxxxx@ep-mute-poetry-58679204.us-east-2.aws.neon.tech/hyperdrive-demo?sslmode=require

なおxxxxxxxxxxxxxxxxの部分はパスワードです。

次にWorkers の Hello World プロジェクトを立ち上げます。

npm create cloudflare@latest

ディレクトリ = hyperdrive-tutorial
アプリケーションの種類 = "Hello World" script
TypeScript = Yes
Gitの使用 = No
Deploy? = Yes
一度ブラウザでアクセスをしたのち、Hello Worldが表示されることを確認しておきます。

cd hyperdrive-tutorial

で作業ディレクトリを移動します。
以下のコマンドを実行しHyperdriveを作成します。

wrangler hyperdrive create hyperdrive-demo --connection-string="postgresql://harunobu:xxxxxxxx@ep-mute-poetry-58679204.us-east-2.aws.neon.tech/hyperdrive-demo?sslmode=require"
 {
  "id": "xxxxxxxxxx",
  "name": "hyperdrive-demo",
  "origin": {
    "host": "ep-mute-poetry-58679204.us-east-2.aws.neon.tech",
    "port": 5432,
    "database": "hyperdrive-demo",
    "user": "harunobu"
  },
  "caching": {
    "disabled": false
  }
}

idの部分はCloudflare内部の識別子なのでメモしておきます。
次にwrangler.tomlに以下を追記します。

node_compat = true # required for database drivers to function

[[hyperdrive]]
binding = "HYPERDRIVE"
id = "xxxxxxxxxxxxxxxxxxxx" 

idは先ほどのものを挿入します。node_compat = trueですが、WorkersはNode.jsサポートは限定的であるものの一部の機能はサポートしています。Hyperdriveの機能にNode.jsは必要ありませんが、次の手順で出てくるPostgres用ツールをWorkersにImportする際に必要となります。
では

npm i pg

でPostgres用ツールをインストールします。次にindex.ts (作業している環境によってはworkers.tsになっているバージョンもあります)を以下に置き換えます。

index.ts
import { Client } from 'pg';

export interface Env {
	// If you set another name in wrangler.toml as the value for 'binding',
	// replace "HYPERDRIVE" with the variable name you defined.
	HYPERDRIVE: Hyperdrive;
}

export default {
	async fetch(request: Request, env: Env, ctx: ExecutionContext) {
		console.log(JSON.stringify(env))
		// Create a database client that connects to our database via Hyperdrive
		// Hyperdrive generates a unique connection string you can pass to
		// supported drivers, including node-postgres, Postgres.js, and the many
		// ORMs and query builders that use these drivers.
		const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });

		try {
			// Connect to our database
			const begin = performance.now();
			
			await client.connect();
			// Test query
			let result = await client.query({ text: 'SELECT * FROM pg_tables' });

			const end = performance.now();

			console.log(end - begin);
			// Return result rows as JSON
			return Response.json({ result: result });
		} catch (e) {
			console.log(e);
			return Response.json({ error: JSON.stringify(e) }, { status: 500 });
		}
	},
};

Cloudflare の WorkersコンソールからSQLの処理にかかった時間が取れるようにしてあります。

npx wrangler deploy

でデプロイを行います。
CloudflareのWorkersコンソールでログをオンにしておきます。

ブラウザでアクセスをするとSELECT * FROM pg_tablesの実行結果が戻ってきます。
コンソールに処理時間が出ています。

私の場合、初回接続で1800ms~300ms程度のばらつきがみられ、2回目以降は60ms程度になります。
(US-WESTにNeonを立ち上げて、WorkersへのアクセスはTKO)
Hyperdriveはデフォルトで1分間のキャッシュ期間が設定されおり、1時間まで伸ばすことが可能です。
Hyperdriveによるコネクションプーリング機能は使いたいが、SQL結果のキャッシュ機能は切りたい場合以下のコマンドで切り替えが可能です。

wrangler hyperdrive update <id> --origin-password xxxxxxxxxx --caching-disabled false  

<id>はHyperdriveのIDに置き換えます。

Hyperdrive を用いない Postgresとの比較

ではWorkers Connect経由でHyperdriveを用いずNeonに接続するとどうなるでしょうか。
その手順はここにまとまっていますので、解説は控えます。
https://developers.cloudflare.com/workers/tutorials/postgres/
だいぶパフォーマンスに差が出ていることがわかります。

注意点:初回接続、ないしはHyperdriveのコネクションがExpireした後のパフォーマンスは、Hyperdriveなしの状態とありの状態に差は出ませんので、気を付けてください。

Discussion