dely engineering blog

レシピ動画サービス「kurashiru」を運営するdelyのテックブログ

超手軽に構築する!サーバレスなWEBパフォーマンス定点観測基盤

はじめに

本記事は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

前置きはいいから構築方法だけ知りたいという方は こちら!

f:id:gomesuit:20181202191536p:plain

目次

WEBパフォーマンスについて

2018年7月のGoogleのスピードアップデートでも分かる通り、WEBページの読み込み速度はPCかモバイルかに関わらずより一層重要視されてきています。 読み込み速度の遅いWEBページを改善しようとなったとき、まずはじめに現状を把握する必要がありそのためにはWEBのパフォーマンス計測を行う必要があります。

現在、WEBのパフォーマンスを計測する手段としては

などいくつかありますが、本記事では現在delyで利用しているsitespeed.ioというツールを紹介したいと思います。

sitespeed.ioについて

sitespeed.ioはオープンソースのWEBパフォーマンス計測ツールです。

www.sitespeed.io

主な機能

sitespeed.ioを使うことで下記のようなデータをWEBブラウザで閲覧することが可能になります。

各種スコア

f:id:gomesuit:20181126225433p:plain:w600

Waterfall

f:id:gomesuit:20181126225636p:plain:w600

Visual Metrics

f:id:gomesuit:20181126225720p:plain:w600

Browser Metrics

f:id:gomesuit:20181126225736p:plain:w600

レンダリング時の動画再生

f:id:gomesuit:20181126225824p:plain:w600

スコアに対するアドバイスの表示

f:id:gomesuit:20181126225851p:plain:w600

レスポンスの遅いリクエスト

f:id:gomesuit:20181126225927p:plain:w600

サイズの大きい画像やjavascript

f:id:gomesuit:20181126225915p:plain:w600

主な特徴

また前段で挙げた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を使ってコード化しているので、定点観測基盤を手軽に構築することが可能です。

構成図

f:id:gomesuit:20181202191536p:plain

  • 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連携を済ませてください。

f:id:gomesuit:20181201200034p:plain

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

f:id:gomesuit:20181202005018p:plain

SQL

AWSコンソールのAthenaでSQLを実行すると結果が取得できるようになっています。

SQL例

SELECT * FROM "webperf_by_codebuild_d85de1e5e348"."json" limit 10;

f:id:gomesuit:20181202004551p:plain

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;

f:id:gomesuit:20181202022902p:plain

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;

下記のような結果を得ています。

f:id:gomesuit:20181127175929p:plain

また上記の結果を下記のようにRedashを使ってグラフ化しています。

f:id:gomesuit:20181127163011p:plain

上記は弊社での例ですが、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