Serverless(2)アドベントカレンダーの6日目の記事です。
なにげにQiita上には初投稿なのでお手柔らかにお願いします。
普段はQiita team使っているので、そっちと記事との共有ができれば良いのになーと小言を言ってみたり。。。
今回は、表題の通り、サーバーレスでWebサイト作った話です。
Webサイトの要件
- ブログのようなサイト
- 静的URLで配信したいが、動きとしては動的な部分もあり
実現してみた方法
API Gatewayでhtmlを返しただけ
※当初はコンテンツをAjaxで取ってくる形式にしてたのですが、クローラーさんの結果がうまく行かず、サーバーサイドレンダリングにしちゃいました
実装環境
- Serverless Framework 0系
- node.js 4.3
- Typescript 1系
アーキテクチャ
- cloudfrontでパスを振り分け
- 静的なコンテンツのみS3へ振り分け
- 動的ページはAPI Gatewayに振り分けて、LambdaがRDSからデータ取得して、HTML形式に変換して返却
レスポンスの定義
下記のような設定でレスポンスでもってコントロール
※まだServerlessFramework 0系で実装しています。
"responses": {
"400": {
"statusCode": "400"
},
"503": {
"selectionPattern": ".*Task timed out after .+ seconds",
"statusCode": "503"
},
"404": {
"selectionPattern": "(.|\\n)*\\\"status\\\"\\:\\s*\\n*\\s*\\\"notfound\\\"(.|\\n)*",
"statusCode": "404"
},
"default": {
"statusCode": "200",
"responseParameters": {},
"responseModels": {
"text/html": "Empty"
},
"responseTemplates": {
"text/html": "#set($inputRoot = $input.path('$'))$inputRoot.variableHTML"
}
}
}
lambdaのコードの一部
lambdaのコードはtypescriptで実装しています。
vue-serverでレンダリングしてhtmlを返却しています。
var root = new Vue({
template: htmlPage
});
root.$on('vueServer.htmlReady', function(html: string) {
var htmlPretty = require('html');
html = htmlPretty.prettyPrint(html, { indent_size: 2 , indent_caractor: '\t\t'});
const $ = cheerio.load(html);
$('title').text("ほげほげ");
$('h1').text("ほげほげについて");
var result = {
variableHTML: $.html({decodeEntities: false})
}
cb(null, <any>result);
});
ハマりポイント
ENI作成処理によるタイムアウト
西谷さんが下記の記事で書いている通り、Lambda→RDSの通信で同じVPC内でもENI作成処理に数十秒かかる場合があるようで、
結構タイムアウトが頻発してました。
記事にもある通り、完全な解決策はないようですが、
5分ごとにポーリングする設定を入れたらほぼタイムアウトは出なくなりました。
http://qiita.com/Keisuke69/items/1d84684f0511a062e968
パフォーマンスが出ない
これはアーキテクチャに少し依存するのですが、cloudfrontとAPIGatewayを置いているので、デフォルトで数百ms × 2のレイテンシが発生しています。
※APIGatewayも内部的にCloudfront使っているため
ここの解決策は、今後キャッシュ戦略をどうとるのかにかかっているので課題です。
まとめ
突貫で記事書いたのでまとまりなくて申し訳ないです。
SEO条件なんだよーとか、前提条件をあまり書けてないですが、Serverlessを検討している方の参考になれば幸いです。