ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2010-11-28

はてなブックマークウィジェット高速化大作戦

本ブログで利用しているはてなブックマークの人気または注目エントリーを表示するブログパーツである「はてなブックマークウィジェット」が、最近極端にロードに時間がかかるようになってしまった。はてなブックマークウィジェットは多くのサイトで採用されているので目にする人も多いことだろうと思う。データのロード中はクルクル回るgifアニメーションが表示されるのだが、最近はもっぱらクルクル回っているところばかりを目にするようになってしまった。「クルクル回ってる間にエントリを読み終えてしまうんじゃないか!?」とすら思えてしまう。あまりにも時間がかかるので、先日Twitterで「はてブの人気エントリーウィジェットが遅い」などと愚痴をこぼしてしまったのだが、そんな他力本願じゃイカン!!と腐った根性を改めて、ウィジェットの高速化に取り組んでみた。

はてなブックマークウィジェットは本当に遅いのか?

遅いと感じるかどうかは個人差があるかも知れないし、筆者の環境がダメなだけかも知れない。なので実物を皆さんにまず見てもらったほうが良いだろう。これだ!




現在、筆者の環境では表示されるまでに30秒〜1分程度掛かるようだ。筆者の感覚では、これは「遅い」と感じるのだがいかがだろう?

他のサイト、例えば筆者が愛読している404 Blog Not Foundでもこのウィジェットが使われているが、こちらもかなりロードに時間がかかっているようだ。(従って筆者のブログだけの問題ではないようである。)404 Blog Not Foundのウィジェットは本ブログのものよりもロードにかなり時間がかかるように感じるのだが、ブックマーク数が多いせいであろうか?

高速化の仕組み

はてなブックマークウィジェットは http://b.hatena.ne.jp/entrylist/json からJSONでデータを取得して整形して表示するというごくありふれた仕組みになっている。この仕組みが遅いということは、JSONのロードに時間が掛かっていると考えるのが妥当であろう。CSSもロードするようだがこちらは静的ファイルのようなので、ロード時間に多少の影響はあるだろうが、割合的にはJSONの生成に時間が掛かっていると考えられる。

誰でも考えることだとは思うが「JSONのデータを取得するのに時間がかかるなら、予めJSONのデータを取得して、レスポンスの良いサイトでキャッシュすればいいじゃないか!?」と。どのぐらいの頻度でキャッシュを更新するかにも拠るが、間に処理を挟むとデータ更新のリアルタム性は多少犠牲になってしまう。これはトレードオフだが、今回のような用途では別に正確な統計情報が求められることはないので、定期的にキャッシュをリフレッシュすれば実用上ほぼ問題はない。

ではどのサイトにキャッシュするべきか?ということになるが、個人が空いた時間に運営するブログなのでお金が掛かったり面倒だったりするのは極力避けたい。というわけで、まずは実験的に無料で使い始められて管理不要なGoogle App Engine(以下GAE)を使ってみることにした。GAEは月間500万PV相当まで無料なので、本ブログのアクセス数を基準に考えるとまるで心配が要らない。

GAEにはてなブックマークの人気エントリーをキャッシュしておき、ブラウザ(ウィジェット)がデータを参照する先をはてなではなくこちらへ変更することにより表示が速くなるという寸法だ。データを取得するURLが変わってしまうので当然ウィジェット側にも手をいれなければならない。現在は自体もはてなのサイトからダウンロードするようになっているのだが、せっかくなのでさらに高速化するべくウィジェットも自作することにした。

というわけで、
  • GAE上にはてなブックマークの人気エントリーのデータ(JSON形式)をキャッシュする仕組み
  • キャッシュしたデータを表示するウィジェット
の2点を自作することになった。作成したオレオレウィジェットは既に本ブログの右側に配置してあるので、オリジナルとロード時間を見比べてみて欲しい。

サーバー側アプリ概要

何を隠そう、筆者はこれまでGAEを使ったことがなく、今回が初めてのチャレンジである!初心者は初心者らしく、チュートリアルを片手にトライしたのだが、使い方は至って簡単であった。GAEでは言語としてJavaとPythonが選べるのだが、今回はサクサクっと作りたかったのでPythonをチョイスした。

