LINEのインフラの舞台裏

三枝慶寛氏:みなさん、こんにちは。このセッションでは、LINEのインフラについてお話ししていきたいと思います。

私は三枝慶寛と申します。よろしくお願いします。

2005年に、当時のNHN Japan、今のLINE株式会社に入社をしました。それ以来、10年以上にわたってネットワークやデータセンターといったインフラに携わっています。

そして現在は、去年からLINEのプライベートクラウドを開発する部門に移って、インフラ的な課題をプラットフォームのレベルで解決する役割を担っています。

まずは、LINEのインフラのスコープについてお話ししたいと思います。

このレイヤーの構造についてご説明します。LINEでは、データセンターからOSまでのレイヤーを、インフラとして扱っています。そして、データベース、ストレージといったデータストア系のコンポーネントも、インフラ部門で運用・管理しています。

長年私がネットワークに携わってきて、現在インフラプラットフォームに携わっていますので、主にこの2つの部分に焦点を絞ってお話ししていきたいと思います。

LINEがリリースされてから、すでに7年以上が経っています。当然ですが、今までさまざまな課題に直面してきました。サービスの成長に伴って、インフラの規模そのものが拡大しました。そして、それを支えるエンジニアの規模・拠点数も増えました。

まず、現在どの程度の規模感かというと、ユーザー向けのトラフィックで1Tbps以上あります。データセンターにあるサーバの数は3万台を超えていて、エンジニアの数はグローバルで約2,300名、その拠点は国内外10拠点以上にまたがっています。

こういった規模の拡大によって引き起こされた課題を分類すると大きく3つあります。

まず1つ目、規模の拡大によってキャパシティ的な問題が引き起こされました。2つ目、従来のアーキテクチャでは解決が難しい、あるいは、アーキテクチャが古くなったがために、キャパシティの管理上、非常に効率が悪くなりました。そして3つ目が、運用コストの増加という課題です。それぞれの課題について、1つずつ見ていきたいと思います。

ネットワークのキャパシティ不足

まず、ネットワークの課題です。先ほどユーザー向けのトラフィックのお話をしましたが、実際のところ、トラックの規模としては、データセンターの中で発生するサーバ間通信のほうが圧倒的に多いです。ですので、ネットワークを設計するときには「このデータセンター間のサーバ間通信をいかにして捌くのか?」というところに主眼を置いて設計をしています。

従来の設計では、1つのネットワークの単位でサーバを3,200台収容できるようにしていました。サーバは1台あたり10Gのネットワークのインターフェースを持っています。ネットワークのPOD全体では1万6,000Gのキャパシティがあります。それを「2N」と呼ばれる2台1セットで冗長を組む構成で、インフラを提供していました。

はじめに起きた問題が、ネットワークのボトルネックという課題です。サーバ3,200台に対してネットワークのキャパシティが1万6,000Gですので、10Gを使い切るサーバがたくさんあるような状況だと、構造的にネットワークにボトルネックが発生してしまいます。

そうすると通信が不安定になってしまいますので、そうならないように、「トラフィックをたくさん出すサーバ同士はできるだけネットワーク的に近い位置に置く」という運用を続けていました。これがサーバ数の拡大によって、非常につらくなってきたという問題がまず1つ。

そしてもう1つが、この2Nという冗長方式の効率の悪化です。1万6,000Gのネットワークキャパシティを提供するためには、3万2,000Gのネットワークのインフラを構築する必要があります。これはNの規模が大きくなればなるほど、どんどん効率が悪化してしまいます。

ですので、このボトルネックの課題と、2Nという冗長方式のコストパフォーマンスの悪化が課題になっていました。

コネクション数にまつわる問題

次がコネクション数の問題です。LINEが主に使われている日本・台湾・タイ・インドネシアの4ヶ国で、月間アクティブユーザーの合計は1億6,500万人います。

そのデイリーのアクティブユーザー比率は70パーセント以上ありますので、このLINEのインフラは、常にユーザーの何千万というTCPコネクションを同時に取り扱う必要があります。

