Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Erlang/OTP と ejabberd を活用した Nintendo Switch(TM)向け プッシュ通知システム 「NPNS」の 開発事例

Erlang/OTP と ejabberd を活用した Nintendo Switch(TM)向け プッシュ通知システム 「NPNS」の 開発事例

任天堂 ネットワークシステム部
わたなべ たいよう
渡邉 大洋

私たちは、家庭用ゲーム機 Nintendo Switch (TM) 向けに、プッシュ通知のシステム「Nintendo Push Notification Service (NPNS)」を開発・運用しています。
NPNS には常に1000万台超のデバイスが接続していますが、日々安定してさまざまな通知を送り続けています。

NPNS の全体像およびインフラ面の構成については別の機会にお話ししたことがありますが、今回の Erlang and Elixir Festでは、特に NPNS の常時接続部分の基盤技術として採用している Erlang/OTP、およびその上で動作する OSS である ejabberd に重点を置いて説明します。

具体的には、NPNS に求められる要件に対して、
・Erlang/OTP および ejabberd を選定するに至った理由
・事前の負荷試験/障害試験を受けて行った NPNS ならではのカスタマイズ
・実運用上で直面した課題とその分析・対策の内容
などをお話しします。
NPNS で対応してきた課題の多くはWebシステム開発において普遍的なものですのでErlang/OTP になじみが無い方にも参考になる内容があると考えております。

なお NPNS は現在、企画・開発・運用をすべて社内のメンバーで行っていますので、任天堂のネットワークサービス開発における考え方や実際の開発の雰囲気の一端を皆様に感じとっていただける機会になれば幸いです。

elixirfest

June 01, 2019
Tweet

More Decks by elixirfest

Other Decks in Technology

