はじめに 本記事はdely Advent Calendar 2018の4日目の記事です。 dely Advent Calendar 2018 - Adventar dely Advent Calendar 2018 - Qiita 昨日は弊社の機械学習エンジニアの辻がNixOSについての記事を書きましたので興味のある方は是非読んでみてください。 tech.dely.jp こんにちは!delyでSREをやっている井上です。 本記事では、WEBパフォーマンスの定点観測の仕組みを手軽に構築出来るようにしたのでその紹介をしたいと思います。 本記事では下記のサービスやツールを利用しています。 AWS Terraform sitespeed.io 前置きはいいから構築方法だけ知りたいという方は こちら! 目次 はじめに 目次 WEBパフォーマンスについて sitespeed.ioについて 主な機能 各種スコア Waterfall Visual Metrics Browser Metrics レンダリング時の動画再生 スコアに対するアドバイスの表示 レスポンスの遅いリクエスト サイズの大きい画像やjavascript 主な特徴 定点観測について 定点観測の方法 CodeBuildのメリット 定点観測基盤の構築方法 構成図 前提 準備 1.レポジトリのフォーク 2.Terraformのtfstateファイル管理用のS3バケットの作成 3.terraform.tfvarsの作成 4.backend.tfvarsの作成 5.Terraform作業ディレクトリの初期化 6.対象サイトの指定 構築 sitespeed.ioによる計測結果の参照 HTML SQL VIEW作成 Redashによる可視化例 カスタマイズ sitespeed.ioの試行回数の調整 計測間隔の調整 料金について さいごに WEBパフォーマンスについて 2018年7月のGoogleのスピードアップデートでも分かる通り、WEBページの読み込み速度はPCかモバイルかに関わらずより一層重要視されてきています。 読み込み速度の遅いWEBページを改善しようとなったとき、まずはじめに現状を把握する必要がありそのためにはWEBのパフォーマンス計測を行う必要があります。 現在、WEBのパフォーマンスを計測する手段としては google chromeのLighthouse機能 WebPageTest( https://www.webpagetest.org ) PageSpeed Insights( https://developers.google.com/speed/pagespeed/insights/ ) などいくつかありますが、本記事では現在delyで利用しているsitespeed.ioというツールを紹介したいと思います。 sitespeed.ioについて sitespeed.ioはオープンソースのWEBパフォーマンス計測ツールです。 www.sitespeed.io 主な機能 sitespeed.ioを使うことで下記のようなデータをWEBブラウザで閲覧することが可能になります。 各種スコア Waterfall Visual Metrics Browser Metrics レンダリング時の動画再生 スコアに対するアドバイスの表示 レスポンスの遅いリクエスト サイズの大きい画像やjavascript 主な特徴 また前段で挙げたWEBパフォーマンス計測ツールと違い、下記のような特徴を持っています。 Dockerによる簡単な実行 公式のdocker imageがあるので、下記のコマンドによって簡単に実行することが可能です。 $ docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:7.7.2 https://www.sitespeed.io/ 結果のhtml出力 実行後、計測結果がhtmlで出力されているのでWEBブラウザで簡単に閲覧することが可能になっています。 ※ YYYY-MM-DD-HH-mm-ss は実行時刻が入ります $ open sitespeed-result/www.sitespeed.io/YYYY-MM-DD-HH-mm-ss/index.html 他にも下記のような機能を標準で備えているので、柔軟な運用が可能になっています。 htmlをS3にアップロードする機能 結果をSlackに通知する機能 結果のメトリクスをjson形式で出力する機能 定点観測について WEBのパフォーマンスにおいてボトルネックを特定するだけであれば、その時点で数回の計測を実施すればよいですが、ボトルネックに対して対策を行った後、どの程度改善したのかについて知りたい場合は対策後に再度計測を実施する必要があります。 複数の対策を長期的に実施していく場合などは、対策を実施する度に計測を実施する必要があり非常に大変です。 また、上記とは反対に何かのタイミングで意図せずパフォーマンスが悪くなっていないかをチェックしたいときやパフォーマンスが悪くなった前後でまたそのタイミングで何が原因かなどは遡って確認したいこともあります。 そういった要件を達成するためには、一定間隔で繰り返しWEBパフォーマンス計測を実施する必要があります。 定点観測の方法 定期的にWEBのパフォーマンス計測を行うには下記のような方法が考えられます。 定期的に手動で実施 一番単純なのは定期的に手動で行うことです。 ただ現実的には手作業で行うため忘れることがあったり、そもそも同じ時間に実行するのが難しかったりします。 サーバを構築してcronやCIツールで定期的に実行 次はサーバを立ててcronで実行したりJenkinsなどのCIツールで定期的に実行する方法です。 この方法は、他の処理が裏側で動いていてパフォーマンス計測に影響があることを考慮する必要があったり、 そもそもサーバの管理が必要になってしまうことにデメリットを感じてしまいます。 ECSのタスク実行機能やAWS Batchで定期的に実行 理論的には実現できそうですが、WEBパフォーマンスの定点観測を行うだけなので少し大げさな気がします。 上記に3つほど方法を挙げて見ましたが、どれもいまいちという感じです(主観)。 そこで提案したいのがAWSのCodeBuildによる定期実行です! CodeBuildのメリット CodeBuildは本来CIで利用するサービスですが、サーバレスな実行環境としても優れていると思います。 WEBパフォーマンス計測の実行環境として使うことにおいては下記のようなメリットがあります。 サーバレスなのでリソースを気にしなくてよい 実行時間による従量課金 CloudWatch Event連携でcronフォーマットによる定期実行も可能 定点観測基盤の構築方法 ここからは具体的な構築方法を紹介します。 本記事で使用するコードは全てGithubにあげています。 github.com AWSのリソースをTerraformを使ってコード化しているので、定点観測基盤を手軽に構築することが可能です。 構成図 CodeBuild sitespeed.ioを実行する実行環境として利用します。 CloudWatch Event CodeBuildを定期的に実行するスケジューラとして利用します。 S3 sitespeed.ioによる計測結果の格納と、HTMLのホスティングとして利用します。 Glue sitespeed.ioによる計測結果のスキーマを定義するために利用します。 Athena sitespeed.ioによる計測結果に対してSQLを実行するために利用します。 前提 基盤構築に伴って最低限下記が実行環境に設定されている必要があります。 awscliのインストールとcredentialの設定 Terraformの利用に伴ってAWSのアクセスキーとシークレットキーの設定が必要です。 Terraformのインストール IAMに対するTerraformを実行するための十分な権限設定 AWS CodeBuildとGitHubの接続 AWSコンソール上のCodeBuildにおいてプロジェクト設定時のページで下記のように、「GitHubアカウントを切断」と表示されている必要があります。されていない場合は「GitHubに接続」ボタンからGitHub連携を済ませてください。 CodeBuildとGitHubが接続されていないとTerraformのapply時にエラーになりますのでご注意ください。 準備 1.レポジトリのフォーク 下記のレポジトリをご自身のアカウントにForkします。Cloneして新しくレポジトリを作成しても大丈夫です。 GitHub - gomesuit/webperf-by-codebuild 2.Terraformのtfstateファイル管理用のS3バケットの作成 空のS3バケットを1つ作成します。 既存のものでも大丈夫ですが、tfstateファイルのkeyをコードにべた書きしているので新規でS3バケットを作成することをおすすめします。 3.terraform.tfvarsの作成 sitespeed.ioの出力したhtmlをS3のホスティング機能を使って参照するため、自身のIPでアクセス制限をかけます。 またCodeBuildがソースを取得する先を、手順で作成したレポジトリのURLに変更します。 サンプルファイルがあるのでコピーしてから、 $ cd terraform $ cp terraform.tfvars.sample terraform.tfvars ファイル内のIPアドレスとレポジトリを変更します。 # S3のアクセス元IP my_ip = "XXX.XXX.XXX.XXX/32" # 作成した自身のGitHubレポジトリ git_repository = "https://github.com/<user-name>/<repository-name>" 4.backend.tfvarsの作成 Terraformのtfstateファイル管理用のS3バケットを terraform init のタイミングで指定するためファイルを作成します。 サンプルファイルがあるのでコピーしてから、 # ./terraform ディレクトリで実施 $ cp backend.tfvars.sample backend.tfvars ファイル内のバケット名を変更します。 # tfstateを格納するS3バケット bucket = "自身で作成したS3バケットの名前" 5.Terraform作業ディレクトリの初期化 下記のコマンドでTerraformの作業ディレクトリを初期化します。 エラーがでなければOKです。 # ./terraform ディレクトリで実施 $ terraform init -backend-config backend.tfvars 6.対象サイトの指定 計測するページのURLをurls.csvに記載します。 一行に ドメイン名,対象URL,カテゴリ の順で記載します。 複数行記載すると1回のCodeBuildの実行で複数のURLが計測されます。 カテゴリ名は対象URLをカテゴライズするために付与します。任意の文字列を入力してください。 例えば https://www.kurashiru.com/ を計測対象URLとする場合、下記のようになります。 トップページなのでカテゴリはtopとしました。 計測対象のWEBサイトはご自身が管理されているものを記載してください。 www.kurashiru.com,https://www.kurashiru.com/,top 構築 Terraformを実行します。 # ./terraform ディレクトリで実施 $ terraform apply しばらくすると下記のようにコンソールに出力されるので、確認の後に「yes」と入力するとリソースの生成が始まります。 Plan: 16 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: 上記コマンドで生成したリソースを削除する場合は下記コマンドを実行します。 # ./terraform ディレクトリで実施 $ terraform destroy sitespeed.ioによる計測結果の参照 最大1時間待つか設定済みのCodeBuildを手動で1度実行するとS3に計測結果が置かれます。 HTML S3バケットにhtmlが出力されているのでブラウザで開くことで計測結果を閲覧することができます。 例えばURLは下記のようなものになります。 https://s3-ap-northeast-1.amazonaws.com/webperf-by-codebuild-d85de1e5e348/raw/www.sitespeed.io/desktop/top/2018/12/01/15/38/index.html SQL AWSコンソールのAthenaでSQLを実行すると結果が取得できるようになっています。 SQL例 SELECT * FROM "webperf_by_codebuild_d85de1e5e348"."json" limit 10; VIEW作成 このままでも問題はないのですが、SQLを作成するときにSQLが複雑にならないようにVIEWを設定するのをおすすめします。 例えば下記のようなVIEWを生成することでS3のURLとtimestampのカラムを事前に定義しておくことが可能です。 SQLの下記の部分を自身でTerraformを実行した結果に置き換えてください。 「<Terraformによって生成されたS3バケット>」 「<Terraformによって生成されたデータベース>」 CREATE OR REPLACE VIEW " <Terraformによって生成されたデータベース> " . " site " AS SELECT CAST ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " YEAR " , ' - ' ), " MONTH " ), ' - ' ), " DAY " ), ' ' ), " hour " ), ' : ' ), " minute " ) AS timestamp) " time " , " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( ' https://s3-ap-northeast-1.amazonaws.com/<terraformによって生成されたS3バケット>/raw/ ' , " domain " ), ' / ' ), " device " ), ' / ' ), " category " ), ' / ' ), " year " ), ' / ' ), " month " ), ' / ' ), " day " ), ' / ' ), " hour " ), ' / ' ), " minute " ), ' /index.html ' ) " link " , * FROM " <Terraformによって生成されたデータベース> " . " json " 置き換え例 CREATE OR REPLACE VIEW " webperf_by_codebuild_d85de1e5e348 " . " site " AS SELECT CAST ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " YEAR " , ' - ' ), " MONTH " ), ' - ' ), " DAY " ), ' ' ), " hour " ), ' : ' ), " minute " ) AS timestamp) " time " , " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( " concat " ( ' https://s3-ap-northeast-1.amazonaws.com/webperf-by-codebuild-d85de1e5e348/raw/ ' , " domain " ), ' / ' ), " device " ), ' / ' ), " category " ), ' / ' ), " year " ), ' / ' ), " month " ), ' / ' ), " day " ), ' / ' ), " hour " ), ' / ' ), " minute " ), ' /index.html ' ) " link " , * FROM " webperf_by_codebuild_d85de1e5e348 " . " json " 結果例 SELECT * FROM " webperf_by_codebuild_d85de1e5e348 " . " site " limit 10 ; URLとtimestampのカラムが追加されていることを確認できます。 Redashによる可視化例 弊社では例えば下記のSQLを実行することによって、 SELECT * FROM " <Terraformによって生成されたデータベース> " . " site " WHERE device = ' desktop ' AND time >= current_timestamp - interval ' 1 ' month AND category = ' top ' AND domain = ' www.kurashiru.com ' ORDER BY time desc ; 下記のような結果を得ています。 また上記の結果を下記のようにRedashを使ってグラフ化しています。 上記は弊社での例ですが、sitespeed.ioによって様々なメトリクスが取得されているので色々な指標の相対的な変動を計測することが可能になっています。 カスタマイズ sitespeed.ioの試行回数の調整 WEBサイトのパフォーマンスはサードパーティーコンテンツによって影響を受けるのでリクエストするたびにパフォーマンスにずれが発生することが多いです。 そのため1回の計測で数回施行することが一般的です。 sitespeed.ioは設定ファイルのパラメータを変更することで試行回数を調節することができます。 設定ファイルはレポジトリのルートにあるconfig.jsonというファイルで、iterationsというパラメータを3から変更することで施行回数を調節することが可能です。 { " browsertime ": { " iterations ": 3 , " speedIndex ": true } , " s3 ": { " region ": " ap-northeast-1 " } , " crawler ": { " depth ": 1 } , " plugins ": { " load ": [ " analysisstorer " ] } } 計測間隔の調整 計測のトリガーはCloudWatch Eventで行っています。そのためCloudWatch Eventの設定を変更することで計測間隔の調整をすることが可能です。 Terraformの該当ファイルは terraform/codebuild_trigger.tf です。schedule_expressionの cron(0 * * * ? *) を変更することで間隔を変更することが可能です。 反映するにはもう一度 terraform apply を実行します。 料金について 本記事の設定で実際にかかっている料金をご参考までにお伝えします。 現在4つのURLの計測を1時間毎に実行していますが、CodeBuildの該当料金は1ヶ月に約$40になります。 決して安くはないですが、サーバの管理がいらないため負荷や障害を気にせず運用することが可能です。 さいごに WEBパフォーマンスの定点観測についてお話しました。 手間をかけずにとりあえずパフォーマンス計測を始めたいという要件にもってこいではないでしょうか。ぜひ皆様のWEBパフォーマンス分析の参考にしていただけたらと思います。 明日は検索エンジニアのsakura (@818uuu) が「クラシルの検索エンジニアが検索をよくするために取り組んだこと まとめ」というタイトルで投稿します!お楽しみに! tech.dely.jp