しかし、静的ファイルのストレージと配布を整理するタスクが与えられた場合はどうでしょうか? きっと多くの人はすべてがシンプルだと思うでしょう。 また、そのようなファイルが10億個ある場合、1日に数百テラバイト、数十億のリクエストがありますか? また、多くの異なるシステムが、ストレージ用に異なる形式とサイズのファイルを送信します。 このクエストはもはやそれほど単純ではないようです。 カットの下には、このような問題をどのように解決したか、これにどのような困難が生じ、どのようにそれらを克服したかというストーリーがあります。
Avitoは最初の数日から急速に発展しました。 たとえば、広告用の新しい画像のダウンロード速度は、初期の数倍に増加しました。 このため、初期段階では、リソースが限られている状況で、アーキテクチャに関連する問題をできるだけ迅速かつ効率的に解決する必要がありました。 さらに、サポートリソースをほとんど必要としないシンプルなソリューションを常に優先していました。 KISSの原則(「短く簡潔に保つ」)は、当社の価値の1つです。
最初の決定
広告に写真を追加する機能は確かにユーザーにとって重要なものであるため、広告の保存方法と広告の写真の提供方法の問題はすぐに生じました。顧客は購入内容を確認したいのです。
当時、Avitoは10台未満のサーバーに適合していました。 最初の最速のソリューションは、1つのサーバー上のディレクトリツリーにイメージファイルを保存し、クラウンとバックアップを同期することでした。
ファイルへのパスは、写真の一意のデジタル識別子に基づいて決定されました。 最初は、それぞれに100個のディレクトリの2つのネストレベルがありました。
時間が経つにつれて、サーバースペースが終わりに近づき、それを使って何かをしなければなりませんでした。 今回は、複数のサーバーに接続されたネットワークを使用することを選択しました。 これに先立って、テストモードのネットワークストレージはデータセンター自体によってサービスとして提供され、その時点でのテスト測定によると、十分に機能していました。 しかし、負荷が大きくなるにつれて、速度が低下し始めました。 データセンターによるストレージの最適化は根本的には役に立たず、常に稼働しているとは限りませんでした。 ストレージを最適化する方法に影響を与える能力は限られており、そのような最適化の可能性が遅かれ早かれ枯渇しないことを確信できませんでした。 その時までにサーバーパークは著しく増加し、数十から数え始めました。 配布されたglusterfsを迅速に上げる試みがなされました。 ただし、軽負荷の場合にのみ十分に機能しました。 それらが完全な容量になるとすぐに、クラスターは「崩壊」するか、クラスターへのすべての要求が「ハングアップ」します。 彼を調整する試みは失敗しました
私たちは何か他のものが必要であることに気付きました。 新しいストレージシステムの要件が特定されました。
- できるだけシンプル
- シンプルで実績のあるコンポーネントから構築
- 低いサポートリソース
- 何が起こっているかを最大限に簡単に制御
- 優れたスケーラビリティ
- 現在のソリューションからの実装および移行の非常に速い期限
- サーバーの修復中に一部のイメージにアクセスできなくなることは許容されます(サーバーは多かれ少なかれ迅速に修復されました)
- サーバーの1つが完全に破壊された場合、写真のごく一部の損失が許可されます。 Avitoが存在する間、これは一度も起こったことがないと言わなければなりません。 3 *うーん。
新しいスキーム
簡単にするために、このイメージは2つのサーバー上の4つのノードのみを示しています。
議論の中で、私たちはそのような計画に到達しました。 ファイルは同じディレクトリツリーに格納されますが、最上位ディレクトリはサーバーのグループ全体に分散されます。 その時までに、同じディスク構成のサーバーを蓄積し、そのディスクは「アイドル」であったと言わなければなりません。 ファイルにはすべて同じnginxが与えられます。 各サーバーで、サーバー上にある特定の最上位ディレクトリに対応するIPが生成されます。 当時は、データセンターが私たちのためにトラフィックを分散していたため、トラフィックの分散については考えていませんでした。 バランシングロジックは、リクエストの送信先ドメイン(合計100ドメイン)に応じて、リクエストを適切なサーバー上にある内部IPに送信するというものでした。
異なるサーバーにまたがって配布される場合、サイトコードがどのようにリポジトリに画像をアップロードするかという疑問が生じました。 ユーザーからファイルが送られてきたのと同じhttpプロトコルを使用することは論理的でした。 ファイルを保存するサーバー側でファイルを受け入れるサービスとして使用できるものを探し始めました。 ファイルアップロードのために、開いているnginxモジュールに目が行きました。 しかし、彼の研究中に、彼の仕事の論理が私たちの計画に合わないことが判明しました。 しかし、これはオープンソースであり、Cでのプログラミングの経験があります。しばらくの間、他のタスクの間にモジュールが完成し、nginxの一部として機能するようになり、ファイルを取得して適切なディレクトリに保存しました。 将来的には、本番環境での作業中に、メモリリークが検出され、最初は夜間に再起動して処理され、その後、時間があれば、理由を見つけて修正しました。
負荷が増えています
時間が経つにつれて、このストレージを写真だけでなく他の静的ファイルにも使用するようになり、パフォーマンスとファイルへのアクセスに影響するnginxパラメーターで柔軟に調整しました。
リクエストの数とデータの量が増加するにつれて、高負荷のもとで迅速かつ効果的なソリューションを必要とする多くの問題に遭遇しました(時には事前に予測していました)。
これらの問題の1つは、データセンターがF5 Viprionロードバランサーで提供していたバランシングです。 100個の外部IP(各ノードに1つ)を割り当てることにより、トラフィック処理パスから削除することにしました。 そこで、ボトルネックを取り除き、データ配信を高速化し、信頼性を高めました。
1つのディレクトリ内のファイルの数が増えていたため、ディレクトリの内容の読み取り時間が長くなるため、コンポーネントの速度が低下しました。 応答として、100個のディレクトリの別のレベルを追加しました。 各ストレージノードに100 ^ 3 = 1Mのディレクトリがあり、全体的な速度が向上しました。
nginxとディスクキャッシュの設定を最適化することで多くの実験を行いました。 観察した写真では、ディスクキャッシュはキャッシュに対して完全なリターンを与えないという印象があり、tmpfsでnginxを使用したキャッシュはうまく機能しますが、ピーク時にキャッシュをクリアするとシステムが著しくロードされます。 まず、nginxリクエストのロギングをファイルに組み込み、デーモンを作成しました。デーモンは深夜にこのファイルを読み取り、クリーンアップし、最も関連性の高いファイルを検出し、キャッシュから残りをクリアしました。 したがって、キャッシュのクリーニングは、システムの負荷が大きくない夜間に限定しました。 これは、一定の負荷レベルまでの一定期間、非常にうまく機能しました。 統計の構築とキャッシュのクリアは、夜間の間隔に収まらず、さらに、ディスクスペースがすぐになくなることが明らかになりました。
私たちは、第1レベルと同様の第2レベルのデータストレージを編成することにしましたが、いくつかの違いがあります。
- 各サーバーのディスクサブシステムのサイズの50倍。 ただし、ディスク速度は遅くなる場合があります。
- より少ないサーバー
- ファイルへの外部アクセスは、最初のレベルを介したプロキシ経由でのみ可能です
これは私たちに機会を与えました:
- キャッシュオプションをより柔軟に構成する
- 安価な機器を使用して大量のデータを保存する
- 将来のシステムのスケーリングがさらに簡単に
ただし、これには、ストレージシステムに新しいファイルをアップロードするためのシステム構成とコードの複雑さが必要でした。
次の図は、最初のレベルのサーバーと2番目のサーバーを使用して、2つのストレージレベルに2つのストレージノード(00と01)を配置する方法を示しています。 サーバーに異なる数のノードを配置できることは明らかであり、各ストレージレベルのサーバーの数は100から100までです。 簡単にするために、図のすべてのノードとサーバーは示されていません。
簡単にするために、このイメージは2つのサーバー上の2つのノードのみを示しています
おわりに
その結果、何が得られましたか? 静的ファイルを保存するためのシステム。中級レベルの専門家が簡単に把握でき、信頼性の高い実績のあるオープン要素に基づいて構築され、必要に応じて低価格で交換または変更できます。 さらに、システムはユーザーに1日に数十のPBデータを提供し、数百テラバイトのデータを保存できます。
短所も。 たとえば、データ複製の欠如、機器の故障に対する完全な保護。 また、最初はシステムを設計するときに、リスク評価に従ってすぐに決定および合意されましたが、これらのマイナスを平準化できる追加ツールのセットがあります(バックアップシステム、テスト、回復、同期、移動などのスクリプト)
将来の計画では、おそらく一部の遅延キューを介して、ファイルの一部のレプリケーションを柔軟に構成する機能を追加します。
実装の詳細、作業のロジック(何も言われなかった)、設定のニュアンスを意図的に掘り下げなかったので、記事を引きずり出して主要な考えを伝えないようにしましょう:優れた強力なシステムを構築したい場合、正しい方法の1つはオープンで実績のある製品を使用することです比較的シンプルで信頼できるスキームで接続されています。 普通にやれば、普通になります!