Monthly Archives: 9月 2017

2017-09-26

Alpine Linuxのその後、そしてLinuxKitとは?

GMOアドマーケティングSSP開発グループのn.yです。

前提

以前コチラの過去記事にてDockerによるローカル環境構築に関する記事を書かせて頂きましたが、今回もDockerの環境構築とりわけAlpine LinuxLinuxKitを巡る事情に関してお話できればと思います。

まずAlpine Linuxに関して軽くおさらい

  • 軽量なLinux OS(ベースイメージは約5MB(ちなみにUbuntuだと100MB以上))

→ 他に同様の軽量なLinux OSで代表的なものにCoreOS, RancherOS, Red Hat’s Atomic Host など色々。

  • DockerのオフィシャルのイメージをUbuntuからAlpine Linuxに置き換えている

ぐらいを押さえておくと良いです。要は軽量Docker推しのLinux OSだということです。

その後、Alpine Linuxはどうなったのか?

早速、主要言語実行環境&Webサーバに関して、オフィシャルのイメージがAlpine Linuxへどれだけ置き換えられているのかをDocker Hubにて調べてみました(2017/08/21時点)

latestタグに関してのみ調査(docker pullコマンドでlatestタグはデフォルトで使用される為、Docker側が本当に現状で推奨しているかの判断の基準にしてみました)

詳細はコチラのDockerの公式ドキュメントを参照

それでは行ってみましょう!

まずはPythonから。

latestこの並びにある様ですね。

んん。。?jessieの並びにありますね。これはもしやDebianをベースにしているのでは?

試しにDebianのバージョンを下記コマンドで調べてみます。(コンテナが既に立ち上がっている状態)

Debianベースなのは間違いないですね。多分無いとは思いますが、下記コマンドにてAlpineベースなのかをチェック。

残念ながらどれもダメですね。と言うことはつまりデフォルトではPythonの実行環境は現状Debianベースということですね。

ちなみにDockerfileの中身も確認してみます。

やはりDebianベースですね。

少し嫌な予感がしますね。幸先が悪い予感が。。

では続けて、他の主要言語の実行環境も調べてみましょう。

  • Ruby やはりlatestタグはjessieの並びからのDockerfileもやはりDebianベース
  • PHP これまた同様にDebianベース
  • Apache(httpd) こちらも同様にDebianベース

最後にこちらも

  • Nginx やはりDebianベース

調査結果

今回調査したものは全てDebianベースとなっていました。

つまり現状ではDebianベースがまだデフォルトだけど、Alpineベースもあるよって感じのスタンスみたいです。

続いてLinuxKitについて

そういった状況の中今年4月にアメリカはテキサスで開催されましたDockercon 2017にてLinuxKitなるものが発表されました。

内容を見てみると、コンテナを動かせるようにすることに特化したツールらしくWindowsだったりmac OSなどのネイティブではLinux環境を持たないところでもコンテナの実行環境を構築することが可能になり、例によって軽量で約35MBとのことです。

これはかなり画期的なことで、Linux環境を雑に言えばどこにでも構築できる様になったことを意味します。

そしてこのプロジェクトにDocker社を始め、Intel社やARM社だったり各クラウドプロバイダーも共同で参加しているとのことです。

まとめ

ただし注意して欲しい点としてはAlpine LinuxLinuxKitは似て非なるものです。

Alpine Linuxはあくまでも軽量なLinux OSであり、LinuxKitはコンテナプラットフォームを構築することに特化したツールだからです。

この点に気をつけて頂ければと思います。

LinuxKitを使って環境構築してみたい方は下記のGitHubのページのREADMEを是非ご参考下さい。

https://github.com/linuxkit/linuxkit

以上、Alpine Linuxのその後、そしてLinuxKitの位置づけについてのお話でした。

 

2017-09-20

TensorBoardでTensorFlowの数値計算を可視化する

