ホームページ > データベース > SQL > データベースはデータベースとテーブルに分かれています。分割方法は?

データベースはデータベースとテーブルに分かれています。分割方法は?

リリース: 2023-08-17 16:31:55
転載
1060 人が閲覧しました


#1. データのセグメント化

リレーショナル データベースです。 1 台のマシンのストレージ容量、接続数、処理能力には制限があります。単一テーブルのデータ量が 1000W または 100G に達すると、クエリ ディメンションの数が多くなるため、スレーブ データベースを追加してインデックスを最適化したとしても、多くの操作を実行するとパフォーマンスが大幅に低下します。このとき、データベースへの負担を軽減し、クエリ時間を短縮するためにセグメント化を検討する必要があります。

1000W または 100G は、業界の参考値 と言えます。詳細は、現在のシステムのハードウェア設備、テーブル構造の設計、その他の要因によって異なります。 。

データベース分散の中核となる内容は、データのセグメント化 (

シャーディング) と、セグメント化後のデータの位置付けと統合にほかなりません。データのセグメント化とは、データを複数のデータベースに分散して保存することで、単一のデータベースのデータ量を削減し、ホストの数を拡張することで単一のデータベースのパフォーマンスの問題を軽減し、データベースの運用を改善するという目的を達成することです。パフォーマンス。

データ セグメンテーションは、セグメンテーション タイプに応じて、垂直 (縦方向) セグメンテーションと水平 (水平) セグメンテーションの 2 つの方法に分けることができます。

1. 垂直 (垂直) セグメンテーション

垂直セグメンテーションは、通常、垂直データベース パーティショニングと垂直テーブル パーティショニングの 2 つのタイプに分類されます。

垂直データベースシャーディングとは、ビジネス結合に基づいて、相関性の低い異なるテーブルを異なるデータベースに保存することです。このアプローチは、大規模なシステムを複数の小規模なシステムに分割し、ビジネス分類に従って独立して分割するのと似ています。 「マイクロサービス ガバナンス」のアプローチと同様に、各マイクロサービスは個別のデータベースを使用します。写真に示すように:

データベースはデータベースとテーブルに分かれています。分割方法は?

#垂直テーブル パーティショニングは、データベースの「列」に基づいています。テーブルに多くのフィールドがある場合は、新しい拡張テーブルを作成できます。頻繁に使用されるフィールドやフィールド長の長いフィールドは拡張テーブルに分割されません。多くのフィールドがある場合 (たとえば、大きなテーブルに 100 を超えるフィールドがある場合)、「大きなテーブルを小さなテーブルに分割する」方が開発と保守が容易で、ページ間の問題も回避できます。データ ページを介して保存されます。あまりにも多くのスペースを記録すると、ページの交差が発生し、追加のパフォーマンス オーバーヘッドが発生します。また、データベースは行単位でデータをメモリにロードするため、テーブル内のフィールド長が短くなり、アクセス頻度が高くなり、より多くのデータをメモリにロードできるようになり、ヒット率が高くなり、ディスク IO が向上します。削減されるため、データベースのパフォーマンスが向上します。

データベースはデータベースとテーブルに分かれています。分割方法は?

垂直セグメンテーションの利点:

1. ビジネス システム レベルで結合を解決し、ビジネスを明確にする2. マイクロサービスのガバナンスは同様であり、異なるビジネスのデータの階層的な管理、保守、監視、拡張も実行できます 3. 同時実行性の高いシナリオでは、垂直セグメンテーションにより IO、データベース接続、

欠点:

1. 一部のテーブルは結合できず、インターフェース集約によってのみ解決できるため、開発の複雑さが増大します。トランザクション処理が複雑である 3. 単一テーブル内に依然として過剰な量のデータがある 問題 (水平セグメンテーションが必要)

2. 水平 (水平) セグメンテーション

アプリケーションでのきめ細かい垂直分割が困難な場合、または分割後のデータ行数が膨大で、単一データベースの読み取り、書き込み、およびストレージのパフォーマンスにボトルネックがある場合。 、水平方向のセグメンテーションが必要です。

