ISUCON8予選問題においてPerl実装で25万点を突破する方法

この記事はDeNA Advent Calendar 2018の15日目の記事です。遅刻!

こんにちは、@karupaneruraです。今日はDeNAが問題提供したISUCON8予選に関する話です。

ISUCONとは

ISUCONはIiknajini Speed Up CONtestのことで、Webアプリケーションのチューニング技術を競うコンテストです。 競技開始時刻にそれまで秘密にされていたあるアプリケーションがチームごとにサーバーごとまるっと渡されて、それを制限時間内にどこまでチューニングできるかを競います。

サーバーでは参照実装としてある仕様を満たしたアプリケーションが動いていて、その外部仕様を崩さずに(外見上)同様の挙動をするアプリケーションをそれぞれのチームがチューニングしていきます。 そして、ベンチマーカーをチームごとに実行すると仕様や整合性のチェックとパフォーマンス計測が行われて総合的にスコアとして数値化されてランキングが作れるという感じです。

参照実装は各言語の実装が提供されていて、各々の得意な言語を使うことができるほか、フルスクラッチで書き直すことも許されます。ミドルウェアの制限もないので、時間の許す限り本当に各々がベストだと思うソリューションを選択できる競技です。ぼくはWebエンジニアリング技術の総合格闘技のような競技だと思っています。

ISUCON8はどうだったか

そんなISUCONですが2018年は第8回目のISUCON8として開催されました。主催はLINEさん、サーバー提供はGMOさん(ConoHa)、問題提供はカヤックさんとDeNAで行いました。 DeNAは予選問題、カヤックさんは本戦問題という形で役割分担をした形です。

僕は予選問題の作問と模範解答(事前チューニング)を行いました。 解説記事も書いています。(おかげさまで大変好評でした)

ところで、ISUCON8では感想戦という形でチューニングの続きを行ってもらえる試みをやったのですが、その際にこの模範解答のスコアを出していました。

261421点というスコアですが、25万点オーバーを安定して出していました。 作問者なので当然に勘所はわかってるし、問題をブラッシュアップしながら並行して育てたので競技参加者の皆さんと同じ条件下のスコアではないわけですが、ここまではPerlでチューニングできるという事実を示しています。ちなみに競技中の最高スコアは10万点ほどでした。

前置きが長くなりましたが、今回の記事はこのスコアを出す構成はどのようにして作られたのかを語っていきます。

模範解答を作る目的

模範解答は、そのアプリケーションを最適化したときにベンチマーカー側に問題が起きないことの確認、攻略の際にどのボトルネックがどのように現れるのかの確認のために作成しました。(便宜上、模範解答という呼び方をしています。) これがあることで、ベンチマーカー側のレースコーディション問題の発見や問題の調整の意思決定がすばやく行えます。また、 攻略難易度が高すぎる/低すぎるの判断や、問題の調整もしやすくなります。 そのため、模範解答は早めの段階から作成していました。

模範解答を作るときに考えたこと

上記のような目的があるので、競技中に到達し得るスコアより高いスコアを出す実装にする必要があります。 そのため、実装時間は度外視して極限までチューニングすることを考えました。

極限までチューニングするにはどうするか、全体観を得たらそこから逆算して設計を考えていきます。 今回の場合は大きな難関はマイページと予約/キャンセルです。ユーザー毎にレスポンスが変わる部分があるので、ISUCON2の模範解答のアプローチのような、静的ファイルとしてすべてのデータを書き出すといった方法はとりにくいでしょう。なので、動的にレスポンスを返す形で高速化していきました。

動的に返すレスポンスを最適化するには、最終的に返したいデータモデルから逆算して必要なデータを考えていきます。最小限の手数で高速にレスポンスを作るために今回はRedisを使いました。Redisは低レイテンシーでレスポンスを返してくれて、かつメモリ消費量がMySQLと比べて少なく済む点が今回の課題では有利に働きました。

基本的な戦略は以下です:

  • キャッシュできる情報は基本的にキャッシュする
  • レスポンスはRedisのデータだけで基本的に解決できるようにする
  • 更新はRedis上のデータとMySQLを更新する
  • レポートだけデータ量の多さと整合性を顧みてMySQLを使って返す

また、構成としては最終的にアプリケーションのCPUがボトルネックになったため以下の構成を採用しました:

  • nginx - h2o - app / mysql / redis
  • h2o - app
  • h2o - app

nginxをLBとして、h2oでhttpを受けてアプリケーションへはunix domain socketでデータを送ります。

アプリケーションの実装はこちら: webapp/perl/lib/Torb/Web.pm

基本的にはこの方針と解説記事に書いたアプローチを理解できればすべての実装に説明が付きます。 ほか、細かいMySQLやRedisのチューニングやカーネルパラメータのチューニングも当然やっていますが、それらは普通のことしかやってないので今回は特に紹介しません。リポジトリにあるのでよかったら見てください。

実装は難しい部分もあるので実装の分かりにくいポイントを紹介します

GET /initialize

ベンチマーカーからベンチマーク開始時に叩かれるデータ初期化用エンドポイントですが、ここはレギュレーション上一定時間以内の処理が許されています。 そこで、初期データをキャッシュに載せてしまうことで全体の高速化を図ります。