そのTCPコネクションは、ロードバランサを経由して、Messaging Gatewayと呼ばれるサーバに振り分けられます。1つのTCPコネクションは同じサーバに振り分けないと通信が成立しませんので、ロードバランサは、それを実現するためにセッションテーブルと呼ばれるものを管理しています。このセッションテーブルの管理をどうスケールさせるかという部分が、ロードバランサの運用の肝になっています。

どういうことかというと、このセッションテーブルのサイズはロードバランサの各ノードのメモリのサイズに依存します。メモリのサイズは有限ですので、このセッションテーブルのキャパシティも当然有限になります。仮にセッションテーブルが溢れてしまうと、そこに該当する通信は成立しませんので、LINEのユーザーで一部サービスが使えないような状況が発生してしまいます。

それを回避するために、ロードバランサを複数並べて、キャパシティの確保をしています。

ロードバランシングの方式として、DSRと呼ばれる方式を採用しています。これはどういった方式かというと、クライアントからサーバに向かう通信だけロードバランサを経由させて、サーバからクライアントに戻す通信はロードバランサを経由させない。そんな構成になります。

通常、「クライアントからサーバ方向のトラフィック」のほうが「サーバから戻るトラフィック」に比べて容量が小さいです。ですので、その小さなトラフィックに合わせてロードバランサのキャパシティを設計できる。そういうメリットがあります。

ただ、やはりデメリットもあって、先ほどご説明したセッションテーブルに関するきめ細かやなコントロールができにくい方式でもあります。

どういったときに問題になるかというと、例えば、LINEのユーザーを多数抱える通信事業者側でなにかしら大きな障害があった場合、あるいはLINEのユーザー自体に問題があった場合に、LINEのクライアントがサーバと通信しようとして、TCPレベルのリトライがたくさん発生します。

そういったリトライの通信一つ一つがロードバランサ上でセッションテーブルとして乗っかってきてしまって、その状況が続くと、しまいにはロードバランサのセッションテーブルが溢れてしまうということが起こりやすい、という弱点があります。

このセッションテーブルのスケールの課題と、ロードバランサの2Nと呼ばれる冗長方式を採用していましたので、コストパフォーマンスの悪化が課題になっていました。

開発者数の増加にどう対応するか?

最後の課題が、開発者数とその拠点の増加に関する課題です。LINEには、各インフラのレイヤー内にそのレイヤーを専門で見るインフラのチームがいます。

開発者がアプリケーションをプロダクション環境にデプロイしたいときには、その各インフラチームに依頼を出すかたちで対応していました。

この方法は、開発者の数が少なく拠点も多くなかった時には回していけましたが、現在2,000名以上の開発者がいます。その状態でこれをやろうとすると、全部の開発者が、「じゃあどのインフラチームにどんな依頼をどのように出せば、自分が欲しいインフラリソースが手に入るのか?」ということを理解して学習しなければいけせん。その学習コストが非常に負担になっていました。

そして、2,000名という規模から依頼が来ますので、それを運用する依頼を処理する人たちの負担が日々増加していきました。ですので、この双方の負担に対する改善が必要に迫られていました。

いかにして課題を解決したか?

今まで課題を説明してきましたが、これから、それに対してどんなアプローチで解決をしてきたのかをお話ししたいと思います。その前に、私たちが課題解決する上で原則としている考え方がありますので、それをご紹介したいと思います。

まず1つ目は、課題を根本的に解決をするということです。小手先での対応ではなくて、必要であればアーキテクチャレベルでの対応・改善というようなことをしようとしています。

それともう1つが、運用の負荷を下げられるものであることです。たとえどんなに大きなキャパシティを持つインフラが構築できて、そのインフラが非常に効率のよい仕組みであったとしても、その運用が難しい非常に手間がかかるものであったら、積極的には採用したくないですよね。

ですので、課題を根本的に解決をして、かつ、運用の負荷がトータルで減らせるということを課題解決の原則としています。

これらの課題を解決するために、3つの基本的な要件をまず定めました。

