mixiのサーバOS移行のお話 - ビルド&Kernel編
こんにちは。年末と年度末になるとブログを書きたくなる運用部アプリ運用グループの清水です。
気づけば前回の記事から3ヶ月が経過してしまいました…
今回は、ビルド&Kernel編と題して、Fedora 17向けにおこなったパッケージのビルドや、KernelのConfig、TCP周りの変更点について紹介したいと思います。
パッケージのビルド
OSが大幅にバージョンアップすると、依存しているライブラリに大きな変更が入ったり、RPMの仕様変更もあるため、Fedora 8時代のパッケージのリビルドなど、多くのRPMパッケージを作りなおさなければなりません。
mixiでは、Fedora標準パッケージとは別に150個以上のパッケージを、
- configureなどビルドオプションを変える
- Fedoraで提供されないパッケージを作る
- ディストリビューションに依存しない構成のパッケージを作る(あとで紹介するPerlなど)
といった場合に作成しています。
ビルドは、ビルド専用のマシンでrpmbuildをおこない、作成されたrpmをmixi向けのyumリポジトリにコピーしてcreaterepoを実行、各サーバからyumで取得できるようにする、といったごく一般的な方法をとっています。自作のrpmは、releasesやupdatesとは別に用意したextrasディレクトリに格納しています。
それらのパッケージを作る上で直面した問題の一部を紹介したいと思います。
gcc 4.7.0でのビルド
Fedora 17で標準で用意されるgccのバージョンは、4.7.0です。Fedora 8で使っていたgccのバージョンは、4.1.2なのでかなりの差分があると言えます。
Cのソースコードをコンパイルする時、gccの新しいバージョンだと、例えば、#includeでヘッダファイルを足さないとコンパイルが失敗することが多々ありました。そのたびにパッチを作成してコンパイルを通しています。gcc以外にもautomakeやautoconfもバージョンアップしたことで記法も一部変わったりするので要注意です。
公式な情報として、
というサイトがあるので、gcc 4.7に移行する場合は参考にすると非常に便利です。
MySQL(Percona Server)
mixiでメインで使っているデータベースサーバは公式のMySQLではなく、Percona社がMySQLを独自に改良したPercona Serverを採用しています。Percona Serverについての説明は、ご存じの方も多いと思うのでここでは省きます。もし知らないという方は、
公式のMySQLとの機能比較ページ
http://www.percona.com/doc/percona-server/5.1/feature_comparison.html
がありますので、こちらをご参考ください。
残念ながら、Percona ServerはFedora 17向けのバイナリパッケージはありません(Fedora 19ではMariaDBが標準採用という方向のようですが…)。そのため、Fedora 17の環境では、Perconaから入手した5.1系のSource RPMをリビルドしています。しかし、gcc 4.7.0では、同梱されているHandlerSocketのビルドのところで通らなかったので、パッチを作ってビルドしていました。
現在、本家でこの修正は行われ、Percona Serverの新しいバージョンで取り込まれてビルドが問題なく通るようになっています。
Ability to compile HandlerSocket under a gcc-4.7
(commit)
Perl
ご存知の通り、mixiではPerlがメインの言語です。ここでは深くは触れませんが、Fedora 17への移行にあわせて、Perlのバージョンアップも実施しました。5.8系から5.14系に変わり、コード側の対応もおこないました。今後はOSのPerlバージョンに依存しないように、独立したディレクトリを使うように構成したPerl関連の独自のRPMを用意しています。
(きっとこのあたりの詳細は誰かが記事にしてくれると期待して…)
Kernel
Fedora 17の標準のカーネルバージョンは3.3.4。Fedora 17のパッケージ群は、日々バージョンアップされ、updatesレポジトリにどんどん新しいバージョンのKernelが置かれていきます。(この記事の執筆時は3.8.3まで上がっていました)
mixiでは、サーバを安定的に運用するために、ある時点のupdatesレポジトリのスナップショットをとり、それをある期間使い続けるようにしています(問題のあるパッケージが発見された場合を除く)。
Kernelにおいても、ある時点の3.3.4以降のバージョンを採用していますが、標準のビルドそのままに使うことはしていません。というのも、標準Kernelのバイナリは、デスクトップ向けOSという位置付けのために、非常に多くのConfigが有効化された状態でビルドされています。
これでは、サーバ運用上、余計なConfigが多いため、必要最低限のConfigとハードウェアに合わせたConfigを選択してリビルドして使っています。主には不要なドライバの削除、組み込む必要のないファイルシステムのモジュール化、マシンのCPUに合わせたConfig、使わないネットワーク系の機能の削除など。これらは、複数のKernel有識者によるKernel Configレビューをおこなって選定しています。
KVM
KernelのConfig選定にあたって問題に直面したこともありました。たとえば、仮想環境用に、KVM(Kernel-based Virtual Machine)を使うため、make menuconfigで
Virtualization -> Kernel-based Virtual Machine (KVM) support
を有効にして、Fedora 17におけるKVMの動作検証をおこなっていたところ、KVMと密接な関係にあるlibvirtdがデッドロックする問題に遭遇しました。
新しいlibvirtdはLXC(Linux Containers)にも依存しているようで、KernelのConfigにLXC関連のものを追加したところ、一切デッドロックしなくなりました。
追加したConfigは以下の箇所。
General setup -> Namespaces support Networking support -> Networking options -> QoS and/or fair queueing -> Control Group Classifier
TCP周りの改良
ビルドの話ではありませんが、Fedora 17にしたことでKernelに取り込まれた新機能の数々を使うことができるようになっています。
最近のKernelではTCP周りの改良がたびたび入るようになりました。大半はConfigで制御するものではなく、Kernelのコードに取り込まれています。代表的なものについて以下に紹介したいと思います。
Kernel 3.0
tcp: Increase the initial congestion window to 10.
(commit)
輻輳ウインドウサイズの初期値のデフォルトが10へ変更になっています。これにより、スロースタート開始時から最大10パケットをまとめて送るようになりました。これは、Kernel 2.6系も2.6.39から、RHELは6.2からデフォルト値が変わっています。
参考:
Tuning initcwnd for optimum performance
http://www.cdnplanet.com/blog/tune-tcp-initcwnd-for-optimum-performance/
Increasing the TCP initial congestion window
https://lwn.net/Articles/427104/
最近のクライアントOSではRWIN(receivers advertised window size)は65,535バイトに設定されていることが多く、初期に10パケット送られても十分に受け取れるケースが増えています。ただ、モバイルのネットワークなどのパケットロスが起きやすい環境では再送が増える場合もあります。mixiではデフォルト値である10を使用しています。この値は、ipコマンドで動的に変更することができます。
コマンドの例:
sudo ip route change default via x.x.x.x dev em1 initcwnd 3
Kernel 3.1
tcp: RFC2988bis + taking RTT sample from 3WHS for the passive open side
(commit)
再送タイムアウト値であるRTO(retransmission time out)の初期値が、3秒から1秒へ変更になっています。これにより、より早いタイミングで再送が行われることになり、パフォーマンスアップを図っています。ただし、SYN、SYN-ACKが再送された場合は、従来の3秒のタイムアウトにフォールバックされます。
また、3way handshakeにおけるRTT(round trip time)をサンプリングして、その値をデータ転送フェーズでのRTO(retransmission time out)初期値に利用するようになりました。
さらに、3way handshakeで再送が起きた場合には、データ転送フェーズ開始時の輻輳ウインドウサイズの初期値を1にして、さらなる再送が起きにくいようにしています。
Kernel 3.2
Proportional Rate Reduction for TCP.
(commit)
Proportional Rate Reduction (PRR)という仕組みがKernel 3.2で導入されました。
再送が発生した場合に輻輳ウインドウサイズの半分のサイズをssthreshとして記録し、それをスロースタートの開始値とするFast Recoveryというものが従来からありますが、このFast Recoveryが発生した際に、送信レートを調整し決定するアルゴリズムがPRRになります。
PRRは、再送時におけるウインドウサイズの削減をし過ぎないように、輻輳制御アルゴリズムによって決定されたウインドウサイズにより近づけるようすることで、送信データ量の精度向上につながります。
上記の3つの機能は、実際にmixiのサーバで有効になっています。
以降のKernel
この他にも、Googleが提唱する"Make the Web Faster"の一環で、Kernel 3.5でTCP Early Retransmit、Kernel 3.6でTCP Fast Openが採用されています。少しだけ触れておこうと思います。
Kernel 3.5
TCP Early Retransmit
(commit 1 2 3)
未処理のパケットが3つ以下の場合、Duplicate ACKの閾値(dupthresh)を減らすことで、Fast Retransmitを発生させます。これによりパケットロスからの回復を早め、結果としてレイテンシの改善につながります。特にスケールの大きいWebサーバでは、パフォーマンスに大きな効果をもたらします。
より詳細な仕組みと効果については、以下のGoogleの研究者による論文(section 6)に掲載されています。
Proportional Rate Reduction for TCP
http://research.google.com/pubs/pub37486.html
Kernel 3.6
TCP Fast Open
(commit 1 2 3 4 5 6 7)
同一ホストからの毎回のリクエストごとに通常の3way handshakeをおこなわないことで効率化を図っています。
1回目のhandshake時に、クライアントはサーバをcookieリクエスト、サーバはソースIPアドレスをもとに作成したcookieを発行します。
以後のhandshake時は、クライアントはSYNパケットにcookieとデータをのせてサーバに送信。サーバはクライアントからのACKを待たずにレスポンスを返します。
これによってhandshakeにかかる時間を削減し、パフォーマンス向上を図る仕組みとなっています。これは、クライアントとサーバの両方に実装が必要になります。
参考:
TCP Fast Open: expediting web services
http://lwn.net/Articles/508865/
まとめ
Fedora 17への移行に際して、さまざまなパッケージをビルドしてきました。コンパイラや依存するライブラリによって、いままですんなりビルドできていたものが通らなくなることもあります。発生したエラー内容の調査、gccのサイト等で情報収集等をおこない、必要に応じてコードやspecを修正して対処してきました。
また、今回採用したKernelでは、従来のKernelにはなかった様々な機能が追加されています。mixiのようなWebサービスでは、特にネットワーク周りの変更点に気を配る必要があり、変更内容についても、なるべく理解を深める必要があると考えています。tcpdump+wiresharkによるパケットの流れを確認することも欠かせませんでした。
次回予告
次回は、cobblerによるOSインストールについて紹介したいと思います。お楽しみに!