こんにちは。GMOアドマーケティングのT.Iです。
機械学習のブームとともにChainerやCNTK, Theanoといった、ディープラーニング・機械学習に関するライブラリが数多く登場しています。
今回はその機械学習(数値計算)ライブラリの一つである「TensorFlow」の環境構築と、その可視化ツールである「TensorBoard」について紹介します。

TensorFlowとTensorBoard

TensorFlowはGoogle社が提供する機械学習(数値計算)のためのライブラリです。
2015年11月にオープンソースとして公開され、現在では数多くの企業でTensorFlowが活用されています。(公式サイト上にCompanies using TensorFlowとしていくつかの企業が紹介されています)
そのTensorFlowの特徴の一つに、TensorBoardによる強力な可視化機能があります。
では早速、TensorFlowの環境構築とTensorBoardによる可視化を試してみます。

TensorFlowの導入

TensorFlowのインストール方法はいくつかありますが、今回は検証なのでローカルマシンのMac上にDockerで環境を作ってみます。

なお、Dockerは Docker for Mac で導入しました。

TensorFlowは公式のDockerイメージが公開されているので、まずはDockerイメージを入手します。

特にタグを指定しない場合、 CPU onlyのTensorFlowが選択されます。

問題なくpullできました。

GPU対応版のTensorFlowを導入したい場合は以下のようにタグを付与してみて下さい。

 

続いてコンテナを起動します。

このあとTensorBoardへ接続するためにローカルマシンから localhost:6006 へアクセスする必要があるため、オプションでポートを公開しています。

ログインできたので、まずはPythonとTensorFlowのバージョンを確認してみます。

Python :2.7.12、TensorFlow :1.3.0 がインストールされました。

同時にTensorBoardも導入されていることが確認できます。

 

TensorBoardで可視化する

まず初めに、GitHubで公開されているTensorFlowのサンプルコードを動かしてみます。

無事に動作しましたが、これだけでは面白くないのでTensorBoardで計算過程を可視化してみましょう。

TensorBoardを動作させるために少しコードを修正します。

tf.summary.FileWriter でTensorBoardで表示するための計算グラフイメージをイベントファイルに書き込んでいます。

上記のコードを実行すると、実行したディレクトリ上に「data」というディレクトリが作成されるので、作成されたディレクトリを以下のように指定・実行し、ローカルマシンから localhost:6006 へアクセスしてみましょう。

localhost:6006 へアクセスすると、TensorBoardの画面が表示されます。

「GRAPHS」のタブへ移動すると、上記計算の計算グラフが確認でき、それぞれの要素を選択することでさらに詳細の情報を表示することが可能です。

 

さらに複雑な計算グラフを可視化するため、MNISTデータセット(手書き数字の画像セット)のチュートリアルであるMNIST For ML BeginnersをTensorBoardで可視化してみます。

サンプルのソースコードに対して先程のように tf.summary.FileWriter を追加し、計算グラフをよりわかりやすくするため、以下のように変数・プレースホルダーの名前付けを行っています。

可視化したものはこちらになります。

入力に対して重みやバイアスがどのように働いているのかが確認することが出来ます。

 

それぞれのシンボルについては公式ページで詳細に解説されているので、ぜひ参考にしてみて下さい。

さいごに

今回はDockerを使ったTensorFlowの環境構築と、TensorFlowの可視化ツールである「TensorBoard」について紹介しました。

今回は計算グラフの可視化のみの紹介でしたが、TensorBoardには画像や学習過程の可視化など様々な機能があるので、興味のある方はぜひ試してみて下さい。

「とりあえず全部試してみたい!」という方はこちらの公式チュートリアルも参考にしてみて下さい。

2017-09-13

Yomerumoのスマホページの表示速度が約半分にまでなった話

主にYomerumoのフロントエンドを担当しておりますGMOアドマーケティングのy.aです。

Yomerumoは芸能・エンタメ中心に、有名人の情報やニュースなど様々な情報を豊富に取りそろえているニュースサイトです。
http://news.merumo.ne.jp/

Yomerumoのスマホページ

アクセスの多くはモバイル端末からなのですが、以前からそのモバイルで表示速度の遅さに頭を抱えていました。

