Browse Month: October 2011

DNS キャッシュについての考察

比較的アクセスのあるウェブサーバがあって、そのウェブサーバから結構な回数で Web API をたたいています。ご存じのとおり、Linux では DNS をキャッシュしてくれないので、Web API をたたくために毎回 DNS へのアクセスが発生して、DNS の負荷がすこし上がってきたので、ウェブサーバに DNS キャッシュを入れてみることにしました。

今回の用件は、次のとおりです。

  • Web API でたたくときにドメインを、それぞれのウェブサーバでキャッシュしたい
  • おもに外部ドメインをキャッシュするので、DNS ラウンドロビンにはできれば対応したい

ということで、いろいろと調査したり、友人からアドバイスをもらったところ、UnboundDnsmasqcaching-server、の三つの選択肢があることが分かりました。それぞれ、CentOS 5.7 x86_64 の環境で、試していました。

まずは、本命といえる Unbound インストールは簡単です。Unbound の設定は /etc/unbound/unbound.conf ですが、デフォルトの設定だと、DLV が設定されているので DLV が解決できない環境では名前解決が遅くしまうので注意しましよう。

Unboud の特長は、次のとおりです。インストールは、unbound パッケージをインストールするだけです。

  • 設定が比較的容易
  • DNS ラウンドロビンには対応していない
  • cache-min-ttl という設定項目で、最低限 Unbound でキャッシュする最低 TTL を設定することができる

今回の用件では、外部ドメインをキャッシュすることを目的にするため、DNS ラウンドロビンに対応していないというのは痛いです。

次に Dnsmasq です。特長は、次のとおりです。インストールは、dnsmasq パッケージをインストールするだけですが、すでにインストールされていました。

  • 設定が比較的容易
  • DNS ラウンドロビンに対応している
  • DHCP 情報もキャッシュすることが可能
  • /etc/hosts や他の特定ファイルを hosts ファイルとして読み込んでキャッシュすることができる

公式ホームページをみると、おもに自宅で NAT 環境を使っている人向けに開発したとありますが、1000 クライアント規模程度から動作するようなので、大規模な環境でない限りは問題はなさそうです。今回は、まったく大規模ではないので、問題なさそうです。また、Dnsmasq はデフォルト設定で、/etc/resolv.conf を読み込んでいるため、/etc/resolv.cnf を nameserver 127.0.0.1 とすると「ignoring nameserver 127.0.0.1 – local interface」というエラーが発生してしまうため、no-resolv を設定していくとよいでしょう(参考)。

 

次に caching-server ですが、bind 系のものになります。インストールは、caching-nameserver と bind をインストールするだけです。設定は、このページに詳しく書かれていますので割愛します。特長は、次のとおりです。

  • bind に慣れている人なら設定は同じ
  • DNS ラウンドロビンに対応している

caching-server もよさそうです。ただし、bind なので普段から bind を使っている人は設定が同じなのでまったく問題ないですが、DNS キャッシュ以外の通常の DNS 機能も備えているのでちょっと今回の用件には大げさなのかもしれません。しかも、今回負荷が上がっている DNS は bind なのでなんとなく同じような負荷になってしまう恐れもありました。

 

DNS ラウンドロビンに対応しているかは、dig コマンドで簡単に確認することができます。


$ dig google.com @localhost
; < <>> DiG 9.3.6-P1-RedHat-9.3.6-16.P1.el5 < <>> google.com @localhost
;; global options: printcmd
;; Got answer:
;; ->>HEADER< ;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 4, ADDITIONAL: 4

;; QUESTION SECTION:
;google.com. IN A

;; ANSWER SECTION:
google.com. 5 IN A 74.125.31.147
google.com. 5 IN A 74.125.31.99
google.com. 5 IN A 74.125.31.103

上のような感じで、ローカルのそれぞれの DNS キャッシュをたてて dig コマンドを繰り返して発行して IP アドレスが入れ替わるかで DNS ラウンドロビンに対応しているかは分かります。Unbound の場合は、IP アドレスがまったく入れ替わりません。

次に本当に DNS キャッシュされているかですが、Unboud だと次のコマンドで確認することができます。

$ sudo unbound-control dump_cache
START_RRSET_CACHE
;rrset 4 1 0 1 2
ns4.google.com. 4 IN A 216.239.38.10
...
END

