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

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

格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(1)

先日、早めの夏休みで青島(チンタオ)にビールを飲みに行って来ましたインフラエンジニアのETOです。
弊社は旅行好きの人が多いため、旅行休暇を取りやすいので助かっています。
旅行好きな方は是非弊社で一緒に働きましょう。ご検討ください。


さて、長期間休みを取る際にいつも気になるのは、自分がいない間のサーバ故障の発生です。
当然ながら冗長化ができている公開系に比べると、どうしても対策が後回しになりがちな開発系や、
ちょっとした社内サーバがこういう時に限って壊れたりするものです。
 
「あー壊れちゃいましたね」では済まないインフラエンジニアとしてはいつも余裕を持ったリソースを確保しておきたいものですが、なかなか(主にコスト絡みで)そうはいきません。
 
そこで同じような悩みを抱える諸兄におすすめしたいのが今回のお題、
「格安サーバで作る ESXi+NFS の仮想マシン環境」です。


・目指すところ
安く手軽に"実用的"な仮想サーバ環境を手に入れるのが目的です。
実サーバのバックアップや、故障時の緊急避難先などに大活躍!当然本運用も可能です。
ZFSベースのNFS外部ストレージも自作することでデータの保全性も同時に確保してしまいましょう。

・用意するもの
各サーバ機として、HP社のML110G7を2台使います。
格安サーバとして2万円以下で手に入るコストパフォーマンス抜群のサーバ機です。
これにメモリとHDDを追加します。余っているものがあればそれを流用しても構わないと思います。

今回の具体的なハード&ソフトウェア構成は以下になります。
 ・仮想マシンホストサーバ
  OS:ESXi5.0U1
  ハード: HP ML110G7 
      メモリ 16GB
      USBメモリ起動 8GB
      HDD ナシ ZEROスピンドル!

 ・NFS外部ストレージサーバ
  OS:openindiana 151a
  ハード: HP ML110G7
      メモリ 8GB
      USBメモリ起動 8GB
      HDD 2TB*4

詳細は伏せますが、全部あわせても10万円かからない金額で調達しました。
現在はもっと安いかもしれません。


・構成図 
このような構成で構築します。
kousei





突然ですがQ&A。

Q:なぜKVMではなくESXiなの?
A:無料で使えるGUIの管理ツールが揃っていて楽だからです!
 
これだけだと色々と反論を受けそうですので補足。
やはりVMware社の企業として統一されたポリシーで作られている以下のツール群の使い勝手が良いため、KVMなどと比べるとアドバンテージがあると思っています。
  • VMware vSphere Client(管理コンソール)
  • VMware vCenter Converter Standalone(P2Vツール)


Q:なぜローカルディスクにしないの?
A:ESXiで"実用になる"RAIDカードが高いからです。

ESXiではソフトウェアRAIDや廉価なオンボード系のRAIDが使えません。 また、RAIDカードは原則的にデータ保護のためにHDDのキャッシュを無効化するため、 キャッシュメモリ未搭載の安いRAIDカードを使うととても遅くて実用に耐えません。
※この点においてはLinuxで使えるRAID構成をそのままストレージとして使えるKVMにアドバンテージがあるのですがそれはまた別の話。

いくらお手軽環境 とはいえ「HDDが壊れたらデータが飛びました」ではお話にならないのは言うまでもありません。
しかしご安心を。ESXiではNFSやiSCSIを利用することで、ネットワーク越しの外部ストレージに仮想マシンイメージを置くことが可能になっていますので、今回はZFSベースのNFS外部ストレージを作り、最低限+αくらいのデータの保全性を確保したいと思います。 


Q:ZFSってなに?
A:主にSolarisやFreeBSDで使える次世代ファイルシステムです。

旧Sun社(Oracle社に買収されました)により開発された次世代ファイルシステムです。様々な仕組みで信頼性と性能を向上させているため、高価なストレージシステムを買わなくても耐障害性の高い高速なストレージ環境を手に入れることができます。
今回はZFSのソフトウェアRAIDでNFS外部ストレージを構築します。ZFSについて詳しく知りたい方はOracle社のドキュメントをご覧ください。 


Q:なぜiSCSIじゃなくてNFSなの?
A:取り回しが楽だからです。

「今時NFSはないだろう」とか「ESXiなら普通はiSCSIでしょう」とかいう声が聞こえてきますが、今回は性能を求めるわけではないので多少のオーバーヘッドは無視してNFSを選択します。
皆さんご存知の通り、NFSは取り回しが楽ちんで素敵です。偉い人にはそれがわからんのです。


諸々ご納得いただけたでしょうか。
さて、次回から実際の構築に入って行きたいと思います。
言語を検出 » Japanese

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

記事検索