1つ目は、今後キャパシティの問題で悩まされることがないように、圧倒的な大きなパフォーマンスを提供することです。次が、そのキャパシティに対して、2Nというような方式ではなくて、N+1でスケールアウトが可能なものを実現することを要件にしました。3つ目が、運用のコストを下げるというものです。

実際ネットワークの課題に対しては、まず、ボトルネックのないネットワークを作ろうと考えました。すべてのサーバが10Gのトラフィックを使い切ったとしても、ネットワーク上では原理的に詰まる箇所がないようなネットワークです。

これを実現するためには、当然ですが、アーキテクチャレベルでの改善が必要でした。

基本となるアーキテクチャについては、他社の大規模データセンターネットワークの構築事例でも採用されていたCLOS Networkでいこう、ということはすぐに決まりました。

このCLOS Networkというアーキテクチャは、すべてのネットワークのレイヤーでN+1でスケールアウトが可能な構成になります。運用の負荷を下げるために、このCLOS Networkをホワイトボックススイッチを使って実現できないかということを考えました。

なぜホワイトボックススイッチかというと、 LinuxベースのOSで動作させることができるので、それまでのスイッチの管理のやり方をサーバを管理するような手法に切り替えることができます。LINEではすでに数万台という規模でサーバを管理させる手法が確立されていましたので、その恩恵を受けることができるだろうと考えました。

そういった経緯で、ホワイトボックススイッチを使ったCLOS Networkの検討が始まりました。最後までネットワークのデザインの部分で悩んだのが、このサーバを収容しているToRのスイッチと、このサーバの間のネットワークの構成でした。

LINEではToRのスイッチを二重化しています。従来の方法だと、L2でサーバとToRを接続するという方法でしたが、もう1つのオプションを考えました。サーバとToRのスイッチの間をL3で接続しようというオプションですね。

この2つのオプションの決定的な差は、メンテナンスのしやすさになります。L2接続の場合には、当然L2のテクノロジーですので、ToRのスイッチをグレースフルに切り替えることができません。必ず切り替える際にはパケットロスが発生します。

その一方で、L3の接続にした場合には、ルーティングの技術を使いますので、スイッチ側の操作だけで、ToRスイッチ間のグレースフルなフェイルオーバーが実現できます。

やはりメンテナンスのしやすさは非常に魅力でしたので、このL3で接続するパターンで検討しようということになりました。ただ、そのパターンでいった場合には、サーバ側のネットワークのコンフィギュレーションを変更する必要があります。

この変更によってアプリケーションに影響を与えてはいけませんので、開発者に協力をしてもらって、主要なアプリケーションでテストをしたあとに、このL3の接続でホワイトボックススイッチを使ったCLOS Networkの採用を決めました。

(スライドを指して)この絵は、実際にあるサイトで動作をしているCLOS Networkの構成になります。1つのPODあたりサーバ7,200台を収容できて、そのサーバ7,200台の中にすべて10Gのトラフィックを出したとしても、ボトルネックのないネットワークになっています。このPODが2つあって、全部で948台のホワイトボックススイッチで構成されています。

CLOS Networkであれば、これぐらいの規模のインフラであっても、十分スケールするものが作れることがおわかりいただけるかなと思います。

ロードバランサの課題を改善する

ロードバランサの課題についても、アーキテクチャレベルの改善を試みました。

基本的なアーキテクチャとしては、L3、L4、L7のMulti-Tierな構成にしようと考えました。このL7というのは、先ほど説明したMessaging Gatewayが来る位置になります。

各レイヤーでN+1でスケールアウトが可能なものを実現しようと考えました。L3の部分に関しては、ECMPやAnycastといったルーティングの技術を使えば、簡単にN+1で分散が可能です。

やはり悩んだのはこのL4の部分で、従来どおりステートフルな方式で進めると、仮にL4ノード1つあたりの障害とかメンテナンスをするといった場合に、ユーザー影響を少なくするためには、全部のL4ノードが同じセッション情報を持っていないとユーザーに影響が出てしまいます。

ということは、すべてのL4ノードが全部の情報を持たなければいけないことになってしまいます。これはセッションテーブルが有限であることを考えると、まったく現実的な方法ではありません。ですので、セッションテーブルを管理するような方式ではなくて、ステートレスな方式で改善ができないかということを考え始めました。