基本的にRedisにpipelineしてクエリを投げまくるだけなのですが、ユーザー毎の最終更新イベントを作るときに課題があります。 ユーザー毎の最終更新イベントは、各ユーザーが最後に予約/キャンセルしたイベントをユニークに5件表示するという機能です。これをRedisでやる場合はSorted Setを使ってユーザーとイベントの組み毎に最終予約/キャンセル時刻を入れておく必要があります。 しかし、これを素直に解決するとユーザー数ぶんのN+1問題になってしまいます。SQL一撃で解決するためには窓関数を使う必要があります。

-- https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L249
SELECT id, user_id, event_id, updated_at FROM (SELECT user_id, event_id, id, updated_at, ROW_NUMBER() OVER (PARTITION BY user_id, event_id ORDER BY updated_at DESC) AS `rank` FROM reservations) a WHERE a.rank = 1 GROUP BY user_id, event_id

これで一発です。MySQLは8.0から窓関数をサポートしているのでこういうことができます。

また、全体売上レポートも一定のデータはキャッシュしておくことができます。終了していないイベントでまだキャンセルされてないまたは終了したイベントの最も古い予約より古い予約は、すべて終了しているイベントかキャンセルされた予約になっているはずです。そのため、そのID以前までキャッシュすることができます。

-- https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L171
SELECT MIN(r.id) FROM reservations r INNER JOIN events e ON r.event_id = e.id WHERE NOT ((e.closed_fg = 0 AND r.canceled_at IS NOT NULL) OR e.closed_fg = 1)

こういう感じで取ってきてCSVをファイルに書き出して使っておくと便利です。 この実装ではPSGIのStreaming Responseのフォーマットでレスポンスを返しているので、それを直接つかってキャッシュファイルを生成することができます。(レスポンスをそのままファイルに書き込みます)

# https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L173
my $rid = $self->dbh->select_one('SELECT MIN(r.id) FROM reservations r INNER JOIN events e ON r.event_id = e.id WHERE NOT ((e.closed_fg = 0 AND r.canceled_at IS NOT NULL) OR e.closed_fg = 1)');
my $res = $self->render_report_csv('SELECT * FROM reservations WHERE id < ? ORDER BY id ASC', $rid);
$res->finalize()->(sub {
    my $header_line = shift;
    open my $fh, '>', "/tmp/report_all_prefix_$rid.csv" or die $!;
    return Plack::Util::inline_object(
        write => sub {
            print {$fh} @_;
        },
        close => sub {
            close $fh or die $!;
        },
    );
});

ちなみに、これらの処理の過程でそこそこのメモリアロケーションが発生します。psgix.harakiri.commit を使ってプロセスごと殺してまっさらにしておくとスッキリです。

GET /admin/api/reports/sales

前の項で触れたとおりキャッシュデータを使える場合はそれをまるっと流しつつ、解説記事でも触れたとおり mysql_use_result を使ってMySQLから受け取ったデータをそのまんま流しましょう。適度にバッファリングしてwriteすると本当はもっとよいです。 なお、KossyはデフォルトでStreaming Responseをサポートしていないので、以下のようなモンキーパッチでお茶を濁しました。(忘れてなければ年末正月あたりの暇な時間にPull-Requestを投げます)

# https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L981-L1001
package Kossy::Response {
    use Scalar::Util qw/reftype/;

    sub new_with_code {
        my ($class, $code) = @_;
        bless \$code, $class;
    }

    BEGIN {
        my $super = \&finalize;
        no warnings qw/redefine/;
        *finalize = sub {
            my $self = shift;
            if (reftype $self eq 'REF') {
                return $$self;
            }

            $self->$super(@_);
        };
    };
};

まとめ

こういうアプローチでISUCON8予選問題の模範解答としては25万点オーバーを安定して出すことができました。 普段あまり使わない機能もときと場合によっては便利に使えるので、たとえば仕事で突然ISUCONになったときのためにも普段から素振りしておけると良いですね。ちなみに僕は初めて使う機能が結構ありました!(窓関数とか) ISUCONを出題するとこんな感じで色々と遊ぶことができるので楽しいです。みなさんもチャンスがあればぜひ出題にチャレンジしてみてください!

また、DeNAでは大規模なトラフィックを捌く仕事もあって楽しいです。よかったらぜひ一緒に働きましょう!

16日目はrexitorgさんです!もう読めます: GAE/Go, Firestoreでマスターデータを管理してみた件

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAにおけるOpenStack運用#3

DeNAのOpenStackインフラ運用を担当している窪田です。 最後にご紹介するのはSDS Cephについてです。採用の背景と、これまで運用していく中で直面したパフォーマンスの問題、それをどのようにシューティングしたのかについてご紹介します。

採用の背景

第一回の小野の記事で、Ceph導入によって実現されたこととして、OpenStackとの連携、ストレージプールの外部化、ライブマイグレーションを取り上げました。実のところこれらのことはCephでなくても近年リリースされている商用ストレージやSDSをうたうプロダクトであれば大抵できることで、これらの実現の他にも重要視していることがありました。 決め手となったのはOSSプロダクトであることです。OSSだとなぜいいのかというと、ソースコードが公開されていることによって、やろうと思えばソフトウェアの振る舞いを詳細に把握することが可能ですし、そうすることでパフォーマンス上のトラブルが起きたときに自力で何がボトルネックとなっているのかを見極め、問題をうやむやにせず納得のいく対応策を練ることができる場合があるからです。これまでDeNAのインフラを運用してきた経験からその重要性を無視できず、中身がブラックボックスなものはできれば避けたいという思いがありました。

