マルチテナントデータベースアーキテクチャで増え続けるテナントの処理


26

アプリケーションのテナントのインスタンスごとに個別のデータベースを持つ共通サーバーで適度な数の顧客(テナント)を処理するのは比較的簡単で、通常これを行う正しい方法です。現在、各テナントが独自のデータベースインスタンスを持つアプリケーションのアーキテクチャを検討しています。

ただし、問題は、このアプリケーションに多数のテナント(5,000〜10,000)があり、かなりの数のユーザー(おそらく単一のテナントでは2,000)があることです。毎週数人のテナントによるシステムの成長をサポートする必要があります。

さらに、すべてのテナントとそのユーザーに共通のログインプロセスが表示されます(つまり、各テナントが独自のURLを持つことはできません)。これを行うには、集中ログインプロセスと、システムにデータベースを動的に追加し、ユーザーを登録する手段が必要です。

  • 登録およびデータベース作成プロセスをどのように堅牢に自動化できますか?

  • システムでテナントのデータベースを作成および登録するプロセスは、パフォーマンスまたはロックの問題を引き起こす可能性がありますか?これが問題になると思われる場合、誰でもそれを軽減する方法を提案できますか?

  • ユーザー資格情報が特定のテナントのデータベースに関連付けられているが、ユーザーは共通のページからログインできる(つまり、すべて同じログインURLであるが、ホームアプリケーションは特定のテナントのデータベースにある)方法で中央認証を管理する方法)。テナントは独自のログインとアクセス許可を維持できる必要がありますが、中央ログインシステムはこれらを認識している必要があります。誰でもこれを行う方法を提案できますか?

  • 複数のデータベースサーバーを追加して「スケールアウト」する必要がある場合、サーバー全体のユーザーIDの管理(なりすましなど)で対処しなければならない問題と、それらの問題を軽減する方法を誰か提案できますか?


1
このような状況に対処する必要はありませんでしたが、私の直感では、サーバーが処理できると考えられる数のテナントデータベースを事前に構成してテナントのロールアウトを処理し、事前に構築されたテナントデータベースを新しいテナントとして割り当てるだけですサインアップ。これにより、少なくともテナントDBを展開する際にリソースの競合を心配する必要がなくなります。
ジョエルブラウン

1
5,000〜10,000テナントに近い場所を確保しますか?そして、あなたのすべてのテナントは2,000ユーザーの範囲にいるのでしょうか?私のシステムでは、単一のテナントに対するアプリケーションのユーザーの最大数は約100人だと思います。そのうちわずか20人ほどが常にアクティブでした。業界/アプリケーションとは何ですか?
アーロンバートランド

@AaronBertrandは、サービスの一部が無料で一部が有料の学習管理システムです。
-coddey

回答:


25

下端(500テナント/ 10000ユーザー)では、これが私がやった方法です。まず、グローバルで中央の「コントロール」データベースがあり、テナントとユーザーに関するすべての情報が含まれています(これらをSQL authログインとして管理したいとは本当に思わないでしょう)。したがって、次の表を持つ「Control」というデータベースを想像してください。

CREATE TABLE dbo.Instances
(
  InstanceID INT PRIMARY KEY,
  Connection VARCHAR(255)
  --, ...
);

INSERT dbo.Instances SELECT 1, 'PROD1\Instance1';
INSERT dbo.Instances SELECT 1, 'PROD2\Instance1';
-- ...

CREATE TABLE dbo.Tenants
(
  TenantID INT PRIMARY KEY,
  Name NVARCHAR(255) NOT NULL UNIQUE,
  InstanceID INT -- Foreign key tells which instance this tenant's DB is on
  --, ...
);

INSERT dbo.Tenants SELECT 1, 'MyTenant', 1;
-- ...

CREATE TABLE dbo.Users
(
  UserID INT PRIMARY KEY,
  Username VARCHAR(320) NOT NULL UNIQUE,
  PasswordHash VARBINARY(64), -- because you never store plain text, right?
  TenantID INT -- foreign key
  --, ...
);

INSERT dbo.Users SELECT 1, 'foo@bar.com', 0x43..., 1;

私たちの場合、新しいテナントを追加したときにデータベースを動的に構築しますが、管理ユーザーがUIで[OK]をクリックしたときではなく、5分ごとに新しいデータベースをキューから取り出し、modelをsingle_userに設定するバックグラウンドジョブがありました、そして各新しいデータベースを順次作成しました。これは、(a)管理者ユーザーがデータベースの作成を待つのを防ぐため、および(b)2人の管理者ユーザーが同時にデータベースを作成しようとしたり、モデルをロックする機能を拒否されたりするのを防ぐために行いました(新しいデータベースの作成時に必要) )。

データベースはTenant000000xxxx表されている名前スキームで作成されましたTenants.TenantID。これは、代わりに名前付きデータベースのすべての種類有するので、非常に簡単メンテナンスジョブを作ったBurgerKingMcDonaldsKFCその一例としてだけ使用して、我々はファーストフードにあったていないことなどを。

