web-dev-qa-db-ja.com

SQL Server 2016、シャードを備えたマルチテナントシステム、またはテナントごとに個別のデータベースを介してテナントを分離する必要がありますか?

ユースケースを考えると:

  • テナントデータはクロストークしないでください。あるテナントは別のテナントのデータを必要としません。
  • 各テナントは、潜在的に大量の履歴データ量を持つ可能性があります。
  • SQL ServerはAWS EC2インスタンスでホストされています。
  • 各テナントは地理的に離れています。
  • PowerBI Embeddedなどのサードパーティの視覚化ツールを使用する意図があります
  • データ量は時間とともに増加すると予想されます
  • システムのコストは制限されています。
  • このソリューションは、年中無休の運用DBAがなくても保守可能でなければなりません。
  • ソリューションは水平方向に拡張できる必要があります。
  • テナントの総数が50未満

推奨アーキテクチャは何ですか?このユースケースのリファレンス実装はありますか?多くの人がエンタープライズソフトウェア開発でこの問題にすでに直面していると思います。

これは マルチテナントデータベースアーキテクチャで増加するテナントの処理 とは異なる状況だと思います。その質問で言及されているユースケースは、より多くのテナントを扱っています。言及されたアーキテクチャはここでの解決策かもしれません。それが私がもっと知りたいことです。

12
D.S.

シャーディングの問題点は、アプリケーションが照会するシャードを認識している必要があることです。通常、これはクライアントのようなものにシャーディングすることによって行われます。私は 私の古いブログ投稿の1つ を私の回答として使用するように適応させます。

多くのクライアント向けのアプリケーションを構築する場合、データベースを設計する一般的な方法は2つあります。

  • オプションA:すべてのクライアントを同じデータベースに配置する
  • オプション2:クライアントごとに1つのデータベースを構築する

すべてのクライアントを同じデータベースに置く

簡単です。スキーマの最上部にClientテーブルを追加し、ClientUsersテーブルを追加して、自分のデータのみが表示されるようにしてください。

このアプローチの利点:

より簡単なスキーマ管理。開発者がアプリケーションの新しいバージョンを展開するとき、1つのデータベースでスキーマを変更するだけで済みます。異なる顧客が同期していない、または間違ったバージョンであるという心配はありません。

パフォーマンスのチューニングが簡単になりました。インデックスの使用状況と統計情報を1か所で確認し、改善を簡単に実装して、すべてのクライアントですぐに効果を確認できます。数百または数千のデータベースでは、小さな変更でも調整が困難な場合があります。プロシージャキャッシュの内容を確認して、アプリケーション全体で最もクエリまたはストアドプロシージャが最も集中していることを確認できますが、クライアントごとに個別のデータベースを使用している場合、さまざまな実行プラン間でクエリの使用を集計するのに時間がかかります。

外部APIの構築がより簡単になりました。部外者が製品を構築するためにデータベース全体へのアクセスを許可する必要がある場合、すべてのデータは単一のデータベースにあります。 APIが複数のサーバー上の複数のデータベースからのデータのグループ化を処理する必要がある場合、開発とテストの時間が追加されます。 (その一方で、「複数のサーバー」ということは、1つのデータベースからすべてのルールへのシナリオの制限を示唆し始めます。1つのデータベースは通常、すべての負荷が1つのデータベースサーバーにのみ影響することを意味します。) 、PowerBIでは、全員を1つのデータベースに含めることで、接続の管理がはるかに簡単になります。

高可用性と災害復旧がより簡単になりました。データベースミラーリング、ログ配布、レプリケーション、およびクラスタリングを管理するのが本当に簡単なのは、 1つのデータベースのみ。インフラストラクチャーを素早く構築できます。

各クライアントを独自のデータベースまたはシャードに配置する

クライアントのリストはまだ必要ですが、ディレクトリになりました-各クライアントについて、それが存在するシャードも追跡します。起動時に、アプリはこのテーブルをクエリし、RAMにキャッシュします。クライアントのデータが必要な場合、そのシャード(データベースとサーバー)に直接接続します。

このアプローチの利点:

より簡単な単一クライアントの復元。クライアントは信頼できないミートバッグです。 (私のものを除いて-彼らは信頼できるミートバッグです。)彼らはすべてのデータを特定の時点に戻す必要があるあらゆる種類の「おっと」瞬間を持っています。同じテーブル内の他のクライアントデータ。単一クライアントデータベースシナリオでの復元は非常に簡単です。クライアントのデータベースを復元するだけです。他の誰も影響を受けません。

より簡単なデータのエクスポート。クライアントはデータを手に入れることが大好きです。彼らは、恐ろしいベンダーロックインシナリオを回避し、いつでも自分のデータを取り出せるというセキュリティを求めており、独自のレポートを作成したいと考えています。各クライアントのデータが独自のデータベースに分離されているため、クライアントに独自のデータベースバックアップのコピーを提供するだけです。データエクスポートAPIを構築する必要はありません。