構成

本題に入る前に弊社環境の構成について触れておきます。弊社インフラの全てがこの構成で運用しているわけでなく、まだ社内の開発者用のインフラに限定しています。 Cephはブロックストレージ、オブジェクトストレージ、ファイルシステムの三用途に使えますが、弊社ではKVM仮想マシンのストレージとして使うのが目的なのでブロックストレージ機能のみ使っています。 Cephのバージョンは0.94.6のHammerリリースを使っています。最新版ではないのでこれから述べることは最新版では当てはまらない情報も含まれていますがそこはご容赦ください。

個々のサーバのハードウェアとソフトウェアの構成は下図のようになっています。

ceph-blog-node.png

ALL HDDです。ネットワークは物理的に一つのLANに全Ceph nodeがつながっています。 Cephのパフォーマンスをより引き出すには、Ceph nodeのクラスタにそれ専用のサーバを設け、Cephクラスタ内の通信は専用のネットワークを敷く(Cluster Network)など考えられますが、 まずは今あるハードウェア資産を活かして最小限のハードウェアコストで構成し、ボトルネックを見極め、どうしてもハードウェアリソースの増強が必要な場合は追加投資、あるいはCephの導入を見送る選択肢も残しつつ進めていくことにしました。 結果、後述するチューニングを経てこの物理構成を崩さず今に至っています。ですが問題がないわけではありません。ネットワークでいえば輻輳しやすい問題があります。

今はコストを抑えたハードウェア構成を組んでいますが、これで十分と考えているわけでなく、物理的なI/Oの性能が不足しているならSSDを導入することや、後述のfsync/fdatasyncの性能問題のようなCephならではの欠点を補えるようなストレージを導入してマルチバックエンドストレージ構成にするなども視野に入れて検討しています。

ネットワークの輻輳

各Ceph nodeで稼働しているOSDが相互にTCPセッションをはってメッシュ状に通信している上に、Ceph nodeはCompute nodeも兼ねているので、OSDはCephクライアントとなるNova instanceともTCPセッションをはっています。なので各node間の同時通信が発生しやすく、バーストトラフィックによるパケットの廃棄(パケロス)が起きやすい構成です。 パケロスを抑える効果的な手段は、大きなフレームバッファを搭載しているネットワークスイッチを導入する、CephのPublic NetworkとCluster Networkを物理的に分ける、など考えられますが、既存資産を限りなく使い切りたいので、発想を変えてパケロスを抑えるのを諦め、BigSwitchとLinuxのQoS機能を組み合わせ、Nova instanceのトラフィックを優先してユーザ影響を軽減するような仕組みにできないかを検証しています。

パフォーマンスチューニング

上図のようなハードウェア構成でぜひやるべきことが2つあります。

  • ジャーナルとデータ領域を一つの物理ディスクに共存させない
  • tcmallocのキャッシュサイズを拡張する

Cephは一つのOSDに対して二度の書き込みを行います。一度目がジャーナル領域、二度目がデータ領域です。ジャーナルに書き込まれた時点でOSDはクライアントに書き込み完了のレスポンスを返すことができるので、ジャーナルにSSDのような高速なハードウェアを使う方が良いという話を聞きますが、弊社ではSSDは使わず、4つのHDDを下図のように構成しています。

ceph-blog-disk.png

Linuxルートファイルシステムが保存されているディスクは冗長化のためHW RAIDでミラーリング(RAID1)し、同ディスクに全OSDのジャーナルをファイルとして置いた構成です。 ディスクの数にもよりますが、一つのディスクにジャーナルとデータ領域を共存させるよりも、ジャーナルはデータ領域とは物理的に別のディスクを使ったほうがI/Oスループットが向上します。ジャーナルへのI/Oはシーケンシャルwriteなので、ランダムI/O中心のデータ領域と比べてディスクへの負荷が低く、高いIOPSが出やすいです。

ご参考までに、ディスクの負荷がどの程度改善するのかを、データ領域側ディスクのiostatの%utilをグラフ化したもので比較すると、下のように50%前後で推移していたのが15%前後まで下がりました。

ジャーナルと共存した場合 ceph-blog-before.png

ジャーナルと共存しない場合 ceph-blog-after.png

あとこの構成にする上で設定しておくべきこととしてあるのが、ジャーナル側ディスクのLinux I/OスケジューラをDeadlineスケジューラにすることです。その他のI/Oスケジューラだと複数のOSDからくるシーケンシャルwriteを効率良くさばけず、パフォーマンスを維持できないのでDeadlineスケジューラは必須です。

tcmallocのキャッシュサイズを拡張するチューニングについてはCephコミュニティなどからも報告があり、詳細はそちらに譲ります。 tcmallocのキャッシュサイズ拡張は、あらゆるワークロードでパフォーマンスが向上するわけではなさそうですが、弊社環境では劇的な効果がありました。 弊社では前述したように28 Ceph node、56 OSDで約1,500のNova instance(KVM仮想マシン)がCeph上で常時稼働していますが、 Nova instanceが増えるにつれて1 OSDあたりがさばくメッセージ量が増え、tcmallocのキャッシュメモリの獲得、解放にかかるCPU処理が重くなり、 クライアントのI/Oリクエストが数秒から数十秒以上待たされる現象が頻発していたのですが、このチューニングによって秒単位の遅延がほとんど発生しなくなりました。 Cephクライアントを増やしていくとパフォーマンスが劣化するような現象にあたった場合は試してみるとよいでしょう。