1つのTCPフローを判別するには、Source IPアドレスの情報、Destination IPアドレスの情報、Source ポート番号、Destination ポート番号、そしてプロトコル番号という5つのデータがあれば、1つのTCPフローを判別できます。

ですので、この5つのデータを使ってハッシュを計算してあげて、そのハッシュ値に基づいて振り分けるサーバを決めれば、同じTCPフローは同じサーバに振り分けられるということが実現できるだろうと考えました。そして、L4ノードが全部同じハッシュアルゴリズムで動作をしていれば、L4ノード1つあたりの障害とかメンテナンスのユーザー影響を少なくすることができます。

L4ノード1つあたりのパフォーマンスについて

残る課題は、L4ノード1つあたりのパフォーマンスでした。圧倒的に大きなパフォーマンスを提供するという要件でしたので、L4ノード1つあたりに求められるパフォーマンス要件は「秒間700万パケットを処理できる能力」としました。

このL4ノードは、コストの面とか運用性を考えて、 Linuxサーバ上で動くソフトウェアとして実装を進めていました。通常のLinuxカーネルのネットワークスタックだと、その秒間700万パケットというのはオーバーヘッドが大きすぎて実現が難しいことがわかりました。

そこで、「じゃあパケットの高速処理のためにどうすればいいか?」ということを悩み始めたところ、ちょうどタイミングよくLinuxカーネルのほうにXDPと呼ばれる機能が追加になりました。

XDPは、通常のLinux関連のネットワークスタックにパケットが渡る前に、NICのドライバーのレベルで直接パケットを高速処理できる機能になります。これを使えば、求めるパフォーマンス要件を達成できるのではないかと考えて、XDPを使ったテストをはじめました。

そうしたところ、秒間700万パケットという処理能力が難なく達成できることがわかって、このXDPを使ったソフトウェアベースのステートレスなロードバランサというものを開発しました。

実際このロードバランサは、今年の8月にプロダクション環境に適用済みで、午前中のセッションで聞かれた方もいらっしゃるかもしれませんが、そこでお話のあったLINEの広告プラットフォームも、実際にこのロードバランサ上で動作しています。

開発者・拠点数の増加にどう対応するか?

最後の課題が、開発者とその拠点数の増加の課題でした。この課題は、LINEのインフラを利用する側の利用コストと、そのインフラを運用する側の運用コストが課題でした。

これらを解決するために、「インフラプラットフォーム」というレイヤーを追加して、そこでインフラに対する自動化をしてあげて。さらに、開発者にはインフラを必要以上に意識させない仕組みとして、API・WebUIを経由してインフラをオペレーションするというようなアプローチで試みました。端的に言えば、LINEのインフラのプライベートクラウド化ということになると思います。

このプライベートクラウドは「Verda」という社内プロダクト名で開発をしました。このVerdaについては、去年のLINE DEVELOPER DAYでお話ししていますので、もし詳細を知りたい方がいらっしゃいましたら、去年のスライドビデオ等をご覧いただければと思います。

今回、「このVerdaが利用者に必要以上にインフラを意識させない仕組みをどう実現しているのか?」といった事例をご紹介したいと思います。

VMを複数デプロイして、それに対してロードバランサのVIPを割り当てるような場合を考えてみたいと思います。

VMを複数デプロイするときに、そのVMが1つのfailure domain上に配置されてしまっては意味がありません。複数のVMを複数のfailure domainに分散して配置をする必要があります。

従来ではこのオペレーションを、インフラの運用者・開発者から依頼をもらって、運用者はその依頼の内容を見て「じゃあ、これをこういうふうに配置しよう」ということを決めていました。

そういったオペレーションをVerdaを通じて開発者にそのままやってもらうとなったら、単なるオペレーションコストのつけ替えでしかありませんので、実際にはこれはVerda上のプラットフォームのロジックとして実装されています。ですので、開発者はまったく意識をする必要はなく、適切に配置されたインフラリソースを手に入れることができるような仕組みになっています。