水平セグメンテーションは、データベース内シャーディングとサブデータベース シャーディングに分けられ、テーブル内のデータの固有の論理関係に基づいて、同じテーブルを異なる条件に応じて複数のデータベースまたは複数のテーブルに分散します。各テーブルにはデータの一部のみが含まれるため、1 つのテーブル内のデータ量が削減され、分散効果が実現します。図に示すように:

データベースはデータベースとテーブルに分かれています。分割方法は?

#内部テーブル パーティショニングは、単一テーブル内の過剰なデータ量の問題を解決するだけであり、分散はしません。テーブルを異なるマシン上のライブラリに保存するため、MySQL データベースへの負荷を軽減するのにはあまり役に立ちません。同じ物理マシンの CPU、メモリ、およびネットワーク IO を依然として誰もが奪い合います。これはサブデータベースとネットワークによって解決するのが最適です。テーブル。

水平シャーディングの利点:

1. 単一データベース内の過剰なデータ量と高い同時実行性によって引き起こされるパフォーマンスのボトルネックがなくなり、システムの安定性と負荷容量が向上します。側面の変換が小さいため、ビジネス モジュールを分割する必要がありません

欠点:

1. シャード間のトランザクションの一貫性を保証するのが難しい 2. データベース間の結合クエリのパフォーマンスが低い 3. データの複数の拡張が難しく、メンテナンスの量が膨大になる.

同じテーブル水平分割後 複数のデータベース/テーブルに出現し、それぞれのデータベース/テーブルの内容は異なります。典型的なデータ断片化ルールは次のとおりです:

1. 時間間隔または ID 間隔に応じて、値の範囲

に従って分割します。たとえば、異なる月または日のデータを日付ごとに異なるライブラリに分散し、userId が 1 ~ 9999 のレコードを最初のライブラリに割り当て、userId が 10000 ~ 20000 のレコードを 2 番目のライブラリに割り当てます。ある意味、一部のシステムで使用されている「ホット データとコールド データの分離」、あまり使用されていない履歴データの一部を他のライブラリに移行し、ビジネス機能でホット データ クエリのみを提供する方法も同様の手法です。

この利点は次のとおりです:

1. 単一テーブルのサイズを制御できる 2. 水平方向の拡張が当然簡単であるため、後でシャード クラスター全体を拡張したい場合は、必要なのはノードを追加することだけであり、他のシャードからデータを移行する必要はありません。 3. 範囲検索にシャード フィールドを使用する場合、連続シャーディングにより迅速なクエリのためにシャードをすばやく見つけることができ、シャード間のクエリの問題を効果的に回避できます。

欠点:

ホットスポット データがパフォーマンスのボトルネックになります。連続シャーディングには、時間フィールドによるシャーディングなどのデータ ホットスポットが存在する場合があります。一部のシャードには、最新の期間のデータが保存され、頻繁に読み書きされる可能性がありますが、一部のシャードには、めったにクエリされない履歴データが保存されます

データベースはデータベースとテーブルに分かれています。分割方法は?

2. 数値に基づいて係数を取得します。

# 通常、Mod を取得するにはハッシュを使用します。分割方法。例: Customer テーブルを cusno フィールドに基づいて 4 つのライブラリに分割し、残りの 0 を最初のライブラリに、残りの 1 を 2 番目のライブラリに配置します。これにより、同じユーザーのデータが同じデータベースに分散されるため、クエリ条件に cusno フィールドが含まれている場合、対応するデータベースをクエリの対象として明確に配置できます。

#利点:

データの断片化は比較的均等であり、ホットスポットや同時アクセスのボトルネックが発生しにくいです。

欠点:

1. 後でシャードクラスターを拡張する場合、古いデータを移行する必要があります (一貫したハッシュアルゴリズムを使用すると、この問題をより適切に回避できます) 2. クロスシャードクエリの複雑な問題に直面するのは簡単です。例えば、上記の例では、頻繁に使用するクエリ条件にcusnoが含まれていないとデータベースが見つからないため、4つのライブラリに同時にクエリを開始し、メモリ上のデータをマージする必要があります。 、最小セットを取得してアプリケーションに返すと、ライブラリがドラッグになってしまいます。