ログ分析

パフォーマンスボトルネックの解析で実際に役立ったログの分析方法を一つご紹介します。 CephはI/Oのパフォーマンスが何らかの要因で劣化すると、クライアントからのI/Oリクエストの遅延間隔をログに記録します。slow requestと書かれたログです。弊社では遅延の要因を判断する上でslow requestをよくみています。slow requestのログの末尾にはOSDの何の処理に時間がかかっているのかがマーキングされており、チューニングの判断材料にしています。下記のようなログが書き出されます。

  • "currently no flag points reached"
  • "currently started"
  • "currently waiting for rw locks"
  • "currently waiting for subops from "
  • "currently commit_sent"

この中でも"currently commit_sent"はあまり深刻に受け止める必要のないログです。このログはジャーナルにwrite済みのデータをデータ領域にwriteするのが遅れていることを示しており、言い換えればジャーナルにデータが何秒滞留しているかを示しています。クライアントへのレスポンスが遅延しているわけではなく、ジャーナルのサイズに余裕がある場合はこのログが断片的に出ても問題ないとみなしており、弊社ではほぼ無視しています。

その他のログは重要です。ここでは"currently waiting for subops from "だけ取り上げてみましょう。 OSDのwrite処理はまずPrimary OSDがクライアントからwriteのメッセージを受けてSecondary OSDとTertiary OSDにwriteメッセージを投げます(レプリケーション数3で運用しています)が、投げたメッセージに対してSecondaryかTertiaryのどちらかのレスポンスが遅れるとこのログが出ます。ログのfromの後ろにSecondaryとTertiaryのIDが入るのでどのSecondaryまたはTertiaryかは特定できます。なのでこのログが出たときはログを出しているPrimaryに遅延の原因があるわけでなく、そのOSDとレプリケーションを組んでいるSecondaryかTertiaryのどちらかに原因があるはずです。

他にもslow requestのログに含まれる情報で役に立つものとしてRBD imageのIDがあります。RBD imageはCinder volumeでもあるので、どのCinder volumeのI/Oが遅延しているのかを特定できます。

fsync問題

前述のチューニングである程度パフォーマンスは改善するのですが、それでもなお課題として残っているのがfsync/fdatasyncシステムコールを多用するwrite処理が苦手なことです。そのようなアプリケーションで例をいえばMySQLのトランザクションのコミット処理が当てはまります。 なぜ苦手なのかというと、Cephは複数のI/Oを同時並行処理するようなワークロードが得意ですが、fsyncのようなデータ同期を挟まれてしまうと後続のwriteが待たされてしまいます。図にするとこのようなイメージです。

ceph-blog-write.png

Cephのようにネットワークまたぎで同期レプリケーションまでやるストレージだと、サーバローカルのストレージへのI/Oで完結する場合に比べてどうしてもレイテンシが長くなり、fsyncによるレスポンス待ちの影響が際立ちます。

弊社ではこの問題の根本解決は現状無理だと判断し、クライアントのローカルファイルシステム(ext4やxfs)のバリアオプションを無効にすることでfsyncによるパフォーマンスの劣化を抑えています。バリアオプションを無効化すればfsyncによるデータ同期を回避でき、同時並行writeを維持しやすく、writeレスポンス待ちの影響を軽減できます。ただしバリアオプションの無効化には副作用があり、リスクを許容できるかを検討した上で使う必要があるのでご注意ください。弊社では前述したように社内の開発者向け環境で、最悪、データが一部欠損するようなことがあっても大きな問題にはならないようなものなどに限定して使っています。

まとめ

Cephのパフォーマンスチューニングにフォーカスしてこれまで取り組んできたことをいくつかご紹介しました。冒頭でCephの良さの一つにソースコードが公開されていることをあげましたが、ここでご紹介したパフォーマンス問題の解析でもそれが大いに役立ってくれました。まだまだCephの運用経験が浅く、わかってないことも多いのですが、今後も経験を積むことで理解がどこまでも深まっていくと思います。この記事でCephを使ってみたくなった方が少しでも増えればと思っています。

最後に

DeNAのOpenStackインフラについて三回にわたってご紹介しましたがいかがでしたでしょうか。 宣伝ですが、2017年2月10日(金) に DeNA TechCon 2017 が開催されます。OpenStackに関するセクションも予定しており、ブログでご紹介しきれなかった内容もお話できればと思っているのでぜひご参加ください。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAにおけるOpenStack運用#2

こんにちは。IT基盤部でOpenStackの運用をしています酒井です。
私からは弊社OpenStack環境で使用しているSDNについてご紹介したいと思います。前回の記事で紹介しましたように、弊社ではBigSwitch Networks社のBig Cloud Fabric(以下BCF)を使用しています。本エントリーでは弊社がどのようにBCFをOpenStackとインテグレーションしているか、どのように運用しているのかについて紹介させていただきます。

OpenStackとSDNの導入の狙い