ロードバランサも同様です。VIPを複数のロードバランサのクラスタに分散して配置をすれば、ロードバランサに対する可用性が高まります。これも意識してオペレーションするものではなくて、勝手にVerdaというプラットフォーム側でやってくれる、そういうような仕組みになります。

ネットワークの設定についてもまったく同じで、従来の古いアーキテクチャのネットワークと新しいアーキテクチャのネットワークでは、当然ながらネットワークの設定が異なります。

じゃあこれを利用する側が「古いネットワークに配置されたから、こういうネットワーク設定をしよう」とやっていては、非常に利用コストの高いインフラになってしまいますので、まったく意識することなくVMのネットワーク設定がされるようになっています。

必要以上にインフラを意識してほしくはないんですけれども、意識してほしいところはきっちり意識させるというような設計ポリシーにもなっています。

外部にサービスを公開をする場合がこれにあたります。ロードバランサのVIPを単純にグローバルIP、パプリックIPでもって設定をするだけでは、外部にサービスが公開されません。これは利用者側で「このサービスは外部に公開するんです」というような依頼を出してもらって、しかるべき承認フローを通過したのちに、はじめて外部にサービスが公開されます。

これはなぜこうしてるかというと、意図せずに内部向けのサービスをオペレーションミスによって外部に公開してしまうことを防ぐ狙いがあります。なので、必要以上に意識させない仕組みは実装しているんですけれども、意識させるところはきちんと意識してもらうというような設計ポリシーでこのプラットフォームは開発しました。

インフラの改善において苦労したこと

ここまで、私たちLINEのインフラへの取り組み事例についてご紹介をしました。こうやってお話だけしていると、非常にトントン拍子に課題解決をしてきたかのように聞こえたかもしれまん。ただ、実際にはぜんぜんそうではなくて、むしろ苦労の連続でした。

やはり一番苦労したのが、課題解決に伴う変化の部分です。今までのやり方をそのままにして、課題だけを解決するということはできません。

ネットワークの運用の負荷を下げるためにホワイトボックススイッチを使ったネットワークを導入した場合は、それまでのネットワークの運用の仕方を変えて、サーバを管理するような手法に変えるという変化が伴いました。

インフラのプラットフォームレベルでの自動化も、従来のタスクの部分的な自動化ではなくて、全体を一貫したポリシーを持ったソフトウェアのシステムとして再構築する必要がありました。

いずれのケースについても、それまでの取り組みをずっと続けていれば、その延長線上で達成できるというものではありません。非常に大きな変化が伴います。そういった変化に対してトップダウンで頭ごなしに物事を進めるようなやり方もあるかもしれませんが、そういったやり方は短期的にはうまくいっても、いずれその反動が来て反発を招いてしまう。

実際にこれらのプロジェクトを進める過程でも、そういったことを何回も経験しました。ですので、こういった大きな変化を進めるときには、ゴールを明確にして、それに対してみんなに共感してもらって、一つ一つ物事をていねいに進めていくことが大事であることを痛感しました。

もう1つは時間ですね。こういった大きな改善、アーキテクチャレベルの改善を進める上では、ライフサイクルに合わせて導入をすることが非常に重要になってきます。とくにインフラはハードウェアも絡みますので、そのライフサイクルが非常に長いです。短くても3年。長いと、データセンターなんかだと10年15年は珍しくありません。

ですので、一度その改善のタイミングを逃すと、次に実施ができるタイミングは、はるか先になってしまいます。なので、そのタイミングを逃さないというのは非常に重要です。

ふだんから、新しい技術・新しいアプローチを適用するために、その要素技術の研究であるとか必要な人材の育成・採用、こういった一朝一夕ではいかないことがたくさんあります。課題解決のタイミングを逃さないために、そういった下地を作っていく努力がやっぱり非常に大事であることを、これらのプロジェクトを通じて学びました。

現在取り組んでいること

最後に、現在LINEで取り組んでいる事例をいくつかご紹介して、終わりたいと思います。

