Raccoon Tech Blog [株式会社ラクーン 技術戦略部ブログ]

株式会社ラクーン 技術戦略部より、tipsやノウハウなど技術的な話題を発信いたします。

2012年07月

Google Analytics (other)対策

こんにちは!名前だけ編集長をやっている羽山です。

弊社では無料で利用できるアクセス解析ツールのGoogle Analyticsを利用しています。
今回は大規模サイトで問題になる(other)について一般的な対策から裏技的な方法までご紹介します。

(other)とは
Google Analyticsが一意のURLとして1日に認識できるのは50,000URLまでです。それを超えた場合、ページビューの低いURLから優先的に(other)というURLに変化してしまいます。
5万と聞くと十分な数に思えますが、弊社の運営するスーパーデリバリーでは30万点超の商品があり、それに商品一覧のページが加わると果てしない数のURLになります。 

弊社で実施している3つの対策
1. 50,000URLに収まるようにフィルタ設定してプロファイルを分割する
Analyticsのヘルプにも記載してある最も一般的な対策です。
ヘルプによると高トラフィックのページビューをフィルタで削除することによって50,000URLに抑えなさい。となっています。

完全に分離されたいくつかのセグメントがあるならば、それぞれプロファイルを作成してAnalyticsが公式にオススメする方法に従えば問題ありません。しかしそういったセグメントがないのなら情報が各プロファイルに分離してしまうので全体のセッション数やページビューなどをつかみづらくなります。

そこで弊社ではいくつかのページを同一のページとして書き換えることによってURL数を減らしています。
この方法ではセッション数やページビューには影響が出ないため、対象のURL自体を解析したい場合以外は特に意識せずに利用できるというメリットがあります。

スーパーデリバリーの例では商品詳細ページのURLが多数を占めていました。
そこでプロファイルを3つに分けるという対策をとっています。
  • (a) フィルタなしプロファイル
  • (b) 商品詳細ページのURLをすべて1つのURLにまとめたプロファイル
  • (c) 商品詳細ページ以外のURLをすべて削除したプロファイル
(b)の設定は下記のようになっています。
カスタムフィルタ、詳細
フィールド A -> 引用 A: リクエストURI, ^/p/r/pd_p/[0-9]+/
フィールド B -> 引用 B: -
出力先 -> 構成: リクエストURI, /p/r/pd_p/0000000/
出力フィールドを上書き: はい
この例では下記のようにURLが変化します。

(置き換え前)
http://www.superdelivery.com/p/r/pd_p/1234567/

(置き換え後)
http://www.superdelivery.com/p/r/pd_p/0000000/
 
通常の解析では(b)のプロファイルを利用して、商品詳細を解析したい場合は(c)を使います。
(a)はこの後に出てくるアドバンスセグメントを利用した方法やReporting APIを利用してデータを抽出する場合に利用しています。


2. 直近の数値を見る
実は50,000URLの制限は前々日以前のデータにのみ適用されます。
例えば今日が7月30日だとして、7月29日のデータを閲覧する場合は50,000URLを超えたデータを閲覧可能です。ただし、直近のデータの閲覧については保証されていない場合もある点は注意が必要です。


3. アドバンスセグメントを利用する
Analyticsの内部データとしては50,000URLに制限せずに保持されています。
50,000URLに制限されるのはAnalytics側である程度集計されたパターンの解析を行う場合に適用されます。
その枠を超えて動的な解析が必要な操作を行うと元データから解析されるため、50,000URLを超えたデータを閲覧できます。

早速試してみます。
下記のようなアドバンスセグメントを作成します。
名前: すべて
一致, ページ, 正規表現一致として、テキストボックスに . (ドット) 一文字を入力
すべてのページに一致する条件なので、セッションは一切絞り込まれない素通しのアドバンスセグメントです。

作成したら早速そのアドバンスセグメントを適用してデータを見ると (other) がなくなり、すべてのデータが表示されます。ただし、アドバンスセグメントではデータの件数によってはサンプリングされることがあるので、その場合は期間を短くするか[データ精度を優先]する設定に変更して下さい。


弊社では上記3つの方法を組み合わせて50,000URLの制限とうまく付き合っています。
他にもPreminumを利用するという方法もありますが、それなりに高価なので現時点では採用していません。

以上、今回はAnalyticsの話題でした。また次回よろしくお願いします!

ブログ開設のごあいさつ&strace活用事例

はじめまして!

本日、ラクーン技術戦略部によるブログを開設いたします。
tips、ノウハウ、新技術の紹介など、技術者ならではの情報発信をしていければと思います。



では僭越ながら記念すべきファーストエントリを書かせていただきます。

今回はphp用プロファイラ「xhprof」の導入、問題発生、及びstraceによる原因究明の顛末を書いてみようかと思います。

0, 前提

[開発用サーバ]
CentOS 5.x
PHP 5.2.x
Oracle Instant Client

1, xhprof導入

httpdの公開ディレクトリを/var/www/htmlとします。

まず、xhprofをビルドし、php.iniにxhprof.so読込設定を追加しました。
ビルド方法に関してはウェブ上にたくさん情報があるので割愛します。

次にxhprofのソース一式の中にある下記ディレクトリをhttpdの公開ディレクトリ配下にコピーしました。
/var/www/html/xhprof_lib
/var/www/html/xhprof_html
さらに下記ソースのファイルをxhprof.phpという名前で公開ディレクトリ直下に保存し、
<?php

define('XHPROF_ROOT',   '/var/www/html');
define('XHPROF_SOURCE', 'test-application'); // name of your application