従来はネットワークのconfig変更をする場合、サーバエンジニアからネットワークエンジニアにその作業を「依頼」する形を取っていたのですが、この「依頼」を無くすことが狙いでした。依頼内容としてはスイッチへのVLAN設定やACL設定、LBへのオブジェクト追加など比較的簡単な作業です。しかし、依頼件数が多い時などはネットワークエンジニアがその依頼を作業するまでに数日要することもあり、スピード感に欠ける状況となっていました。それをOpenStackとSDNの導入によって、自動化したり、サーバエンジニアが自ら行うことができるようにすることで作業のスピードを上げることができ、またネットワークエンジニアもより高度なスキルを要する業務に集中できるのではないかと考えました。

構成

OpenStack + BCF 構成パターン

BCFをOpenStackと共に使用する方法としては3パターンあります。一つめはOpenStackのアンダーレイネットワークとしてBCFを使用する方法でこの場合はOpenStackとBCFの連携はありません。二つ目はP-Fabricと呼ばれる方法でOpenStackとBCFでLayer2の情報のみ連携しルーティングは物理ネットワーク上で行います。それに対しP+V FabricというパターンではLayer2, Layer3が連携され、各Compute Node上で分散ルーティングされます。P+V Fabricの方が柔軟なネットワーク構成が可能ではあるのですが、NATが必須となる仕様となっておりNATの運用に手間をかけたくなかったため、弊社ではP-Fabricのパターンを採用しました。 OpenStack_BCF_integration_pattern.png

BCFの構成

BCFはリーフ&スパイン型のスイッチ郡とBCFコントローラから構成されます。BCFコントローラが全スイッチを集中管理しており、設定作業をする際も個別のスイッチにログインする必要はなくBCFコントローラで全ての作業ができます。POD全体を一つの大きなスイッチ(文字通りBIG SWITCH)のように扱うことができる、というのが特徴です。また、BCFコントローラ、スイッチともLinuxが動作しているため、いざとなればサーバ管理者が慣れ親しんだLinuxコマンドでトラブルシューティングする、ということも可能です。弊社ではスイッチにはDELL社の製品を使用し、リーフ - スパイン間は40Gbps、リーフ - サーバ間は10Gbpsで接続しています。 ONE_BIG_SWITCH.png

OpenStackのネットワーク構成

OpenStackのネットワーク構成としては、ネットワークオプションの一つであるプロバイダーネットワークとして構成しています。Controller Nodeでneutron-serverが動作し、各Compute Nodeではneutron-openvswitch-agentが動作します。neutron-serverではbigswitch社のプラグインであるbsnstacklibと弊社内製プラグインのnetworking-bigswitch-l3-peを使用しています。内製プラグインを開発した背景については後述します。

OpenStackとBCFの連携

ここではOpenStackがどのようにBCFと連携をしているのかを具体的に紹介したいと思います。こちらがBCFのコンフィグの例になります。

tenant demo.openstack
  id 1a2cf63967ca4f26ae5356bb2e6c818c
  origination openstack
  !
  logical-router
    route 0.0.0.0/0 next-hop tenant system
    interface segment net_demo
      ip address 10.66.16.1/24
    interface tenant system
  !
  segment net_demo
    id 5310d836-c170-4fda-882c-8a61324d90c6
    origination openstack
    !
    endpoint 0485e7a0-198f-4b88-a877-ca79d3e882bc
      attachment-point interface-group osvdev0013 vlan 300
      ip 10.66.16.2
      mac fa:16:3e:ef:4f:f4
      origination openstack
    !
    member interface-group osvdev0013 vlan 300
      origination openstackdev

OpenStackとBCFのオブジェクトの対応は以下の通りです。

OpenStackBCF
Projecttenant
Networksegment
Portendpoint
Routerlogical-router

前述したようにP-fabricの構成ではLayer 2の情報が連携されます。具体的には、Project, Network, Portの情報がneutron-serverのbsnstacklibプラグインによってBCF Controllerに同期されます。しかし、Layer 3の情報に相当する logical-router のコンフィグは同期されない仕様となっています。そのため、プロジェクト毎にネットワークを作成する場合はlogical-router部分の設定を手動で追加する必要がありましたが、これでは不便なためnetworking-bigswitch-l3-peプラグインを開発しました。BCF ControllerにはAPIが用意されており、このようにpluginからAPIをコールしています。

障害事例

ここでOpenStack + BCF環境で弊社が遭遇した障害の一つとその解決方法についてご紹介しましょう。

障害内容

ある時、新規に作成したインスタンスが通信できないという障害が発生しました。各Compute Node上のneutron-openvswitch-agentのログを調べてみると、以下のようなneutron-serverに対するリクエストが失敗し続けていました。

2016-08-31 03:48:25.294 9269 ERROR neutron.plugins.ml2.drivers.openvswitch.agent.ovsneutronagent [req-57ee640e-5534-4c17-8818-4ec71381ab07 - - - - -] processnetworkports - iteration:1081082 - failure while retrieving port details from server

調査してみると、neutron-sererのbsnstacklibプラグインの不具合が原因となりリクエストがタイムアウトしていました(この不具合については既に修正済みとなっています)。neutron-openvswitch-agentはこのリクエストが失敗すると全ての管理情報を再同期しようとするため(ソースコードだとこの辺り)、さらにneutron-serverに大量のリクエストが集まり処理しきれず再度失敗する、ということを繰り返していました。

復旧方法

