このトピックは、過去1か月半にわたって私が受け継いだいくつかの(3+)インタビューの過程で提起されました。 よく知られているように見えますが、私が与えたすべての答えと説明を収集した(そして、Googleで後で見つけた)ため、それらをGoogleドライブに保存せず、短いレビューを書くことにしました。
それはJavaの小規模で典型的なエンタープライズ/ Webアプリケーションに関するもので、その多くがあります(1万から1万人の顧客、100万の訪問など)。 質問と回答の形式の一般化された対話にしましょう。
Q:トマト(Apache Tomcat)にデプロイされたアプリケーション(たとえば、最も一般的な-JSP、Spring、Hibernate)があり、トマトのあるサーバーの平均負荷が80%であることに気づいたとします。 どうする
A:複数のトマトを別々のサーバーに並行して配置します。 同じサーバー上の同じデータベースを引き続き使用します。
Q:しかし、ユーザーはどのように複数のサーバーにアクセスしますか?
A:ロードバランサーを使用します。たとえば、mod_proxyを使用したapache(Apache httpd)は、tomkatの前に立つことができます。これは、すべてのtomkat間で着信する(プロキシ)要求を分散します。
Q:しかし、ユーザーが1つのTomcatにログオンし、次のロードバランサーリクエストが別のTomcatに送信され、ユーザーがログインしていないことが判明する場合があります。
A:セッションの編成方法について話しているところです。 たとえば、スティッキーセッションを実行します(たとえば、ロードバランサーがリクエストにプロキシを追加するとき、どのTomcatがこのリクエストをプロキシするかを示し、このCookieを含む後続のリクエストをすべて同じサーバーに送信します。サーバー。
Q:そして、この特定のサーバーがクラッシュした場合はどうなりますか?
A:ユーザーセッションは失われます。 したがって、キャッシュ内のセッションストレージを使用することをお勧めします。 Tomcatは、デフォルトでmemcachedに保存する方法を知っています。 つまり、設定に行を追加し、別のサーバーでmemcachedを実行します-これですべてのtomkatsはセッションを保存し、ユーザーが別のサーバーへの次のリクエストを受け取っても、これに気付かない-セッションはとにかく動作します
Q:セッションキャッシュのその他の利点は何ですか?
A:たとえば、アプリケーションの新しいバージョンをいくつかのトマトのうち1つだけにデプロイできるため、ユーザーの25%が新しいログインページを表示し、それが気に入らない場合は希望を表明する時間があると言います。 彼らは無意識のうちにベータテスターとして働いています:)
Q:しかし、アプリケーションのバージョンが異なる方法でデータベースを使用する場合はどうなりますか?
A:基本的な変更を設計して、2つの隣接するバージョン間の下位互換性を維持できます。 難しくありません。 たとえば、新しいバージョンとともに列を追加する必要がありますが、不要なのは次のリリースでのみ削除してください。
Q:さて、今私たちのベースはボトルネックになっています。 負荷を増やしてどうしますか?
A:まず、ベースとトムカットの間にキャッシュを作成すると便利です。 さらに以前は、おそらくORMレベル(たとえば、Hibernateの2番目のキャッシュレベル)でキャッシュを使用します。 一般的なポイントは、セッション中、ユーザーは限られたデータセットを使用するため、それらをキャッシュすると便利です。
Q:それでも、キャッシュでさえも私たちを救っていないとしましょう。 ベースの負荷を減らすにはどうすればよいですか?
A:いくつかの方法があります。 たとえば、データベースの一部(特にポンピングテーブル)を別のサーバー上の別のデータベースに割り当てることができます。NoSQLストレージや特別なキャッシュにさえもできます。 もちろん、設計中にこの分離を行うことをお勧めします:)
Q:他の方法は何ですか? データベースレベルのソリューションは何ですか?
A:シャーディングを使用できます。この場合、テーブルは複数のサーバーに分割され、必要なサーバーへのアクセスが発生します(たとえば、id-shnikに関して)。 場合によっては、たとえば、トランザクション、トランザクション、電子文書などをすぐに分割できます。 通常、ユーザーは他の人のドキュメントを操作しないため、1人のユーザーに関することです。つまり、すべてのデータを1台のサーバーに便利に保存できます。
Q:このアプローチの欠点は何ですか?
A:その後、そのようなテーブルで作業することがより困難になります-複数のサーバーにあるテーブルとの結合は明らかに効率が低下します-インデックス付け、基準によるクエリなどはより複雑になります。 一般に、設計自体は非常に複雑です。
Q:さて、他のオプションを知っていますか?
A:最も簡単な方法は、たとえば、データベースに複数のサーバー上のコピーが含まれるようにレプリケーションを構成することです。そのうちの1つは書き込みに使用され、残りは読み取りに使用されます。 後者は、コンテンツを更新と迅速に同期します。 データベースへのクエリの総数が複数のマシンに分散されていることがわかりました。 もちろん、これは書くよりも読むときに便利です。
Q:他にどのようなスケーリングパスを提供できますか?
A:たとえば、メッセージキュー。 ユーザーが新しいトランザクションを保存したとしましょう-しかし、私たちはそれを自分でデータベースに書き込みません。 代わりに、そのようなデータを保存する必要があるというメッセージ(RabbitMQなど)をキューに送信します。 このメッセージは、データベースを処理して保存する複数のサーバーのいずれかに発行されます。 このようなサーバーの数を増やす(分散/複製されたデータベースまたはキャッシュを使用する場合)は、一般的に非常に簡単です。 ただし、このレベルのアーキテクチャ自体には、より多くの注意とリフレクションが既に必要です-たぶんこれは、アプリケーション全体を書き換える価値がある瞬間です:)
Q:わかりました、これは明らかです、何か他のものについて話しましょう...(そして、ここでガベージコレクターについて開始するか、配列でバイナリ検索を書くように頼むことができます-シラミをチェックします-しかし、これはもう重要ではありません)
インタビューで「観察」を共有したので、もちろん、追加、訂正などを喜んでいます。 私や他の同僚に役立つかもしれません:)