発明のための再発明

Webプログラマーが、プログラムの内部動作を通してプログラムを作る時の参考になるような情報を書くブログ(サーバーサイドやDevOpsメイン)

巨大企業のサーバー構成や内部ツールを覗く

はじめに

この記事は設計・アーキテクチャ Advent Calendar 2018の1日目の記事です。

大きなサービスを支えるのは一筋縄では行かず、考えることは多くあります。しかし、ありがたいことに巨大な企業の中にも自社のサーバー構成やそれを支えるツールを公開している企業があります。
この記事では、彼らの叡智に触れるため、有名企業の事例を取り上げ要約をします。
各事例には元記事へのリンクを書いているので、興味があればリンク先も覗いてみてください。

※新しいものばかりではないので、古くなっていたり既に別の方法に移行している可能性があることに注意してください。


LINE: 25k/secのスパイクをさばくアーキテクチャ

元記事: 25K request/secをさばいた「LINEのお年玉」のアーキテクチャの裏側

最初に紹介するのは、LINEが2018年に実施した、「LINEのお年玉」というイベントをさばいたアーキテクチャです。
この記事では、アーキテクチャの他にイベントで発生した問題についても書かれています。

Kafkaを軸とした多段構成

f:id:mrasu:20181130233406p:plain

「LINEのお年玉」では、即時に反映する必要が有る処理を前段で受けつつ、非同期でも問題ない処理をKafka(Streams)に流す構成を取ったそうです。
「LINEのお年玉」はスパイクが見込まれるイベントであることから、キューを挟むことによって、前段の負荷を減らして遅延処理できるように注意した構成ですね。
また、キューとは別にバッチ処理も行ったようです。
仕様技術はKafka, Prometheus, Fluentdです。

WeChat: アクションに応じた負荷制御システム DAGOR

元記事: Overload Control for Scaling WeChat Microservices

次は、中国でLINEのようなサービスを展開するWeChatです。
WeChat内で実装されている負荷制御に関する論文の内容が興味深かったので紹介します。
※ 元記事を読んだのではなく、The morning paperにあったまとめを読んだだけなので、原文とは異なった解釈をしているかもしれません。

負荷が高くなった場合は、優先度の低い行動に対する応答を止める

LINEと同じく、WeChatでも正月(春節旧正月)のアクセスは平常時を大きく超えるらしく、DAGORという負荷制御システムを実装して負荷に対応しているそうです。
DAGORは事前に各サービスの優先度を設定し、負荷の高まりを検知した時に

  • 処理可能な基準を変更することで、特定の優先度以上のサービスへの処理は止める
  • 大きなボトルネックが特定の優先度上にある場合、ユーザー単位に優先度を割り当てることによって処理を止めるユーザーを選択する

という動作をします。
下の図の矢印部分に制御が入るイメージです。

f:id:mrasu:20181130233835p:plain

これによって、「支払い処理は動作するが、動画のアップロードは出来ない」という制御を自動化で出来ると共に、サービス間連携の流れを把握せずにDAGORの運用することが可能になります。
ちなみに、ユーザー単位に優先度を設定することに関して、セッション単位に優先度を割り当てても良さそうな気がします。しかし、セッションを使用すると、ユーザーが「エラーが出たら再ログインし続ければ治る」ということに気がつき、再ログインを繰り返してしまうそうです。結果UXの低下につながるので、セッション単位での優先度割当は使わないそうです。

Salesforce: マルチテナントを支えるDB運用

元動画: Salesforce Multi Tenant Architecture: How We Do the Magic We Do
別スライド: SlidShare

次は、マルチテナントの運用で有名なSalesforceです。
SaaS企業ではほぼ必須になるマルチテナントですが、Salesforceは奇抜なデータ構造を持っています。
この発表では、彼らの「データとメタデータを分けたテーブル設計」とそれに伴う処理方法や、彼らの持つスケーラビリティ性を説明しています。

DataTables vs MetadataTables vs SpecializedPivotTables

f:id:mrasu:20181130234451p:plain