Transcript

  1. 1
    Erlang/OTP と ejabberd を活⽤した
    Nintendo Switch(TM)向け
    プッシュ通知システム
    「NPNS」の 開発事例
    任天堂 ネットワークシステム部
    渡邉 大洋
    わ た な べ た い よ う

    View Slide

  2. 2
    所属の紹介
    任天堂 ネットワークシステム部
    社内情報システム部門
    自社ゲーム機向けネットワークサービス/
    ゲーム連動サービスの開発・運用
    主力言語は Java, Ruby
    必要に応じて技術選定 (今回の事例)
    私は
    こちら

    View Slide

  3. 3
    発表者の紹介
    渡邉 ⼤洋
    キャリア入社、6年目
    経歴: Web開発 → 組み込み家電 → Web開発(現職)
    任天堂でのお仕事
    ニンテンドーネットワークID サーバ
    NPNS サーバ
    好きなプログラミング言語
    Erlang / Elixir / Ruby

    View Slide

  4. 4
    今⽇お話しすること
    ü NPNSの概要
    常時接続部分の
    ü 技術選定
    ü サービス開始までの開発
    ü サービス開始
    ü サービス開始後の開発
    ü ふりかえり

    View Slide

  5. 5
    今⽇お話ししないこと
    ü インフラやクラウドの話
    (興味がある⽅は AWS Summit Tokyo 2018 の資料を)

    View Slide

  6. 6
    NPNSの概要

    View Slide

  7. 7
    Nintendo Switch
    世界 3474 万台 (2019年3⽉末時点)

    View Slide

  8. 8
    NPNS (Nintendo Push Notification Service)
    ひとことで
    Switch向けプッシュ通知システム(同カテゴリ: APNS, FCM)
    API + 常時接続 の構成
    常時接続=プッシュ通知では必須、同時接続数が激増
    採⽤技術
    API部分: Ruby on Rails
    常時接続部分: Erlang/OTP + ejabberd
    開発体制
    要件定義・開発・運用まで社内で対応、数人の小規模チーム

    View Slide

  9. 9
    NPNSの要件
    スケーラビリティ 1億接続に備える
    送信対象 プレイ中本体、およびスリープ中の本体
    遅延 ~数秒
    通知の種類 (次のページで紹介)
    サービス分析 大量のログを出力・収集

    View Slide

  10. 10
    通知の種類
    個別指定通知
    トピック指定通知 (PubSub)
    ユーザに
    見てほしい情報
    本体システムに
    届けたい情報
    みんなに
    配りたい情報

    View Slide

  11. 11
    ユーザに
    見てほしい情報
    • フレンドのオンライン通知
    • ゲームサーバのメンテナンス通知
    プレイ中のみ
    本体システムに
    届けたい情報
    個別指定通知
    トピック指定通知 (PubSub)
    みんなに
    配りたい情報
    通知の種類

    View Slide

  12. 12
    個別指定通知
    トピック指定通知 (PubSub)
    みんなに
    配りたい情報
    通知の種類
    ユーザに
    見てほしい情報
    • フレンドのオンライン通知
    • ゲームサーバのメンテナンス通知
    プレイ中のみ
    本体システムに
    届けたい情報
    • PC版Nintendo eShopで購入したソフトのDL開始
    • 『Nintendo みまもり Switch』アプリでの設定変更
    接続中は常に
    (一時保存も)

    View Slide

  13. 13
    通知の種類
    個別指定通知
    トピック指定通知 (PubSub)
    ユーザに
    見てほしい情報
    • フレンドのオンライン通知
    • ゲームサーバのメンテナンス通知
    プレイ中のみ
    本体システムに
    届けたい情報
    • PC版Nintendo eShopで購入したソフトのDL開始
    • 『Nintendo みまもり Switch』アプリでの設定変更
    接続中は常に
    (一時保存も)
    みんなに
    配りたい情報
    • 本体更新/パッチ配信のおしらせ
    • ゲームニュース
    接続中は常に

    毎ログイン時
    (Retain方式)

    View Slide

  14. 14
    通知の種類
    個別指定通知
    トピック指定通知 (PubSub)
    ユーザに
    見てほしい情報
    • フレンドのオンライン通知
    • ゲームサーバのメンテナンス通知
    プレイ中のみ
    本体システムに
    届けたい情報
    • PC版Nintendo eShopで購入したソフトのDL開始
    • 『Nintendo みまもり Switch』アプリでの設定変更
    接続中は常に
    (一時保存も)
    みんなに
    配りたい情報
    • 本体更新/パッチ配信のおしらせ
    • ゲームニュース
    接続中は常に

    毎ログイン時
    (Retain方式)

    View Slide

  15. 15
    XMPP Cluster
    XMPP Cluster
    全体の構成
    XMPP Cluster
    Provider API
    Consumer API
    通知送信者
    常時接続
    API
    XMPP
    HTTP
    HTTP
    NPNS

    View Slide

  16. 16
    XMPP Cluster
    XMPP Cluster
    通知の流れ(個別&トピック)
    XMPP Cluster
    Provider API
    Consumer API
    通知送信者
    常時接続
    API
    XMPP
    HTTP
    NPNS

    View Slide

  17. 17
    XMPPクラスタ分割の理由
    スケーラビリティ
    クラスタ追加でシンプルにスケール
    負荷試験もクラスタ単位で
    安定性
    ノード数を抑える
    障害の局所化

    View Slide

  18. 18
    常時接続部分の
    技術選定

    View Slide

  19. 19
    XMPP 選定理由
    TCPの常時接続は経験が無い
    いきなりこの規模で大丈夫か?
    常時接続プロトコルを扱うOSS/SaaSの活用を検討
    XMPPが適切では?
    機能: 個別指定とトピック指定、両方の通知に対応
    安定性: 歴史が有り規格の変化が少ない
    拡張性: XEP (XMPPの拡張プロトコル) が多数
    実績: 大規模な同時接続の事例が豊富

    View Slide

  20. 20
    ejabberd 選定理由
    評価指標
    ライセンス/提供機能/開発の活発度/
    導入実績/サポート
    注⽬ポイント: クラスタ化の⽅式
    Erlang: 処理系がクラスタ対応
    新規⾔語への対応は︖
    書籍での技術習得
    チーム内での勉強会

    View Slide

  21. 21
    ejabberdの特徴
    XMPP サーバソフトウェア
    Erlang + C言語拡張(NIF,driver)
    XMPP Core + 多数の XEP (XMPP拡張規格) に対応
    コンフィグによるモジュラビリティ
    機能の選択
    ストレージミドルウェアの選択
    クラスタ化に対応
    フルメッシュ構造
    ノード間で通知を直接送信

    View Slide

  22. 22
    常時接続部分の
    サービス開始までの開発

    View Slide

  23. 23
    ejabberdクラスタの構造
    Redis MySQL
    ユーザ情報
    トピック情報
    セッション情報
    SQS
    inner ejabberd
    inner ejabberd
    outer ejabberd
    outer ejabberd
    outer ejabberd
    outer ejabberd
    クラスタの内側/外側でノードの役割を分けて、効率化を狙う
    内側 inner ejabberd 通知をejabberdクラスタに⼊れる役割 CPU バウンド (通知量に⽐例)
    外側 outer ejabberd 通知をSwitchに渡す役割 メモリバウンド(接続数に⽐例)

    View Slide

  24. 24
    機能
    ejabberd の機能を使って、短期間で実現
    使った機能
    個別指定通知: Message
    トピック指定通知: PubSub (XEP-0060)
    一時保存: Offline Message (XEP-0013)
    稼働状況で送り分ける: Presence
    (使っていない機能)
    フレンドグラフ: Roster
    クラスタ間の転送: Server-to-Server (XEP-0288)

    View Slide

  25. 25
    性能
    求める性能
    [キャパシティ] 1ノードに大量につなぎたい
    接続キャパシティ → 50万~100万ぐらい
    [スループット] ワーストケースでもシステムが破綻しない
    一斉ログイン → 30分くらい
    一斉配信 → 軽負荷で
    一斉切断 → すぐ再接続できるように
    [遅延] 大量のログを低遅延で書きたい
    ログ出力 → 他の処理に影響を与えないように

    View Slide

  26. 26
    負荷試験結果
    項⽬ 期待する性能 当初の測定値
    接続
    キャパシティ
    最低50万台接続
    (r3.largeを想定、メモリ 15.25GiB)
    30万
    ⼀⻫ログイン 50万台が30分で接続完了 = 277接続/秒 150接続/秒
    ⼀⻫配信 軽負荷で、50万台に30分以内に配信 負荷:⼤
    ⼀⻫切断 切断の処理は数分以内に完了 30分
    ログ出⼒ 軽負荷、遅延は数分以内 2時間
    ejabberdは汎⽤性の⾼い構造
    → NPNSの機能や構成に特化して性能改善を

    View Slide

  27. 27
    改善の流れ
    負荷試験でボトルネックを特定しつつ改善
    現象/課題 ⇒ 原因 ⇒ 対策 ⇒ 効果 のサイクル
    「問題はひとつずつ解決していこう」

    View Slide

  28. 28
    接続キャパシティ [BEFORE]
    [現象] ⼤量接続時、Erlang VM のメモリ消費が多い
    1接続あたりの消費メモリを減らして、接続数を増やしたい
    ejabberd は hibernate を使っているが、それでもまだ多い
    hibernate = プロセスのメモリを切り詰める ≒ 布団圧縮袋
    system 領域が processes 領域の6倍程度大きい
    調査: instrument:memory_status(types) で内訳を集計
    [原因] C拡張の中で確保しているメモリだった
    XMLパーザ (expat)
    TLS (OpenSSL)

    View Slide

  29. 29
    接続キャパシティ [AFTER]
    [対策] C拡張部分の使い⽅を分析&改造
    XMLパーザ (expat)
    à hibernate 前に一旦使用終了して解放
    TLS (OpenSSL)
    à OpenSSLパラメータ最小化、不要バッファの解放
    [効果] メモリ削減 & 接続数増加
    1接続あたり 40% に削減
    接続可能上限で表すと 30万 → 75万に増加

    View Slide

  30. 30
    ⼀⻫ログイン [BEFORE]
    [現象] 処理詰まりが発⽣
    (赤矢印の箇所)
    1. ソケットの accept
    2. トピックアイテムの配信
    調査: etop (Erlang top)
    [原因] プロセスボトルネック
    1つのプロセスが大量の
    リクエストを受ける構造
    大量アクセスに不向き
    おう
    listen

    listener
    receiver accept

    c2s
    conn pool
    Redis
    MySQL
    conn pool
    process
    topic配信
    (クライアントの数だけ生成)
    conn pool
    process
    conn pool
    outer ejabberd
    軽量
    プロセス
    ソケット
    メッセージ
    プロセス起動

    View Slide

  31. 31
    ⼀⻫ログイン [AFTER]
    [対策] workerを都度⽣成
    1. ソケットの accept
    à launch worker
    2. トピックアイテムの配信
    à topic配信 worker
    [効果] 詰まり解消
    ログインレートも向上
    150 → 300 接続/秒
    listen

    listener
    receiver accept

    c2s
    conn pool
    Redis
    MySQL
    (クライアントの数だけ生成)
    launch
    worker
    topic配信
    worker
    conn pool
    process
    conn pool
    process
    conn pool
    outer ejabberd

    View Slide

  32. 32
    ⼀⻫配信 [BEFORE]
    [現象] 配信時に⼤量通信&⾼負荷
    通信① MySQL → inner
    (購読者一覧)×1
    通信② Redis → inner
    (セッション情報)×購読者
    通信③ inner → outer
    (通知)×接続済みの購読者
    調査: メトリクスとErlangトレース
    [原因] 個別配信と同じ送り⽅
    inner 側で送信先を選別
    inner ejabberd
    inner ejabberd
    outer ejabberd
    outer ejabberd
    outer ejabberd
    outer ejabberd
    Redis MySQL
    ユーザ情報
    セッション情報



    SQS

    View Slide

  33. 33
    ⼀⻫配信 [AFTER]
    [対策] outer 側で選別
    XMPPログイン時に、
    c2sプロセス辞書に「購読情報」保存
    配信時、inneràouterにばらまき
    その後outer内のプロセスを全走査
    (processes/0, process_info/2)
    通信① inner→outer (通知)×outer数
    [効果] 負荷/通信量減
    スケール性も向上
    (outer増加で配信レートも増加)
    inner ejabberd
    inner ejabberd
    outer ejabberd
    outer ejabberd
    outer ejabberd
    outer ejabberd
    Redis MySQL
    ユーザ情報
    セッション情報

    c2s
    process
    {jid, user1}
    {sub,[1,2,3]}
    c2s
    process
    {jid, user42}
    {sub,[2,3,5]}
    プロセス辞書

    View Slide

  34. 34
    ⼀⻫切断 [BEFORE]
    [現象] セッション処理が多い
    切断数がそもそも多い
    (最悪値は、全接続数が一斉に切断)
    切断時のセッション操作が多い
    Redis上ではHASHに保存
    HASHを取得してから削除
    調査: Erlangトレース
    [原因] XMPPはマルチログイン
    同一IDで複数デバイスから接続可能
    NPNSは 1 ID = 1 セッションなのに…
    Redis
    c2s
    1. 自分が最後か?
    2. 自IDの全セッションを取得 (HASH)
    3. 自分のセッションだけ削除 (HASH)
    【XMPP切断時のセッション操作フロー】

    View Slide

  35. 35
    ⼀⻫切断 [AFTER]
    [対策] 切断時は「なにもしない」
    シングルログイン構造に変更
    他のデバイスを気にしなくてよい
    Redis上ではTEXTに
    セッションにEXPIREを設定
    ログイン中は定期的にRefresh
    切断後、いつかは自動で消える
    [効果] 切断処理の短縮と軽量化
    30分以上 → 1分
    Redis
    c2s
    (なにもしない)
    【XMPP切断時のセッション操作フロー】

    View Slide

  36. 36
    ログ出⼒ [BEFORE]
    [課題] メトリクス⽤にログを⼤量に出⼒したい
    データ間引きはしたくない/一時的な遅延は許容する
    通常の logger とは別系統にしたい
    [対策] 専⽤ログサーバプロセスを作成
    ログのBINARY文字列を受け取り、ファイルに書き込むだけ
    OTPのgen_serverビヘイビアを使用
    file:open/2 で raw, delayed_write を使う
    c2s
    ``
    log_server log file
    ログBINARY を cast
    file:write/2
    c2s
    ``
    c2s
    message
    queue

    View Slide

  37. 37
    ログ出⼒ [BEFORE-2]
    [現象] 処理時間が⾮線形に増加
    1万ログ → 1秒未満
    50万ログ → 2時間!
    その間、1コアを100%使用
    調査: トレース、プロファイル
    [原因] reduction処理が重い︖
    erlang:bump_reductions/1→37%
    gen_server:try_dispatch/3→62%
    log_serverがファイル出力をや
    めると、処理遅延は起きない
    00:00
    00:15
    00:30
    00:45
    01:00
    01:15
    01:30
    01:45
    02:00
    1万 5万 10万 15万 20万 25万 30万 35万 40万 45万 50万
    ログ処理にかかる時間

    View Slide

  38. 38
    ログ出⼒ [AFTER]
    [対策] ダムをつくる
    ダムはほぼ何もしない
    後段のメッセージキュー
    長を監視、放流を制御
    process_info/2 を利用
    それ以外はsleep
    [効果] 処理時間を⼤幅に短縮
    50万ログの処理時間が
    2時間 → 30秒
    他に良い方法あればアドバイスを!
    c2s ダム log file
    ログBINARY
    を cast
    file:write/2
    log_server
    ログBINARY
    を cast
    c2
    c2s
    message
    queue
    message
    queue
    ここは数⼗万たまっ
    ても遅くならない
    ここは最⼤1万ま
    でにおさえる

    View Slide

  39. 39
    ここまでのまとめ
    項⽬ 期待する性能 BEFORE AFTER
    接続
    キャパシティ
    最低50万台接続
    (r3.largeを想定、約16GiB)
    30万 75万
    ⼀⻫ログイン 50万台が30分で接続完了 = 277接続/秒 150接続/秒 300接続/秒
    ⼀⻫配信 軽負荷で、50万台に30分以内に配信 負荷:⼤ 負荷:⼩
    ⼀⻫切断 切断の処理は数分以内に完了 30分 1分
    ログ出⼒ 軽負荷、遅延は数分以内 2時間 30秒
    ⼗分な性能を確保できた(と思われる)

    View Slide

  40. 40
    サービス開始
    =予期せぬ課題との出会い

    View Slide

  41. 41
    Redis⾼負荷事件
    メトリクスでRedisの負荷が⾼い!?
    想定の5倍以上、負荷試験では見たことが無い
    このペースだと、2日後には Redis の負荷に余裕がなくなる
    Redisはスケールアップが難しい
    原因は︖
    おそらく、特定タイミングの切断で、メッセージループが発生
    「一斉切断」の改造が不十分だった?

    View Slide

  42. 42
    (メッセージループ)
    [BEFORE]
    Redis
    c2s
    1. 自分が最後か?
    2. 自IDの全セッションを取得 (HASH)
    3. 自分のセッションだけ削除(HASH)
    4. だれかいないか?
    5. 残通知を転送
    この部分を
    ⾒落としていた
    未処理の通知が残っている場合

    View Slide

  43. 43
    (メッセージループ)
    [BEFORE] [AFTER]
    Redis
    c2s
    5. 残通知を転送
    ここで
    メッセージ
    ループが
    発⽣

    ここを⽌めれば
    解決か︖
    (なにもしない)
    6.だれかいないか? → 自分
    7. 残通知を転送
    ...
    4. だれかいないか? → 自分
    8.だれかいないか? → 自分
    9. 残通知を転送
    未処理の通知が残っている場合
    Redis
    c2s
    1. 自分が最後か?
    2. 自IDの全セッションを取得 (HASH)
    3. 自分のセッションだけ削除(HASH)
    4. だれかいないか?
    5. 残通知を転送
    この部分を
    ⾒落としていた
    未処理の通知が残っている場合

    View Slide

  44. 44
    Redis⾼負荷事件
    早期対応をどのように︖
    修正コードを書いたが、本当にこの問題か断定できない
    常時接続サービスではお試しデプロイが難しい
    本番環境でそのまま試せたらよいのに…

    View Slide

  45. 45
    Redis⾼負荷事件 [解決編]
    Erlang には hot code deploy 機能がある︕
    無停止で本番環境1台だけに適用(カナリアリリース)
    ただし手作業 (code:soft_purge/1, code:load_file/1)
    Erlang リモートシェルで接続して更新を実施
    手順チェック×3人 → 予行演習×2 → 実施
    Redis アクセス回数が激減、修正効果を確認
    その後、通常の手順で全クラスタにデプロイ
    早期解決︕
    ユーザ影響無しで、余裕のあるうちに解決できた

    View Slide

  46. 46
    サービス開始後の開発
    常時接続部分の

    View Slide

  47. 47
    サービス開始後も継続的に改善
    すでに機能/性能要件は満たしているが、
    メトリクスやアラートなどから改善の余地を探す
    「トラブルを防ぐのが私の仕事」

    View Slide

  48. 48
    トピック配信の負荷 [BEFORE]
    [現象]トピック配信時の outer ejabberd の負荷が
    処理のわりに⾼い(ように思える)
    全力で送るとCPUがMAXにはりついてしまうので、シーケン
    シャルに送信し、合間に timer:sleep/1 を入れている
    sleepの値とCPU利用率が相関しない
    例: 20ms と 50ms でほぼ同じ負荷
    不要にCPUパワーを使っているのでは?
    調査: Erlang関連の情報収集
    0%
    5%
    10%
    15%
    20%
    25%
    30%
    35%
    40%
    45%
    50%
    0 10 20 30 40 50
    トピック配信時の負荷
    sleep 値 [ms]
    CPU利用率

    View Slide

  49. 49
    トピック配信の負荷 [AFTER]
    [原因] VMスケジューラのビジーウェイト状態
    「負荷の低いスケジューラスレッドがすぐスリープ状態にならないように、
    Erlangスケジューラの扱うスレッドはしばらくビジーウェイト状態にな
    ります」 -- “Erlang in Anger” 日本語版, 5.1.2 CPU, p.37
    ※この日本語訳は、昨年の Erlang & Elixir Fest を契機にプロジェクト
    化されたとのこと。ありがとうございます。
    [対策] VM パラメータを設定
    +sbwt medium à very_short
    [効果] outer ejabberd の負荷減少
    CPU使用率が 30% → 21%
    ↓ medium: 30%
    ↑ very_short: 21%
    時刻
    CPU利用率

    View Slide

  50. 50
    セッションアクセス削減 [BEFORE]
    [課題] ログイン時のセッション
    問合せを最適化したい
    必須アクセスは2回のはず
    既存セッション問合せ
    新規セッション書き込み
    実際は数回~十数回程度発生
    調査: Erlangトレース
    [原因] topic配信worker
    workerから通知を送るたびに
    セッションを問い合わせていた
    listen

    listener
    receiver accept

    c2s
    conn pool
    Redis
    MySQL
    (クライアントの数だけ生成)
    launch
    worker
    topic配信
    worker
    outer ejabberd
    conn pool
    process
    conn pool
    process
    conn pool

    View Slide

  51. 51
    セッションアクセス削減 [AFTER]
    [対策] pidを直接指定して送信
    送信先の pid (プロセスID)を
    workerプロセス辞書に保存
    プロセス辞書を見て、
    セッションを引かずにすぐ送信
    [効果] 最適化完了
    Redisコマンド発行数: 1/2に
    Redis CPU利用率: 4/5に
    listen

    listener
    receiver accept

    c2s
    conn pool
    Redis
    MySQL
    (クライアントの数だけ生成)
    launch
    worker
    topic配信
    worker
    {c2s_pid, <0.x.y>}
    プロセス辞書
    outer ejabberd
    conn pool
    process
    conn pool
    process
    conn pool

    View Slide

  52. 52
    性能改善のまとめ
    まずは負荷試験
    満足行く性能ならそこで終了
    ボトルネックを探す
    メモリ不足 → C拡張に要注意
    メッセージキュー詰まり → プロセスボトルネック
    負荷 (reduction) が高い → profile 実施 (eprof, fprof)
    改善策
    並列性を上げる (worker作成、負荷を “外側” に移す)
    処理量を減らす
    メッセージキューを積み過ぎない (前段にダムを作る)

    View Slide

  53. 53
    Switch 接続数増加への対応
    インフラ増強
    クラスタ数を増やす
    クラスタ内のノード数を増やす
    アプリ改善
    性能向上 = 1台あたりの処理能力増 = 台数を削減可能
    台数削減=障害発生数も削減
    インフラコストと運用コストを削減

    View Slide

  54. 54
    サービス規模
    1000万+ 同時接続
    約20億 通/⽇
    クラスタ停止は一度も発生していない

    View Slide

  55. 55
    outer 1ノードあたりの処理
    InstanceType: r5.large (CPU 2コア、メモリ 16GiB)
    接続数
    最大50万、通常は10~20万程度(AZ障害への冗長対応)
    個別指定通知
    200通/秒
    トピック指定通知
    100〜400通/秒
    ※CPU負荷に配慮して低めに抑えている

    View Slide

  56. 56
    振り返り
    常時接続部分の

    View Slide

  57. 57
    要件のふりかえり
    スケーラビリティ 1億接続に備える
    ... クラスタ分割+性能改善で実現
    送信対象 プレイ中本体、およびスリープ中の本体
    ... Presenceで送り分け
    遅延 ~数秒(正常時)、~数分(異常時)
    ... 元々の高い並列性で、混雑時も低遅延
    通知の種類 個別通知/トピック通知
    ... XMPP の機能で実現
    サービス分析 大量のログを出力・収集
    ... 専用ログサーバ + ダムで実現

    View Slide

  58. 58
    Erlangとejabberdを採⽤してみて
    機能
    個別指定とトピック指定を短期間で実現できた
    クラスタ化とその維持が簡単、運用の負担も小さい(ほぼ無い)
    性能
    NPNSの機能/構成に特化して改造、期待する性能を実現
    リモートシェルとトレース機能で、動作理解や状況把握が容易
    シングルスレッド性能は高くない → 重い処理はC言語拡張
    安定性
    Erlang VMのクラッシュは本番環境では無し

    View Slide

  59. 59
    特筆したい点
    メモリ効率が⾮常に良い
    hibernateと多少の効率化で、1接続あたり十数KiB
    GCで回収したメモリをOSに返却してくれる
    mmapでの取得/解放と、世代別コピーGCの合わせ技
    OSのメモリだけを監視すればよい
    リモートシェル (remsh) が万能ツール
    本番環境の状況をダイレクトに把握・改変
    困ったら remsh、(やろうと思えば)ライブパッチも可能

    View Slide

  60. 60
    Erlang/OTP
    特徴
    安定したネットワークサーバを書きやすい
    supervisor、軽量プロセス、パターンマッチ、hibernate
    文法がシンプルで、暗黙の知識が少ない
    動的トレースのおかげで、既存コードの把握がしやすい
    コード密度が高く、少量の変更で大きな改造ができる
    現状と期待
    誕生から30年以上たっても活発な開発が続いている
    今後もネットワークサーバ開発の選択肢の一つとなってほしい

    View Slide

  61. 61
    ご静聴ありがとうございました

    View Slide

  62. 62

    View Slide

  63. 63
    告知
    キャリア採⽤募集してます
    Webエンジニア
    ネットワークインフラエンジニア
    ネットワークサービスシステムエンジニア
    サーバセキュリティエンジニア
    AWS Summit Osaka でも発表有り
    『Nintendo Switch Onlineを支えるサーバーシステム開発』
    Ruby on Rails で大規模をさばくシステムの開発

    View Slide