下記は遅かった頃(高速化施策を始める前)の表示速度です。

期間 Android iOS
[2017/01/01~2017/03/31] 平均読み込み時間(秒) 14.88 6.16

※Google Analytics調べ

遅いですよね。。Google Analyticsの「平均読み込み時間」はページビューの開始(ページへのリンクがクリックされたときなど)から、ブラウザで読み込みが完了するまでの時間を表すため、一概に「ページが表示されるまでの時間」とイコールとは限りません。ただそれでもiOSはまだともかく、Androidはここまで遅いとユーザーに不便を与えていることは明らかです。
これまでもCSS/JSファイルの圧縮やCSSスプライトなどの対応はしていたのですが、今年に入ってから「表示が遅い」「より根本的に見直ししてほしい」というご意見を内外から少しずつ頂くようになりました。

ということで3月から本格対応を始めたのですが、3カ月間の試行錯誤を経て出た表示速度の結果が以下の表です。

期間 Android iOS
[2017/01/01~2017/03/31] 平均読み込み時間(秒) 14.88 6.16
[2017/07/01~2017/08/31] 平均読み込み時間(秒) 7.77 3.23

※Google Analytics調べ

表示速度をそれまでの約1/2に改善出来ました!当然数値だけではなく、体感的にも早く感じられるようになっております。

今回はそのYomerumoで行った表示速度UPのための施策について皆さんに共有します。
なお以下で紹介する施策は全てフロントエンドの内容となりますのでご了承ください。


指標と計測ツール

対応するにしても、何がサイト表示を遅くしているか原因が分からないといけません。
そしてその原因を探るためには計測が必要です。

当初速度改善はPageSpeed Insightsを参考に進めていました。
https://developers.google.com/speed/pagespeed/insights/?hl=ja

ただご存知の通り「PageSpeed Insights」はベストプラクティスの達成具合を見ています。つまりサイトの表示を遅くしている原因を提示してくれるわけではありません。(もちろんベストプラクティスを達成していないことが遅い原因と言えなくもありませんが。)
そういう意味では提示内容を全てクリアしても必ずしも表示速度向上を達成できるとは言い切れないところがあります。
また今回は複数メンバーで週ごとに検証していたため、体感的な表示速度を定量的に、かつページ表示までの流れを詳細に、そして可能であれば問題点の共有が容易なものが必要となっておりました。

そこで新たな速さの指標として「Speed Index」、そしてそれを計測するために主に「WebPagetest」を使用することにしました。
https://www.webpagetest.org/

「Speed Index」は可視範囲内での表示速度の平均値を測る指標です。つまりファーストビューでの表示速度を表しています。「Speed Index」はスコアが低ければ低いほど描画が早いということになります。今回の目標としている体感的な表示速度改善の指標として一番合っていました。

黄色でハイライトした箇所が「WebPagetest」で計測したSpeed Indexの値
よく参考にしていたのは「Speed Index」を算出するVisual Progress

また何をもって早いと考えるのかという中で、よりユーザー視点でページの表示過程を確認できる「WebPagetest」のビデオキャプチャ(filmtrip)がとても役に立ちました。

filmstripの一例。3Gで計測したというのもありますが、他社メディア様と比べても遅いです。。

ChromeのDevツールでも「Performance」を使えばビデオキャプチャを確認できますが、「WebPagetest」であれば先の「Speed Index」のスコアとあわせてビデオキャプチャも撮れます。
記録可能なビデオキャプチャであるためチーム内で問題事項の共有が容易になりました。


遅くしていた原因

上記「WebPagetest」等で計測し分析を進めた結果、Webフォントアイコンの使用、JSの動的なコンテンツ表示処理などフロント側の実装の問題点がたくさん見つかりました。
ただその中でも一番表示速度に影響を与えていたのは「ファーストビュー時のリクエスト数の多さ」でした。

例えば当時のトップページでは、ファーストビューのタイミングでYomerumoからリクエストする外部JSの数は14~5、画像は20程度でしたが、広告から出される広告に関するリクエスト(js、imgなど)は約250以上近くありました。。