通常のテーブル設計では、テーブルは「事前に決めた対象分野のデータ」を入れるためにあると考えますが、Salesforceではあらゆるデータを放り込む「Data Table」と、そのテーブルの行と列の「意味」を保持する「Metadata Table」に分かれています。
さらに、インデックスや制約を保持する「SpecializedPivotalTable」なども存在します。

つまり、DataTableの各列に意味はなく、列名もテナントのidなどを除いて、Value1,Value2,Value3...となっています。Value1が何を表すかはMetadataTableを参照することで確認できる様になっています。
この構成により、どんなデータにも対応可能になり、柔軟性を発揮しているそうです。

Dropbox: 全文検索エンジン Nautilus

元記事: Architecture of Nautilus, the new Dropbox search engine

次は、Dropboxが内部で使用している全文検索エンジンNautilus」についてです。
Dropboxともなるとデータは地理的に分散されています。加えてユーザー毎にシャーディングするわけに行かないせいで、検索が大変そうです。

Indexing vs Serving

Nautilusは「Indexing」と「Serving」の2役に分かれて動作しています

f:id:mrasu:20181130234625p:plain

Indexingは、保存しているドキュメントからメタデータを生成して検索出来るようにすることが仕事です。
メタデータは、「ドキュメントから直接取り出したもの」と、「そこから更に加工されたもの(加工するものをannotatorという)」で構成されています。
さらにメタデータ作成とは別に、転置インデックス作成のためのoffline buildが別のタイミングで実行されます。
メタデータ作成とインデックス作成が分離しているので、新規annotatorに対するカナリアリリースや既存ドキュメントへの反映が、特別な処理をすることなく実現できています。

ServingではOctopusというシステムを中心に、

  • Nautilus上での検索
  • 外部サービス(Dropbox paperなど)への検索依頼
  • 結果のランク付け
  • アクセスコントロール

が実行されます。
このように、IndexingとServingの2役に分割されていることで、両者が独立して動けるようになっています。

Netflix: コンテナマネジメントシステム Titus

元記事: Titus: Introducing Containers to the Netflix Cloud

最後はNetflixが内部で使用しているコンテナマネジメントツール「Titus」です。
NetflixAWSを使用していることから、Kubernetesとは違い、AWSの各種サービスと連携する事を前提としています。

既存システムを考慮したコンテナ移行

Netflixがコンテナへ移行する際には、既存インフラとの連携や「小さく変える」というのが重視されたようで、Titusでは以下を考慮して作られたそうです。

  • 変更無しで、既存のアプリケーションがコンテナ上で動く
  • コンテナに乗せたアプリケーションが簡単に他のアプリケーションやAWSサービスに繋げられる
  • バッチやジョブが同じリソースプール上で動く
  • 効率的で信頼性がある

Titusは、EC2インスタンス内で動いている「Titus Agent」と、インスタンスにコンテナを配置する「Titus Master」、外からリクエストを受け付ける「Titus API」で構成されています。

f:id:mrasu:20181130234707p:plain

ミドルウェアでは、ZookeeperがMasterのリーダー選出を、Cassandraが永続化を担当しています。

AWS連携

TitusはAWSのサービス(S3やSQS)を使うため、各コンテナのIAMを管理したいところですが、IAMはインスタンス単位で制御されています。
そのため、TitusAgentがプロキシとなり、各コンテナに必要な情報のみをコンテナに渡しています。
またコンテナのIPについて、各コンテナは同一VPC内の固有IPを割り当てられます。それによって、ポート管理やゲートウェイ管理、セキュリティグループ管理が簡単になっています。

他にも、ワークロードの違うアプリケーションを両立させる管理方法や、既存のデプロイツール(Spinnaker)への連携、CloudWatchに連動した独自オートスケール管理といった興味深いトピックが以下の記事で公開されています


まとめ

以上、巨大企業のサーバー構成や内部ツールに関する記事を紹介しました。
今回の記事のように、このブログではプログラムを作る時の参考になることを書き続けるつもりです。
もし興味があれば、twitterやブログのフォローしていただけると嬉しいです。