Dnsmasq と caching-server には専用のコマンドがなさそうな感じだったので、tcpdump で DNS へのアクセスが行われているかみることで確認しました。いずれもちゃんと DNS キャッシュされていました。

最後にそれぞれのパフォーマンスを計測してみました。計測したツールは、google が提供している namebench というツールです。測定方法は、それぞれの DNS キャッシュを起動した状態で、ローカルの DNS に対してパフォーマンスを計測しました。
結果は、次のとおりでした。

$ ./namebench.py --system_only --query_count=100 --num_servers=10

caching-nameserver
Mean response (in milliseconds):
——————————–
SYS-127.0.0.1 ##################################################### 144.51

Dnsmasq
Mean response (in milliseconds):
——————————-
SYS-127.0.0.1 ###################################################### 126.80

unbound
Mean response (in milliseconds):
——————————–
SYS-127.0.0.1 ##################################################### 155.89

いくぶんか Dnsmasq のパフォーマンスがよかったです。DNS ラウンドロビンにも対応していますし、今回の用件にはあっていそうでした。

その他、先日の YAPC::Asia 2011 にて @xaicron さんが「大規模環境におけるマニアックなキャッシュ利用術」というタイトルで Mobage で行われている DNS キャッシュについてトークがありました。ローカルに Memcached をたてて、そこに数秒おきにバッチを実行して DNS キャッシュを作る方法が紹介されていました。なるほどこれも素晴らしいと思ったのですが、規模的にはまったく大規模でないこと、アプリケーション側のコードを変更する必要があること、といった点で今回はこの方法は採用しないことにしました。大規模な場合は、この方法は素晴らしいと思いますので、そのときになったらやってみたいと思っています。

ということで、今回は Dnsmasq をそれぞれのウェブサーバに DNS キャッシュとしてたてることにしました。当然ながら、DNS キャッシュをたてるので、nagios でちゃんと監視するようにしました。

しばらくこれ様子を見てみたいと思います。

tuningathon #2 に参加してきた

第2弾!いろいろチューニングしてパフォーマンスを競うバトルイベント開催!「Tuningathon」2!! #tuningathon on Zusaar に @xcir こといわなちゃんとチームで参戦してきました。
すでに @xcir こといわなちゃんのブログに詳細なまとめがありますが、僕といわなちゃんがそれぞれ行ったことをまとめておきます。

まず、一番最初に行ったことは、与えられた 2 台の AMI 上で作業を行えやすい環境を整えました。

  1. いわなちゃんに Google Docs を作成してもらって二人で共有した
  2. .zshrc をコピーして、シェルを zsh に変更した(いわなちゃんがすこしびびっていました…w)
  3. 自分の MBA から、SSH 公開鍵でログインできるように設定した
  4. それぞれの AMI 上に SSH 鍵を作成して、たがいに .ssh/config を設定して公開鍵でログインできるようにした(/etc/hosts にも書いた方がよかったかも)
  5. 不要なサービス yum-updatesd、iptables、ntpd サービスを停止した(本番運用では、後者の二つのサービスは停止することはありえませんが)
  6. いわなちゃんの SSH 公開鍵を、自分に与えられた 2 台の AMI に登録した

次に、チューニングする前に、現状のパフォーマンスをチェックしました。http_load をダウンロードしてきて、コンパイルして、1 記事 URL に対してどのくらいかを確認しました。
url.txt は、wikipedia の「特別:おまかせ表示」の機能を利用して、記事の URL を抽出するプログラムをさくっと書いてテスト用の URL を抽出しました。


$ ./http_load -parallel 1 url.txt

初期状態で、おおよそ 秒間 1 程度のパフォーマンスであることを把握しました。

次に、いわなちゃんと相談して、1 台の AMI の空きメモリがおおよそ 1.7GB くらい、Apache の 1 プロセスのメモリ使用量は 3M くらい、明らかに CPU ネック、200 万記事をすべて静的ページにするのは他のサーバを使えば可能かもしれないが(たぶん、これってルール違反?なので却下)、2 台フロントした方が感覚的にパフォーマンスがよいはず、メモリの配分は 0.2GB Apache / 1.5 GB MySQL くらいの配分でいこうなどを相談しました。