コメントが示唆するように何千ものデータベースを事前に割り当てなかった理由は、管理ユーザーは通常、テナントがどれだけ大きくなるか、優先度が高いかどうかなどをある程度知っていたためです。初期サイズと自動拡張設定、データ/ログファイルの保存先となるディスクサブシステム、リカバリ設定、ヒンジオフするバックアップスケジュール、および使用量を最適に分散するためにデータベースを展開するインスタンスについても決定します(ただし、管理者がこれをオーバーライドできます)。データベースが作成されると、テナントテーブルが選択したインスタンスで更新され、テナントの管理ユーザーが作成され、管理者に新しいテナントに渡す資格情報が電子メールで送信されました。

単一のエントリポイントを使用している場合、複数のテナントに同じユーザー名を持つユーザーを許可することはできません。電子メールアドレスを使用することを選択しました。すべてのユーザーが会社で働いており、企業の電子メールアドレスを使用している場合は問題ありません。ただし、次の2つの理由により、ソリューションは最終的に複雑になりました。

  1. 複数のクライアントで働くコンサルタントがいて、複数のクライアントにアクセスする必要がありました
  2. 実際に複数のテナントで構成されるテナントがありました

そのため、TenantUsers1人のユーザーを複数のテナントに関連付けることができるテーブルができました。

ユーザーが最初にログインすると、アプリは制御データベースの接続文字列のみを認識します。ログインが成功すると、見つかった情報に基づいて接続文字列を作成できます。例えば

SELECT i.Connection
  FROM dbo.Instances AS i
  INNER JOIN dbo.Tenants AS t
  ON i.InstanceID = t.InstanceID
  INNER JOIN dbo.TenantUsers AS u
  ON i.TenantID = u.TenantID
  WHERE u.UserID = @UserID;

これで、アプリはユーザーのデータベースに接続できるようになり(各ユーザーにはデフォルトのテナントがありました)、ユーザーはアクセス可能なテナントから選択できるようになりました。その後、アプリは新しい接続文字列を取得し、そのテナントのホームページにリダイレクトするだけです。

あなたが提案するこの10MMのユーザーエリアに入ると、あなたは間違いなくこれをより良くバランスさせる必要があります。異なる制御データベースに接続する異なるエントリポイントを持つように、アプリケーションを統合することができます。各テナントにサブドメイン(TenantName.YourApplicationDomain.comなど)を付与すると、さらにスケールアウトする必要があるときにそれらを中断することなく、DNS /ルーティングでバックグラウンドでこれを行うことができます。

これにはもっと多くのことがあります-@Darinのように、ここで表面をひっかいているだけです。非無料相談が必要な場合はお知らせください。:-)


経験を共有していただきありがとうございます。しかし、すでにNon-freeを書いています。:(
coddey

1
私のポイントは、無料のアドバイスに割り当てる時間しかないということです。:-)
アーロンバートランド

+1-以前に使用したのとほぼ同じアプローチ。〜同じ数のテナントも、本当にうまくいきました。
AdaTheDev

マスターデータベースとテナントデータベース間の関係を処理する方法 (トリガーなどを使用せず)
Jitendra Pancholi

@jitendraはあまり多くのオプションではありません-マスターデータベースのデータに関連付ける必要があるテナントデータベースには実際にどのくらいのデータがありますか?...適切に書かれたトリガの恐れることは何もありません-私はまた必ず、私はトリガの人気の恐怖は理解していないよ
アーロンバートランド

10

あなたには、とても興味深いプロジェクトがあります。少なくともSQL Serverでこれほど大きなものを実装しようとする人を直接見たことはありません。あなたの投稿を読むほど、私はより多くの質問を思いつきます...

インフラストラクチャの観点からみた最悪のケースシナリオ(実際にはビジネスの観点から見てベストケースシナリオです)には、1万のデータベースと2万のユーザーが必要です。これは20,000,000人のユーザーです。20 MのSQL Serverログインを管理しようとしても成功しません。IMO。サーバーからサーバーへの移動、IDの衝突と不一致IDの監視、およびsys.server_principalsの20 M行でSQL Serverがどのように動作するかはわかりません。さらに、Webアプリはおそらく、単一の、または非常に少数のユーザーとして接続したいと思うでしょう。IISは、DSN文字列が同一でない限り、接続をプールできません。DSN文字列の属性の1つはユーザー名です。異なるユーザーはプーリングを意味しません。

独自のユーザー資格情報スキームを展開する必要があります。ユーザーがどのテナントに属しているかを把握できるようにする必要があり、Webコードは適切なデータベースを選択する必要があります。そのユーザーメタデータは重要であり、どこかに保存する必要があり、クラスター化またはミラーリングする必要があり、高速であり、十分に保護する必要があります(セキュリティの観点から。IOW、暗号化してください。)。ここでSQLが良いアイデアであると仮定すると、このデータベースは、テナントをサーバーするインスタンスから遠ざけます。これは、セキュリティの観点と負荷の観点から役立ちますが、ユーザーが検証され、Webアプリが別のインスタンスの正しいデータベースにステアリングされると、それに関連するこのユーザーメタデータのクエリはこれ以上なくなると思いますユーザー。

