Server Side Rendering の技術概要

Adventarを支える技術 Advent Calendar 2019 の10日目です。

今日は Adventar の Server Side Rendering(以下 SSR)している技術構成について書きます。

インフラ構成

まず、先日の記事に書いたように、Adventar ではすべてのページを SSR しているのではなく、カレンダーの詳細ページだけを SSR しています。SSR するカレンダー詳細は API Gateway で受けて Lambda でレンダリングしており、そうでない静的なアセットは S3 で配信しています。その前段のルーティングは CloufFront でおこなっています。

f:id:hokaccha:20191210124537p:plain

S3 で捌いているのは、JS や CSS などの静的ファイルは当然ですが、例えばトップページなどの HTML も S3 が返します。ただしこの HTML は SSR されていない、JS と CSS のリンクだけしかない HTML で、クライアントサイドで API を呼び出してコンテンツをレンダリングします。

なぜ Lambda か

Lambda でも Cloud Functions でもよかったのですが、単に他のインフラ構成要素が AWS になったからで、Cloud Functions との技術的な比較はしていません。

常駐型のサーバーと比べて Lambda などのサーバーレス環境を利用するのは、管理コスト(費用、手間)が安く済むというのが大きいでしょう。うまく使えば安く済むし、サーバーを管理しなくていいというのは非常に大きいメリットです。

一方デメリットとしては、パフォーマンスなどが挙げられると思います。Lambda は遅くはないですが、コールドスタートなどのデメリットもあるし、常駐型のサーバーと比べるとパフォーマンスの最適化はしづらい側面があると思っています。これについては、先日発表された Provisioned Concurrency によって解決できるかもしれないですけどまだちゃんと試してません。

https://aws.amazon.com/jp/blogs/aws/new-provisioned-concurrency-for-lambda-functions/

今回は SSR した結果を CDN でキャッシュするという予定だったので、パフォーマンス、費用面ともに常駐サーバーよりは有利になる予定でした。前日にも書いたとおり、現状は一旦キャッシュの実装は見送って毎回 Lambda が呼ばれていますが、費用的にはサーバーを用意するよりは安く済みそうです。パフォーマンスは HTML のレスポンスタイムが200ms〜300ms ぐらいかかっているので、速くはないが、激遅でもないという感じです。

Lambda で Nuxt.js の SSR

Nuxt.js は

$ nuxt start

SSR なサーバーを起動することができ、レールを外れずに使う場合はこれでいいのですが、今回は Lambda を使って SSR したいのでこれは使えません。

Nuxt.js はカスタムサーバーを利用する場合、nuxt.renderという express の middleware などと互換性のある API を提供しているのでこれを使います。

https://nuxtjs.org/api/nuxt-render/

また、Lambda で express などのサーバーを利用するための serverless-http というモジュールがあるので、これも利用します。

https://www.npmjs.com/package/serverless-http

これらを利用すると、以下のような感じで Nuxt.js を Lambda で利用できます。

import { Nuxt } from "nuxt";
import serverless from "serverless-http";
import express from "express";
import config from "~/nuxt.config";

const app = express();
const nuxt = new Nuxt(config);
app.use(nuxt.render);
module.exports.handler = serverless(app);

他にも RSS などの動的コンテンツを同時に配信しているので、少し複雑になっていますが、コードは以下のような感じです。

https://github.com/adventar/adventar/blob/b491c3be64b8d35b3484b69e4f9ce8f6ecfb93eb/frontend/server.ts

これを Lambda で実行すれば、クライアント側で同じコードで HTML が生成されて返ってきます。前述したように、API Gateway を通してカレンダーページだけでこれを実行しているわけです。

まとめ

Adventar における SSR の技術構成について書きました。明日は SSR を含めた、フロントエンドのデプロイについて書こうと思います。