<?xml version="1.0" encoding="UTF-8"?> 
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="ja">
<title>DSAS開発者の部屋</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/" />
<link rel="service.post" type="application/x.atom+xml" href="http://cms.blog.livedoor.com/atom/blog_id=1623805" title="DSAS開発者の部屋" />
<link rel="hub" href="http://pubsubhubbub.appspot.com" />
<link rel="self" href="http://dsas.blog.klab.org/atom.xml" />
<modified>2012-05-16T00:39:23Z</modified> 
<tagline><![CDATA[]]></tagline> 
<id>tag:blog.livedoor.jp,2006:klab_gijutsu2</id>
<author>
<name>klab_gijutsu2</name> 
</author>
<generator url="http://blog.livedoor.com/" version="1.0">livedoor Blog</generator> 
<copyright>Copyright (c) 2012, klab_gijutsu2 </copyright>
<entry>
<title>因縁の Google 独自言語対決！ Go 1 vs PyPy</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52050749.html" />
<modified>2012-03-29T03:45:43Z</modified> 
<issued>2012-03-29T12:45:43+09:00</issued> 
<id>tag:blog.livedoor.jp,2012:klab_gijutsu2.52050749</id>
<summary type="text/plain">
エイプリルフールネタが思いつかないけど4/1は休日なんで問題ありません。 methane です。

