私がこれまでに対処しなければならなかったすべてのプロジェクトは、単一のサーバー上の単一のデータベースのみを必要としました。負荷の管理を支援するために、スケーリングが必要なプロジェクトを複数のデータベースやサーバーに移動する方法について、もっと知りたいと思っています。私は High Scalability を知っていますが、この件についてさらに読むことができるいくつかのコード例や追加のリソースに特に興味があります。
例えば:
では、分解してみましょう。
これは非常に簡単です。 SQLオブジェクトには、1〜4つの部分からなる命名規則があります。
Servername.databasename.schemaname.tablename
すべてのテーブルが同じデータベース上の同じサーバー上にあり、同じ所有者/スキーマを持つ場合、最初の3つの部分を無視して、最も慣れているものを使用できます。
Select a.*,b.* from
tableA a inner join
tableB b on a.col1=b.col1
テーブルの1つが別のデータベースにあり、両方がデータベースのデフォルトスキーマを使用している場合は、データベースを2番目のテーブルに追加するだけです。
Select a.*,b.* from
tableA a inner join
databaseC..tableB b on a.col1 = b.col1
クエリしているデータベースのいずれとも異なる3番目のデータベースにいる場合は、両方のデータベース名を明示的に使用します。
Select a.*,b.* from
databaseD..tableA a inner join
databaseC..tableB b on a.col1 = b.col1
異なるスキーマや所有者を使用することになる場合は、それらを次の場所に追加できます。
Select a.*,b.* from
databaseD.john.tableA a inner join
databaseC.accounting.tableB b on a.col1 = b.col1
最後に、非常に注意深く、十分な理由がある場合は、別のサーバーの(通常は小さい)テーブルに参加できます。
Select a.* from
databaseD.john.TableA a inner join
ATLANTA.databaseC.accounting.tableB b on a.col1 = b.col1
一緒に行くので、これら2つを組み合わせます。ほとんどの場合、設計/ビジネス/技術上の制約によりさらに使用するように強制されるまで、1つのデータベースと1つのサーバーで十分であるという想定から始めるのが一般的です。
したがって、最初の2番目の質問に最初に答えるには、一般にデータベースが個別にある理由があるので、何かがどこにあるか、システムの設計を知ることからかなり明白になるはずです。
単一のデータベースを超えて移動する必要がある場合/理由について。通常、これはビジネスルール、政治、技術的な理由の組み合わせです。
たとえば、私が作業している場所には、4つのサーバーに分散した16のデータベースがあります。 MainDB、ImageDB、referencetableDB、HighvolumeTransactionDB、ReportingDB、StagingDB、ProcessingDB、ArchiveDB、FinancialDBがあります。それらが異なる理由の例をいくつか挙げます。
•アプリケーションコードは、1つ以上のデータベースが複数のサーバーに分散していることを認識する必要がありますか?そうでない場合、要求はどのレベルでフィルタリングされますか?
広い意味では、おそらくそうです。少なくとも、データベース接続文字列で指しているサーバーを知る必要があります。処理、レポート、メインなど.
そこから、データベースコンテキストを実行する必要があります。一般に、これはアプリケーションで最も使用されるものです。おそらく、アプリケーションの1データベース/ 1サーバー日からのオリジナルのものです。すべての呼び出しでアプリケーションにデータベースコンテキストを明示的に切り替えることはできますが、アプリを変更せずにデータベースを調整することは非常に困難です。
通常の(または少なくとも私の通常の)アプローチは、常に1つまたはおそらく2つのメインデータベースを介してアクセスすることです。
次に、必要に応じて、ストアドプロシージャを介したデータベースとのインターフェイスと組み合わせて、他のデータベースへのビューを作成します。
だから説明する:
クライアントの人口統計情報、販売データ、クレジット残高を取得したいとします。これらは、もともとすべてMainDBにある3つのテーブルにまたがっています。
したがって、アプリからの呼び出しを記述します。
Select c.ClientName, c.ClientAddress, s.totalSales,f.CreditBlance from
Clients c join Sales s on c.clientid = s.clientid inner join AccountReceivable f on
c.clientid=f.clientid where c.clientid = @clientid
驚くばかり。ただし、今では、カラム名を変更したり、テーブルの名前を変更したり移動したりするたびに、アプリのコードを更新する必要があります。したがって、代わりに次の2つのことを行います。
クライアント、セールス、AccountReceivablesビューを作成します(選択*は使用しませんが、ここではデモを行っています)
Use MainDB
GO
Create view v_Clients as select * from Clients
Create view v_Sales as select * from Sales
Create view v_AccountReceivable as select * from AccountReceivable
Go
次に、ストアドプロシージャspGetClientSalesARも作成します。
Create proc spGetClientSalesAR @clientID int
as
Select c.ClientName as ClientName,
c.ClientAddress as ClientAddress,
s.totalSales as TotalSales,
f.CreditBlance as CreditBalance
from
v_Clients c join v_Sales s
on c.clientid = s.clientid
inner join v_AccountReceivable f
on c.clientid=f.clientid
where c.clientid = @clientid
そしてあなたのアプリにそれを呼ばせてください。
このストアドプロシージャのインターフェイスを変更しない限り、スケールアップまたはスケールアウトするためにバックエンドデータベースに対して行う必要があることはほとんど何でもできます。
極端な場合、私が作成したこれらのビューの下が次のようになるように、古いMainDBを一連のシェル化されたストアドプロシージャとビューにすることもできます。
Create view v_Clients as select * from ServerX.DatabaseY.dbo.Clients
Create view v_Sales as select * from ServerQ.DatabaseP.dbo.Sales
Create view v_AccountReceivable as select * from ServerJ.DatabaseK.dbo.AccountReceivable
そして、あなたのアプリはその違いを決して知りません(とりわけ、高速パイプと適切にステージングされたデータを想定しています)。
明らかにそれは極端であり、私がすべてがこのように計画されたと言ったら嘘をつくでしょうが、リファクタリング中にそれを実行しても、ストアドプロシージャ/ビューを使用すると、アプリがその1つのデータベース/ 1つのサーバーから大きくなるにつれて、多くの柔軟性が得られます始まり。
Webの世界で複数のデータベースサーバーに遭遇した主な方法(質問にPHPのタグが付けられているため)は、1つの「マスター」(書き込み)データベースと、1つ以上の複製された「スレーブ」(読み取り)データベースがあったセットアップです。データベースの書き込みは、「マスター」データベースに対して実行されます。そのデータベースの内容は、ほぼリアルタイムで「スレーブ」サーバーに複製されます。次に、クエリ(特に集中的なレポート)が「スレーブ」データベースの1つに対して実行され、それらのサーバーに負荷がシフトされます。この特定の設定は、読み取りは多いが書き込みは多くないアプリケーションに最適です。 物事をアレンジする唯一の方法ではありません。
複数のデータベースの2つのテーブル間で結合はどのように構築されますか? (ここのコード例は役に立ちます)。
そうではありません。 NoSQLデータベースは「結合」をまったく行わないため、 could でRDBMSサーバー間でSQL結合を行ったとしても、パフォーマンスを重視する場合はそうしたくないでしょう(cf- 分散コンピューティングの誤り )。
どのテーブルがどのデータベースにあるかを追跡するための特別な戦略はありますか?
リレーショナル/ SQLデータベースでは、パーティション化は通常、異なるディスクに配置された異なるファイルを使用して、単一のサーバー/データベースの範囲内で行われます。ほぼ定義により、水平スケーリングソリューションは、 all データベースに all テーブルがあり、何らかのトランザクションミラーリング、レプリケーション、またはカスタムがあることを意味しますすべてのデータが想定された場所に確実に到達するようにする結果整合性ソリューション。
実際にデータベースを物理的にだけでなく logical /に分割している場合、DALまたはORMで定義されたマッピングは、どのデータベースがどのデータベースにあるかを宣言します。
NoSQLデータベースは、パーティション分割ソリューションの混合です。時々、パーティション化されるのは「テーブル」(またはより一般的には「コレクション」)です。それ以外の場合は、「行」(または「ドキュメント」)です。 HBaseのような列指向のデータベースのように、実際には columns の場合もあります。それはあなたが使っているテクノロジーに完全に依存します。これらすべてに共通していることの1つは、エンジン自体がすべてを追跡するため、ドキュメントまたは行を要求するだけです。
もちろん、実際にシャーディング機能を利用していて、さまざまなデータベースを作成するだけではないことを前提としています。後者を実行している場合は、自分で行います。
アプリケーションコードは、1つ以上のデータベースが複数のサーバーに分散していることを知る必要がありますか?そうでない場合、どのレベルでリクエストがフィルタリングされますか?
それらが異なる logical データベースであれば、はい。それらが physically のみに分散されている場合は、特定のデータベースがシャーディングをネイティブでサポートしているか、またはロードバランシングソリューション(SQLデータベースの場合)を使用していると想定してください。また、すべての操作がステートレスであると仮定します。水平スケーリングが必要な場合は、ACIDをあきらめる必要があります。
1データベース/ 1サーバーの設定を超える時期はいつですか?これを行う必要があるのはどのくらい一般的ですか?
1つのサーバーで可能な限りすべてを最適化しても、I/O負荷の制約のために十分なパフォーマンスを引き出すことができないときです。質問しなければならない場合、それは早すぎます。
まともなRDBMS製品(Oracle、SQL Server)でのパフォーマンスの問題は、設計の悪さ、インデックスの不足、クエリの不足、ロックの競合などが原因であることが多いことに注意してください。これらの製品は、とんでもない程度に垂直に拡張できます。繰り返しますが、絶対に確実である場合は、「1データベース/ 1サーバーの設定を超えて移動する」ことを検討する必要があります。パフォーマンスの問題は、ハードウェアの制限によるものであり、単なる準設計/実装ではありません。
あるいは、一部の人々が分散データベースに切り替えるもう1つの理由は、ライセンス料に多額の(またはすべての)お金を払う準備ができておらず、低コストをアプリケーションの複雑さの増大と引き換えに意識的な選択肢としてSQLを捨てたい場合です。ソフトウェアの新興企業であるが、通常は企業部門には該当しない場合は、完全に正当な理由。
データベースのレプリケーション構成には、主に3つのタイプがあります。
マスタースレーブの例:MySQLマスター+ MySQLスレーブ、MongoDB
マスターマスターの例:CouchDB、Cassandra、Riak
コンセンサスの例:ScalienDB
...いくつか例を挙げましょう。
これらには異なる特徴があります。マスター/スレーブ構成により、マスターサーバーがデータの整合性を担当している間に、スレーブノードが最大速度でマスターに追いつき、読み取り要求を非常に迅速に処理できます。すべての書き込みはマスターに送られるため、単一の比較的遅いライターが多くのリーダーをブロックしているため、ロック競合はありませんが、一方でスレーブサーバーは最終的に一貫しており、トランザクションの分離が保証されません。マスターからのみ読むことから。 (参考資料:ACIDとBASE、トランザクション分離レベル、データベースレプリケーション、MVCC /分離:スナップショット、トランザクションレプリケーション)
マスター-マスターは常に書き込みを許可するため、何が正しいのかについて複数の権限を持つことになります。これは、アプリケーションの動作に応じて、問題になる場合とそうでない場合がありますが、競合するデータを書き込むと、次にアプリケーションロジックとマージする必要があるそのキー/行/列を読み取るときに複数の結果が得られる可能性があります。データベースに保存し直します。 (参考資料:CAP-theorem、CouchDBレプリケーション、Riakレプリケーション、一貫性のあるハッシュ、Bitcask&StormDB、クォーラム-w/MongoDB(ネットワーク分割、マージ解決戦略))
Scalienなどのノード間でレプリケーションを行うコンセンサスベースのデータベースは、書き込みでは常に整合性がありますが、書き込みにACKを送信する前に複数のメッセージを交換するという犠牲が伴います。高速のイーサネットを使用していて、ACKする前にディスクに書き込む必要がない場合、これはそれほど問題ではありません。最低3台のサーバーが別々の電源装置を備えた異なるサーバーラックにある場合は必要ありません(1つ死ぬ;他の2つはそれらがディスクに保存されたことを確認する)。 (参考資料:PAXOS、PAXOS COMMIT、分散トランザクションを使用する2フェーズコミット、3フェーズコミット)
その他の参考資料:(本:「分散コンピューティングの要素」、ベクトルクロック、バージョンベクトル、行列ベクトル、論理クロック、ベーカリーアルゴリズム、インターバルツリークロック、アクターとリアクティブプログラミングとリアクター、ソフトウェアトランザクションメモリ、トランザクション、AKKA、Stact、分散コンピューティングの誤り、ゴシッププロトコル、Cassandraのアンチエントロピーゴシッププロトコル拡張、分散ハッシュテーブル、分散設定でのデータのマージに関する論文、ZooKeeperアーキテクチャ、「非同期プロトコル」に関するInfoQプレゼンテーション、HBaseアーキテクチャ、MapReduce論文、Amazon Dynamo論文それはすべてのNoSQLもの、キューイング、rabbitmq高可用性クラスタリングを開始しました)
私は考えのためにいくつかの食べ物を与えたと思います:)このことについてツイートしたい場合は、Twitter @henrikfeldtで私をフォローしてください。
では、スケーラビリティに関する別の視点を見てみましょう。
データであることの意味、振る舞いを持つことの意味、アプリケーションロジックを持つことの意味について説明しましょう。
通常、企業アプリケーションなどの領域に進出すると、階層化のアイデアに触れることになります。もちろん、レイヤーは、ネットワークスタック(ISOモデル)、グラフィック(Photoshop)、またはSOA)などのコンピューター内のあらゆる場所にあります(サービスは兄弟または子を呼び出す場合があります。しかし、両親はありません)。
ただし、これまで何も考慮されずに悪用されてきた特定の種類の階層化は、「GUI」、「ビジネスロジックレイヤー」、「データアクセスレイヤー」のレイヤーです。つまり、そうです、共産主義は原則的に良いのと同じように、アイデアは原則的に良いですが、実際にはそうではありません。
その理由を見てみましょう。私が使うつもりの議論はカップリングについてです。別のレイヤーのポイントに接触する1つのレイヤーのポイント。人々が入るdefault-enterprisey-modeでn層(レイヤードアプリ)の作成を開始すると、レイヤー間に非常に多くの接点が作成されます。
基本的に、レイヤーは交換可能であるという考え方です。しかし、そうではありません!どうして?すべての呼び出しサイトのカップリングのため。
代わりに、ネットワークが分離されている理由を確認してください!インターフェイスが開いているソケットを指す単一のファイルポインター上のバイトストリームであるためです! ISOモデルのすべてのレイヤーは、オブジェクト指向に対する「責任の連鎖」と呼ばれる設計パターンのようなものです。各層は、基になる層のデータのセマンティクスを知らなくても、基になる層をラップします。
データのパッケージがイーサネットと生の電気信号に向かって歩いていくと、固有のメッセージエンベロープ、つまり送信できる独自の「バイトのバッチ」のみを知っているレイヤーによって継続的にラップされます。何もありません。パッケージの内容に応じて、呼び出しパスを変更する必要はありません。
これをn層と比較すると、データベースへの途中でレイヤーをトラバースする「コール」でアプリケーションレイヤーのコールパスを変更する必要があります。 「サブクラスごとのテーブル」を使用するので、データ(エンティティ)がレイヤーをトラバースしているので、これについて知る必要があります。いわゆる「ビジネスロジックレイヤー」と、実際に保存を行っているデータレイヤーの両方で。
コンピューティングの観点から見ると、スケーラブルでも最適でもありません。
なぜスケーラブルではないのですか?アーキテクチャが結合されているため、多くのノードにスケールアウトしようとしていたのと同じ古いDB内にいることになります。ただし、これにはACID、その3番目のエンティティ(データオブジェクト)が必要なので、トランザクションを実行する単一のデータベースにそれらを含める必要があります。
正解です。そういうわけではありません。他にどのような方法がありますか?
さて、「SOA」と呼ばれる憎まれた頭字語、つまりサービス指向アーキテクチャがあります。もちろん、 Tomas Erls of the world を使用すると、すべてのレイヤーを実装できますが、代わりにXMLとSOAPを使用します。
上記のすべての理由から、これは間違った方法です。上で説明したように、アプリケーションレイヤーに自分を結合するのと同じように、これらのXMLプロキシに自分を結合するからです。
代わりに、メッセージングを使用して、機能を実装するものは何でも、それらをリッスンしてください。サービスサーフェイスは、送信可能なメッセージのリストになり、操作をサービスファサードに結合していません。他のルーティングメカニズムが正しいコンシューマにルーティングするメッセージをパブリッシュするだけなので、これらの操作を実装するアプリケーションまたはエンドポイントを知る必要もありません。
サービスファサードを、実行する実際の操作から切り離したため、複数のサービスを追加できます。実際、これがNetflixのやり方です。次のプレゼンテーションをご覧ください: http://www.slideshare.net/adrianco/global-netflix-platform 。 http://www.slideshare.net/adrianco/global-netflix-platform 。いいね!
弾性スケーリングプロパティを持つと主張されているベータ版の 新しいSQL(ACID)データベース があります。現在進行中の無料のベータプログラムがあり、NuoDBと呼ばれる、ご覧になることをお勧めします。
どうやら、それはシングルスレッドマシン上でもMySQLを簡単に上回りますが、特定のベンチマークでは70以上のインスタンスにうまくスケーリングします。