まずneutron-serverの負荷を減らしリクエストを捌ききるために、各Compute Node上のneutron-openvswtich-agentを1台ずつ止めていく、というオペレーションをしていきました。すると無事neutron-serverに溜まっていたリクエストがなくなりました。次は止めたneutron-openvswitch-agentを起動していくわけですが、しかし、ここで一つ問題ありました。その時使用していたneutron-openvswitch-agentのバージョン(liberty, 2:7.0.4-0ubuntu1~cloud0)だと、起動時にインスタンスの通信が数秒途切れることが分かっていました。neutronのリポジトリを調べてみるとこれらのパッチ(Cleanup stale OVS flows for physical bridges, Don't disconnect br-int from phys br if connected)で修正されていることが分かりました。これらのパッチを適用した後、止めていたneutron-openvswitch-agentを一つずつ起動しneutron-serverがリクエストを処理し終わるのを待つ、というオペレーションをしていくことで無事復旧することができました。

まとめ

OpenStack環境のSDNに使用しているBCFについて紹介させていただきました。当初の狙い通り、OpenStackとBCFを連携させることで、ネットワークエンジニアへ依頼をすることなく、サーバエンジニアが自らネットワーク構築や設定変更ができる環境を構築することができました。
BCFとのインテグレーションについてご紹介したように、製品自体がユースケースに合わない場合でもAPIを完備していることでユーザ自身がカスタマイズできることはSDN製品の良いところだと思います。またトラブルシューティングについても、OpenStackやそのプラグインはオープンソースなのでいざとなればユーザ自身が調査し問題解決できることもご理解いただけたかと思います。

次回はいよいよSDS編です。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAにおけるOpenStack運用#1

DeNAでシステムインフラを運用しています小野です。
今回から3回に渡って、OpenStackの運用についてご紹介したいと思います。

OpenStackとは

OpenStackとは、いわゆるクラウド環境を構築/運用管理するためのOSS platformです。2010年にRack Space社とNASAのjoint projectとして始まり現在ではOpenStack Foundationが管理しています。

openstack-cloud-software-vertical-web.png

OpenStackは多数のOSSで構成されています。mysqlやrabbitmqなどお馴染みのOSSもbackendに使われていますが、OpenStack固有のOSSが主要コンポーネントになっています。例えばcomputing(vmやcontainer)の管理をするnova、ネットワークを管理するneutron、WebUIを管理するhorizonなどなどです。こちらでどういったコンポーネントがあるかを確認できます。

stackalytics.comというサイトでOpenStackの開発状況のactivityが見れるのですが、最新versionでは150社以上が開発に参加しているようで非常にglobal且つ活発であることがわかります。

半年毎に新versionがリリースされるスケジュールになっており、名称はアルファベット順に頭文字を使うルールになっています。Aから始まり最新versionではMまで進んでおりMitakaと呼ばれています。次期version(もう間もなくリリース予定なのですが)はMの次のNの頭文字を使いNuetonに決まっています。

この半年のリリーススケジュールに合わせ、半期毎にOpenStack summitというカンファレンスが開催されておりOpenStack界では一番のイベントとなっています。ここでは最新knowledgeの共有やuser事例紹介、次期version設計の為のdiscussionがopenに行われます。DeNAでも2014年11月に開催されたパリsummit以降参加するようになりました。

以前は完成度の低さが揶揄されていた時期もあったようですが、現在ではprivated cloudのみならずPublic cloudの基盤としても使われており、今やこの分野では完全なデファクトになっています。日本でも数年前からIT系企業を中心に利用する企業が増えています。

取組みの背景

何が課題だった?

DeNAでは以前からマイクロなレベルの効率化を追求していましたが長らく大きくは変わっていないところがあり、それはネットワーク管理の部分でした。この分野はサーバ管理と比べるとレガシー度が高く、市場環境として商用ハードウェアアプライアンス製品の独壇場になっていたことが主要因でなかなか効率化が進んでいませんでした。サーバ管理がよりオープンに進化しエコシステムが形成されていったのと比べると、違いは歴然です。その為自動化・効率化したくてもし難いという状況が続き、ネットワークのconfig変更が発生すると「依頼」という形で専任の担当者に作業してもらうということが続いていました。

またサーバがハードウェア故障等でお亡くなりになってしまった場合、代替機を構築する必要が発生します。いくらそれなりにprovisioningを自動化していようとも、creativeではない作業に時間を割くのは何となく気が乗らず不毛に感じるもので、こういうのを何とかしたいという考えがありました。

Publicクラウドの充実

一方でここ3〜5年ほどでPublicクラウドの品質/機能も著しく向上し、クラウドfirstが普通になってきました。あらゆることを 最少人数且つ最速でやり易いこういった環境と比べると、オンプレミスの作業効率は見劣っています。それならばPublicクラウドに移行するという考えもあり得るわけですが、弊社の現時点での試算ではコストが割に合いません。CAPEXではなくOPEXで考えてもです。その為オンプレのまま作業効率を上げたいという方向での取組も重要と捉えていました。
※ とはいえ適材適所でPublicクラウドもかなり利用してはいます

高難度技術への取組み

また違う観点として、より広範な人材を育てるべくサーバー管理、ネットワーク管理の融合を進めたいという考えもありました。
どうしてもある程度組織的に大きくなると業務分担が進みます。現在のDeNAでもサーバ管理とネットワーク管理でグループが別れているのですが、以前は違っておりその方がスピード感がありました。
なのでそれに近付けたいという思いと、OpenStackの運用は非常に広範囲な技術知識が要求されますので、個々人にとってもより広範な技術領域の習得に繋がる機会を創出することはプラスであるという考えからも、この両者の管理を融合してきたいという考えを持っていました。

ちなみにDeNAのインフラ部門では以前からアプリケーションレイヤーも含めた全方位的な管理スタイルをとっています。アプリケーションがトラブルを起こすことは極めて多いので、one stopで障害対応等する為にはアプリケーションのソースを理解しカバーすることが重要と考えています。

以前のOpenStackは単にサーバーをサーブするだけの仕組みにしかみえず、その割にバックエンドの構成が複雑なことと、そういう範囲であれば既に内製開発した同機能を提供するtoolを持っていたことから利用メリットを感じませんでした。
それが近年この分野でOpenStackがデファクトの位置を得始めるとOpenStackとのintegrationをうたう製品やソフトウェアが増え始め、ネットワーク管理とのintegrationも現実的になってきました。その為最初に挙げたような課題解決の為の基盤の中心としてOpenStackの導入を本格検討し始めました。
そしてDeNAでも2016年3月よりOpenStackを使った新世代のインフラ基盤の稼働を開始しています。
今年年初の弊社のTechカンファレンスで発表させて頂いた構想で、ほぼこれを実現したものになります。 ※ 但し最後の方にあるOSコンテナ、S(M)R-IOVなどはまだこれからのロードマップになっています。

SDX integration

SDXとは?

DeNAではOpenStackを導入するにあたって、SDN(Software Defined Network)とSDS(Software Defined Storage)を当初から導入しています。Software Defined Xというのは、XをSoftware的に扱うという意味です。ネットワークもストレージも従来はハードウェアアプライアンスが支配的で管理操作のためのAPIというのは非常に貧弱でしたが、そういったものにAPIをしっかり持たせてあらゆる操作をAPI経由で行う≒ソフトウェア的に扱えるようにしよう、というものでよく使われる表現です。

SDN(Software Defined Network)

SDNにはBigSwitch Networks社のBigCloudFabric(以下BCF)という製品を使っています。 bcf_pv0616a.png

BCFの場合各スイッチを管理するcontrollerが存在し、configuration変更等はcontrollerを介して各スイッチに反映されます。
なので何かを変更したい、情報を取得したいという場合controllerに投げればあとはよしなにやってくれるというわけです。
こう出来ると、サーバを起動する前にネットワーク(VRF/VLAN)の作成をしそこに配置する、なんて連携も簡単に出来ます。awsでvpcを作成しsecurity groupでacl管理するような事ができるわけです。

スクリーンショット 2016-09-27 14.37.25.png OpenStack画面上からのネットワーク作成がスイッチ側に伝わる様子
プロジェクトの作成はVRFの作成にあたります

スイッチ上ではSwitch Light OSというLinux(Debian)ベースのネットワークOSが動いておりcontrollerからの指示を受け自身の設定変更などを行っています。このSwitch Light OSもBigSwitch社が提供していますが、スイッチそのものはDELL社の製品を使っています。
このようにハードウェアとOSが分かれて組合せ出来るのはサーバ管理の世界では当たり前ですが、ネットワーク機器においてはこういうことも長らくできなかったわけです。

switch_light_archictecture.png

BCFの機能上の特徴としてはunderlayネットワークをサポートしてるというのがあります。underlayネットワークの説明をするには、その逆のoverlayネットワークの説明をした方がわかりやすいです。

overlayネットワークとは、ネットワークアドレスが重複しても動作できるネットワークのことです。例えば172.16.0.1/24というネットワークをいくつ作っても動作出来るようなネットワークです。Publicクラウドではこれが当たり前に出来ないと困ります。利用者側で自由にアドレス設計出来ないと使い難くてしょうがないですからね。

overlayネットワークはvxlanやgreというプロトコルを使うことで実現します。実は現在世にあるSDN製品は殆どが何故かoverlayを前提にしています。
underlayはその逆で、ネットワークアドレスの重複を認めないネットワークです。従来型のネットワークと言え、オンプレミスの環境ではこちらが普通です。

overlayネットワークは非常に柔軟性は高いのですが、それを実現する為のprotocolが重く性能面でのデメリットがあるのと、セグメントを跨って通信するにはNATが必要になるという制約も発生します。オンプレミス環境ではIP managementを自分達で出来ますのでoverlayの必要性はそもそも低く、余計なプロトコル層が増えることで負荷や障害の難易度をいたずらに上げたくはないというのもあり、DeNAではunderlayネットワークでの運用を優先しBCFを採用しています。

SDS(Software Defined Storage)

そしてSDSとしてはCephを使っています。

Ceph_Logo_Standard_RGB_120411_fa.png

Cephは分散ストレージソフトウェアです。カリフォルニア大学サンタクルーズ校で開発された後2006年にOSS化されました。現在ではRedHat社がメンテナンスをしており商用サポートも行っています。
blockストレージとしてもobjectストレージとしてもfileストレージとしても使える代物なのですが、DeNAでは主にblockストレージとして使っています。awsで言えばEBSにあたる使い方になります。

CephはOpenStackのBlock Strage Interfaceであるcinderに対応してるので、cinderのapi callでcephに自由にボリュームを作成することが出来ます。

DeNAではcephをguestの起動diskとして使っています。こうすることで再構築のような作業をほぼ0にすることが出来ます。 仮にguestが稼働しているhostサーバが死んでもすぐ別のhostサーバで起動すればいいだけなので。

スクリーンショット 2016-09-27 15.33.31.png

cephによるstorage poolからguestのimageを再読込して別のhostサーバで起動する様子
cephはデータを3重化して保持しておりこのstorage pool自体が壊れてしまうことはない想定

また、livemigrationも可能になりハードの不調が疑われる筐体からguestを逃がす事が簡易に出来るなど、運用面でかなりのメリットを得ています。

なお、ハードウェア構成としてはいわゆるハイパーコンバージドな、compute nodeとstorage nodeを一体化した構成にしており、hypervisorはKVMを使っています。

最後に

SDNやSDSで実現してることはPublicクラウドでは当たり前のことですが、それがオンプレの環境でも出来るというのをイメージ頂けたかと思います。
OpenStackを使うならSDN、SDSもしっかり含めインフラ全体をintegrationし、単なるvmをサーブするだけではない環境として高い運用効率を得ることがポイントではないかと思います。

PublicクラウドはこういったIaaSだけではなくPaaSも充実してるものもありますが、OpenStackもPaaS関連のprojectが多々あるので、今後はそこも似てくるかもしれません。

OpenStackはOSSですが、各ベンダーが商用サポートを付けているdistrubusion版が多数存在します。CentOSに対するRedHat Enterpriseのようなものです。
そういうものが存在するというのは、裏を返せば運用していくのはそれなりの難易度が必要ということで、そこそこ骨が折れるのが正直なところです。
次回以降はSDN、SDS周りのより詳細な部分をお伝えしたいと思います。
本格運用を開始してまだ半年程度ではありますが、結構いろいろな格闘がありました。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

『詳解Linuxカーネル』の輪読を始めました

初めまして!
IT基盤部の安武です。

本日は、社内で最近始めた『詳解Linuxカーネル』という書籍の輪読会について紹介します。
この本は文字通り、Linux カーネルの仕組みについて詳細に解説した、1000ページ超の大型本です。

the-linux-kernel-cover.jpg

O'Reilly Japan - 詳解 Linuxカーネル 第3版
Daniel P. Bovet, Marco Cesati 著、高橋 浩和 監訳
2007年2月発行

決して易しい本ではありませんが、カーネルのアーキテクチャを理解しておくことはアプリケーション開発者にとっても、運用担当のエンジニアにとっても、アドバンテージになる技術スキルだと思います。

私は 2〜3 年ほど前にこの本を購入しました。
しかし、ときどきリファレンス的にピンポイントで参照することはあったものの、実質ほぼ「積ん読」状態(*1)になっていました。

「複数人で輪読(*2)したら読み進められるだろうな」と思いついたのが最近のこと。
社内の Slack チャンネルで何気なくつぶやいてみたところ、意外とすぐに反応が返ってきました。

linux-kernel-slack-screenshot.png

その後、複数のチャンネルで声を掛けて回ったところ、IT基盤部以外の部署からも参加者が集まり、合計で9名になりました。 それが、先月下旬のことでした。

第1回の輪読会はその翌週、7/2 19:00〜 に行いました。
その会の後、Twitter で輪読の良さについてつぶやいたところ、更に「参加したい」というメンバーが増え、7/13 現在、発表担当でない者も含めて、合計で15名が輪読会に参加しています。

rindoku-linux-kernel-2nd.jpg

写真は 7/7 に実施した第2回の輪読会の模様です。

輪読の進め方として、最初にシンプルなものを定めました。

  • 担当の人は該当章をよく読んで、かんたんな要約を作っておく
  • 担当外の人もなるべく読んで、1個以上質問を用意しておく

業務外の活動ですし、自分としては読むきっかけが生まれるだけでもありがたかったので、ルールは厳格にせずゆるく進める方針でいます。

要約のフォーマットとしては、一番楽だろうと「Gist など」と最初に提示しておきましたが、2回の輪読会を経て、スライド形式に落ち着きつつあります。その方が図表など交えてビジュアルに説明しやすいからです。

実際に輪読をやってみて、よかったと感じていることを挙げてみます。

  • 集団で取り組むことである種の強制力が生まれ、積ん読状態だった本を読み進めることができた。
  • 輪読会での議論を通して、より理解を深めることができる。

特に後者については、『Linux カーネル2.6解読室』を読んだメンバーや、CPU周りの低レイヤの仕組みに詳しいメンバーもいて、有意義な議論ができているのではないかと思います。

以上、私が発起人になって始めた『詳解Linuxカーネル』輪読会の紹介でした。

ここ最近、社内でどの程度、有志による輪読会が開かれていたかわかりませんが、今回の輪読会を進めながら Slack に #rindoku チャンネルを作り、社内 Wiki に「Rindoku」というスペースを作ってみました。
ので、今後更に別の輪読会が生まれてくるのではないかと期待しています。

1人で読むことと比較して、理解がより深まり、他者から刺激を得られますので、輪読、オススメです。

脚注

(*1) つんどく - ウィクショナリー日本語版
(*2) もし輪読そのものに詳しくないという方には、例えばこちらの記事が参考になると思います。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る