とうとう ゴー のバージョン 1 がリリースされましたね。おめでとうございます。
まだRC2が出てからあまり時間が経ってない気がするのですが、パイソンにグーグル独自言語の称号を...</summary> 
<dc:subject>golang</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52050749.html">
<![CDATA[<p>
エイプリルフールネタが思いつかないけど4/1は休日なんで問題ありません。 methane です。
<p>
とうとう ゴー のバージョン 1 がリリースされましたね。おめでとうございます。
まだRC2が出てからあまり時間が経ってない気がするのですが、パイソンにグーグル独自言語の称号を奪われそうになって慌てたのかもしれません。
<p>
<a href="http://dsas.blog.klab.org/archives/51993306.html">前回のechoサーバー対決</a> から半年すこし経ったのですが、この間にどれくらい高速化したのか、早速ベンチマークをアップデートしました。
<p>
<a href="https://github.com/methane/echoserver">echoserver on github</a><br/>
<a href="https://docs.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0Ao7uIKzqTU1JdGt4SkNjM1YweGJYTU1STHFkYkRIM0E&single=true&gid=0&output=html">Google Docs Spreadsheet</a>
<br />
<p>
前回のスコアと比較してみると、 Go の r59 では
<pre>
Throughput: 52087.16 [#/sec]
Throughput: 52070.02 [#/sec]
Throughput: 52068.27 [#/sec]
</pre>
だったのが、 Go 1 では
<pre>
Throughput: 55872.09 [#/sec]
Throughput: 55857.82 [#/sec]
Throughput: 55949.57 [#/sec]
</pre>
と、順位に変動があるほどではありませんが、着実に速くなってます。一方、 PyPy 1.6では
<pre>
Throughput: 79193.30 [#/sec]
Throughput: 81063.83 [#/sec]
Throughput: 81442.70 [#/sec]
</pre>
だったのが、 PyPy 1.8 だと、、、
<pre>
Throughput: 84852.55 [#/sec]
Throughput: 106760.88 [#/sec]
Throughput: 107032.43 [#/sec]
</pre>
<p>
なんと、シングルスレッドのC++（epoll版）に迫る性能を叩き出すようになってます。
<p>
今回は Go と PyPy だけの更新ですが、夏までには軽量スレッド最速環境である Haskell の新しい Haskell Platform というディストリビューションが出ると思うので、それを待って全体的に更新したいと思います。
<hr>
<div style="margin: 1px 3px 1px 0px; text-align: right;">@methane</div>]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>Android アプリ「AppNetBlocker」を公開しました</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52026407.html" />
<modified>2012-05-15T04:18:20Z</modified> 
<issued>2011-12-26T10:00:45+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52026407</id>
<summary type="text/plain">以前から自分自身がほしいと思っていた Android アプリが形になったためマーケットで公開しました。
今回はそのアプリ、「AppNetBlocker」をご紹介します。


AppNetBlocker は、所定のアプリから「完全なインターネットアクセス」の許可を除去するツールです。実行に root ...</summary> 
<dc:subject>Android</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52026407.html">
<![CDATA[以前から自分自身がほしいと思っていた Android アプリが形になったためマーケットで公開しました。
今回はそのアプリ、「AppNetBlocker」をご紹介します。

<p>
AppNetBlocker は、所定のアプリから「完全なインターネットアクセス」の許可を除去するツールです。実行に root 権限は必要ありません。Android 1.6 以上の環境で動作します。興味のある方はご利用下さい。もちろん無料です。

<p>
（2011/12/26 追記）
<br>
本アプリは、現時点では安全面において不安要素の少なくない Android をめぐる状況において Android 利用者が自分自身を守るためにとり得る対策のひとつを形にしたものであり、他者の権利を脅かすことを目的とするものではありません。
<br>
もし、Android を今よりもさらに安全に利用することが可能となればより多くの利用者・開発者の利益につながることでしょう。本アプリはたとえ僅かでもその一助になればと手がけたものであり、開発の動機もそこにあります。
<br>
しかしながら、一部の方から本アプリと Android マーケット規約とのかねあいを懸念するご指摘がありました。その話題については判断の余地があるものと認識していますが、少なくとも利用者の不安を誘引することはまったく本意ではなく、マーケットでの配布という形態は一時中断することとします。

<p>
実験用のいわゆる「野良アプリ」として apk のダウンロードリンクを当面残しておきます。このリンクから端末へ直接インストールすることはできません。意図を理解される方のみ自己責任でご利用下さい。


<center>
<a href="http://dsas.blog.klab.org/data/appnetblocker/AppNetBlocker.apk.bin"><img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/4/0/404eb172.png" border="0"></a>
&nbsp;&nbsp;

<br>
<font size="-1">[ <a href="http://dsas.blog.klab.org/data/appnetblocker/AppNetBlocker.apk.bin">AppNetBlocker.apk</a> ]
<br>
md5sum [CC8104C9DDE44AD308F09FF22B551575]
</font>

</center>


<h4>AppNetBlocker とは？</h4>

<p>
Android 端末上のデータを狙うマルウェアの問題が取り沙汰されていることもあり、アプリに付与された「許可」の内容は何かと気になります。
特に、それがネットワークアプリやバナー広告を表示するアプリではなく、また、機能面でインターネットへのアクセスが必須とは考えにくい内容のアプリであるにもかかわらず「完全なインターネットアクセス」許可を持っている場合は悩ましいですね。
そんな時には AppNetBlocker が役に立つかもしれません。

<a href="http://dsas.blog.klab.org/archives/52026407.html">続きを読む</a>]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>KLab Advent Calendar 2011 「DSAS for Social を支える技術」</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52024957.html" />
<modified>2011-12-22T05:44:14Z</modified> 
<issued>2011-12-25T20:04:45+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52024957</id>
<summary type="text/plain">DSAS Blog もアドベント・カレンダーをはじめます。
最近日記をサボりがちでしたが、平日は毎日更新がんばります。


12/1: MySQL を PDO で使うときは ATTR_EMULATE_PREPARES を設定しよう

12/2: クエリキャッシュは切ったほうがいいんじゃなイカ？

12/5: SHOW FULL PROCE...</summary> 
<dc:subject></dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52024957.html">
<![CDATA[DSAS Blog もアドベント・カレンダーをはじめます。
最近日記をサボりがちでしたが、平日は毎日更新がんばります。

<p>
12/1: <a href="http://dsas.blog.klab.org/archives/52021703.html">MySQL を PDO で使うときは ATTR_EMULATE_PREPARES を設定しよう</a>
<br />
12/2: <a href="http://dsas.blog.klab.org/archives/52021866.html">クエリキャッシュは切ったほうがいいんじゃなイカ？</a>
<br />
12/5: <a href="http://dsas.blog.klab.org/archives/52022689.html">SHOW FULL PROCESSLIST を使った MySQL のプロファイリング</a>
<br />
12/6: <a href="http://dsas.blog.klab.org/archives/52023039.html">JavaScriptでつくる量子コンピューター</a>
<br />
12/7: <a href="http://dsas.blog.klab.org/archives/52023218.html">DSAS for Social での MySQL のボトルネックと今後の方針</a>
<br />
12/8: <a href="http://dsas.blog.klab.org/archives/52023498.html">ソーシャルアプリのボトルネック調査例（strace編）</a>
<br />
12/9: <a href="http://dsas.blog.klab.org/archives/52023738.html">php のプロセス数を絞ろう</a>
<br />
12/12: <a href="http://dsas.blog.klab.org/archives/52024386.html">高負荷でも安定したサービスを提供するためのリバースプロキシ</a>
<br />
12/13: <a href="http://dsas.blog.klab.org/archives/52024598.html">過負荷をかわす Apache の設定</a>
<br />
12/14: <a href="http://dsas.blog.klab.org/archives/52024748.html">Apache の並列数を CPU コア数に応じて決定する</a>
<br />
12/15: <a href="http://dsas.blog.klab.org/archives/52024948.html">SHOW PROCESSLIST を使ったカジュアルなプロファイラを強化しました</a>
<br />
12/16: <a href="http://dsas.blog.klab.org/archives/52025128.html">DSAS環境でのDNS活用法 ～ネットワーク設定の格納にDNSを使う～</a>
<br />
12/19: <a href="http://dsas.blog.klab.org/archives/52025734.html">DSAS環境でのDNS活用法2 ～tinydns-get活用術～</a>
<br />
12/20: <a href="http://dsas.blog.klab.org/archives/52026035.html">トラフィックが急増! ボトルネックを退治しよう～ </a>
<br/>
12/21: <a href="http://dsas.blog.klab.org/archives/52026063.html">Ajax開発のテストツールとしてのPython</a>
<br />]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>トラフィックが急増! ボトルネックを退治しよう～ 【設定編】</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52026455.html" />
<modified>2011-12-22T16:06:53Z</modified> 
<issued>2011-12-22T23:40:33+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52026455</id>
<summary type="text/plain">KLab Advent Calendar 2011 「DSAS for Social を支える技術」 の16日目。最終日?です。 

今日は、14日目の続きになります。前回は、ネットワーク通信において負荷分散機がボトルネックになっているのを解消するために、DSR構成をとるための設定項目をあげて、それぞれに関...</summary> 
<dc:subject>dsas</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52026455.html">
<![CDATA[<a href="http://dsas.blog.klab.org/archives/52024957.html" target="_self" title="">KLab Advent Calendar 2011 「DSAS for Social を支える技術」</a> の16日目。最終日?です。 

今日は、<a href="http://dsas.blog.klab.org/archives/52026035.html" target="_self" title="">14日目</a>の続きになります。前回は、ネットワーク通信において負荷分散機がボトルネックになっているのを解消するために、DSR構成をとるための設定項目をあげて、それぞれに関して説明したところで終わっていました。今日は具体的な設定について説明していきます。

<h3>DSR構成のレシピ</h3>

まずは、設定項目をおさらいしておきましょう。次の6つでした。

<ol type="a">
<li>LVS の負荷分散の設定をDSRに変更する(ipvs の設定)  </li>
<li>Webサーバが、DSRなリクエストパケットを扱えるようにする(iptables の設定)  </li>
<li>Webサーバを、outer VLAN に参加させる(L2 スイッチの設定) </li>
<li>Webサーバが、outer VLAN において通信できるように設定する(VLAN 用インタフェースの追加)  </li>
<li>Webサーバにおいて、上位ルータへの通信経路を設定する(ルーティングと iptablesの設定)  </li>
<li>Webサーバが、上位ルータに対して応答パケットを送信できるように設定する(ARP エントリの設定)  </li>
</ol>

それぞれの設定について、説明していきましょう。

<h4>LVS の負荷分散の設定をDSRに変更する</h4>
ipvs で負荷分散する場合、LVS マシンに到達したクライアントからのパケットを Webサーバへと転送する方法には、3種類あります。1つ目は LVS 上で NATして転送する方法、2つ目は届いた IPパケットをカプセル化して転送する方法、3つ目が DSRです。
ipvs の仮想サービスの設定で DSR を指定するには、は、<code>ipvsadm</code> コマンドで設定する場合でしたら  <code>--masquerading (-m)</code>(＝ NAT)や <code>--ipip (-i)</code>(＝ カプセル化)の代わりに <code>--gatewaying (-g)</code> を指定します。 <code>keepalived</code> を使っているのでしたら、仮想サービスの設定で  <code>lb_kind</code> オプションに  <code>DR</code>を指定します。

<h4>Webサーバが、DSRなリクエストパケットを扱えるようにする</h4>
DSR 構成を採った場合、LVS から Webサーバに転送されてくるパケットは前回説明したように、<b>送信先</b>IPアドレスが LVSの仮想サービス用のアドレス(図では A.B.C.D)のままになっています。

<img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/8/3/83d98792.png" width="253" height="347" border="0" alt="packet" hspace="5" class="pict"  /><br />

<p>このパケットを、Webサーバの OSが受け取ったときに自分宛のパケットだと認識させるためには、追加の設定が必要になります。方法はいくつかありますが、DSAS for Social では Webサーバ上で NAT する方法を使っています。つまり、送信先IPアドレスが <code>A.B.C.D</code> であるパケットを受け採った場合、Webサーバ自身がそのパケットの送信先アドレスを自分のアドレス(<code>ss.tt.uu.vv</code>)に書き換えるのです。そうすれば、そのパケットは Webサーバの OSが自分宛のパケットだと理解して、Apacheなどのアプリケーションに渡してくれるようになります。
<p>設定方法は、OSに依って変わりますが、Linux の場合、次のようにするのが簡単です。

<pre class="prog">
 # iptables -t nat -A PREROUTING -p tcp --dport 80 -d A.B.C.D -j REDIRECT
</pre>

これで、クライアントから LVSを経由して Webサーバに届いた宛先アドレス=<code>A.B.C.D</code>なパケットが、Webサーバ自身で処理されるようになります。

<h4>Webサーバを、outer VLAN に参加させる</h4>
<p>ここからは、Webサーバが直接上位ルータに対して応答パケットを渡すために必要となる設定になります。そのためには、まずは Webサーバが "outer VLAN" に参加しないと始まりません。その際 "inner VLAN" と "outer VLAN" が混ざらないように、どちらかの VLAN には tag VLAN として参加させる必要があります。DSAS for Social では、"outer VLAN" 側を、tag VLAN にして参加させています。
<p>Webサーバを "outer VLAN" に属させるためには、L2 スイッチの設定が必要になります。どのような設定になるのかはスイッチによって変わってきますが、DSAS for Social で主に使っている hp社の Procurve シリーズでは、例えば次のようにします。

<pre class="prog">
 # config 
 (config)# vlan 4
 (vlan-4)# tagged 10-20
</pre>

これは、"outer VLAN" の VLAN番号が 4、Webサーバ(群)が接続されているポートのポート番号が 10番～20番ポートの場合の例です。


<h4>Webサーバが、outer VLAN において通信できるように設定する</h4>
<p>Webサーバが "outer VLAN" に対して通信するには、Webサーバ側でも追加設定が必要になってきます。というのも、先ほどのスイッチの設定において、 Webサーバは tag VLAN で "outer VLAN" に参加するようにしたので、Webサーバがスイッチと "outer VLAN" 向けのパケットをやりとりするときは、VLAN tag をつけてるようにしなければならないのです。Linux において tag VLAN を扱うためには、VLAN ID に対応した<b>仮想的な</b>ネットワークインタフェース(NIC)を作成してやります。この仮想的な NIC は物理的な NIC にひもづけられます。仮想 NIC はどの物理 NIC に対してひもづけるかと言うと、当然ながら先ほどスイッチの設定で "outer VLAN" に参加させたポートに接続している NIC に対してになります。

<img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/9/d/9d7771fd.png" width="200" height="369" border="0" alt="NIC" hspace="5" class="pict"  /><br />

<p>Linux において、tag VLAN 用の仮想 NIC を使うためには、<code>8021q</code>ドライバモジュールが必要となります。カーネルを手元でコンパイルする際にこのドライバを含めるには

<pre class="prog">
CONFIG_VLAN_8021Q
CONFIG_VLAN_8021Q_GVRP
</pre>

の2つのオプションを有効にしてください(モジュールにしても組み込みにしても、どちらでも構いません)。

<p>物理NICに紐づいた tag VLAN 用の仮想 NIC を作成するには、vconfig コマンドを使います。

<pre class="prog">
 # vconfig add eth0 4
 # ip link set eth0.4 up
</pre>

これで、Webサーバが "outer VLAN" 上でパケットをやりとりする準備が整いました。tcpdump などで eth0.4 を観察すれば、broadcast パケットなどが流れる様子が観察できるはずです。

<h4>Webサーバにおいて、上位ルータへの通信経路を設定する</h4>
<p>Web サーバが直接上位ルータとパケットをやりとりするための環境は整いました。しかしこれだけでは OS は Webサーバの応答パケットを上位ルータに渡してはくれません。ルーティングを設定する必要があります。そして、前回の要件であげたように、default gateway を変更すること無く、DSRしたいパケットだけ上位ルータに対してルーティングするように設定する必要があります。
<p>これを実現するためには、Linux のポリシールーティング機能を使います。これは、様々な条件に基づいてルーティング設定を切り替える機能で、Linux の他の機能の例に漏れず非常に柔軟な設定をすることができます。今回は Netfilter の mangle テーブル上で DSRしたいパケットに対してマーキングを行い、そのマーキングしたパケットに対してのみ適用する DSR専用のルーティングテーブルを、通常のルーティングテーブルとは別に作成しすることで、DSRを実現します。<br>

<p>Netfilter の mangle テーブルと、ポリシールーティング機能を使うためには、それぞれカーネルの機能を有効にする必要があります。mangle テーブルを使うには、モジュールがすでにある場合は <code>iptable_mangle</code>モジュールを読み込みます(iptables コマンドで mangleテーブルを触れば自動的にロードされます)。無ければ <code>CONFIG_IP_NF_MANGLE</code>を有効にして、カーネルを作り直してください。ポリシールーティング機能はカーネルモジュールにはできず、組込みにしなければなりません。お使いのカーネルの config を見て、<code>CONFIG_IP_MULTIPLE_TABLES</code> が <code>y</code> になっているか、確認してください。<code>y</code> になってなければ、カーネルを作り直す必要があります。

<img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/1/5/153fc4c3.png" width="409" height="347" border="0" alt="DSR" hspace="5" class="pict"  /><br />

<p>カーネルの機能を有効にしたら設定していきましょう。まずは、DSRしたいパケットに対してマーキングをします。

<pre class="prog">
 # iptables -t mangle -A OUTPUT -s A.B.C.D -j MARK  --set-mark 4
</pre>

<code>-s</code> オプションで DSRしたいパケット＝ソースアドレスが <code>A.B.C.D</code> のものを指定します。そして <code>-j MARK  --set-mark 4</code> でマーキングを施します。最後の 4 は DSRしたいパケットにつける識別ID になります。この後に設定するポリシールーティングにおいて、どのパケットに対して DSR用のルーティングテーブルを適用するのかを、この IDを使って指定します。

<p>ポリシールーティングのための設定は、次の様になります。

<pre class="prog">
 # ip route add H.I.J.K/32 dev eth0.4 table 100
 # ip route add default via H.I.J.K table 100
 # ip rule add prio 100 fwmark 4 table 100
 # ip route add H.I.J.K/32 dev eth0.4
</pre>

まず、デフォルトのルーティングテーブルとは別の、DSR用のルーティングテーブルを作成します。このテーブルの名前をここでは "100" にしています。最初の2行はこの "100" というルーティングテーブルに対して、ルーティング情報を追加しています。つまり、上位ルータ(アドレス＝H.I.J.K)とは eth0.4 という NICを通じてやりとりできることを示し(1行目)、インターネットに対してパケットを送信するときは、その上位ルータを中継すればよいことを指定(2行目)します。
<p>3行目は、先ほど Netfilter の mangle テーブルにて DSRしたいパケットに対してマーキングした <code>4</code>というIDを手がかりにして(fwmark 4 の部分です)、新しく作った "100" というルーティングテーブルを参照するよう、指示しています。つまり、mangle テーブルで 4 という ID を付与されたパケットは、3行目の指示にしたがって、1,2行目で新しく作った特別なルーティングテーブルを参照して、行き先が決定されるようになります。

<h4>Webサーバが、上位ルータに対して応答パケットを送信できるように設定する</h4>
さて最後に、上位ルータと Webサーバがパケットをやりとりする上で必要な、ちょっとした設定を追加します。先ほどは、IP上での(L3的)上位ルータとのやりとりする経路の設定をしました。通常はこれだけで問題なく上位ルータと Webサーバはやりとりができるのですが、今回の設定例では Webサーバの VLAN インタフェースに IPアドレスを振らなかったため、ちょっとした小細工が必要になります。
<p>どういうことかというと、上位ルータの MACアドレス＝Ethrnetのアドレスが、このままでは Webサーバには分からないのです。通常は通信相手の MACアドレスは、 ARPプロトコルを使って自動的に取得されるのですが、Webサーバは上位ルータと直接通信するために必要な、同一のサブネットに属したIPアドレスを持っていないので、ARPプロトコルが使えないのです。しかたがないので、上位ルータの MAC アドレスは、人間が手動で与えてやることにします。やり方は、上位ルータの MACアドレスが hh:ii:jj:kk:ll:mm だとすれば

<pre class="prog">
 # arp -s -i eth0.4 H.I.J.K hh:ii:jj:kk:ll:mm 
</pre>

となります。<br>


<p>以上で、Webサーバが DSRするための設定が完成しました。これでもう負荷分散機がボトルネックになることはありません。]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>Ajax開発のテストツールとしてのPython</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52026063.html" />
<modified>2011-12-21T03:00:10Z</modified> 
<issued>2011-12-21T12:00:00+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52026063</id>
<summary type="text/plain">
KLab Advent Calendar 2011 「DSAS for Social を支える技術」 の15日目です。 



最近はソーシャルゲームの開発案件も増えてきました。Android/iOSアプリの開発をはじめとしたAjax通信の事例が数多くなり、開発スタイルも様変わりしつつあります。以前はWebサイト・Webア...</summary> 
<dc:subject>Python</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52026063.html">
<![CDATA[<p>
KLab Advent Calendar 2011 「DSAS for Social を支える技術」 の15日目です。 
</p>

<p>
最近はソーシャルゲームの開発案件も増えてきました。Android/iOSアプリの開発をはじめとしたAjax通信の事例が数多くなり、開発スタイルも様変わりしつつあります。以前はWebサイト・Webアプリ構築の場合はPCや携帯のブラウザをリロードしながらだったのが、スマートフォンが加わりつつあります。
</p>

<p>
スマートフォンにおいてはさらにアプリ開発が大きな意味を持ちつつあります。携帯時代にもJavaアプリやBREWアプリなど多様なアプリがありましたが、スマートフォンアプリでの違いは、サーバとの通信を非常に多く行うようになったことです。クライアントアプリは多くの場合自前かもしくはWebViewを用い、通信はAjaxが使われます。リクエストもGETだけでなくPOSTを使う事も多くあり、ブラウザだけでサーバ開発・デバッグを進めるのは厳しい事が多くあります。
</p>

<p>
そんなわけで今回、Ajax通信を行う簡単なテストツールがほしいと思って少々探してみたのですが、「<a href="http://seleniumhq.org/" target="_blank" title="">Selenium</a>」というブラウザベースのツール以外見当たらないようでした。私が欲しかったのは単に一回のAjaxリクエストとレスポンスのそれぞれ引数と返値を検査して、想定通りの処理がされてるかどうかを見たかったのですが、今回の用途にはオーバースペックでした。
</p>

<p>
最初はサーバの動作確認にはwgetやcurlといったコマンドラインツールを使用していました。しかし基本的な疎通確認やプログラムがエラーなく動作するかどうかくらいには使えても、Ajaxレスポンスが複雑になってくるにつれてレスポンスのJSONの値が本当に正しいかどうかの判定はできません。目視での確認も限界があります。クライアントアプリが送った認証要求を正しく判別してOK/NGを返すかどうかとか、ゲームロジックとして正しい値を返すかどうか、などなど。開発が進むにつれてAjaxサーバの行う処理も複雑化しますので、早めにダミークライアント、サーバテスト用のスクリプトが是非欲しいところです。
</p>

<p>
Pythonにはユニットテストモジュールunittestが標準ライブラリとして組み込まれています。さらにHTTP通信を行うurllib2やjsonモジュールも標準ですので、これらを組み合わせればAjaxサーバの開発を強力に援護することができます。
</p>

<pre class="code">
import urllib2
import json

import unittest

session = 'xxxxxxxx'
url = 'http://foo.bar/apps/?p={"session_id":"%s","action":"%s","params":"%s"}'

class TestAjaxProcess(unittest.TestCase):
    def test01(self):
        f = urllib2.urlopen(url % (session, 'hoge_action', 1)) 
        result = json.loads(f.read())
        print result

        # Ajaxレスポンスには { "result":"ok", "data":{"response_code":1, ... }} のような内容を想定
        self.assertEqual(result['result'], 'ok')
        self.assertEqual(result['data']['response_code'], 1)

    def test02(self):
        f = urllib2.urlopen(url % (session, 'hoge_action', 2)) 
        result = json.loads(f.read())
        print result

        # Ajaxレスポンスには { "result":"ng", "data":{"message": }} のような内容を想定
        self.assertEqual(result['result'], 'ng')
        self.assertEqual(result['data']['message'], '"params" invalid')

if __name__ == '__main__':
    unittest.main()
</pre>

<p>
下は動作例です。
</p>

<pre class="code">
$ python tester.py
{ u'result':u'ok', u'data': {u'response_code": 1, u'value':100, u'extra_comment': u'hogehoge' }}
{ u'result':u'ng', u'data': {u'message': u'"params" invalid' }}
..
----------------------------------------------------------------------
Ran 2 tests in 0.160s

OK
</pre>

<p>
標準ライブラリが充実したスクリプト言語であれば、このようにAjaxテストスクリプトは容易に組めます。素早い実装柔軟な変更を求められる開発現場において、こうしたAjaxテスト環境を揃えておくことは、今後さらに重要度が増す事でしょう。
</p>]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>トラフィックが急増! ボトルネックを退治しよう～</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52026035.html" />
<modified>2011-12-20T15:59:54Z</modified> 
<issued>2011-12-20T23:30:13+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52026035</id>
<summary type="text/plain">KLab Advent Calendar 2011 「DSAS for Social を支える技術」 の14日目です。 

このシリーズも、初めは専らアプリケーション寄りの話題でしたが、ここ二回ほどはインフラ寄りの話題でした。今日はさらに(OSIの7階層モデルにあてると)下寄りの話題になります…。できるだけ...</summary> 
<dc:subject>dsas</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52026035.html">
<![CDATA[<a href="http://dsas.blog.klab.org/archives/52024957.html">KLab Advent Calendar 2011 「DSAS for Social を支える技術」</a> の14日目です。 <br>

<p>このシリーズも、初めは専らアプリケーション寄りの話題でしたが、ここ二回ほどはインフラ寄りの話題でした。今日はさらに(OSIの7階層モデルにあてると)下寄りの話題になります…。できるだけ分かりやすく書くつもりですので、お付き合い頂ければと思います。 <br>

<h3>負荷分散機がボトルネック</h3>
<p>さて、DSAS for Social ではいくつかのアプリケーションが動いているわけですが、では1つのアプリケーションがピーク時に使う帯域はどれくらいになるか、皆さん想像がつきますでしょうか。答えはもちろんアプリケーションによって全く変わるのですが、今まで記録した中での最大値は、2Gbps を越えました。これは、サーバに搭載されている NIC の能力を越えています。もちろん、1台の web サーバでこのトラフィックを全て捌いたわけじゃないのですが、実は DSAS の構成上、どうしてもこのトラフィックが集中する箇所があります。それは、負荷分散機の部分です。 <br>

<h4>なぜ負荷分散機がボトルネックになるのか</h4>
<p>DSAS for Social では、負荷分散機に、Linux 上に実装された L4 負荷分散システムである、<a href="http://www.linuxvirtualserver.org/software/ipvs.html" target="_self" title="">IPVS</a> を使っています(以下、この IPVS が動作するマシンのことを、LVSマシンと呼びます)。そして LVS マシンは、DSAS for Social におけるルータの役割を兼用しています。つまりどういうことかというと、DSAS for Social における外部との相互通信は、全て LVS マシンを経由する、ということです。図で書くと、次のようになります。

<a href="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/6/8/68fa023f.png" title="L3-1" target="_blank"><img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/6/8/68fa023f-s.png" width="480" height="338" border="0" alt="L3-1" hspace="5" class="pict"  /></a><br />

<p>LVS マシンは、負荷分散機だからと言って、特別なマシンを使っているわけではありません。Webサーバと同じものを使っています。これは LVS マシンがこわれた場合、隣に並んでいる Webサーバを使って LVS マシンの代わりをさせることができるように、という考えに基づいてこうしています。ですので、LVS マシンに搭載されている NIC(Network Interface Card) も、普通の 1Gbps のものです。DSAS for Social 以前の DSAS では、LVS が捌かなければならない帯域が 1Gbps を越えることは無く問題にはなりませんでした。しかしながら冒頭にも書いたように、DSAS for Social では 1つのアプリケーションが 2Gbps の帯域を消費するケースも出てきます。そのため、LVS がネットワーク通信に置いてボトルネックになってしまいました。 <br>

<h3>ボトルネックを解消するには</h3>
<p>このボトルネックを解消するには、いくつかの方法があります。例えば NIC をもっと広帯域のものに変える、あるいは複数の NIC を束ねて帯域を太くする、などです。しかし、いずれの方法でもハードウェア的な変更が必要となるため、LVS用マシンが特別なマシンとなり、故障時に web サーバを代わりに充てる、ということが手軽にできなくなってしまいます。ということで、ハードウェアを拡張すること無く、どうにかできる方法を考えてみました。 <br>

<h4>DSAS for Social における L2ネットワークは、どうなっているのか</h4>
<p>さて先ほどの図は DSAS for Social の IP ネットワーク = L3 ネットワークの図でした。これがどのような Ethernet のネットワーク = L2 ネットワークの上に載っているかというと、次のようになっています。<br>

<img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/9/7/974b0897.png" width="465" height="320" border="0" alt="L2-1" hspace="5" class="pict"  /><br />

インターネットの回線＝上位ルータ(データセンタが管理している)は、直接 LVS に接続せずに一旦 L2 スイッチに収容しています(これも、Webサーバを LVSマシンの代替機にし得るようにするための工夫の1つです)。このスイッチには Webサーバや DBサーバも接続されているため、内部のネットワークと外部のネットワークが混在しないように、VLANを使って分離しています。LVS は両方の VLAN に接続し、それぞれの間を IP レベル(L3レベル)で橋渡し(ルーティング)しています。 <br>

<p>クライアントからの Webサーバに対する通信は、次のような経路を通ることになります。

<img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/6/c/6c40c5ed.png" width="465" height="344" border="0" alt="L2-2" hspace="5" class="pict"  /><br />

つまり、外部のネットワークから送られてくるパケットは、図にある outer のVLANを通って LVS に到達し、LVS が Web サーバへと渡します。Webサーバからの応答パケットは、この逆順をたどります。 <br>

<p>この図を見ていると、何となく、Webサーバからの応答パケットが LVS を経由してクライアントへと送信されいていることが、無駄なように思えてきます。なぜわざわざ LVS を経由させているかというと、外部との通信が全て LVS を経由するこの形であれば、通信でトラブルが発生した場合でも、LVS 上で全ての状況を観察できるため、運用上都合がよいからです。 <br>

<h4>どうすれば、ボトルネックを解消できるか</h4>
<p>しかしながら、どうしても LVSの部分が通信のボトルネックになってしまいます。ですので DSAS for Social では、トラフィックの多い一部のアプリケーションに関しては、次の図のように、Webサーバからの応答パケットが LVS を経由しないような通信経路に切り替えることにしました。いわゆる、DSR(Direct Server Return)構成というやつです。

<img src="http://livedoor.blogimg.jp/klab_gijutsu2/imgs/d/b/dba5f13e.png" width="472" height="368" border="0" alt="L2-3" hspace="5" class="pict"  /><br />

<p>これでもまだクライアントからのリクエストパケットは、LVSを経由しているので、ここがボトルネックになるんじゃないかと思われるかもしれません。しかしながら Webアプリケーションにおいて、そのトラフィックのほとんどは Webサーバからの応答パケットによるものです。クライアントからのリクエストパケットに要する帯域は応答パケットのものに比べると微々たるものです。冒頭で紹介した最大 2Gbpsを記録したトラフィックも、応答パケットのものです。ですので、今回の問題はこの構成で解決できるのです。 <br>

<h4>解決策のまとめ</h4>
<p>以上、長い前フリが終わったところで、要件をまとめておきましょう。

<ol>
<li> ipvs の設定と Webサーバの動作を、DSR 構成にする</li>
<li> HTTP リクエスト以外の通信に関しては、これまでどおり LVS を経由して通信する</li>
</ol>

2つ目の要件はどういうことかというと、例えば Webアプリケーションが外部のサーバへ問い合わせをするときなどには、これまでどおり LVSを経由して通信する、ということです。というのも、WebサーバはグローバルIPアドレスを持っていませんので、そのままでは外部のサーバと直接通信できないのです。そのためどこかで NATする必要があるのですが、これは LVSマシンのルータとしての役割の1つなので、どうしても LVSマシンを経由するようにしておく必要があります。 <br>

<h3>DSAS for Social におけるDSR構成の作り方</h3>
<p>では要件が明確になったところで、次に設定するべき項目をあげていきましょう。

<ol type=a>
<li>LVS の負荷分散の設定をDSRに変更する(ipvs の設定)  </li>
<li>Webサーバが、DSRなリクエストパケットを扱えるようにする(iptables の設定)  </li>
<li>Webサーバを、outer VLAN に参加させる(L2 スイッチの設定) </li>
<li>Webサーバが、outer VLAN において通信できるように設定する(VLAN 用インタフェースの追加)  </li>
<li>Webサーバにおいて、上位ルータへの通信経路を設定する(ルーティングと iptablesの設定)  </li>
<li>Webサーバが、上位ルータに対して応答パケットを送信できるように設定する(ARP エントリの設定)  </li>
</ol>

となります。(この記事で説明する設定は、あくまで DSAS for Social の実状に合わせた設定になります。DSR構成をとる上で、設定方法はここで説明する方法だけではなく、他にもいろいろな方法が考えられます。ここで説明する方法はどちらかといえば特殊な設定方法になると思います。)

<p>それぞれどういうことか、簡単に説明していきましょう。

<h4>DSR 構成をとるためには </h4>
<p>まず DSR な負荷分散構成を採る場合、Webサーバに届くリクエストパケットは、負荷分散機などにおいて何も手を加えられてないものになります。どういうことかというと、(Webサーバに届いた)リクエストパケットに記述されている<b>送信先</b>IPアドレスは、いわゆる仮想サービス用のアドレスになります。つまり、LVS へとパケットが届けられたときに送信先アドレスとして使われたグローバルアドレスそのままです。これはWebサーバに割り振られた(プライベート)IPアドレスとは別物です。Webサーバはこのパケットを受け入れて、かつ、応答を返信する際は<b>送信元</b>アドレスとして同じグローバルアドレスを記述して送信しなければいけません。これを解決するのが (b) の設定になります。

<p>(c) と (d) に関しては特に難しい問題は孕んでいません。ちょっと変わっている点は、(d) で作る VLAN 用のインタフェースに、IPアドレスを設定しないことくらいです。しかし、IPアドレスを振らずにすませるために1つ小細工が必要になります。それが (f) です。

<p>(e) は、要件の 2 を実現するための設定です。今回 Webサーバのルーティングテーブルに設定するデフォルトゲートウェイのアドレスは、LVS のIPアドレスのまま変更しません。その上で DSR の応答パケットのみルーティングを切り替えて、上位ルータに渡すようにしたいのです。そのための小細工が必要になります。

<p>さて、ではいよいよ設定です… といきたいところですが、紙面がつきました(笑)ので、続きは明日に…]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>DSAS環境でのDNS活用法2 ～tinydns-get活用術～</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52025734.html" />
<modified>2011-12-19T10:15:11Z</modified> 
<issued>2011-12-19T16:19:58+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52025734</id>
<summary type="text/plain">
KLab Advent Calendar 2011 「DSAS for Social を支える技術」
の13日目です。



先週に引き続き、DSAS 環境での DNS 活用法を紹介します。


スクリプト中でのゾーン参照方法


DSAS で使用している各種スクリプト内で、DNS の情報を参照する際に使ってるコードを紹介しま...</summary> 
<dc:subject>dsas</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52025734.html">
<![CDATA[<p>
<a href="http://dsas.blog.klab.org/archives/52024957.html">KLab Advent Calendar 2011 「DSAS for Social を支える技術」</a>
の13日目です。
</p>

<p>
先週に引き続き、DSAS 環境での DNS 活用法を紹介します。
</p>

<h4><u>スクリプト中でのゾーン参照方法</u></h4>

<p>
DSAS で使用している各種スクリプト内で、DNS の情報を参照する際に使ってるコードを紹介します。
</p>

<pre class="prog">
# 設定情報用のゾーン(.dsas)を検索
mzone () 
{ 
    R="$1";
    ( cd $INTERNALZONE 2> /dev/null;
    _zone TXT $R.dsas )
}

# 名前解決を行う
# tinydnsのゾーンファイルのコピーがあればtinydns-getを使用
# ゾーンファイルがなければDNS問い合わせを行う
_zone () 
{ 
    if [ -r data.cdb ]; then
        DNSCMD="_zonedjb";
    else
        DNSCMD="_zonedig";
    fi;
    if [ -z "$2" ]; then
        Q="A";
        R="$1";
    else
        Q="$1";
        R="$2";
    fi;
    $DNSCMD $Q $R
}

_zonedig () 
{
    dig +short $1 $2 | sed 's/^\"\(.*\)\"$/\1/'
}

# tinydns-getを使い、カレントディレクトリのdata.cdbを検索
_zonedjb () 
{ 
    tinydns-get $1 $2
}
</pre>

<p>
mzone() と呼んでいる関数では、前回紹介した TXT レコードによる設定データを参照します。<br>
この他に、通常の内部ホスト名の名前解決を行う pzone() や、そのグローバル版の gzone() 等を定義しています。<br>
各サーバでは、起動スクリプト中でこれらの関数等を使い、設定ファイルを生成しています。
</p>

<p>
下記に抜粋したコードでは、この関数を使い、keepalived.conf の VRRP に関する設定を生成しています。
</p>

<pre class="prog">
lan=$(mzone net.private)
lan=$(pzone lvs)/${lan#*/}
wan=$(mzone net.link)
wan=$(mzone lvs.link)/${wan#*/}
cat &lt;&lt;EOF
vrrp_instance VI {
  state BACKUP
  interface bond0
  garp_master_delay 5
  virtual_router_id $(mzone lvs.vrid)
  priority ${PRIO}
  nopreempt  y
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass ********
  }
  virtual_ipaddress {
    ${lan} dev bond0
    ${wan} dev bond0
  }
}
EOF
</pre>

<p>
パラメータ部分を DNS に逃すことで、生成スクリプトの環境依存部分を極力減らせるほか、複数のスクリプトから参照している設定情報を１箇所で管理することができるようになります。
</p>


<h4><u>オフライン時の内部ゾーン参照</u></h4>

<p>
DSAS 環境では、多くの設定ファイルを同様の方法で起動時に生成しています。<br>
ネットワークインタフェースはもちろん、resolv.confや、全サーバのローカルで動いているDNSキャッシュサーバの設定ファイルも起動時に生成しているため、これらの生成スクリプトは、ネットワークが使えない状態でも動作出来る必要があります。
</p>

<p>
ネットワーク設定の生成にネットワークアクセス(DNS参照)が必要という矛盾した状況ですが、とても単純な方法で解決しています。<br>
そもそも DNS 上の情報は、それほど頻繁に更新されるものではないため、サーバの起動時にゾーンファイルを転送してローカルで検索を行い、起動が完了したら DNS の参照に切り替えてやればいいのです。
</p>

<p>
先ほど紹介した、検索用の関数でも、ローカルにゾーンファイルの一時コピー(data.cdb)が存在するかをキーに動作が切り替わるようになっています。<br>
この方法では、ゾーンファイルの一時コピーを消し忘れると、いつまでも古い情報を参照してしまう恐れがあるので、起動処理の一番最後で必ずゾーンファイルを削除するようにします。
</p>


<h4><u>tinydns-getの使い方</u></h4>

<p>
tinydns-get はカレントディレクトリの data.cdb をゾーンファイルとして読み込むため、ゾーンファイルの置かれてるディレクトリに移動して、下記のように実行します。
</p>

<pre class="terminal">
$ tinydns-get A www.klab.jp
1 www.klab.jp:
189 bytes, 1+1+4+4 records, response, authoritative, noerror
query: 1 www.klab.jp
answer: www.klab.jp 86400 A 211.13.209.202
authority: klab.jp 259200 NS ns1.klab.org
authority: klab.jp 259200 NS ns2.klab.org
authority: klab.jp 259200 NS ns8.klab.org
authority: klab.jp 259200 NS ns9.klab.org
additional: ns1.klab.org 14400 A 61.195.64.249
additional: ns2.klab.org 14400 A 61.195.64.247
additional: ns8.klab.org 86400 A 211.13.207.96
additional: ns9.klab.org 86400 A 211.13.207.97
</pre>

<p>
「answer:」の行がクエリの結果です。<br>
tinydns-get では、dig のような「+short」オプションがなく、自分で出力を加工する必要がある上に、TXT レコードの処理に問題があります。
</p>

<pre class="terminal">
'test.dsas.jp:TEST
answer: test.dsas.jp 86400 16 \004TEST

'test.dsas.jp:TEST5678901234567890123456789TEST
answer: test.dsas.jp 86400 16 !TEST5678901234567890123456789TEST

'test.dsas.jp:TEST5678901234567890123456789012345678901234567890
              12345678901234567890123456789012345678901234567890
              123456789012345678901234567TEST
answer: test.dsas.jp 86400 16 \177TEST56789012345678901234567890
                              1234567890123456789012345678901234
                              5678901234567890123456789012345678
                              90123456789012345678901234567\004T
                              EST
</pre>

<p>
上記は、上段がバイナリ変換前のゾーンファイルでのレコード、下段が tinydns-get コマンドを使って検索した結果を示します。<br>
各レコードは、1桁目がレコードの種類(TXTレコードは「'」)、続いてコロン区切りでFQDNとレコードの値が続きます。<br>
answer行の各カラムは、検索したFQDN、TTL、レコードのタイプ値(TXTは16)、レコードの値となっています。
</p>

<p>
ご覧のとおり、レコードの値に「\004」、「!」など、元のゾーンにない文字列が混ざってしまっています。
</p>

<p>
なんと tinydns-get は、TXT レコードに対応しておらず、data.cdb ファイルに格納されている 「1バイトの文字列長 + 最大127バイトのデータ値」の繰り返しによるデータ列をそのまま表示してしまっているのです。<br>
データにより、「\xxx」や「!」など、表示され方に差があるのは、出力時に ASCII Printable であればそのまま、制御コードなどであれば8進数表記に変換して表示しているためです。
</p>

<a href="http://log.blog.klab.org/support/20111219/tinydns-get-support-txtrr.patch">
tinydns-get-support-txtrr.patch
</a>
<br>
<a href="http://log.blog.klab.org/support/20111219/tinydns-get-suppress-msgs.patch">
tinydns-get-suppress-msgs.patch
</a>

<p>
上記のパッチを当てると、tinydns-get が TXT レコードに対応し、余分な文字列を出力しなくなります。<br>
また、少々手荒に書いたパッチですが、２つ目のパッチを当てると、検索結果に関する余分な情報が出力されなくなり、スクリプト等で使いやすくなると思います。
</p>


<hr>
<div style="margin: 1px 3px 1px 0px; text-align: right;">#dSn</div>
]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>DSAS環境でのDNS活用法 ～ネットワーク設定の格納にDNSを使う～</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52025128.html" />
<modified>2011-12-16T09:55:56Z</modified> 
<issued>2011-12-16T18:29:27+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52025128</id>
<summary type="text/plain">
KLab Advent Calendar 2011 「DSAS for Social を支える技術」
の12日目です。



昨日までの apache の話題からガラリとかわって DNS についてお話します。


DSAS 内では、サービスに用いるドメインに関する権威サーバのほかに、システム内部の各サーバのホスト名や DB、m...</summary> 
<dc:subject>dsas</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52025128.html">
<![CDATA[<p>
<a href="http://dsas.blog.klab.org/archives/52024957.html">KLab Advent Calendar 2011 「DSAS for Social を支える技術」</a>
の12日目です。
</p>

<p>
昨日までの apache の話題からガラリとかわって DNS についてお話します。
</p>
<p>
DSAS 内では、サービスに用いるドメインに関する権威サーバのほかに、システム内部の各サーバのホスト名や DB、memcache などの役割に応じた名前を登録した内部向けドメインの権威サーバやキャッシュサーバを運用しています。<br>
システム内に、内部向けの権威サーバや、キャッシュサーバを設置するのは、珍しい構成ではありませんが、DSAS では、内部向け DNS サーバに、システムの設定情報を一部格納しています。
</p>
<p>
今回は、DSAS 環境で DNS サーバに設定情報を格納している理由や運用方法を紹介します。
</p>


<h4><u>ネットブートと設定ファイルの動的生成</u></h4>

<p>
DNS の話題に入る前に、DSAS の特徴を 1 つ紹介します。
</p>
<p>
DSAS では、マスタとなる冗長化された１組のサーバ以外、全てのサーバはネットブートによって起動します。
</p>
<p>
マスタサーバには、ロードバランサ用・Webサーバ用・DBサーバ用等の役割のサーバを構成するファイル一式が圧縮されたアーカイブが置かれていて、これをOSイメージと呼んでいます。<br>
PXEブートにより、カーネルと initramfs がロードされて起動処理が開始されると、マスタサーバから自分の役割に応じたOSイメージ等をダウンロードして、tmpfs に展開します。<br>
この OS イメージは、さすがに個々のサーバごとに個別に用意するわけにはいかないため、機能毎の共通ファイルとなっています。
</p>
<p>
そこで問題となるのが、個々のサーバに個別のパラメータを記述する必要がある設定ファイル類の扱いです。<br>
DB サーバの MySQL で使用する server-id、ロードバランサやmemcacheの冗長化に使っている VRRP のルータID 等の各種デーモンの設定ファイルはもちろん、自身のネットワークインタフェースに割り当てるIPアドレスすら、起動処理内で決定する必要があります。
</p>
<p>
DSAS では、これらの設定ファイル類は、いくつかのタネになる情報を元にして、起動スクリプト内で動的に生成する仕組みを導入しています。<br>
各デーモンや、インタフェースの設定を行う rc スクリプトの前に、設定ファイルを生成するための rc スクリプトを実行するという方法です。
</p>
<p>
そして、設定ファイルを生成するためのタネ情報を仕込む場所の１つが DNS サーバなのです。
</p>


<h4><u>DNSに格納するパラメータの例</u></h4>

<p>
DSAS 環境で DNS に登録するパラメータの一例を紹介します。
</p>
<p>
主に、ネットワークの設定を生成するために必要な情報が中心になります。
</p>
<p>
パラメータを登録するドメインとして、とあるゾーンを定義して、下記のようにTXTレコードで値を登録しています。<br>
なお、実際の DSAS 環境では、権威サーバの実装に tinydns を使用しているため、tinydns-data フォーマットで記述しています。
</p>

<pre class="code">
private          IN  TXT  "dsas.jp"
net.private      IN  TXT  "192.168.0.0/20"
global           IN  TXT  "example.klab.jp"
net.global       IN  TXT  "XXX.XXX.XXX.XXX/xx"

net.link         IN  TYT  "YYY.YYY.YYY.0/29"
lv1.link         IN  TYT  "YYY.YYY.YYY.4"
lv2.link         IN  TYT  "YYY.YYY.YYY.5"
lvs.link         IN  TYT  "YYY.YYY.YYY.6"
gw.link          IN  TYT  "YYY.YYY.YYY.3"

lv1.vlanid.link  IN  TXT  "1"
lv2.vlanid.link  IN  TXT  "1"
lvs.vrid.link    IN  TXT  "100"
</pre>

<p>
private/global/net.private/net.globalは、それぞれ内部用・外部用のドメイン名、プライベートアドレス、サービス用グローバルIPアドレスのレンジになっています。
</p>
<p>
真ん中の *.link 系のレコードは、ロードバランサが自身のネットワーク設定を行うための情報です。<br>
データセンタ側の上位ネットワークと DSAS をつなぐセグメントのアドレスや、その中で使用するIPアドレスなどが定義されています。<br>
( lv1、lv2というのは、冗長化された2台のロードバランサを指し、lvs は VRRP で使用する仮想IPアドレスを指します)
</p>
<p>
VRRP のルータIDや、インタフェースに設定する VLAN I Dなども登録されているので、ロードバランサのインタフェース設定に必要な情報は、殆ど DNS 内の情報を編集するだけで調整できます。
</p>

<p>
このロードバランサを含め、ほとんどのサーバが起動時に DNS 上の情報を参照して、自身のネットワーク設定を行なっています。<br>
すると、ネットワーク設定のために DNS を参照する必要があって、それにはネットワークが必要という、鶏が先か卵が先かという問題が発生してしまいます。<br>
次週は、この問題を解決するための方法や、使用しているdjbdnsのツールを紹介したいと思います。
</p>

<hr>
<div style="margin: 1px 3px 1px 0px; text-align: right;">#dSn</div>]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>SHOW PROCESSLIST を使ったカジュアルなプロファイラを強化しました</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52024948.html" />
<modified>2011-12-15T12:36:10Z</modified> 
<issued>2011-12-15T19:34:33+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52024948</id>
<summary type="text/plain">
KLab Advent Calendar 2011 「DSAS for Social を支える技術」の11日目です。



「SHOW FULL PROCESSLIST を使った MySQL のプロファイリング」
 で紹介したプロファイラですが、 id:sh2 さんからはてブで


秒間10回叩く例も http://developer.cybozu.co.jp/kazuho/2009/0...</summary> 
<dc:subject>mysql</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52024948.html">
<![CDATA[<p>
<a href="http://dsas.blog.klab.org/archives/52024957.html">KLab Advent Calendar 2011 「DSAS for Social を支える技術」</a>の11日目です。

<p>
<a href="http://dsas.blog.klab.org/archives/52022689.html">
「SHOW FULL PROCESSLIST を使った MySQL のプロファイリング」
</a> で紹介したプロファイラですが、 id:sh2 さんからはてブで

<blockquote>
秒間10回叩く例も http://developer.cybozu.co.jp/kazuho/2009/07/mysql-539d.html 。変数ぽい部分をカットする処理はmysqldumpslowのコードを移植するといいかも
</blockquote>

<p>
というコメントをいただきました。
<s>そろそろネタに困っていたので、</s> せっかくなので、多くのユースケースで
便利に使えるように改良しました。ぜひご活用ください。

<p>
<a href="https://gist.github.com/1432916">myprofiler.py (gist)</a> <br />
<a href="https://github.com/methane/myprofiler">github</a>

<h3>解説</h3>

<h4>クエリのサマライズ</h4>
<p>
前のバージョンでは = 以降をバッサリとカットしてしまっていたのですが、
例えば "WHERE user_id='xyz' AND enable=1" が "WHERE user_id=" になってしまうので、
問題のクエリを探すのが難しいケースがありました。

<p>
mysqldumpslow を参考にクエリのサマライズを改良し、
"WHERE user_id='S' AND enable=N" のような形式で集計できるようにしました。


<h4>ini形式のファイルからMySQLの設定を読み込むように</h4>
<p>
オプション無しで実行した場合、 ~/.my.cnf の [DEFAULT] セクションから
user, password, host, port などを読み込みます。 (port はオプション)。

<p>
別のファイルから読み込むときは -c 設定ファイルパス でファイルを指定できます。

<p>
別のセクションから設定を読み込むときは -s セクション名 でセクション名を指定できます。

<h4>行数やインターバルを指定できるように</h4>
<p>
頻出する順で何件を表示するかを -n オプションで指定できるようにしました。
<p>
また、 show full processlist を実行する間隔を -i オプションで指定できます。
秒間10回サンプリングしたい場合は -i 0.1 と指定してください。

<h4>加工前のクエリを出力できるように</h4>
<p>
標準出力に表示しているクエリは、同じ形のクエリをまとめて集計するために
実際のパラメータ等が消えてしまっています。例えば LIMIT 100 でも LIMIT 5
でも LIMIT N と表示されてしまいます。

<p>
実際のパラメータを調べたり、 explain を実行するために、元のクエリが見えた
方がいいこともあるので、 -o 出力ファイル名 で、取得したクエリをファイルに
出力できるようにしました。

<h3>注意点</h3>
<p>
Python 2.6 以上で動くようにするつもりで書いていますが、自分の環境も
DSAS for Social も Python 2.7 を利用しているので Python 2.6 での動作は
未確認です。 <s>(Python 2.5 以下は窓から投げ捨ててください)</s>
(追記: Python 2.5 で使えない機能も避けました。未確認ですが使えるかもしれません)

<p>
MySQL への接続に MySQLdb を使っていますが、これは拡張ライブラリなので、
インストールには libmysqlclient のヘッダファイルや Python のヘッダファイルが
必要になります。 手軽にインストールしたい場合は、ピュアPythonの
<a href="https://github.com/petehunt/PyMySQL">PyMySQL</a> をインストールしてください。

<hr>
<div style="margin: 1px 3px 1px 0px; text-align: right;">@methane</div>]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>

<entry>
<title>Apache の並列数を CPU コア数に応じて決定する</title> 
<link rel="alternate" type="text/html" href="http://dsas.blog.klab.org/archives/52024748.html" />
<modified>2011-12-15T12:36:26Z</modified> 
<issued>2011-12-14T18:39:54+09:00</issued> 
<id>tag:blog.livedoor.jp,2011:klab_gijutsu2.52024748</id>
<summary type="text/plain">
KLab Advent Calendar 2011 「DSAS for Social を支える技術」の10日目です。


昨日の記事 では並列数を設定する基本的な方法を紹介しました。
今日は実際に DSAS for Social で利用している設定方法を紹介します。

背景

実際の並列数の設定はマシンのCPUスペックやアプ...</summary> 
<dc:subject>apache</dc:subject>
<content type="text/html" mode="escaped" xml:lang="ja" xml:base="http://dsas.blog.klab.org/archives/52024748.html">
<![CDATA[<p>
<a href="http://dsas.blog.klab.org/archives/52024957.html">KLab Advent Calendar 2011 「DSAS for Social を支える技術」</a>の10日目です。
<p>
<a href="http://dsas.blog.klab.org/archives/52024598.html">
昨日の記事</a> では並列数を設定する基本的な方法を紹介しました。
今日は実際に DSAS for Social で利用している設定方法を紹介します。

<h3>背景</h3>
<p>
実際の並列数の設定はマシンのCPUスペックやアプリの特性(レスポンスタイムの
何割をWebサーバーのCPUを使う処理が占めているか)に応じて設定するのですが、
DSAS for Social ではアプリの負荷に応じて柔軟にWebサーバーを
追加・削除するので、CPUスペックが一定ではありません。
具体的に言えば、 Core2 世代の4コアサーバーと、Core i7世代の4コア8スレッド
サーバーが Web サーバーとして利用されています。

<p>
でも、Webサーバーごとに違う設定ファイルを用意したくはありません。
なんとかできないかと思っていたところ、 @hamano が httpd.conf 内で環境変数が
使えるよ、と教えてくれました。

<h3>CPUコア数から並列数を計算し設定する</h3>
<p>
DSAS for Social では daemon tools を使って Apache を起動しています。
なので、 run スクリプトでコア数に応じて並列数を計算します。
<p>
あるMVCフレームワークを使ったCPU使用率の高いphpアプリでは、
コア数+2 に設定しています。(Core2世代4コアなら6並列、Core i7世代4コア8スレッド
なら10並列になります)

<pre class="terminal">
CPUCOUNT=`getconf _NPROCESSORS_ONLN`
export MAX_CLIENTS=$((CPUCOUNT+2))
</pre>

<p>
次に、httpd.conf でこの環境変数を利用して並列数を設定します。

<pre class="terminal">
  MinSpareServers      ${MAX_CLIENTS}
  MaxSpareServers      ${MAX_CLIENTS}
  StartServers         ${MAX_CLIENTS}
  ServerLimit          ${MAX_CLIENTS}
  MaxClients           ${MAX_CLIENTS}
</pre>

<p>
これで Web サーバーを40台まで増やしても MySQL の接続数は400以下に抑えられますし、
実際にCPU使用率が80%以上になってレスポンスタイムが伸びてきても安定して
サービスが継続できています。

<h3>補足: ProxyPass の connectiontimeout を1秒未満に設定する</h3>
<p>
昨日の記事で使っていたテスト環境は apache 2.2.10 を利用していたのですが、
connectiontimeout パラメータは 2.2.10 で導入された後、 2.2.11 から ms という
サフィックスを付けて1秒未満の値を設定できるようになりました。
<p>
ループバックアダプタへの接続は backlog が足りていたら 1ms もかからないので、
"connectiontimeout=10ms" などに設定したらいいと思います。

<hr>
<div style="margin: 1px 3px 1px 0px; text-align: right;">@methane</div>
]]> 
</content>
<author>
<name>klab_gijutsu2</name> 
</author>
</entry>
</feed>

