データベースのスケーラビリティパターンを説明するオンラインの記事はたくさんありますが、それらはほとんどが散在する記事であり、多くのコンテキストなしで無計画に定義された手法にすぎません。それらは段階的に定義されていないことがわかり、どのスケーリングオプションをいつ選択するか、どのスケーリングオプションが実際に実行可能であるか、およびその理由については説明していません。
したがって、今後の記事でいくつかのテクニックについて詳しく説明する予定です。まず、独自の方法でいくつかのコンテキストを使用して段階的な手法について話し合う方がよいと思います。この記事は高レベルの記事です。ここではスケーリング手法の詳細については説明しませんが、概要を説明します。それでは始めましょう。
安いコストでライドシェアリングを提供するスタートアップを構築したと仮定します。最初は都市をターゲットにしていて、最初の広告の後で数十人の顧客がいることはほとんどありません。
すべての顧客、旅行、場所、予約データ、および顧客の旅行履歴を同じデータベースに保存するか、ほとんどの場合、単一の物理マシンに保存します。アプリは非常に新しいため、問題を解決するための派手なキャッシュやビッグデータパイプラインはありません。たとえば、顧客が非常に少なく、システムが5分間に1回の旅行を予約することはほとんどないため、これは現時点でのユースケースに最適です。
しかし、時間が経つにつれて、あなたは市場で最も安いサービスであり、あなたのプロモーションと広告のおかげで、より多くの人々があなたのシステムにサインアップし始めます。たとえば、1分あたり10件の予約を開始すると、その数は徐々に20、1分あたり30件の予約に増加します。
この時点で、システムのパフォーマンスが低下し始めていることに気付きます。APIレイテンシが大幅に増加し、一部のトランザクションがデッドロックまたは飢餓状態になり、最終的に失敗します。アプリの応答に時間がかかり、顧客の不満を引き起こしています。問題を解決するために何ができますか?
パターン1-クエリの最適化と接続プールの実装:
頭に浮かぶ最初の解決策は、キャッシュが予約履歴、支払い履歴、ユーザープロファイルなどの非動的データを頻繁に使用することです。ただし、このアプリケーションレイヤーのキャッシュ後は、APIが公開するレイテンシの問題を解決できません。たとえば、特定の顧客の現在の運転手の位置や最寄りのタクシー、または旅行開始後の特定の時点での現在の旅行費用などの動的データが公開されます。
データベースがおそらく大幅に正規化されていることを確認したため、冗長な列をいくつか導入します(これらの列はWHERE
に頻繁に表示されます またはJOIN ON
非正規化のために頻繁に使用されるテーブルのクエリの句)。これにより、結合クエリが削減され、大きなクエリが複数の小さなクエリに分割され、その結果がアプリケーション層に追加されます。
実行できるもう1つの並列最適化は、データベース接続を微調整することです。データベースクライアントライブラリと外部ライブラリは、ほとんどすべてのプログラミング言語で利用できます。接続プールライブラリを使用してデータベース接続をキャッシュしたり、データベース管理システム自体で接続プールのサイズを構成したりできます。
ネットワーク接続の作成には、クライアントとサーバー間の通信が必要になるため、コストがかかります。接続をプールすると、接続数を最適化するのに役立つ場合があります。接続プールライブラリは、接続を多重化するのに役立つ場合があります—複数のアプリケーションスレッドが同じデータベース接続を使用できます。接続プールについては、後で別の記事で詳しく説明できるかどうかを確認します。
APIのレイテンシーを測定し、おそらく20〜50%以上のレイテンシーの削減を見つけます。これは、現時点では適切な最適化です。
これで、ビジネスをもう1つの都市に拡大し、より多くの顧客を登録し、1分あたり80〜100件の予約をゆっくりと開始します。お使いのシステムはこのスケールを処理できません。ここでも、APIレイテンシが増加し、データベースレイヤーが放棄されていることがわかりますが、今回は、クエリの最適化によってパフォーマンスが大幅に向上することはありません。システムメトリックを確認すると、ディスクスペースがほぼいっぱいで、CPUが80%の時間ビジーで、RAMがすぐにいっぱいになっていることがわかります。
パターン2-垂直方向のスケーリングまたはスケールアップ:
すべてのシステムメトリックを調べた後、システムのハードウェアをアップグレードする以外に簡単な解決策はないことがわかります。 RAMサイズを2倍にアップグレードし、ディスク容量をたとえば3倍以上アップグレードします。これは、垂直スケーリングまたはシステムのスケールアップと呼ばれます。インフラストラクチャチーム、DevOpsチーム、またはサードパーティのデータセンターエージェントに、マシンをアップグレードするように通知します。
しかし、垂直スケーリング用にマシンをどのように設定しますか?
より大きなマシンを割り当てます。 1つのアプローチは、古いマシンから手動でデータを移行するのではなく、新しいマシンをreplica
として設定することです。 既存のマシンに(primary
)-一時的なprimary replica
を作成します 構成。複製が自然に行われるようにします。レプリケーションが完了したら、新しいマシンをプライマリに昇格させ、古いマシンをオフラインにします。より大きなマシンがすべての要求を処理することが期待されるため、すべての読み取り/書き込みはこのマシンで行われます。
涼しい。システムが再び稼働し、パフォーマンスが向上します。
あなたのビジネスは非常に順調に進んでおり、さらに3つの都市に拡大することにしました。現在、合計5つの都市で事業を展開しています。トラフィックは以前の3倍であり、1分あたり約300件の予約が予想されます。この目標予約を達成する前に、パフォーマンスが再び低下し、データベースインデックスのサイズがメモリ内で大幅に増加し、定期的なメンテナンスが必要になり、インデックスを使用したテーブルスキャンがこれまでになく遅くなっています。マシンをさらにスケールアップするコストを計算しますが、コストに納得していません。今何をしていますか?
パターン3-コマンドクエリ責任分離(CQRS):
大きなマシンがすべてのread/write
を処理できるわけではないことを確認します リクエスト。また、ほとんどの場合、どの企業でもwrite
のトランザクション機能が必要です。 ただし、read
にはありません オペレーション。また、少し一貫性がないか、read
が遅れても問題ありません。 運用とあなたのビジネスにも問題はありません。 read
を分離するのが良いオプションかもしれない機会があります &write
物理的な機械の賢明な操作。個々のマシンがより多くのread/write
を処理するためのスコープを作成します オペレーション。
ここで、さらに2台の大きなマシンを使用して、それらをreplica
として設定します。 現在のマシンに。データベースレプリケーションは、primary
からのデータの配布を処理します マシンからreplica
マシン。すべての読み取りクエリをナビゲートします(クエリ(Q
)CQRS
で )レプリカへ—任意のreplica
任意の読み取り要求を処理でき、すべての書き込みクエリをナビゲートします(コマンド(C
)CQRS
で )primary
。レプリケーションには少し遅れがあるかもしれませんが、ビジネスのユースケースによるとそれで問題ありません。
毎日数十万のリクエストを処理する中規模のスタートアップのほとんどは、古いデータを定期的にアーカイブすることを条件に、プライマリレプリカの設定で生き残ることができます。
次に、さらに2つの都市にスケーリングすると、primary
すべてのwrite
を処理することはできません リクエスト。多くのwrite
リクエストにはレイテンシがあります。さらに、primary
間のラグ &replica
顧客とドライバーに影響を与えることがあります。例—旅行が終了すると、顧客はドライバーに正常に支払いますが、顧客のアクティビティはwrite
であるため、ドライバーは支払いを確認できません。 primary
に送信されるリクエスト 、ドライバーのアクティビティはread
レプリカの1つに送信される要求。システム全体が非常に遅いため、ドライバーは少なくとも30分は支払いを確認できません。これは、ドライバーと顧客の両方にとって苛立たしいことです。どのように解決しますか?
primary-replica
で非常にうまくスケーリングしました 構成ですが、書き込みパフォーマンスを向上させる必要があります。 read
で少し妥協する準備ができているかもしれません パフォーマンスを要求します。書き込みリクエストをreplica
に配布してみませんか また?
multi-primary
構成では、すべてのマシンが両方のprimary
として機能できます &replica
。 multi-primary
について考えることができます マシンのサークルが言うようにA->B->C->D->A
。 B
A
からデータを複製できます 、C
B
からデータを複製できます 、D
C
からデータを複製できます 、A
D
からデータを複製できます 。任意のノードにデータを書き込むことができ、データを読み取るときに、応答が返されるすべてのノードにクエリをブロードキャストできます。すべてのノードは同じデータベーススキーマ、同じテーブルセット、インデックスなどを持ちます。したがって、id
に衝突がないことを確認する必要があります。 同じテーブル内のノード間で、そうでない場合、ブロードキャスト中に、複数のノードが同じid
に対して異なるデータを返します。 。
通常、UUID
を使用することをお勧めします またはGUID
idの場合。この手法のもう1つの欠点は、read
クエリのブロードキャストと正しい結果の取得が含まれるため、クエリは非効率的である可能性があります。基本的にはスキャッターギャザーアプローチです。
今、あなたはさらに5つの都市に拡大し、あなたのシステムは再び苦しんでいます。 1秒あたり約50のリクエストを処理することが期待されます。大量の同時リクエストを処理する必要があります。どうやってそれを達成しますか?
パターン5-パーティショニング:
あなたはあなたのlocation
を知っています データベースはwrite
が高くなっているものです &read
トラフィック。おそらくwrite:read
比率は7:3
。これは、既存のデータベースに大きなプレッシャーをかけています。 location
テーブルには、longitude
などの主要なデータがほとんど含まれていません 、latitude
、timestamp
、driver id
、trip id
など。ユーザーの旅行、ユーザーデータ、支払いデータなどとはあまり関係ありません。location
を分離するのはどうでしょうか。 別のデータベーススキーマのテーブル?そのデータベースを適切なprimary-replica
を使用して別のマシンに配置するのはどうでしょうか。 またはmulti-primary
構成?
これは、機能によるデータのパーティション化と呼ばれます。さまざまなデータベースで、さまざまな機能によって分類されたデータをホストできます。必要に応じて、結果をバックエンドレイヤーに集約できます。この手法を使用すると、高いread/write
を必要とする機能を適切にスケーリングすることに集中できます。 リクエスト。バックエンドまたはアプリケーション層は、必要に応じて結果を結合する責任を負う必要がありますが、コードがさらに変更される可能性があります。
今、あなたがあなたの国の合計20の都市にあなたのビジネスを拡大し、まもなくオーストラリアに拡大することを計画していると想像してください。アプリに対する需要の高まりには、より迅速な対応が必要です。上記の方法のどれも今あなたを極端に助けることができません。他の国/地域に拡張するために、エンジニアリングやアーキテクチャを頻繁に変更する必要がないように、システムを拡張する必要があります。どうしますか?
パターン6-水平スケーリング:
あなたは多くのグーグルを行い、他の企業がこの問題をどのように解決したかについて多くを読み、水平方向にスケーリングする必要があるという結論に達します。たとえば50台のマシンを割り当てます。すべて同じデータベーススキーマがあり、同じデータベーススキーマに同じテーブルのセットが含まれています。すべてのマシンはデータの一部を保持しているだけです。
すべてのデータベースには同じテーブルのセットが含まれているため、データの局所性が存在するようにシステムを設計できます。関連するすべてのデータは同じマシンに格納されます。各マシンは独自のレプリカを持つことができ、レプリカは障害回復に使用できます。各データベースはshard
と呼ばれます 。物理マシンは、1つまたは複数のshards
を持つことができます —あなたが望む方法はあなたのデザイン次第です。 sharding key
を決定する必要があります 単一のsharding key
が 常に同じマシンを指します。したがって、多くのマシンがすべて同じテーブルのセットに関連データを保持していることを想像できます。read/write
同じデータベースマシン内の同じ行または同じリソースセットのリクエスト。
シャーディングは一般的に難しいです—少なくともさまざまな会社のエンジニアがそう言っています。しかし、数百万または数十億のリクエストに対応する場合は、そのような難しい決断を下さなければなりません。
sharding
について説明します 次の投稿で詳しく説明しますので、この投稿でもっと話し合いたいという誘惑を抑えてください。
シャーディングが設定されているので、多くの国に拡張できると確信しています。あなたのビジネスは非常に成長しているので、投資家はあなたに大陸を越えてビジネスを拡大するように促しています。ここでも問題が発生します。再びAPIレイテンシ。あなたのサービスはアメリカでホストされており、ベトナムの人々は本に乗るのに苦労しています。なんで?あなたはそれについてどうしますか?
パターン7-データセンターワイズパーティション:
あなたのビジネスはアメリカ、南アジア、そしてヨーロッパのいくつかの国で成長しています。あなたは毎日何百万もの予約をしていて、何十億ものリクエストがあなたのサーバーにぶつかっています。おめでとうございます-これはあなたのビジネスにとってピークの瞬間です。
ただし、アプリからのリクエストは、インターネット上の数百または数千のサーバーを経由して大陸を移動する必要があるため、遅延が発生します。データセンター間でトラフィックを分散するのはどうですか?南アジアからのすべてのリクエストを処理するシンガポールのデータセンター、ヨーロッパ諸国からのすべてのリクエストを処理できるドイツのデータセンター、米国のすべてのリクエストを処理できるカリフォルニアのデータセンターをセットアップできます。
また、ディザスタリカバリに役立つクロスデータセンターレプリケーションを有効にします。したがって、カリフォルニアのデータセンターがシンガポールのデータセンターに複製を行う場合、電力の問題や自然災害によりカリフォルニアのデータセンターがクラッシュした場合、米国のすべてのリクエストはシンガポールのデータセンターなどにフォールバックできます。
このスケーリング手法は、国を超えてサービスを提供する何百万もの顧客がいて、データの損失に対応できない場合に役立ちます。システムの可用性を常に維持する必要があります。
これらは、データベーススケーリングの一般的なステップバイステップの手法です。ほとんどのエンジニアはこれらの手法を実装する十分な機会を得ることができませんが、全体として、将来的にはより良いシステムとアーキテクチャの設計を行うのに役立つ可能性がある、そのようなシステムについてより広いアイデアを得る方がよいでしょう。
次の記事では、いくつかの概念について詳しく説明します。この投稿について、適切なフィードバックがあればお気軽にお知らせください。
この記事は、もともと著者のメディアアカウントで公開されています:https://medium.com/@kousiknath/understanding-database-scaling-patterns-ac24e5223522