require_once XHPROF_ROOT . '/xhprof_lib/utils/xhprof_lib.php';
require_once XHPROF_ROOT . '/xhprof_lib/utils/xhprof_runs.php';

function xhprof_finish() {
    $xhprof_data = xhprof_disable();

    $xhprof_runs = new XHProfRuns_Default();
    $run_id = $xhprof_runs->save_run($xhprof_data, XHPROF_SOURCE);

    printf(
        "<a href=\"http://%s/xhprof_html/index.php?run=%s&source=%s\">xhprof</a>\n",
        $_SERVER['HTTP_HOST'],
        $run_id,
        XHPROF_SOURCE
    );
}

xhprof_enable();
register_shutdown_function('xhprof_finish');
php.iniに対してプログラム実行前に上記ファイルを読み込む設定+αを追記しました。
auto_prepend_file = "/var/www/html/xhprof.php"
xhprof.output_dir = "/tmp"
この設定により、httpd上のphpが自動でプロファイリング可能となります。
以上で準備は完了し、いざプロファイリングというところで…。

2, 問題発生!そして原因究明へ。

Oracleへ接続できなくなる事態が発生!
具体的にはoci_connect()がfalseを返しており、oci_error()でも有用な情報が得られません。
アプリケーション、httpd共に不審なログは出ていません。

こんなときこそstraceで原因究明!

httpdを一度終了させてから、strace経由で起動します。
# apachectl stop
# strace -o /tmp/strace.log -f apachectl start &
起動しました。
-oオプション指定で結果をファイルに出力、-fオプション指定で子プロセスまで追っかけます。
-oを指定すると画面に何も出力しなくなるので、バックグラウンドで起動します。
アプリケーションをブラウザから叩き、再度エラーを確認したのち、
# apachectl stop
上記コマンドでhttpdもろともstraceを終了させます。

さて、httpdが実行したシステムコールは全て/tmp/strace.logに記録されているので、確認してみると、
12463 execve("/usr/sbin/apachectl", ["apachectl", "start"], [/* 28 vars */]) = 0
12463 brk(0)                            = 0x10b92000
12463 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2ba4b5dd5000
12463 uname({sys="Linux", node="foo.bar.hoge", ...}) = 0
12463 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
といった感じで、最初の数千行はhttpdの起動処理です。
ブラウザから叩いた瞬間より確認したいので、「GET /」で検索します。
12469 read(28, "GET /app HTTP/1.1\r\nHost:"..., 8000) = 493
と書かれた行が見つかりました。
28はhttpdがlistenしていたsocketのファイルハンドルですね。
この行以降に原因が潜んでいそうです。

Oracleの接続時に問題が発生していそうなので、「oracle」で検索してみます。
そうすると、
12469 open("/path/to/oracle/client/lib/libxxxx.so/libyyyy.so", O_RDONLY) = -1 ENOTDIR (Not a directory)
12469 open("/path/to/oracle/client/lib/libxxxx.so/libzzzz.so", O_RDONLY) = -1 ENOTDIR (Not a directory)
12469 lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
12469 lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
12469 lstat("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
12469 lstat("/var/www/html/lib", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
12469 lstat("/var/www/html/lib/DbException.php", {st_mode=S_IFREG|0764, st_size=1005, ...}) = 0
12469 open("/var/www/html/lib/DbException.php", O_RDONLY) = 33
上記のようなおかしな行を発見しました。
最初の2行で「ENOTDIR (Not a directory)」って言われてるし、libxxxx.soってファイル名じゃないの?という疑問が浮かびます。
さらに3行目以降は例外クラスのファイルを探しているので、
if (oci_connect(...) === false) {
    throw new DbException(...);
}
といった内容のプログラムが想像できます。

ここで推理。
この辺のsoファイルを呼び出したいのはphpエクステンション=oci8なハズ。
そこでoci8.soがどのファイルとリンクしているかlddで確認。
# ldd /path/to/php/lib/oci8.so
libxxxx.so => /path/to/oracle/client/lib/libxxxx.so
おっと、前述のディレクトリ扱いされていたsoファイルにリンクしています。
ではこのsoファイルは前述のlibyyyy.so、libzzzz.soとリンクしているのか確認。
# ldd /path/to/oracle/client/lib/libxxxx.so
しかしリンクしておらず。

今度はxhprofを無効にした状態(=Oracleへ正常に接続できる状態)でstraceしてみます。
※php.iniのauto_prepend_fileをコメントアウトしてhttpdをリスタート

するとstraceの結果から下記の行が見つかりました。
13951 open("/path/to/oracle/client/lib/libyyyy.so", O_RDONLY) = 33
正常に読込できています。

以上の結果を鑑みて、xhprofが原因でOracleのクライアントライブラリに不具合を及ぼしたと判断できます。
xhprofは内部であちこちフックしていそうなので、なんとなくイメージはつきますね。

3, 原因究明後

その後いろいろ調べた結果、Instant ClientではなくFull Clientを導入すると解決しそうなことが分かりました。

以上の通り、straceはトラブルシューティングツールとして素晴らしいものです。
しかし、アプローチがどうしてもローレベルなため、少し敷居が高いところが玉にキズですね。
ただ、使いこなせれば非常に強力なツールですので、使ったことがない方は是非お試しください!



最後になりましたが、TECH BLOG by raccoonを今後ともよろしくお願いいたします。
研究のための3つの理由
言語を検出 » Japanese

言語を検出 » Japanese

言語を検出 » Japanese

記事検索