Twitterはどうやって1秒に3,000もの画像を処理しているのか
現在、Twitterは1秒間あたり3,000(200GB)画像を作成し持続している。さらに良いのは、2015年にTwitterはメディア・ストレージ・ポリシーを改善したために、600万ドルを節約することができたのだ。
いつもそうだったわけではない。Twitterは、2012年には主にテキストベースだった。ホグワーツであのかっこいい動く絵が壁にかかってないようなものだ。2016年の今では、Twitterはメディアを駆使した方向へと移行している。Twitterは、プレビュー、マルチフォト、gif、vine、埋め込みビデオなどで写真をサポートできる新たなメディア・プラットフォームの開発を経て移行したのだ。
Twitter社のソフトウェア開発エンジニアであるHenna Kermani氏が、Mobile @Scale Londonでの面白いトーク「3,000 images per second」の中で、メディア・プラットフォームのストーリーを語った。トークは主に画像のパイプラインに焦点を当てているが、細かい部分ではほとんどが他のメディアにも当てはまると彼女は言う。
トークで一番面白い教訓をいくつか挙げてみよう。
- 多分うまくいくだろうと思われる、最も単純なことでハマる可能性がある。オールオアナッシングの融通の利かない処理の際に画像付きツイートをアップロードする単純な方法は、一種のロックインだった。特に貧弱なネットワークにおいてはスケーラビリティが低かったため、Twitterにとって新機能を追加することは難しかった。
- 分離。ツイート投稿からメディアアップロードを切り離すことで、Twitterは各パスウェイを独立して最適化することが可能となり、より柔軟な運用ができるようになった。
- ブロブじゃなくてハンドルを動かせ。システム内で大きなデータの塊を動かすな。帯域幅を食って、データに触れるあらゆるサービスにおいてパフォーマンスの問題を引き起こす。その代わりに、データを保存してそれをハンドルで参照したほうがいい。
- アップロードを、セグメント化された再開可能なものへと移行した結果、メディアアップロードの失敗率が大幅に減った。
- 実験と研究。Twitterは、リサーチを通して、20日TTL(有効期間)の画像バリエーション(サムネイル、スモール、ラージ等)がストレージと計算のバランスの取れたスイートスポットであることを発見した。20日を過ぎた画像はアクセスされる可能性が下がるため、削除すれば計算サーバが必要とする数の半分である1日につき約4TBのデータストレージを節約でき、1年間に何百万ドルも節約できることになる。
- オンデマンド。古い画像は削除されてもいい。なぜなら事前計算されるより、オンザフライで再現できるかもしれないからだ。必要に応じてサービスを処理することで、柔軟性が増し、タスクがどう処理されているかうまく立ち回れるようにしてくれるだけでなく、一元的に管理できるようにしてくれる。
- プログレッシブJPEGは標準画像フォーマットで大人気を博している。これは、フロントエンドとバックエンドのサポートが素晴らしく、低速ネットワークにおけるパフォーマンスが高い。
Twitterがメディア・リッチへと変わっていく旅の途中には、たくさんの良いことが起こった。彼らがどうやったのかについて学んでいこう…。
従来のやり方 ― 2012年のTwitter
書き込みパス
- ユーザがアプリでツイートを作成し、場合によってはそれに画像を添付する。
- クライアントはそのツイートをモノリシックなエンドポイントに転記する。画像はその他すべてのツイートメタデータとともにまとめてアップロードされ、プロセスに関与するあらゆるサービスに回される。
- エンドポイントは、従来のデザインで多くの問題の原因となっていた。
- 問題その1:ネットワーク回線容量の大量浪費
- ツイートの作成とメディアのアップロードは、一つの操作に密結合されていた。
- アップロードは、完全に成功しようが完全に失敗しようが一回限りだった。ネットワークのちょっとした問題や一時エラーなど、失敗の理由が何であったにせよ、再開するには、メディアのアップロードを含むアップロードのプロセス全体をやり直す必要があった。アップロードが95%まで完了している状態でも、何か不具合があればまたアップロードを最初からやり直さなければならなかった。
- 問題その2:新しく大きいメディアサイズでは、十分なスケーラビリティが得られない
- この方法では、動画のように大きいサイズのメディアに対しては十分なスケーラビリティが得られない。大きいサイズは、特にブラジル、インド、インドネシアなどネットワークが遅く、信頼性の低い場所である新興市場において、不具合の発生率を高める。こうした地域は、ツイートのアップロード成功率を本当に高めたい場所でもある。
- 問題その3:内部帯域幅の非効率的な使用
- エンドポイントはTFE(Twitterフロントエンド)に接続しており、TFEがユーザ認証とルーティングを処理していた。ユーザImage Serviceに回されていた。
- Image Serviceは、様々なサイズ(小、中、大、サムネイルなど)の画像のインスタンスを生成するVariant Generatorと通信をする。これらは画像や動画のような大きなペイロードに最適化された、キーと値の記憶装置、BlobStoreに保存される。画像は半永久的にそこに存在し続ける。
- ツイートの作成と持続プロセスに関わるサービスは他にもたくさんある。なぜなら、エンドポイントはモノリシックだったため、メディアとツイートのメタデータを結びつけ、そのまとまりは全サービスを通して流れてしまっていた。この大きなペイロードは、直接画像を処理しないサービスに回された。これらのサービスはメディアパイプラインの一部ではなかったが、大きなペイロード処理の最適化を余儀なくされた。この方法は内部帯域幅の使い方としては非常に非効率だ。
- 問題その4:膨れ上がったストレージ・フットプリント
- もはや要求されることのない長期間経過したツイート画像は、BlogStoreで場所を取りながら永久に生き続けることになっていた。時にツイートが削除された時でさえ、画像はBlogStoreに残り続けただろう。ガベージコレクションがなかったのだ。
読み込みパス
- ユーザは、ツイートとその関連画像を見る。その動画はどこから来ているのか?
- クライアントはCDNから画像のバリエーションを要求する。CDNは起点であるTFEに、画像について問い合わせる必要がある。最終的には特定サイズでのURL画像をBlobStore内で直接参照することになる。
- 問題その5:新しいバリエーションの導入が不可能
- 設計があまり柔軟ではない。新しいバリエーション、つまり様々なサイズの画像を追加するためには、BlobStore内の全ての画像に対して、新しい画像サイズの埋め戻しをする必要がある。オンデマンドのバリエーション機能がなかった。
- 柔軟性に欠けるため、Twitterが新機能をクライアントに追加することは困難だった。
新しい方法 ― 2016年のTwitter
書き込みパス
ツイートからメディアアップロードを切り離している。
- アップロードすることで第一級オブジェクトが作られた。アップロードのエンドポイントが作成され、その唯一の役割は元メディアをBlobStoreに入れることだ。
- これがアップロードの処理方法に柔軟性を与えてくれる。
- クライアントは、BlobStoreに画像を入れるImage Serviceと通信をするTFEとやり取りをして、メタデータストアにデータを入れる。それだけだ。関連する隠しサービスは他にはない。誰もメディアに対処していないし、誰もデータを回していない。
- メディアの一意の識別名であるmediaIdが、Image Serviceから返される。クライアントがツイートまたはDMを作成したいときや、プロフィール写真を更新したいとき、mediaIdはメディアを提供するというよりもむしろ、メディアを参照するためのハンドルとして使われる。
- ちょうどアップロードされたばかりのメディアを付けたツイートを作成したいとしよう。その流れはこのようになる:
- クライアントはmediaIdをpostに渡しつつ、更新エンドポイントに達する。そして、Twitter Front Endに到達する。TFEは作成されているエンティティにふさわしいサービスへの経路を定める。ツイートではTweetyPieだ。DMとプロフィール用のサービスは色々ある。そのすべてのサービスがImage Serviceと通信をする。Image Serverが顔検出や児童ポルノ検出などの機能を扱う後処理キューを持つ。それが終わったらImage Serviceが画像用にImageBird、そして動画用にVideoBirdと通信をする。ImageBirdがバリエーションを生成する。VideoBirdはいくつかのトランスコーディングをする。生成されたメディアが何であれ、BlobStoreに入れられる。
- メディアが渡されることはなく、利用していない帯域幅が大幅に節約された。
セグメント化された再開可能なアップロード。
- 地下鉄に乗り込み、10分後に出てくると、アップロードプロセスが前回中断した場所から再開される。これはユーザにとって完全にシームレスだ。
- クライアントはアップロードAPIを使って、アップロードのセッションを初期化する。バックエンドはそれに、アップロードセッション全体を通して使用する識別子、mediaIdを与える。
- 画像はいくつかのセグメントに分けられる。ここでは3つのセグメントとしよう。APIを使ってセグメントが追加され、それぞれの追加命令がセグメントにインデックスを与える。すべての追加が同じmediaIdのものだ。アップロードが完了すると、最終アップロードが完了となり、メディアを利用する準備が整う。
- この方法はネットワークの不具合に対してより回復力が高い。個々のセグメントが再試行されうる。ネットワークが何らかの理由でダウンした場合、中断してネットワークの調子が戻ったときに中断したセグメントを選ぶことができる。
- 簡単な方法で莫大な利益を得る。50KB以上のファイルにおいては、画像アップロードの不具合がブラジルで33%、インドで30%、インドネシアで19%と大幅に減少した。
読み込みパス
MinaBirdと呼ばれるOrigin ServerをCDNに導入する。
- MinaBirdはImageBirdやVideoBirdと通信できるため、画像サイズや動画フォーマットのバリエーションがない場合、それらをオンザフライで生成することが可能だ。
- MinaBirdはクライアント要求の処理方法において、より流動的でより動的だ。DMCA削除(※訳者注:アメリカのデジタル・ミレニアム著作権法に基づいて、著作権侵害に当たるインターネット上のコンテンツを削除すること)があったとしても、例えば、メディアの特定の部分へのアクセスをブロックしたり、アクセスを再度有効にしたりすることが非常に容易にできる。
- オンザフライでバリエーションとトランスコーディングを生成できることで、Twitterはストレージに関してより一層うまく対処できるようになった。
- オンデマンドのバリエーション生成というのは、BlobStoreに全バリエーションを記憶する必要がないということだ。
- 元画像は削除されるまで保存される。バリエーションは20日しか保存されない。メディアプラットフォームチームは、ベストな期限切れ期間についての調査をたくさん行った。要求された全画像のうちの半数は、最大で15日(くらい)経ったものだ。それ以上の日数画像を保存しておくことは、収穫逓減をもたらす。恐らく誰も古いメディアを要求しないだろう。15日を過ぎると、非常に長いロングテールとなる。
- TTL(有効期間)なし、期限切れなしでは、メディアストレージは毎日6TBずつ成長していくことになる。オンデマンドでバリエーションを生成するというゆるいやり方だと、1日のストレージ成長は5TBとなる。20日間のTTLは、このゆるい方法よりもっとストレージを使わないため、ストレージの消費はほとんどないが、計算という観点からすると大成功だ。ゆるい方法で読み込みの全バリエーションを計算するのはデータセンタあたり150のImageBirdマシンが必要になるのに対し、20日TTLでは75くらいしか必要とならない。だから、20日TTLはストレージと計算のバランスのとれたスイートスポットなのだ。
- ストレージと計算の節約が費用を節約してくれているので、2015年、Twitterは20日TTLの導入により600万ドルを節約した。
クライアントの改善(Android)
- Googleの作成した画像フォーマット、WebPを使った実験を6か月行った。
- 画像はPNGやJPEG対応画像より、平均して25%小さかった。
- 小さい画像サイズを使うことでネットワークストレスが低下する新興市場においては特に、ユーザエンゲージメントの増加が見られた。
- iOSに対してはサポートしていなかった。
- Android 4.0+のみサポートしていた。
- プラットフォームのサポート不足により、WebPのサポート費用が掛かった。
- Twitterが試したもう一つのオプションは、プログレッシブJPEGだ。これは、連続スキャンのレンダリングをする。最初のスキャンは濃淡のむらがあるかもしれないが、連続スキャンしていくことで勝手に綺麗になっていく。
- より良いパフォーマンス
- バックエンドのサポートをしやすい。
- 従来のJPEGより60%エンコーディングが遅い。エンコーディングは1度しか起こらず、処理は何度も発生するため、これは大きな問題ではない。
- 透過のサポートがないので、透過PNGが手元に残されてしまうが、その他はすべてプログレッシブJPEGに集中している。
- クライアント側では、FacebookのFrescoライブラリがサポートを提供している。Frescoに関して、良く言いたいことは山ほどある。2G接続した結果はかなり素晴らしかった。最初のPJPEGスキャンではたったの10kbしか必要としなかったので、ロード時間も長くなかった。ネイティブパイプラインはなんの表示もなしにロード待機していたが、一方のPJPEGは認識できる画像を表示していた。
- ツイートの詳細図におけるロードについての進行中の実験結果。50ロード時間あたり9%減少。95ロード時間あたり27%減少。アクセス失敗率74%低下。低速接続のユーザにとっては本当に大成功だ。
原文:http://highscalability.com/blog/2016/4/20/how-twitter-handles-3000-images-per-second.html (2016-7-15)
※元記事の筆者には直接翻訳の許可を頂いて、翻訳・公開しております。
関連記事
-
-
フログラミングって知ってる?エクストリームな環境あれこれ
日々オフィスや自宅のデスクでプログラムを書く日々、なんだか煮詰まる、変わり映えがしない…と思っていま
-
-
エンジニアなら絶対ワクワクしちゃうコンピュータ映画7選
こんにちは!皆さん、映画観てますか?今回は人よりちょっぴり多く映画を観ていると勝手に自負している僕が
-
-
もう二度と、絶対にMongoDBを使うべきじゃない理由
MongoDBは悪だ。なぜならそれは… …データを無くす(ソース:1、2)。 …実際、長期間、デフォ
-
-
空の上でも仕事ができちゃう!航空機ITサービス事情~ANA・JAL編~
by abdallahh 皆さん旅行は好きですか? 毎日仕事を頑張ったご褒美に南の島へ・・なんて思っ
-
-
【比較表あり】非エンジニアの人にも知ってほしい。エンジニアに優しいチャット・コミュニケーションツールまとめ
エンジニアに合ったコミュニケーションツール プロジェクトを円滑に進行させるためにも、チームでのコミュ
-
-
Appknoxアーキテクチャ – AWSからGoogle Cloudへの切り替え
この記事はAppknox社のフルスタック&DevOpsエンジニアであるdhilipsiva氏による寄
-
-
チーム作業の効率を大幅にアップしてくれるWebサービスまとめ
チーム作業では、一人で黙々と作業をするのとは違ったスキルやコツが必要。 プロジェクトの人数が増え、作
-
-
NGINXのパフォーマンスをスレッドプールで9倍にする
はじめに NGINXが接続処理に非同期かつイベント駆動のアプローチを用いていることは、よく知られてい
-
-
Dockerコンテナとイメージの仕組みを視覚化してみた
この記事は、Docker 102レベルを意図して書かれている。Dockerが何か分からない、または仮
-
-
React/Fluxにおける問題とReducerが切り開く道
私がReact/Fluxアプリケーションを書いてきて、もう1年になる。Flux開発の1年を振り返って