DMM.comの、一番深くておもしろいトコロ。

AWSからオンプレミスに移行したWebRTC配信サーバのその後

AWSからオンプレミスに移行したWebRTC配信サーバのその後

  • このエントリーをはてなブックマークに追加

この記事は、DMMグループAdvent Calendar 2021の21日目の記事です。
DMM.com ITインフラ本部SRE部の松浦が担当します。

はじめに

この記事は2021年7月27日の弊社イベントで発表したWebRTC配信システムのAWS→オンプレミス移設プロジェクトの後日談です。また、発表では軽く流したCentOSバージョンアップやオンプレミス運用のコストなど、気になっている方が多いと思われる部分の補足いたします。

発表時点では「近日切り替え予定」としていましたが、2021年9月中旬から下旬にかけて切り替えを実施しました。切り替えはトラブルもなく、無事「ほぼ」全台オンプレミス環境へ切り替わりました。(「ほぼ」全台の理由はあとで説明します)

発表の内容は以下からご覧いただけます。よろしければあわせてご覧ください。

WebRTC配信システムをAWSからオンプレミスに切り替えている話

DMMはAWS“から”オンプレミス“に”切り替える サーバーとネットワークのコストから見直す適切な環境選び

配信システム前史

発表でも述べましたが、現行システムリリース当初AWSを利用した経緯を振り返ります。 WebRTCベース配信システムを導入する前は、Flashで配信していました。配信システム一式はオンプレミス環境にあり、Flash終息にあわせてAWSへ切り替えました。

この時AWSを選択したのは、WebRTC+HTML5という未知の技術への不確実性の回避が目的です。ざっとあげただけでも下記の不確実要素があります。

  • 使うコーデックは?
  • どんな配信ソフトウェアを使う?
  • どのスペックのサーバを使えばいい?
  • トラフィックはどれくらい発生する?
  • サーバは何台必要?

オンプレミス環境では、欲しいスペックのサーバを必ずしもすぐに入手できるとは限りません。一方EC2なら高スペックなサーバをすぐに何十台も用意できます。リリース当初はEC2を使うことでトラフィック想定やキャパシティプランニングを回避し、利用ソフトウェアやコーデックの選定などにエンジニアリソースを配分できました。もちろんAWS以外のクラウドやホスティングサービスを使うこともできたのですが、エンジニアが使い慣れている点でAWSを選択しました。

最終的にオンプレミス環境でまかなえましたが、これは結果論でしかありません。サーバが思うように調達できなくて、Flash終息に間に合わなくなる最悪の事態を回避するにはEC2を使うのが最適だったと言えます。

もっとも、AWSのデータ転送コストもEC2料金表ページに「1 か月間のデータ転送量が 500 TB を超える場合は、お問い合わせください。」とあるように、非常にトラフィックが多い場合は交渉の余地があります。ですが、DMMではデータセンター回線ですでに帯域消費量のリスクをとっています。もし帯域のうちわずかしか利用できなかったら、回線費用が無駄になります。なので、なるべく帯域は使い切れるようにするべきです。(当然輻輳が起きない範囲ですが)もしAWSと交渉したら安くなるかもしれませんが、オンプレミス回線を余らせるリスクに加えて、AWSでも500TBに達しないリスクが発生します。同じようなリスクを複数の業者に対してとるのは危険ですし、非効率です。帯域消費のリスクはオンプレミス側に寄せて、AWSではオンプレミス回線が輻輳するといった別のリスク軽減のために使うのが有効でしょう。

切り替えの結果

切り替え後、驚くほど何も起きていません。特に障害等もありません。お客様からすると何も変わらず、いつの間にかサーバが入れ替わっています。見えないところで細かいトラブルはあるものの大きな障害には至っていません。

最終的な構成はこのようにしました。ご覧いただくとわかるように、臨時用途の一部サーバは引き続きAWS上で稼働させています。これが「ほぼ」全台切り替えとした理由です。AWSで動かしていても通信はグローバルIPアドレス経由になっています。