データベースはデータベースとテーブルに分かれています。分割方法は?

# 2. データベースとテーブルのシャーディングによって発生する問題 #サブデータベースとサブテーブルは、単一マシンと単一データベースによって引き起こされるパフォーマンスのボトルネックと圧力を効果的に排除し、ネットワーク IO、ハードウェア リソース、接続数のボトルネックを突破し、またいくつかの問題を引き起こすことができます。これらの技術的課題とそれに対応する解決策については以下で説明します。

#1. トランザクションの一貫性の問題

分散トランザクション

When更新されたコンテンツが同時に異なるライブラリに配布されると、データベース間のトランザクションの問題が必然的に発生します。クロスシャードトランザクションも分散トランザクションであり、単純な解決策はありませんが、一般的には「XAプロトコル」と「2フェーズコミット」を利用して対応できます。

分散トランザクションにより、データベース操作のアトミック性が最大限に保証されます。しかし、トランザクションを投入する際には複数のノードを連携させる必要があるため、トランザクションの投入時点が遅れ、トランザクションの実行時間が長くなってしまいます。これにより、トランザクションが共有リソースにアクセスするときに競合やデッドロックが発生する可能性が高くなります。データベースノードの数が増加するにつれて、この傾向はますます深刻になり、データベースレベルでのシステムの水平拡張の足かせとなるでしょう。

最終的な一貫性

高いパフォーマンス要件はあるものの、一貫性要件は低いシステムの場合、多くの場合、システムのリアルタイム パフォーマンスは必要ありません。一貫性。許容期間内に最終的な一貫性が達成される限り、トランザクション補償を使用できます。トランザクション補償は、実行中にエラーが発生した直後にトランザクションをロールバックする方法とは異なり、事後的なチェックと救済策であり、一般的な実装方法には、データの照合チェック、ログに基づく比較、標準との定期的な比較などがあります。データソース、同期など。取引補償もビジネスシステムと併せて考慮する必要があります。

2. クロスノード関連付けクエリ結合の問題

セグメンテーションの前に、システム内の多くのリストと詳細ページに必要なデータが次のようになります。 SQL結合を通じて処理されて完了します。分割後、データが異なるノードに分散される場合がありますが、このとき結合による問題が発生する可能性が高くなりますので、パフォーマンスを考慮して結合クエリの使用は避けてください。

この問題を解決するいくつかの方法:

1) グローバル テーブル

グローバル テーブルは、「」とみなすこともできます。 「データ ディクショナリ テーブル」は、システム内のすべてのモジュールが依存するテーブルです。データベース間の結合クエリを回避するために、このようなテーブルのコピーを各データベースに保存できます。これらのデータは通常、ほとんど変更されないため、一貫性の問題を心配する必要はありません。

2) フィールド冗長性

時間のためにスペースを使用し、パフォーマンスのために結合クエリを回避する典型的なアンチパラダイム設計。たとえば、注文テーブルが userId を保存すると、userName の冗長コピーも保存されるため、注文の詳細をクエリするときに「購入者ユーザー テーブル」をクエリする必要がなくなります。

ただし、この方法を適用できるシナリオも限られており、依存フィールドが比較的少ない状況に適しています。冗長フィールドのデータの一貫性を確保することも困難です。上記の注文テーブルの例と同様に、購入者が userName を変更した後、注文履歴で同期して更新する必要がありますか?これも実際のビジネス シナリオと併せて検討する必要があります。

#3) データ アセンブリ

#システム レベルでは、クエリは 2 つに分割されます。最初のクエリの結果は、検索に重点を置いています。次に、その ID に基づいて 2 番目のリクエストを開始し、関連データを取得します。最後に、取得したデータをフィールドに組み立てます。

4) ER シャーディング

リレーショナル データベースでは、最初にテーブル間の関係を決定し、それらを関連付けることができる場合、リレーショナル テーブルのレコードの場合同じシャードに保存されている場合、シャード間の結合の問題をより適切に回避できます。 1:1や1:nの場合、通常はメインテーブルのID主キーに応じて分割されます。以下の図に示すように、