そして、分担して次の作業を行いました。

  1. MySQL のクエリーログをすべて出力するようにして、http_load から 1 記事 URL にアクセスして、どんなクエリーが発行されているのか、二人で調査
  2. InnoDB plugin for 5.1.52 のインストール、RPM からプラグインだけ抜き出して手動でコピーしてプラグインをインストール(いわなちゃん)
  3. PHP 5.4.0 beta0 のコンパイル(僕、※beta1 が出ていることを知らなかった)
  4. APC 3.1.9 をダウンロードしてきて、PHP 5.4.0 beta0 でコンパイル(僕)いわなちゃんに APC の設定をアドバイスしていただいた(*1)
  5. MySQL の一般的な設定をいわなちゃんに渡して設定してもらいつつ、Apache の設定を僕が調整しました(久しぶりの Prefork だったのですこしとまどった)
  6. PHP の調整をいわなちゃんにお願いしました(*2)(不慣れですいませんでした…><)
  7. InnoDB buffer pool のウォームアップ(いわなちゃん)


(*1) APC の設定は、次のようにしました。
apc.shm_size = 64
apc.optimization = 1
apc.stat = 0


(*2) php.ini は、次のように設定してもらいました。サンクス!
realpath_cache_size = 64k
realpath_cache_ttl =36000
error_reporting = 0
log_errors = Off

あと、nginx をすこし試してみましたが、ほとんど経験がなかったのでうまくいきませんでした。

とやったことは、こんな感じでした。

個人的にやっておけばよかったことを振り返って、次回までは準備しておきたいと思います。

  • PHP 5.4.0 の configure オプションのさらになる最適化(上位の人たちとの差は、ここにありました)
  • Manual:Performance tuning – MediaWiki をチェックして実施すれば良かった
  • 時間内では、ヘビー級の MediaWiki のソースコードをチェックしてプロファイリングするのは大変だろうということ、今回は GET のみだったことを考えると、開始後すぐに mod_disk_cache にキャッシュ作成する時間にすればよかった(かもしれない)
  • 与えられた AMI に必要な初期セットアップスクリプトを作成しておくと(.zshrc のコピー、hosts の定義、hostname の変更、不要なさびービスの停止・無効化など)
  • nginx をいじってみる
  • 次回は、Ruby / Java / Perl あたりになりそうなので何か準備しておく?
  • 定番的な AMI 用のパッケージを準備しておく、PHP 5.4.0 とかw

運営されたゼロスタートのスタッフの皆さん、大変面白いイベントありがとうございました。今後もぜひ開催していただきたいとことで、個人的な次回以降への要望をまとめておきます。

  • レジュレーションで MediaWiki の変更は不可とありましたが、後半で MediaWiki の設定ファイルのデータベース設定は変更していいということになったりと変更範囲が不正確でしたので、もうすこし正確なルールがあるといいと思いました
  • 外部のリソースは、どういう用途なら使ってもよいかということが、個人的にははっきり分からなかったです(例えば、PHP をコンパイルするとき外部のサーバでコンパイルしてもってきてもいいのか、外部のサーバにある RPM をもってきてそのままインストールしてもいいのか、外部のサーバでキャッシュを作って転送してもよいのか、など)
  • チームで参戦するのは、いわなちゃんが繰り上げるかにかかっており、無事繰り上がったけれどチームであることをどのように伝えばよいのか分からなかった(あとで他の人に行くと受付の人に話せばよかったことを知りました)
  • 計測するツールは、事前に準備してほしかった
  • 計測前に再起動するのは、最初のルール説明で話してほしかった
  • サーバはできれば 64bit のものが現在では一般的だと思いますのでよろしくお願い致します

 

次回の開催予定は、来年の 1 月ということで次回も参戦して、ちゃ(ry 人たちには負けないように精進していきたいと思います。おそらく、次は PHP でないと思うので、自分のスキルが存分にいかすことができそうなので楽しみです。

個人的には、このようなチューニングガソンのようなイベントでは、いかに自分で手を動かして実践している技術手法の選択肢がどのくらいあるのかが勝負になってきそうと思いましたので、今後もさまざまな技術手法を実践していきたいと思いました。

 

最後に、僕とチームを組んでくれた @xicr こといわなちゃんありがとうございました。とても勉強になり刺激になりました!また、次回もよろしくお願いします!!!