CloudflareでPrismaを使うとサーバーからデータを取得するのに時間がかかってしまう
これは以下のZennのScrapsに書いた開発記録のまとめです。
- Remix+CloudflareでWebサイトを作る 40(v2.13でheaders機能せず、TTFBが3.8sかかってる問題、計測する、Waterfallを理解する)
- Remix+CloudflareでWebサイトを作る 42(1から作りなおしてCloudflare PagesのTTFBが遅い原因を探る)
- Remix+CloudflareでWebサイトを作る 43(TTFBが遅いの原因はPrisma、Prisma→Drizzleへの移行手順)
背景
Remixで作ったアプリをCloudflare Pagesにデプロイしたところ最初のサーバー応答時間(TTFB)が3,800 ~ 5,000msかかってしまった。
このページでは3つのテーブルから計60個ほどのアイテムを取得していた。
以下は実際のLighthouseでの計測結果。
GoogleではTTFBを800ms以下にすることを推奨していることからも、かなり遅いということがわかる。
技術スタック
- Remix v2.13
- Cloudflare Pages
- shadcn/ui
- Prisma
- Turso(DB)
原因を探す
Remix + Cloudflare Pagesのリポジトリを新たに作って、3つのページを用意し、それぞれのページで3回計測を行った。
URL | 概要 | TTFB |
---|---|---|
/json-placeholder-200 |
JSON PlaceholderからTodoを200件取得 | 240 ~ 430 ms |
/json-placeholder-1000 |
JSON PlaceholderからTodoを1,000件取得 | 500 ~ 600 ms |
/db-connect |
DBの2つのテーブルから5件ずつ、計10件取得 | 1,970 ~ 2,310 ms |
DBに接続しているページで明らかに遅いので原因を考えてみる。
- Remixの書き方がなにかミスっている?
- →
/json-placeholder-200
、/json-placeholder-1000
の結果は問題なさそう
- →
- Cloudflareの設定ミス?
- → 新たにアプリケーションを作成した直後だし問題ない気がするけど...
- TursoのCold startが原因?
- → 月9ドルの有料プランに入ってCold startをなくしてみたけど計測結果変化しなかった
- FreeプランはCold startが存在する
- Turso Database Pricing
- → 月9ドルの有料プランに入ってCold startをなくしてみたけど計測結果変化しなかった
原因わからん。詰んだ/(^o^)\
人に聞こう
偶然にも「Remix Tokyo x Cloudflare Meetup」というものが原因を探していた次の週に開催されて10分ほどプレゼンする予定だったので相談会にさせてもらいました🙇🏻♂️🙇🏻♂️🙇🏻♂️(アドバイスをくださった方ありがとうございました!)
結論
Prismaが原因だった。
エッジで動かすならサイズの小さいDrizzleを使おう。
- エッジで動作させている以上基本的にサイズが大きければ大きいほど遅くなる
- Prismaは850KiBある。Drizzleは67KiB
- Cloudflareは長時間アクセスされない場合は落ちる仕様で、Cloudflareの設定で制御できるものではない
- Prismaは起動が遅い
- 現在改善中とのこと
これは残念ながら事実だ。 しかし、私たちはこの1年間、パフォーマンスを向上させるために懸命に取り組み、成功させた。 来年はさらに努力するつもりであり、私たちが取り組んでいることを共有するのが待ちきれない。
Drizzleを導入して再計測
TTFBの計測
PrismaからDrizzleへ移行して(commit) 再計測を行った結果が以下。
無事早くなりました。
ORM | URL | TTFB |
---|---|---|
Prisma | /db-connect |
1,970 ~ 2,310 ms |
Drizzle | /db-connect |
1,020 ~ 1,210 ms |
サイズの計測
ついでに以下のコマンドでアプリケーションのサイズも測ってみます。
npx wrangler deploy 'functions/[[path]].ts' --outdir bundled/ --dry-run
アプリ | サイズ(gzip) |
---|---|
アプリ作成直後 | 350 KiB |
Prisma追加時 | 1202.67 KiB |
Drizzle追加時 | 417.39 KiB |
つまり、 Prismaが852 KiB (= 1202 - 350) 、Drizzleが67 KiB (= 417 - 350)。PrismaはDrizzleの12.7倍も大きいという結果になりました。
また、Prisma追加時にはCloudflare Workersの制限である1MBを超えているため有料プランに月5ドルで加入する必要がありました。しかし今回Drizzleを導入することで無料プランですませることができました 👏🏻
追記:執筆時の2024-11-24段階では無料プランの上限が1MBでしたが、2024-11-27より上限が3MBになったのでここは取り消します(ただし小さと速いので小ささは正義!)。
mizchiさんのスライドにも1MBをパフォーマンスバジェットにと書いてある。サイズ大事。
おまけ
Meetupでは「Cloudflare Workersの方が機能が多いので基本そっちによせるほうが良い」との声もあったので今回のテスト用リポジトリもCloudflare Workers版を作成してみました。
これを元に自分のアプリもCloudflare Workersにしてみよう。
Discussion