f:id:dmmadcale2021:20211201170802p:plain
通信構成

完全に移行しなかった理由

理由はコストです。臨時用途サーバはEC2の課金体系の方が適していました。EC2はstopped状態のインスタンスは課金されません。一方オンプレミスのサーバは社内の課金ルールの都合上、サーバを削除するまでコストがかかります。臨時サーバは必要な時だけ動かしているので、EC2の方が安価に起動できます。

さらに臨時サーバは通常用途サーバと比べてデータ送信量が少ないため、データ転送コストも無視できるレベルでした。

このように、あえて全部切り替えないことで、当初の想定よりもシステムコストを月額数十万円抑えることができました。

コスト削減効果

AWS請求の推移を見ると、切り替えの効果は一目瞭然です。多くを占めていたデータ送信コストとEC2インスタンスコストが、グラフではよく見えないレベルまで下がりました。

f:id:dmmadcale2021:20211201170333p:plain
AWSコストの推移

AWSコストとオンプレミスコストを合計したグラフはこちらです。合計してもコストが大きく下がっていることがわかります。ネットワークコストも想定通り95%下がっています。下記グラフの最上部にある申し訳程度の線がネットワークコストです。

f:id:dmmadcale2021:20211201170446p:plain
AWS+DCコスト

切り替え後、サーバのCPU利用率が半分に

このシステムは基本的にCPUバウンドなので、CPU利用率を主要なメトリクスとしています。新サーバーではCPU利用率、ロードアベレージいずれも以前の半分程度に抑えられています。色が薄くてわかりづらいのですが、下の方に外れている線が新サーバーの負荷です。EC2時代はc5.12xlarge(48vCPU)、オンプレミスは40vCPU構成なのでvCPUが減っています。それにも関わらず利用率が下がっているので、システムの性能が向上しているといえます。

f:id:dmmadcale2021:20211201170846p:plain
CPU&LA

負荷が下がった理由はいくつか考えられます。一つはソフトウェアのバージョンを新しくしたことです。配信ソフトにパフォーマンス改善の修正が入っているため、性能が向上しているでしょう。

他にもOSをCentOS8→Ubuntu20.04に切り替えています。カーネルのバージョンが新しくなったことにより、性能が向上している可能性があります。同時にいくつも変えてしまったので、残念ながらどれが要因なのかはわかりません。同時に変えてしまったのは開発スケジュールの都合です。本来なら同時に変えず、どの変更がどのくらいパフォーマンスに影響を与えたか調べるべきでした。

オンプレミス化によって失われるもの

もちろんなんでもオンプレミス化すれば良いわけではありません。オンプレミス化することにより、これまでにはなかった課題や考慮すべきことも増えます。

ハードウェアなどのメンテナンスが必要になる

EC2ならハイパーバイザー以下のレイヤーは全てAWSにお任せです。オンプレミス化することで、ファシリティや回線、ハードウェアなども管理することになります。なので一からオンプレミス基盤を作るなら相当な時間と費用がかかります。現在100%クラウド上にあるならオンプレミス移行には相当な覚悟が必要ですし、あまりお勧めできません。

しかしDMMでは元々大規模なオンプレミスシステムを保有しているため、設備や回線など確保されています。上の方で出てきたオンプレミスコストには地代や電力などをはじめ、エンジニアの工数など運用にかかるコストも含まれています。

配信システムが増えても、費用やオペレーション工数はほとんど変わりません。例えば回線なら帯域は400Gbpsを超える帯域がすでにあります。この配信システムも合計5Gbps程度のトラフィックを発生させますが、たかだか1%です。

さらにDMMにはVMwareプライベートクラウド基盤を運用するチームがいて、基盤の構築やメンテナンスなども全て自社で行なっています。スケールメリットと内製化により、パブリッククラウドとも遜色ないコストで運用できるようになっています。

急激なスケールアップがしづらい

