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 は試行錯誤とその結果を調査研究することで、20日間という時間が、画像バリエーション(サムネイル、サイズ小、サイズ大、等)においてストレージサイズと計算量においてうまくバランスするスイートスポットであることを発見した。
これはツイートから20日を過ぎた画像はアクセスされる可能性が下がるため、(画像バリエーションを)削除可能になる(代替処理は後述)。
そして、削除すれば必要となるサーバの半分、1日につき約4TBのデータストレージを節約することになるのである。これは1年間では何百万ドルも節約できるこということである。 - オンデマンド。(ツイートから20日を過ぎる)古い画像バリエーションは削除できる。
なぜなら事前に画像生成して保持するより、必要となった時にその場で画像を生成したほうがよりよい(ストレージの節約)からだ。
このように必要に応じて結果を提供することで、処理の柔軟性が増し、より賢く、さらに一元的に管理できるようにしてくれる。 - プログレッシブJPEG 真の標準画像フォーマットの王者である。 これは、フロントエンドとバックエンドのサポートが素晴らしく、低速ネットワークにおけるパフォーマンスが高い。
これは、フロントエンドとバックエンドのサポートが素晴らしく、低速ネットワークにおけるパフォーマンスが高い。
従来のやり方 ― 2012年のTwitter
書き込みパス
- ユーザがアプリでツイートを作成し、場合によってはそれに画像を添付する。
- クライアントはそのツイートをモノリシックなエンドポイントに転記する。画像はその他すべてのツイートメタデータとともにまとめてアップロードされ、プロセスに関与するあらゆるサービスに回される。
- このエンドポイントは、従来の設計で多くの問題の原因となっていた。
- 問題その1:ネットワーク回線容量の大量浪費
- ツイートの作成とメディアのアップロードは、一つの操作に密結合されていた。
- アップロードは、完全に成功しようが完全に失敗しようが一回限りだった。ネットワークのちょっとした問題や一時エラーなど、失敗の理由が何であったにせよ、再開するには、メディアのアップロードを含むアップロードのプロセス全体をやり直す必要があった。アップロードが95%まで完了している状態でも、何か不具合があればまたアップロードを最初からやり直さなければならなかった。
- 問題その2:新しく大きいメディアサイズでは、十分なスケーラビリティが得られない
- この方法では、動画のように大きいサイズのメディアに対しては十分なスケーラビリティが得られない。大きいサイズは、特にブラジル、インド、インドネシアなどネットワークが遅く、信頼性の低い場所である新興市場において、不具合の発生率を高める。こうした地域は、ツイートのアップロード成功率を本当に高めたい場所でもある。
- 問題その3:内部帯域幅の非効率的な使用
- エンドポイントはTFE(Twitterフロントエンド)に接続しており、TFEがユーザ認証とルーティングを処理していた。ユーザはImage Serviceに回されていた。
- Image Serviceは、様々なサイズ(小、中、大、サムネイルなど)の画像のインスタンスを生成するVariant Generatorと通信をする。これらは画像や動画のような大きなペイロードに最適化された、キーと値の記憶装置、BlobStoreに保存される。画像は半永久的にそこに存在し続ける。
- ツイートの作成と保持のプロセスに関わるサービスは他にもたくさんある。なぜなら、エンドポイントはモノリシックだったため、メディアとツイートのメタデータを結びつけ、そのまとまりは全サービスを通して流れてしまっていた。この大きなペイロードは、直接画像を処理しないサービスに回された。これらのサービスはメディアパイプラインの一部ではなかったが、大きなペイロード処理の最適化を余儀なくされた。この方法は内部帯域幅の使い方としては非常に非効率だ。
- 問題その4:膨れ上がったストレージ・フットプリント
- もはや要求されることのない長期間経過したツイート画像は、BlobStoreで場所を取りながら永久に生き続けることになっていた。時にツイートが削除された時でさえ、画像はBlobStoreに残り続けただろう。ガベージコレクションがなかったのだ。
読み込みパス
- ユーザは、ツイートとその関連画像を見る。その動画はどこから来ているのか?
- クライアントは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)
※元記事の筆者には直接翻訳の許可を頂いて、翻訳・公開しております。
関連記事
-
-
Uberがリアルタイムマーケットプラットフォームをスケールしている方法
Uberは、たった4年で38倍という目覚ましい成長を遂げたという。今回が恐らく初めてだと思うが、Ub
-
-
もう二度と、絶対にMongoDBを使うべきじゃない理由
MongoDBは悪だ。なぜならそれは… …データを無くす(ソース:1、2)。 …実際、長期間、デフォ
-
-
React/Fluxにおける問題とReducerが切り開く道
私がReact/Fluxアプリケーションを書いてきて、もう1年になる。Flux開発の1年を振り返って
-
-
チーム作業の効率を大幅にアップしてくれるWebサービスまとめ
チーム作業では、一人で黙々と作業をするのとは違ったスキルやコツが必要。 プロジェクトの人数が増え、作
-
-
Javaアプリケーションのパフォーマンスを(ほぼ)自動的に上げる方法
コードを書き換えずに簡単な手順をいくつか踏むだけで、複雑なJavaアプリケーションを10%以上スピー
-
-
エンジニア向け!!新しいプログラミング言語を学ぶ時のサイト一覧
最近ではプログラミングスキルが世界で注目されており、就職や転職においても十分なスキルの一つとなってい
-
-
WEBエンジニアの祭典!LL系カンファレンスの歴史
例年夏から秋にかけて開催されているLL(lightweight language, 軽量プログラミン
-
-
Node vs. Go : Roadomatic の実装における比較
目次 概要 サーバ運用 ラウンド1: リクエスト処理 UDPソケット リクエストの検証 ラウンド2:
-
-
Dockerコンテナとイメージの仕組みを視覚化してみた
この記事は、Docker 102レベルを意図して書かれている。Dockerが何か分からない、または仮
-
-
これから必ず伸びる!最低限抑えておきたい技術トレンド3つ
21世紀から早くも15年が経ち、iphoneや電気自動車、タブレットなど私たちの生活を大きく変える製