1つ目の事例は、ネットワークの事例です。LINEのほとんどのサービスは、今まではシングルテナント・シングルネットワークの上で実現・サービスを提供するようなものがほとんどでした。ただ、今日のセッションでもお話のあったとおり、最近はFintech領域に力を入れています。そうなると、今までとは違う要件がインフラに求められるようになりました。

現在は、そういった要件に対して、都度インフラを構築して提供するというようなかたちをとっています。ただ、どうしてもこの方式だと時間がかかりますし、インフラエンジニアのリソースがたくさん取られてしまいます。その課題を解決するために、1つのインフラの上でさまざまな要件を達成できる技術を実現しようという、その要素技術の研究をしています。

私が注目をしているのは「SRv6」と呼ばれる技術です。この技術はSource Routingの技術のうちの1つです。IPv6だけの転送のメカニズムで利用が可能なものという特徴があります。さらに、Source Routingという柔軟なパス選択ができるだけではなくて、ネットワークにいろんな機能を付加することができる、そういったプロトコルになっています。

私たちはこのSRv6をネットワークのマルチテナンシーやサービスチェインといった部分に適用して、ビジネスニーズに対して迅速に対応できる、そういった取り組みをしています。

LINEにおけるKubernetes活用事例

その次が、Kubernetesのプラットフォームを使った取り組みです。LINEではすでにさまざまなプロダクトで、プロダンクションの環境でKubernetesのクラスタを運用しています。

ただ現状は、各開発チームがKubernetesのクラスタを運用しているので、管理のコストが非常に高い状況です。それを解消するためにVerda上でマネージドなKubernetesクラスタを提供する、そういうプロジェクトを始めています。

アーキテクチャを簡単に説明すると、ユーザーが扱うKubernetesのクラスタは、RancherアプリOSSが関与します。ユーザーには直接Rancherを公開するのではなくて、ユーザー向けのインターフェースはVerda上で動作をする、私たちがスクラッチから開発したGateway APIになります。

どうしてこういったアーキテクチャにしているかというと、まず「特定のOSSに依存したくない」というのが1つ。そしてもう1つは、「もしRancher側で、例えばスケーラビリティの問題などが発生した場合に、Gateway API側でそれを解決できるような仕組みにしたかった」というのがあります。

現在のステータスとしては、クローズドβというかたちで開発の協力をしてもらってテストを進めています。来年の春ぐらいにはプロダクション環境で提供ができる予定になっています。

もう1つのKubernetesのプラットフォームになります。内部的に「Event Handler」と呼んでいるプロジェクトです。これはどんなプラットフォームかというと、インフラやアプリケーションの運用をサポートするプラットフォームです。

みなさんが、ふだん運用されている中で「特定のイベントが起きたときに特定のアクションを起こす」ということをよくやられていると思います。例えば「特定のログが発生したときに、〇〇にこういったものの通知を出す」「1時間前にテストを実行する」といったオペレーションですね。

このEvent Handlerは、任意のイベントと任意のアクションを紐づけて、さらにそのアクションをファンクションとして登録して実行ができる、そういうプラットフォームになります。Function as a Serviceのような形態で提供されます。

これができるとなにがうれしいかというと、ふだんこういった仕組みを実現するためには、Webhookのような仕組みを使って、APIサーバを立てて、それを管理するといった手間がかかりますが、その手間が全部省けます。さらに、イベントとそのアクションの結びつきをクラウドのリソースとして管理ができるようになりますので、ふだん埋もれがちなこういったオペレーションの可視化にも役立つと考えています。

このEvent Handlerは、最近GoogleがOSSとして公開した「Knative」をベースに開発を進めています。

ここまでLINEの取り組み事例をご紹介しました。簡単にまとめさせていただくと、ネットワークの課題については、CLOS NetworkやMulti-Tierのロードバランサといったアーキテクチャレベルで改善しました。そして、Verdaというプラットフォームは、利用者と運用者の双方の負担を下げる取り組みをしています。

まだまだ改善が必要な事項、解決が必要な課題はたくさんあります。それを根本的なレベルで運用の負荷が下げられる、そういった原則の下、挑戦をし続けているということが少しでも伝わったらうれしいと思います。

以上になります。ありがとうございました。

(会場拍手)