自社でサーバを持つ場合、常にある程度余剰サーバを抱える必要があります。在庫以上のサーバが必要になってもすぐには準備できません。一方でパブリッククラウドなら(たまに失敗しますが)ボタンを押して数分で調達が完了します。今のところオンプレミス環境に十分なリソースがあるので問題はありませんが、将来的に不足する可能性もあります。

ですが足りなければEC2(あるいはGCEなど)で構築するだけなので、全く心配していません。もちろんネットワーク費用はオンプレミス環境以上にかかりますが、一時的ならさほど影響はありません。

常時使うサーバはオンプレミスで、緊急で確保したければパブリッククラウドを利用するのが有効です。

第3の選択肢としてのベアメタルホスティング

DMMはデータセンターを保有し、大容量回線を用意しています。しかしこれくらい都合よく環境を揃えられることは少ないと思われます。かといってデータセンター探しから始めるのも、コストや工数がかさむので現実的ではありません。それ以上にこの採用難の中、構築運用するエンジニアを探すのは極めて大変です。

しかし世の中には転送コストが安価なサービスだったり、転送したデータ量ではなく契約帯域で課金されるベアメタルホスティングなどもいくつか存在します。初期は一般的なパブリッククラウドで、サービスが成長してきたらこれらへの導入をあらかじめ想定しておくといいかと思います。

システムの監視

配信システムをどのように監視しているかご紹介します。

監視の分掌

システム監視は大きく分けて、OS上の監視とハイパーバイザー以下の監視に分かれます。EC2の場合、ハイパーバイザー以下の監視はAWSの責任ですが、オンプレミスでは全て自分たちで面倒を見る必要があります。DMMではSRE部や開発エンジニアはOS以上のレイヤーを、基盤運用チームがハイパーバイザー以下の面倒をみています。

さらにDMMでは24時間365日監視チームがおり、深夜や休日でも障害時にはすぐ対応できる体制になっています。もしハードウェア障害など発生したら、彼らが一次対応を行ってくれます。

このようにSREや開発エンジニアの立場からは、実はEC2と同じようにハイパーバイザー以下を意識する必要がない運用です。ハードウェアも24時間有人監視体制なので、パブリッククラウドと近い運用体制といえます。

OS監視

OS監視はDatadogと一部NewRelicを利用しています。ボトルネックになりがちなCPUの使用率やディスク消費量を監視しています。他にサーバ証明書の更新忘れを防ぐために有効期限監視を行なっています。

仕組み上ロードバランサーが使えないので、負荷分散や障害ノードのサービスアウトはアプリのロジックで行っています。新たに配信を始めるタイミングで、CPU利用率が規定以下のサーバの中から接続数が最小のものを選択し、配信者に接続URIを払い出します。接続数やCPU利用率監視は、各サーバ上で動いている監視プログラムで行なっています。監視プログラムは定期的に配信ソフトの統計APIから接続数を取得し、CPU利用率、現在時刻と合わせて管理APIに送信します。一定時間API実行がなかったサーバが障害が発生しているとみなして、新たな配信が行われないようにします。

f:id:dmmadcale2021:20211201174201p:plain
配信サーバの監視

統計APIは接続数以外にも通信品質やパケット再送などのデータが取得可能なのですが、現状あまり有効に監視できておりません。現在Elasticsearch(OpenSearch)に送りKibanaで下記グラフのように可視化するべく統計情報取得プログラムを開発中です。統計APIのレスポンスは頻繁に変わるので、なかなか開発が大変です。

f:id:dmmadcale2021:20211201174342p:plain
パケット再送要求数のグラフ


おまけ:CentOS7→CentOS8への移行

発表の中でサーバをCentOS7から8にアップグレードしたことをさらっと流しました。せっかくなのでここで紹介しておきたいと思います。

そもそもの経緯

ピーク時間帯にCPU system利用率が激しくスパイクする現象に悩まさせていました。同時にネットワーク転送量が急激に増えているならまだ理解できるのですが、ネットワーク転送量とは無関係に上昇します。