データベースはデータベースとテーブルに分かれています。分割方法は?

#このようにして、Data Node1 上の orderorder テーブルと orderdetail 注文詳細テーブルを処理できます。 orderId を通じてローカル相関クエリが実行されます。これはデータ ノード 2 にも当てはまります。

3. クロスノードのページング、並べ替え、関数の問題

複数のノードと複数のデータベースにまたがってクエリを実行する場合は、ページングと順序を制限します。ソートが発生するなどの問題が発生します。ページングは​​、指定されたフィールドに従って並べ替える必要があります。並べ替えフィールドがシャーディング フィールドである場合は、シャーディング ルールを通じて指定されたシャードを見つけるのが簡単ですが、並べ替えフィールドがシャーディング フィールドではない場合は、より複雑になります。まずデータをソートして別のシャード ノードに返す必要があります。その後、別のシャードから返された結果セットが要約されて再度ソートされ、最終的にユーザーに返されます。図に示すように:

データベースはデータベースとテーブルに分かれています。分割方法は?

上の図は最初のページのデータのみを取得していますが、これは大きな影響を与えません。パフォーマンス。ただし、取得したページ数が多い場合、各シャード ノードのデータがランダムである可能性があるため、状況はさらに複雑になります。ソートの精度を確保するには、すべてのノードのデータの最初の N ページをソートしてマージする必要があります。このような操作は CPU とメモリ リソースを消費するため、ページ数が増えるほどシステム パフォーマンスが低下します。

Max、Min、Sum、Count などの関数を計算に使用する場合は、最初に各シャードで対応する関数を実行してから、各シャードの結果セットを要約して再度計算する必要もあります。最後に結果を返します。写真が示すように:

データベースはデータベースとテーブルに分かれています。分割方法は?

4. グローバル主キー回避の問題

サブデータベース テーブル環境では、テーブル内のデータが異なるデータベースに同時に存在するため、主キー値の通常の自動インクリメントは役に立たず、パーティション データベースの自己生成 ID が保証されません。世界的にユニーク。したがって、データベース間で主キーが重複しないように、グローバル主キーを個別に設計する必要があります。一般的な主キー生成戦略がいくつかあります。

1) UUID

UUID 標準形式には、5 つのセグメントに分割された 32 個の 16 進数が含まれています。 8-4-4-4-12 の形式の 36 文字。例: 550e8400-e29b-41d4-a716-446655440000

UUID は主キーであり、ローカルで生成される最も単純なソリューションです。パフォーマンスが向上し、ネットワークに時間がかかりません。ただし、欠点も明らかです。UUID は非常に長いため、多くのストレージ スペースを占有します。さらに、主キーとしてインデックスを作成し、そのインデックスに基づいてクエリを実行すると、パフォーマンスの問題が発生します。 UUID が乱れると、データの場所が頻繁に変更され、ページングが発生します。

2) データベースと組み合わせて主キー ID テーブルを維持します

データベースにシーケンス テーブルを作成します:

CREATE TABLE `sequence` (    `id` bigint(20) unsigned NOT NULL auto_increment,    `stub` char(1) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `stub` (`stub`)  ) ENGINE=MyISAM;
ログイン後にコピー

スタブ フィールドは一意のインデックスに設定され、同じスタブ値はシーケンス テーブル内に 1 つのレコードのみを持ち、複数のテーブルに対してグローバル ID を同時に生成できます。シーケンス テーブルの内容は次のとおりです。

+-------------------+------+ | id                | stub |  +-------------------+------+ | 72157623227190423 |    a |  +-------------------+------+
ログイン後にコピー

パフォーマンスを向上させるには、InnoDB の代わりに MyISAM ストレージ エンジンを使用します。 MyISAM はテーブル レベルのロックを使用し、テーブルへの読み取りと書き込みはシリアルであるため、同時実行中に同じ ID 値を 2 回読み取ることを心配する必要はありません。