より簡単なマルチサーバースケーラビリティ。アプリケーションが単一のサーバーから得られるよりも多くの電力を必要とする場合、複数のサーバー間でデータベースを分割できます。また、負荷を地理的に分散して、アジアやヨーロッパのサーバーをクライアントに近づけることもできます。

クライアントごとのパフォーマンスチューニングがより簡単になります。一部のクライアントが異なる機能またはレポートを使用する場合は、これらのクライアントだけのために、インデックスまたはインデックス付きビューの特別なセットを構築できます。全員のデータサイズを拡大する。確かに、ここにはいくつかのリスクがあります。クライアント間のスキーマの違いを許可することにより、コードの展開を少しリスクを高め、パフォーマンス管理をより困難にしました。

より簡単なセキュリティ管理。データベースごとに1人のユーザーでセキュリティを適切にロックダウンしている限り、クライアントXがクライアントにアクセスすることを心配する必要はありません。 Yのデータ。ただし、すべてのユーザーに1つのログインを使用するだけでは、この問題に対処できていません。

より簡単なメンテナンスウィンドウ。顧客が世界中に点在しているグローバル環境では、グループ単位で行うことができれば、メンテナンスのために顧客をオフラインにしたほうが簡単です。ゾーン。

どちらがあなたにぴったりですか?

正しい選択は1つではありません。自分の会社の長所と短所を知る必要があります。 2つのクライアントを例に考えてみましょう。

A社は、ハードウェアパフォーマンスのチューニングに優れています。彼らは本当に、ハードウェアから最後のパフォーマンスを引き出すことに長けており、12〜18か月のサイクルでSQL Serverハードウェアを交換してもかまいません。 (4〜6か月ごとにWebサーバーを更新します!)彼らのアキレス腱は非常に高いコンプライアンスとセキュリティ要件です。彼らには信じられないほどの監査ニーズがあり、数十のサーバー上の数千のデータベースにわたる要件を管理するよりも、単一のサーバー、単一のデータベースに防弾制御を実装する方が簡単です。彼らは1つのデータベース、1つのサーバー、多くのクライアントを選択しました。

Company 2は開発プラクティスに優れています。何千ものデータベースにわたるスキーマの変更とコードの導入の管理は、それらにとって問題ではありません。彼らは世界中にクライアントを抱えており、24時間体制でそれらのクライアントのクレジットカード取引を処理しています。地理的に負荷を分散する機能が必要であり、12〜18か月ごとに世界中のサーバーを交換したくない。彼らはクライアントごとに1つのデータベースを選択し、オフショアクライアント向けにSQL Serverをアジアとヨーロッパに配置し始めたので、それは成果を上げています。

16
Brent Ozar

他の回答ではまだ見たことのないもう1つの考慮事項。

単一のデータベースで多くのテナントを許可する設計にすると、後で柔軟性が得られます。ロード/スケールアウト/セキュリティ/地理的位置の要求により、テナントは新しいインスタンスで現在のDBを復元することで作成できる別のデータベースを作成する必要があることを後で示唆します。他のテナントのデータは、配置されているメカニズムによって保護されています。時間の許す限り、古くなったデータは古いデータベースと新しいデータベースの両方から少しずつ削除できます。

逆は当てはまりません。多くのワンテナントデータベースを統合するには、かなり多くの作業が必要になります。

5
Michael Green

正規化*に違反しても、マルチテナントモデルをはるかに簡単にする1つの方法は、テナントのすべてのテーブルに列を含めることです。あなたはそれをTenantIDと呼ぶことができます。このようにして、データベースに対して実行されるすべてのクエリは、すべてのテーブルのTenantIDでフィルタリングできます。また、データベースパーティションを使用して、各テナントのデータを分離し、パーティションを揃えることでクエリを高速化できます。この方法では、すべてのテナントを1つのデータベースに入れる方がはるかに簡単です。

*常に正規化が解除されるわけではありませんが、解除される可能性があります。たとえば、PersonテーブルとPersonAddressテーブルがあるとします。 PersonテーブルにはTenantID, PersonIDを主キーとして。 PersonAddressテーブルにはTenantID, PersonID, AddressTypeID主キーとして、私が提案しているものを使用します。

通常、PersonIDで十分です。これは、Personテーブルに結合してTenantを見つけることができるためです。薄いキーが機能する場合でも、後続のすべてのテーブルにTenantIDを転送することをお勧めします。

他のデータから導き出される可能性のある情報をテーブルに持ち越すことは、正規化を壊すと考えられていたことが私の理解でした。しかし、おそらく、シンキーの使用は単なるベストプラクティスです。

4
Matthew Sontum