f:id:dmmadcale2021:20211202191321p:plain
問題が起きているサーバのDatadogグラフ

そこで負荷が高い時間帯と低い時間帯で下記のstraceコマンドを実行し、システムコールを比較してみました。

### straceは自動停止しないので、timeoutコマンドで10秒で止めている
# timeout 10 strace -f -p <process id> -c

CPU利用率が低い時間帯

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 22.95   73.763203         568    129826           sendto
 19.97   64.177529        1590     40340      6600 futex
 19.26   61.884056         615    100547           madvise
 17.46   56.105082         561     99927           epoll_ctl
  8.92   28.659279         548     52283      2524 recvfrom

CPU利用率が高い時間帯

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 22.74   85.079455         611    139174           madvise
 21.85   81.771792         568    143779           sendto
 17.01   63.627401         565    112467           epoll_ctl
 16.51   61.778021        1575     39219      6242 futex
  8.75   32.745196         554     59088      3196 recvfrom

配信サーバなのでパケット送受信のsendto, recvfromが高いのは当然として、負荷が高い時間帯はmadviseコールが増加しています。manによるとmadviseは「メモリー利用に関するアドバイスを与える」システムコールで、アドバイスによっていくつか引数が存在します。

man madvise

そこでさらにmadviseコールの引数を下記のstraceコマンドで調べます。

# strace -f -p <process id> -e trace=madvise

するとこのようなMADV_DONTNEEDコールが多発していることが判明しました。