筆者が作成したアプリの作りは非常に簡単で、/fetchへアクセスすると、はてなブックマークからデータを取得してGAEのDataStoreに格納する。GAEではcronと同等の機能が利用できるので、15分おきに/fetchが呼び出されるように設定している。/fetchは少々重い処理であるし、他の人が参照する必要もないため、/fetchへアクセスするには管理者権限が必要であるようにしている。一方、/showへアクセスするとDataStoreからデータを読んでJSONを生成して表示するという寸法だ。/showはJSONPにも対応している。

で、出来たのがコレだ。
http://nippondanji-bm-cache.appspot.com/show

/showには特にアクセス制限は設けてないのでF5アタックをされると涙目なのだが、処理は軽いので多少のことでは料金が発生するまで至らないだろう。無料の分を使いきってしまった場合には、泣きながらオリジナルのウィジェットに切り替えるつもりである。

サーバー側のアプリを作成した当初は、はてなからJSONのデータをコピーしてそのまま返すだけでいいと思ってたのだが、色々と気に入らない点(エントリーが10件までしか取得できない、タイトルが途中で切れてしまう)などの不満が出てきたので、現在ははてなが提供しているJSONではなくウェブページ(HTML)をパースする仕組みになっている。HTMLの解析をElementTreeやminidomでやろうとしたところうまくいかなかったので、XMLでDOMするのは諦め、代わりにHTMLParserを使って実装した。

パースは多少重い処理なのだが、15分に1回しか呼び出さないのでまったく問題はない。ちなみに、15分に1回だとブログに反映されるまでに少しタイムラグが生じてしまうが、そもそも人気エントリーはそんなに変動しないし、リアルタイム性がそれほど重要でない情報なので15分ぐらいは許容範囲だと思っている。それよりはロードが速いほうがずっといい。

ウィジェット概要

ウィジェットはjQueryを使って構築することにした。(jQueryは既にSyntaxHighlighter用に本ブログに設置済みである。)jQueryを使うにあたって悩ましいのは、本ブログで使用しているブログエンジンであるBlogger.comには静的ファイルをアップロードする仕組みがないということだ。そのためjquery.jsなどのjavascriptファイルの置き場に困ることが多いのである。静的ファイルを置くためにGAEのような外部のサーバーを使うというのもアリだと思うのだが、本ブログではHTMLテンプレートにjQueryのソースコードを直接埋め込んでいる。かなりダサいが声を大にしてもう一度言う。jQueryのソースコードをブログのテンプレートに直接埋め込んでいるのだ!テンプレートが肥大化してメンテナンス性は低下してしまうが、jQueryを使うスクリプトは問題なく動作しているし、ブラウザがダウンロードするファイルの個数が減ることによってダウンロードの高速化になるから、実はその方がいいんじゃないかと思ったりもしている。

データの取得にはjQuery.ajax()を使った。そのデータを特定のidを持ったdiv要素に埋め込むようにしている。このやり方だとidが決め打ちなのでひとつのページに2つ以上このウィジェットを表示することが出来ないという、これまたダサい仕様になってしまうのだが、ひとつのページのこのウィジェットを複数表示することは稀だと思うのでこれでヨシとする。なお、筆者の環境ではIE7でウィジェットがうまく表示されない。(Chrome/Firefox/Safari/Opera/IE8は表示可能だった。)IE7で何故表示出来ないかは皆目検討がついていないので、JavaScript guruの知恵を借りられるとありがたい。

まとめ

GAE上にデータをキャッシュする作戦は大成功であった。はてブウィジェットの表示速度は大幅に改善し、まさに劇的ビフォーアフター!!である。初めてGAEを使ってみた感想だが、開発ツールの使い方は簡単だし使い始めは無料だし、非常にお手軽に始められる感じがした。速度的にも申し分なく、ちょこっと使う分にはかなり良い選択肢だと思う。特に筆者のようなサンデープログラマーには持ってこいの環境である。

今回作成したプログラムは、GitHubで公開しているので興味のある人は覗いてみて欲しい。(ちなみに筆者はjQueryもPythonも素人同然なので、フィードバックを頂けるとありがたい!)

最後に筆者の本当の望みを書いておく。やはり一番理想的なのははてなの公式ウィジェットが高速化されることだ。ウィジェットそのものを改善するべくデータのロードをもっと速くして頂けるとありがたいので、どうかよろしくお頼み申しあげます!!>はてなさん

0 コメント:

コメントを投稿