3月時点でのリクエスト数。この中のjsとimageの多くが広告表示に伴ってリクエストされたもの

結局その他諸々全て合計すると毎回ファーストビューの時点でリクエスト数は平均で340~400余に上りました。これでは遅いのも当たり前で、特に古い端末であればあるほどその影響が大きかったと考えています。

上記リクエスト数の結果、当然ロードするバイト数も大きい

今までも全く気付いていなかったわけではないのですが、先の「WebPagetest」で他のニュースサイト様の分析をしても、Yomerumoのリクエスト数の多さが表示速度に影響を与えているのは明らかでした。


どう対処したか

大きくいうと以下の2つです。
1. ファーストビューコンテンツの表示調整
2. リクエスト削減

1. ファーストビューコンテンツの表示調整

ファーストビュー内にあるコンテンツ、パーツなどの表示を早くする調整です。以下2つの対応をしました。

1-1. localStorageの活用

通信を伴って動的に生成する要素がある場合、Ajaxを使用していることがほとんどだと思いますが、非同期ですと最初の描画のタイミングに間に合わず、後でぽつっとそのコンテンツが出てくることがあると思います。YomerumoでもAjaxで取得しているところがあったのですが、それまではプレースホルダーも置くことなく空白のままでした。

そこでそう頻繁に更新のない箇所については、毎回Ajaxせず初回で一度jsonを取得後localStorageを使用してローカル内に保存し、アクセスから10分間は通信せずlocalStorageから出すように変更しました。

これ自体は表示速度の数値には大きく影響与えませんでしたが、通信をしない分早くコンテンツが表示されるようになりました。

1-2. ファーストビュー内にあるパーツの表示調整

一部のパーツで「Font-Awesome」(Webフォントアイコン)を使用していたのですが、これもロードされるまではその部分が空白となってました。
少しでも早く感じてもらうには、やはりなるべくネットワークに依存しない形にするのが一番です。
Yomerumoで言うと右上にメニューのためのハンバーガーアイコンがありますが、当初「Font-Awesome」で表示していたものを、CSSでの3本線(border+border-radius)に変えました。

またロゴ画像も以前はCSSスプライトで表示していましたが、サイズが大きくなりすぎたため、表示が遅れがちでした。
ファーストビュー内の画像は少しでも早く表示させるために先のCSSスプライトから切り離し、タグで出力することによって可能な限り最初の描画に間に合わせるようにしました。

ビデオキャプチャで見ると分かりますが、それまでと比べてコンテンツ・パーツの表示が早くなりました。以下Before/Afterの画像です。

Before. ヘッダのコンテンツがほとんど表示されていない
After. 最初の描画の時点でほぼ表示されている

2. リクエスト削減

2-1. JSをバンドル

読み込む外部JSの数が一般のサイトと比べても多すぎました(14~15)。
これはサイト内に古くから存在していたものは触れず、とりあえず追加に追加を重ねていったため、結果こんな数になってしまったのです。。(反省)

要らないものは除去、まとめられるものはまとめるのが一番です。
このタイミングで改めて各JSの役割・依存関係を徹底調査し明確にした上で、不要なものを削除、残ったものはまとめる(バンドル)ために「webpack」を使用しました。

結論から言うとJSファイル全てを「webpack」によるバンドル対象とすることはできませんでしたが、14~5ほどあった細かいJSファイルを3~4に減らすことに成功しました。

蛇足ですが、「webpack」はリクエスト削減より、バンドルすることでJS同士の依存関係をはっきり出来るのが大きな利点だと思います。確かにリクエスト削減目的で導入しましたが、結果「require」で組んでいくことでコードの見通しが大変良くなり、今後の保守を考えた上でも対応して良かったと感じています。
通常、既に運用が始まっているサイトでwebpackを導入するのは色々とハードルも多いかと思うのですが、これにより不測のトラブルを回避できると思います。

2-2. ファーストビューにないコンテンツはインビュー読み込みに変える