グローバルに一意の 64 ビット ID が必要な場合は、次を実行します。

REPLACE INTO sequence (stub) VALUES ('a'); SELECT LAST_INSERT_ID();
ログイン後にコピー

これら 2 つのステートメントは接続レベルにあり、select lastinsertid() は replace into と同じデータベース接続に存在する必要があります。挿入された新しい ID を取得します。

insert into の代わりに replace into を使用する利点は、テーブルの行数が大きくなりすぎることを避け、定期的なクリーニングが必要ないことです。

この解決策は比較的単純ですが、欠点も明らかです: 単一点の問題があり、DB に強く依存しており、DB が異常になるとシステム全体が使用できなくなります。マスター/スレーブを構成すると可用性が向上しますが、マスター データベースに障害が発生してマスターとスレーブが切り替わった場合、特殊な状況下ではデータの一貫性を保証することが困難になります。さらに、パフォーマンスのボトルネックは、単一の MySQL の読み取りおよび書き込みパフォーマンスに限定されます。

flickr チームが使用する主キー生成戦略は、上記のシーケンス テーブル ソリューションに似ていますが、単一点とパフォーマンスのボトルネックの問題をより適切に解決します。

このソリューションの全体的なアイデアは、2 つ以上のグローバル ID 生成サーバーを確立し、各サーバーにデータベースを 1 つだけ展開し、各データベースには現在のグローバル ID を記録するシーケンス テーブルがあるということです。表内の ID 増加のステップ サイズはライブラリの数であり、ID の生成を各データベースにハッシュできるように、開始値が順番にずらしてあります。以下に示すように:

データベースはデータベースとテーブルに分かれています。分割方法は?

ID は 2 つのデータベース サーバーによって生成され、異なる auto_increment 値が設定されます。最初のシーケンスの開始値は 1 で、各ステップは 2 ずつ増加します。他のシーケンスの開始値は 2 で、各ステップは 2 ずつ増加します。その結果、1 番目のステーションで生成される ID はすべて奇数 (1、3、5、7...) となり、2 番目のステーションで生成される ID はすべて偶数 (2、4、6、8...) になります。 。)。

このソリューションは、ID 生成の圧力を 2 台のマシンに均等に分散します。また、システムの耐障害性も備えており、1 台目のマシンでエラーが発生した場合は、自動的に 2 台目のマシンに切り替えて ID を取得します。ただし、システムにマシンを追加する際の水平展開が煩雑になる、IDを取得するたびにDBを読み書きする必要がある、DBへの負荷が依然として非常に高い、パフォーマンスが低下するなどのデメリットがあります。ヒープマシンに依存することによってのみ改善できます。

flickr のソリューションに基づいて最適化を続けることができます。バッチ方式を使用してデータベースの書き込み圧力を軽減します。毎回 ID 番号セグメントの範囲を取得し、使用後にデータベースにアクセスしてそれらを取得します。これにより、データベースへの負担が大幅に軽減されます。次の図に示すように:

データベースはデータベースとテーブルに分かれています。分割方法は?

可用性を確保するために引き続き 2 つの DB を使用し、現在の最大 ID のみがデータベースに保存されます。 ID 生成サービスは毎回 6 つの ID をバッチで取得し、最初に maxid を 5 に変更します。アプリケーションが ID 生成サービスにアクセスするとき、データベースにアクセスする必要はなく、ID 0 ~ 5 が番号セグメントから順番にディスパッチされます。キャッシュ。これらのIDを発行した後、maxidを11に変更すると、次回からID6~11を配布できるようになります。その結果、データベースへの負担は元の 1/6 に軽減されます。

3) スノーフレーク分散型自己増加 ID アルゴリズム

Twitter のスノーフレーク アルゴリズムは、分散システムがグローバル ID を生成する必要性を解決し、64 個のロング ID を生成します。タイプの桁数、構成要素:

#最初の桁は未使用です

#次の 41 桁はミリ秒レベルの時間であり、41 桁の長さは 69 年間の時間を表すことができます

5 桁の datacenterId、5 桁の workerId。 10 ビットの長さは、最大 1024 ノードの展開をサポートします。