[pid  xxxx] madvise(0x7f95xxxxxxxx, xxxxx, MADV_DONTNEED <unfinished ...>

MADV_DONTNEEDについてman madviseを実行すると、わかるようなわからない説明が出てきます。どうやらカーネルに対して、「この領域を解放してもよい」と伝える命令のようです。

MADV_DONTNEED
              Do not expect access in the near future.  (For the  time  being,
              the  application is finished with the given range, so the kernel
              can free resources associated with it.)  Subsequent accesses  of
              pages  in  this  range  will  succeed, but will result either in
              reloading of the memory contents from the underlying mapped file
              (see  mmap(2)) or zero-fill-on-demand pages for mappings without
              an underlying file.

MADV_DONTNEEDが多いとどうして遅くなるのか、perfコマンドでパフォーマンスデータを取得してみます。perf出力をそのまま見ても何もわからないので、FlameGraphsで可視化します。

## システム全体のログを取得する
## perfコマンドは自動で止まらないので、timeoutコマンドで30秒経過後に終了させる
# timeout 30 perf record -ag
# chown centos:centos perf.data
 
## proc fsからカーネルシンボルを取得して、適当なファイルに書き出しておく。root権限がないとアドレスが全て0になるので注意
# cat /proc/kallsyms > kallsyms
 
## テキストファイルで出力する
## 負荷が高いので、nice値を下げている
$ nice -n 19 perf script --kallsyms=kallsyms > server001.txt
 
## stackcollapseとflamegraphを利用して、SVG図を作成する(とても時間がかかる)
$ stackcollapse-perf.pl server001.txt | flamegraph.pl > server001.svg

Flame Graphsで可視化すると、native_flush_tlb(図のピンク色)が目立っています。

f:id:dmmadcale2021:20211202191753p:plain
flamegraph

この処理が足を引っ張っているようです。

ByteDanceがMADV_DONTNEEDについて記事を書いています。中国語は分からないので、翻訳ツールを使って読んでみました。とても便利な時代です。これによれば、MADV_DONTNEED実行時にはCPU間でTLBを同期させるためにプロセッサ間割り込みが発生します。これがTLB Shootdownと呼ばれる処理です。プロセッサ間割り込みは仮想サーバ上やCPU数が多いシステムでは処理にボトルネックになりがちということが知られています。

深入理解 Linux 内核--jemalloc 引起的 TLB shootdown 及优化

ではなぜこの処理が多いのか。このソフトはErlangで作られており、Erlangで同じような現象に直面している方がいました。 それによれば原因はErlang/OTP 22でメモリ管理処理が変更されたためでした。この変更でpooled carrierと呼ばれるErlangのメモリーブロックに対して、使っていない領域にMADV_FREEコールを実行するようになりました。ただMADV_FREEは比較的新しいコールで、古いカーネルには実装されていません。実装されていない環境ではMADV_DONTNEEDにフォールバックします。

Chasing a Performance Regression with Erlang/OTP 22

Mark free blocks in pooled carriers as unused #2046

    #ifdef MADV_FREE
        /* This is preferred as it doesn't necessarily free the pages right
         * away, which is a bit faster than MADV_DONTNEED. */
        madvise(ptr, size, MADV_FREE);
    #else
        madvise(ptr, size, MADV_DONTNEED);
    #endif

CentOS7のカーネル(3.10.0)はMADV_FREEに対応していません。このためMADV_DONTNEEDが大量に実行されパフォーマンスが劣化していました。コードのコメントには"which is a bit faster than MADV_DONTNEED"と書かれていますが、a bitではないようです。 一方CentOS8(4.18.0)はMADV_FREEが実装されています。そこでCentOS8にバージョンアップしたところ、CPUのスパイク現象は見事に無くなりました。

スパイクが無くなった分サーバを減らせたので、月額数百万円のコスト削減効果がありました。

グラフの緑の線がCentOS8サーバ、青と黄色がCentOS7サーバのCPU利用率です。

f:id:dmmadcale2021:20211202194405p:plain
CentOS7vs8

気づかれた方もいらっしゃるかもしれませんが、このスクリーンショットを作成した数時間後にCentOS8のEOLが発表されました。このソフトもCentOS8対応が打ち切られることになり、Ubuntu20.04への再切り替えというイベントが発生することになりました。

実はこの問題は開発元でも全く認識してないものでした。先述の通りCPU数が多くならないと影響が出づらい処理なので、相当大規模なサーバでないと発生しません。 このシステムではc5.12xlarge(48vCPU)を使ってますが、開発元ではc5n.4xlarge(16vCPU)でテストしていたそうなので、動きも変わってくるでしょう。

この現象を開発元に報告した結果、CentOS7は非推奨扱いになりました。

ここまで読んでいただいてわかるように、配信サーバを運用するためにはカーネルまで調べたりすることもあります。しかし、その効果は大きく成功すれば百万円単位でコスト削減効果があります。 クラウド選択の文脈で"Undifferentiated Heavy Lifting"なる言葉が出てきます。差別化できない重労働という意味で、サーバの構築やらキャパシティプランニングなど、クラウドならやらなくていい(こともある)要素のことです。数台しかなかったり、サービスのコアでないサーバだったら、まさに"Undifferentiated Heavy Lifting"です。しかしこのシステムはサービスのコアで、多くのコストがかかるコンポーネントなので、人的コストをかけるだけの価値はあると考えています。


今後の目標

配信サーバの切り替えが終わり、現在は以下のような計画を考えています。

IPv6対応

DMMデータセンターのネットワークはIPv6に対応しており、動画配信など一部サービスで利用しています。DMM動画での比較検証によれば、IPv6対応によってスループット改善などが見られているので、このシステムでも導入できないかと考えています。

DMM動画、オンプレミスでIPv6経路での配信に対応

モニタリング強化

監視のところで書きましたが、ログや統計情報を有効活用できていないのが現状です。分析基盤を整備し可視化できれば、障害調査なども効率的に実施できます。

AWSマイグレーション

誤植ではありません。もちろん配信サーバではなくDBなどです。このシステムのうちDBなどはオンプレミス環境にあります。このためスケールアップさせたくなっても簡単には増やせません。ECSやRDSを使ってスケールアップダウンを容易にしたいと考えています。

配信サーバ以外の運用といった"Undifferentiated Heavy Lifting"を積極的にマネージド化して、配信システムに十分な人的コストをかけられるようにしたいと考えています。