今回の施策の中で一番効果が大きかったのはこれです。
画像・広告についてはファーストビューで表示されるもの以外は全てインビュー読み込みに変更しました。

やり方の詳細は省かせていただきますが、ある要素がインビューになったらそれをトリガーとして、画像のリクエスト、広告のリクエストを起こすイベントの形に変えたのです。
おかげで今までファーストビュー時に約400あったリクエストが、修正後わずか約100リクエストほどになりました!

赤がBefore、青がAfter
当然バイト数も減ってます

かなり大きいですよね。体感的にも一番ビフォーアフターで違いがはっきりと感じられました。


まとめ

以上の対応の結果、それまでの表示速度の半分の速さを実現することができました。

それまで目標としていた某他社ニュースサイト様と比べても今は「Speed Index」、そして「Load」時間においても、画像も広告数もはるかに多いYomerumoの方が早くなりました。(それまでは全く手の届かないくらい差があったので達成したときは大変感慨深かかったです。。)
実施の過程で、途中いくつも失敗があったのですが無事表示速度改善ができたと言えると思います。
ただ進めれば進めるほど表示速度に関してはまだまだ改善余地あることが分かりました。もっと言えばもう少しUXを考慮に入れた丁寧な調整ができると感じております。

例えばユーザーが「何をもって早く感じるか」ということの分析もその一つです。
取組み通じて分かったのがファーストビューの「最初の描写」(Render Start)が少し遅くなろうとも「最初の描画時点で構成するコンテンツがほぼ揃っている」方が、「最初の描画が早くともコンテンツがあまり揃っていないもの」よりも体感的には早く感じることでした。

例えばページが2.0秒のタイミングでRender Startされようとも、その時にコンテンツが60%近くしか出ていないのであれば、3.0秒のタイミングで、コンテンツが80%出ている方がユーザー体験としても良いでしょう。

上がAfterで下がBefore。確かにBeforeの方が描画が早く始まっているが、コンテンツが40%台から描画されているためユーザー的に早いサイトと感じるかは微妙なところ

フロントエンドで言うと「非同期」というキーワードが表示高速化と結ばれがちですが、
先の気づきもあって今回対応していったなかで多少描画が遅くなろうとも、Render Start時点で可能な限りVisual Progressの比率が高くなるようにあえて「同期」的にした箇所もあります。
よりユーザーに快適に使ってもらうことを考えた場合、「非同期」にすることが100%「正」にならない可能性もあるかもしれません。

赤がbefore、青がAfter。Afterの方がRender Startは遅いものの赤より早く100%に達している

ただいずれにしても、高速化という点だけにおいてはファーストビューにないコンテンツは可能な限り後読みの形にすることは大事なはずです。
モバイル時代に最適化したAMPHTMLを見ても分かりますが「<amp-img>」「<amp-ad>」などこれらのカスタムエレメンツもビューポート等に応じて読み込みを遅らせたりしています。
インビュー読み込みにすることで、無駄なリクエストが発生しないためユーザーにとって望ましい形であることは間違いないです。
(ちなみにYomerumoはAMPにも対応しております!詳しくはこちら

今回紹介した施策以外でもサイト内で一部Resource HintsのAPIを使用していたり、その他まだまだ説明しきれなかった細かいことがたくさんやったのですが、現時点で効果のほどが定かでなかったためまた別の機会にお伝え出来ればと思います。
さらに今後SSL化対応すればService Workerの活用も視野に入りますので、対応した際にはまた共有出来ればと思います。

読者の方にとっては当たり前のことばかりだったかもしれませんが、表示高速化進めるにあたって「PageSpeed Insightsしか使用していなかった」あるいは「なかなか指針を決められない」場合などに、この記事が少しでも有用なものになりましたら幸いです。

今後もYomerumoはよりユーザーに快適にサイトを利用してもらうよう進めてまいります。

※本記事で提示した「WebPagetest」の計測値は全て「From: Japan – EC2 – Chrome – Emulated iPhone 6 – 3GFast – Mobile」の条件で出したものです。