最後の 12 ビットはミリ秒以内のカウントであり、12 ビットのカウント シーケンス番号は、各ノードがミリ秒あたり 4096 個の ID シーケンスを生成することをサポートします

データベースはデータベースとテーブルに分かれています。分割方法は?

この利点は、ミリ秒数が高レベルであり、生成される ID は通常、時間の傾向に応じて増加することです。サードパーティのシステムに依存しており、高い安定性と効率性を備えています理論的には、上位 QPS は約 409.6w/s (1000*2^12) であり、分散システム全体で ID の衝突は発生せず、ビットは柔軟に変更できます独自のビジネスに応じて割り当てられます。

欠点は、マシンクロックに大きく依存することであり、クロックを遅らせるとIDが重複して生成される可能性があります。

要約すると、

データベースとスノーフレークの一意の ID ソリューションを組み合わせると、業界のより成熟したソリューションである Leaf - Meituan-Dianping 分散 ID を参照できます。生成システムを構築し、高可用性、災害復旧、分散クロッキングなどの問題を考慮しています。

5. データの移行と拡張の問題

ビジネスが急速に発展し、パフォーマンスとストレージのボトルネックに直面した場合、シャーディング設計が検討されます。今回は、履歴データの移行の問題を考慮することが避けられません。一般的なアプローチは、最初に履歴データを読み取り、次に指定されたシャーディング ルールに従って各シャード ノードにデータを書き込むことです。さらに、現在のデータ量と QPS、およびビジネス開発の速度に基づいてキャパシティ プランニングを実行し、必要なシャードのおおよその数を計算する必要があります (一般に、単一テーブルのデータ量を計算することをお勧めします)。単一シャードは 1000W を超えません)

数値範囲シャーディングを使用する場合は、ノードを追加して容量を拡張するだけで済み、シャード データを移行する必要はありません。数値モジュロ シャーディングを使用すると、後の拡張問題を考慮するのが比較的面倒になります。

3. セグメンテーションを考慮する場合

データのセグメント化をいつ考慮するかを以下に説明します。

1. 可能な限り分割しないようにしてください

すべてのテーブルを分割する必要があるわけではありません。主にデータの増加に依存します。スピード。セグメント化によりビジネスはある程度複雑になりますが、データベースはデータの保存とクエリの実行に加えて、ビジネスのニーズをより適切に実現するのに役立つ重要なタスクの 1 つです。

「過剰設計」や「時期尚早の最適化」を避けるために絶対に必要な場合を除き、サブデータベースとサブテーブルという大きなトリックは使用しないでください。データベースやテーブルを分割する前に、分割のためだけに分割するのではなく、ハードウェアのアップグレード、ネットワークのアップグレード、読み取りと書き込みの分離、インデックスの最適化など、最初にできることから最善を尽くしてください。データ量が単一テーブルのボトルネックに達した場合は、データベースとテーブルのシャーディングを検討してください。

2. データ量が多すぎるため、通常の運用保守が業務アクセスに影響を与える

ここでいう運用保守とは、以下のことを指します。

1) データベースのバックアップの場合、1 つのテーブルが大きすぎると、バックアップ中に大量のディスク IO とネットワーク IO が必要になります。たとえば、1T のデータがネットワーク上で送信され、50MB を占有する場合、完了までに 20,000 秒かかり、プロセス全体のリスクが比較的高くなります。 , MySQL はテーブル全体をロックしますが、この時間は非常に長くなり、この期間中、ビジネスはこのテーブルにアクセスできなくなり、大きな影響が生じます。 pt-online-schema-changeを使用すると、使用中にトリガーやシャドウテーブルが作成されるため、これにも時間がかかります。この操作中はリスクタイムとしてカウントされます。データテーブルを分割して総量を減らすと、このリスクを軽減できます。

3)大表会经常访问与更新,就更有可能出现锁等待。将数据切分,用空间换时间,变相降低访问压力

3、随着业务发展,需要对某些字段垂直拆分

举个例子,假如项目一开始设计的用户表如下:

id   bigint #用户的IDname varchar #用户的名字last_login_time datetime #最近登录时间personal_info text #私人信息.....  #其他信息字段
ログイン後にコピー

在项目初始阶段,这种设计是满足简单的业务需求的,也方便快速迭代开发。而当业务快速发展时,用户量从10w激增到10亿,用户非常的活跃,每次登录会更新 lastloginname 字段,使得 user 表被不断update,压力很大。而其他字段:id, name, personalinfo 是不变的或很少更新的,此时在业务角度,就要将 lastlogintime 拆分出去,新建一个 usertime 表。

personalinfo 属性是更新和查询频率较低的,并且text字段占据了太多的空间。这时候,就要对此垂直拆分出 userext 表了。

4、数据量快速增长

随着业务的快速发展,单表中的数据量会持续增长,当性能接近瓶颈时,就需要考虑水平切分,做分库分表了。此时一定要选择合适的切分规则,提前预估好数据容量

5、安全性和可用性

鸡蛋不要放在一个篮子里。在业务层面上垂直切分,将不相关的业务的数据库分隔,因为每个业务的数据量、访问量都不同,不能因为一个业务把数据库搞挂而牵连到其他业务。利用水平切分,当一个数据库出现问题时,不会影响到100%的用户,每个库只承担业务的一部分数据,这样整体的可用性就能提高。

四. 案例分析

1、用户中心业务场景

用户中心是一个非常常见的业务,主要提供用户注册、登录、查询/修改等功能,其核心表为:

User(uid, login_name, passwd, sex, age, nickname)
uid为用户ID,  主键login_name, passwd, sex, age, nickname,  用户属性
ログイン後にコピー

任何脱离业务的架构设计都是耍流氓,在进行分库分表前,需要对业务场景需求进行梳理:

用户侧:前台访问,访问量较大,需要保证高可用和高一致性。主要有两类需求:

1. ユーザー ログイン: ログイン名/電話番号/電子メールを介してユーザー情報をクエリします。リクエストの 1% がこのタイプに属します。 2. ユーザー情報のクエリ: ログイン後、uid を介してユーザー情報をクエリします。リクエストの 99% がこのタイプに属します。 運用側: バックエンドにアクセスし、運用ニーズをサポートし、年齢、性別、ログイン時間、登録時間などに基づいてページング クエリを実行します。これは、アクセス量が少なく、可用性と一貫性に関する要件が低い内部システムです。

#2. 水平方向の分割方法

#データ量がますます大きくなると、前述のようにデータベースを水平方向に分割する必要があります。上記 分割方法には、「数値範囲に基づく」と「数値剰余に基づく」があります。

"数値範囲に従って":主キーuidを分割基準として、uidの範囲に応じてデータを複数のデータベースに水平分割します。たとえば、user-db1 は 0 ~ 1000w の範囲の uid を持つデータを格納し、user-db2 は 1000w ~ 2000wuid の範囲の uid を持つデータを格納します。

利点は:拡張が簡単で、容量が足りない場合は新しいデータベースを追加するだけです。

欠点は : リクエスト量が均一ではないことです。一般に、新しく登録されたユーザーの方がアクティブになるため、新しい user-db2 の負荷が user-db1 よりも高くなり、その結果、 Balance

"数値に基づくモジュロ": 主キー uid も除算の基礎として使用され、データは、データに基づいて複数のデータベースに水平に分割されます。 uid のモジュロ値。たとえば、user-db1 は uid データを法 1 で保存し、user-db2 は uid データを法 0 で保存します。

メリットは:データ量とリクエスト量が均等に分散される

デメリットは:拡張が面倒。新しいデータベースを追加します。再ハッシュが必要です。データのスムーズな移行を考慮する必要があります。

3. 非 uid クエリ方法

水平セグメント化後、uid によるクエリの要求は十分に満たされ、直接ルートすることができます。特定のデータベースに。 login_name などの非 uid に基づくクエリの場合、どのライブラリにアクセスする必要があるかが不明であり、この場合、すべてのライブラリを走査する必要があり、パフォーマンスが大幅に低下します。