簡単な質問:2つの異なるテナントに属する2人の異なるユーザーが同じユーザー名を持つことを許可する必要がありますか?

別の簡単な質問:FuBar、Inc.で働いていると言ったら、どうやってそれを知っていますか?FuBarはユーザーのリストを提供し、ユーザーにユーザー名のリストを提供しますか、それともセルフプロビジョニングしますか?

マルチインスタンスに移行する必要があります。それらのユーザーのごく一部が一度にアプリケーションにアクセスすることにした場合、単一のインスタンスが溶けます。これらの要求を一度に実行するのに十分なワーカースレッドがありません。同時に1000人のユーザーのみがインスタンスにヒットした場合、おそらくワーカースレッドが不足し、リクエストはスタックして待機し始めます。これが起こるのを見てきました。近い症状は、それらを処理するための利用可能なワーカースレッドがないため、新しい接続がインスタンスにログインできないことです。これが非常に短命の動作である場合、アプリは存続する可能性があります。そうでない場合、またはアプリがうるさい場合、ユーザーはエラーを受け取ります。

開始するテナントがそれほど多くない場合でも、サーバーが行き詰まり、オンラインにする新しいテナントが10あることがわかると、それはかなり遅すぎて、サービス(およびサービス)あなたのクライアント、そしてすぐに元クライアントになる)は、あなたが問題から抜け出す方法を書くまで苦しみます。

過負荷のサーバーから負荷の軽い(または新しい)サーバーにデータベースを移動する方法が必要になります。ダウンタイムのウィンドウを取得できるかどうかは、SLAに依存します。

SalesForceのような特定のアプリケーションを提供していますか、またはこれらのデータベースはテナントが入れたいものの単なるコンテナですか?

データベースはどれくらいの大きさですか?それほど大きくない場合は、テンプレートを提供するバックアップファイルから復元するだけで済みます。(これは、モデルデータベースの動作と大差ありませんが、SQL 6.5を使用していた頃から、実際にモデルを良い方法で使用している人はいません。)テンプレートが新しいデータベース名に復元されたら、次に、特定のテナントの必要に応じて新しいデータベースをカスタマイズします。明らかに、テナントを持つ前にカスタマイズを行うことはできません。データベースが大きい場合、新しいテナントがスペースを必要とする前に事前に復元を行うことを除いて、同じ基本手順に従うことができます。これらのデータベースを数個、おそらくインスタンスごとに1個保持してください。あまりにも多くのデバイスを保持していると、必要以上のハードウェアやストレージを購入することになります。

これが自分のアプリである場合、スキーマの更新をどのように処理しますか?Webアプリにアクセスする単一のURLを使用している場合、どのようにしてデータベースのバージョンをコードのバージョンと一致させますか?

使用されなくなったデータベースをどのように検出して破棄しますか?A / Rグループが誰かが3か月間請求書を支払っていないと言うまで待ちますか?

テナントが権限を管理している場合、アプリの内部動作をある程度理解していること、またはアプリのロール構造が非常に単純であることを意味します。Bloggerなどを大まかな例として使用すると、ユーザーは(投稿を読む)、(投稿を読んでコメントを作成する)、(...投稿を作成する)、(...他の投稿を編集する)、(...リセットすることができます他のユーザーのパスワード)、または(...など)。これらのさまざまな権限のセットごとに役割を持ち、ユーザーを1つの役割または別の役割に割り当てることは難しくありませんが、アプリで「GRANT」ステートメントを実行することは望ましくありません。階層を持ち、継承に依存するロールには注意してください。混乱する可能性があります。ユーザーを昇格または降格する場合、関連するすべてのロールからそれらを引き出してから、必要な1つのロールに追加し直します。ああ、

私はここで表面をひっかいただけだと思います、そしてこの投稿はすでに長すぎます。本当に必要なのは本、または少なくともこれを行った人からのホワイトペーパーです。それらの人たちのほとんどは、彼らがそれを競争上の優位性とみなすならば、話をしません。


コメントをありがとう。確かにプロジェクトは興味深い。単語の制限により、コメントは非常に正確に保ちます。これは、各テナントが約120〜150のテーブルを持つ学習管理システムです。テナントに関係なく、同じユーザー名を持つユーザーはいません。さらに複雑さを軽減するために、DNS CNAMEマッピングの例としてtenant1.abc.comを使用します。今、沸騰点は-あなたが共有しているすべての提案に応えるために正しい方法で設計することであり、私は心配しています。ホワイトペーパーを入手することは賞賛に値しますが、おそらく簡単ではありません。!!!!
-coddey
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.