ユーザー側では「非uid属性からuidへのマッピング関係を確立する」、運用側では「フロントエンドとバックエンドを分離する」という解決策が採れます。採用することができます。

3.1. 非 uid 属性から uid へのマッピング関係を確立します

1) マッピング関係

例:ログイン名を直接指定することはできません。データベースを見つけて、マッピング関係 login_name→uid を確立し、インデックス テーブルまたはキャッシュを使用してそれを保存できます。 loginname にアクセスするときは、まずマッピング テーブルを介して login_name に対応する uid を照会し、次に uid を介して特定のライブラリを見つけます。

マッピング テーブルには列が 2 つしかなく、大量のデータを保持できます。データ量が多すぎる場合は、マッピング テーブルを水平に分割することもできます。このタイプの kv 形式のインデックス構造では、キャッシュを使用してクエリのパフォーマンスを最適化でき、マッピング関係が頻繁に変更されず、キャッシュ ヒット率が非常に高くなります。

2) 遺伝子メソッド

サブライブラリ遺伝子: ライブラリが uid によって 8 つのライブラリに分割されている場合、uid%8 を使用してルーティングされます。このとき、最後のものによって決定されます。 uid の 3 ビット。ユーザー データのこの行がどのライブラリに該当するかを決定すると、これらの 3 ビットはサブライブラリ遺伝子と見なすことができます。

上記のマッピング関係メソッドでは、マッピング テーブルの追加ストレージが必要です。非 uid フィールドでクエリを実行する場合は、追加のデータベースまたはキャッシュ アクセスが必要です。冗長なストレージとクエリを排除したい場合は、関数 f を使用して、loginname 遺伝子を uid のサブライブラリ遺伝子として取得できます。 uid を生成するときは、上記の分散固有 ID 生成スキームに最後の 3 ビット値 = f (ログイン名) を加えたものを参照してください。ログイン名をクエリする場合、f(ログイン名)%8 の値を計算するだけで、特定のライブラリを見つけることができます。ただし、これには、事前に容量計画を立て、今後数年間でデータ量をいくつのデータベースに分割する必要があるかを見積もり、データベース遺伝子の特定のビット数を予約する必要があります。

##3.2. フロントデスクとバックデスクの分離

ユーザー側では、主な要件は、主に単一行のクエリが使用されることです。これらのフィールドのクエリの問題を解決するには、login_name/phone/email から uid へのマッピング関係を確立する必要があります。

運用面では、バッチページングや様々な条件を伴うクエリが多く、計算量が多く、返されるデータも多く、データベースのパフォーマンスも高くなります。このとき、同じバッチのサービスやデータベースがユーザー側と共有されている場合、少数のバックグラウンドリクエストが大量のデータベースリソースを占有し、ユーザー側のアクセスパフォーマンスの低下やタイムアウトが発生する可能性があります。

このようなビジネスは、運用側のバックエンド事業が独立したサービスやDBを抽出し、フロントエンドとの結合を解決する「フロントエンド・バックエンド分離」ソリューションを採用するのが最適です。エンドビジネスシステム。操作側は可用性や一貫性に対する高い要件を持たないため、リアルタイムライブラリにアクセスする必要はなく、binlog を介して操作ライブラリにデータを非同期に同期してアクセスできます。データ量が多い場合は、ES 検索エンジンや Hive を使用して、バックグラウンドで複雑なクエリ方法に対応することもできます。

5. データベースおよびテーブル シャーディング ミドルウェアのサポート

巨人の肩に乗れば、多くの労力を節約できます現在、データベースとテーブルをシャーディングするための比較的成熟したオープンソース ソリューションがすでにいくつかあります。
  • sharding-jdbc (Dangdang)
  • TSharding (モグストリート)
  • Atlas (Qihoo 360)
  • #Cobar (Alibaba)
  • MyCAT (Cobar ベース)
  • Oceanus (58.com) )
  • Vitess (Google)

以上がデータベースはデータベースとテーブルに分かれています。分割方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:Java后端技术全栈
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート