MySQLテーブルのシャーディングに最適なアプローチは何ですか。私が考えることができるアプローチは次のとおりです:
- アプリケーションレベルのシャーディング?
- MySQLプロキシレイヤーでのシャーディング?
- シャーディング用の中央ルックアップサーバー?
この分野で興味深いプロジェクトやツールを知っていますか?
回答:
MySQLテーブルをシャーディングするための最善の方法は、やむをえず避けられない場合を除き、行わないことです。
アプリケーションを作成するときは、通常、速度、開発者の速度を最大化する方法で行います。レイテンシ(回答の準備ができるまでの時間)またはスループット(時間単位あたりの回答数)は、必要な場合にのみ最適化します。
これらのすべてのパーティションの合計が単一のデータベースサーバーインスタンスに収まらない場合にのみ、パーティションを分割して別のホスト(=シャード)に割り当てます。その理由は、書き込みまたは読み取りのいずれかです。
書き込みのケースは、a)書き込みの頻度がこのサーバーのディスクに永続的に過負荷をかけているか、またはb)書き込みが多すぎるため、レプリケーションがこのレプリケーション階層で永続的に遅れています。
シャーディングの読み取りケースは、データのサイズが大きすぎてデータのワーキングセットがメモリに収まらなくなり、データ読み取りがほとんどの場合メモリから提供される代わりにディスクにヒットし始める場合です。
シャードする必要があるときだけ、それを行います。
シャーディングした瞬間に、複数の方法で支払います。
SQLの多くは宣言型ではなくなりました。
通常、SQLでは、必要なデータをデータベースに伝え、その仕様をデータアクセスプログラムに変換するためにオプティマイザに任せます。柔軟性があり、これらのデータアクセスプログラムの作成は退屈な作業で速度を損なうため、これは良いことです。
シャード環境では、ノードAのテーブルをノードBのデータに結合するか、ノードAおよびBにノードよりも大きいテーブルがあり、そこからノードBおよびCのデータを結合します。これを解決するためにアプリケーション側のハッシュベースの結合解決を手動で記述し始めている(またはMySQLクラスターを再発明している)、つまり、宣言的ではなくなったSQL機能が手続き型の方法で表現されることになります。 (たとえば、ループでSELECTステートメントを使用している)。
多くのネットワーク遅延が発生しています。
通常、SQLクエリはローカルで解決でき、オプティマイザはローカルディスクアクセスに関連するコストを認識し、そのコストを最小限に抑える方法でクエリを解決します。
シャーディング環境では、クエリはネットワークを介して複数のノードにキーと値のアクセスを実行することで(できれば、ラウンドトリップごとに個別のキールックアップではなくバッチキーアクセスを使用して)、またはWHERE
句の一部をノードの前方にプッシュすることで解決されます。適用される(「条件プッシュダウン」と呼ばれる)、またはその両方。
しかし、最良の場合でも、これにはローカルの状況よりもはるかに多くのネットワークラウンドトリップが含まれ、さらに複雑になります。特に、MySQLオプティマイザはネットワーク遅延についてまったく何も知りません(OK、MySQLクラスタは徐々に改善されていますが、クラスタ外のバニラMySQLの場合はまだ当てはまります)。
SQLの多くの表現力を失っています。
OK、それはおそらくそれほど重要ではありませんが、データ整合性のための外部キー制約およびその他のSQLメカニズムは、複数のシャードにまたがることはできません。
MySQLには、正常に動作している非同期クエリを許可するAPIがありません。
同じタイプのデータが複数のノードに存在する場合(ノードA、B、Cのユーザーデータなど)、多くの場合、これらのすべてのノードに対して水平クエリを解決する必要があります(「90日間ログインしていないすべてのユーザーアカウントを見つける以上")。データアクセス時間は、複数のノードを並行して要求でき、結果が到着するときに集計される( "Map-Reduce")場合を除き、ノードの数に比例して増加します。
その前提条件は非同期通信APIであり、MySQLには適切に機能する形では存在しません。代替案は、子プロセスの多くの分岐と接続であり、シーズンパスでサックの世界を訪れます。
シャーディングを開始すると、データ構造とネットワークトポロジがアプリケーションのパフォーマンスポイントとして表示されます。適切に実行するには、アプリケーションがこれらのことを認識している必要があります。つまり、実際にはアプリケーションレベルのシャーディングのみが意味を持ちます。
自動シャーディングを行う場合(たとえば、主キーをハッシュすることによってどの行がどのノードに入るかを判別する場合)、または手動で機能的に分割する場合(「xyzユーザーストーリーに関連する表は、マスター、abcおよびdef関連のテーブルはそのマスターに移動します」)。
機能シャーディングには、ユーザーストーリーに関連するすべてのテーブルをローカルで使用できるため、正しく実行すると、ほとんどの場合ほとんどの開発者から見えなくなるという利点があります。これにより、可能な限り宣言型SQLのメリットを享受できます。また、ネットワーク間の転送の数が最小限に抑えられるため、ネットワークの待機時間が少なくなります。
機能シャーディングには、単一のテーブルを1つのインスタンスより大きくすることができないという欠点があり、設計者の手動による注意が必要です。
機能シャーディングには、既存のコードベースに対して比較的簡単に実行できるという利点があり、過度に大きくない多くの変更が行われます。http://Booking.comは過去数年に何度もそれを行っており、彼らにとってうまくいきました。
そうは言っても、あなたの質問を見て、あなたが間違った質問をしていると思います、または私はあなたの問題のステートメントを完全に誤解しています。
アプリケーションレベルのシャーディング:dbShardsは、「アプリケーションを意識したシャーディング」を実行する唯一の製品です。ウェブサイトにはいくつかの良い記事があります。定義上、アプリケーションを意識したシャーディングはより効率的になります。アプリケーションが、トランザクションを検索したり、プロキシによってリダイレクトされたりすることなく、トランザクションのどこに行くべきかを正確に知っている場合、それ自体が高速になります。そして、誰かがシャーディングを検討しているとき、唯一の懸念事項ではないにしても、速度はしばしば主要な懸念事項の1つです。
一部の人々はプロキシで「シャーディング」しますが、私の目にはシャーディングの目的に反します。別のサーバーを使用して、トランザクションのどこにデータを見つけるか、どこに保存するかを伝えています。アプリケーション対応のシャーディングにより、アプリケーションは独自にどこへ行くべきかを認識します。はるかに効率的です。
これは実際には#2と同じです。
この分野で興味深いプロジェクトやツールを知っていますか?
このスペースのいくつかの新しいプロジェクト:
シャードクエリは、MySQL用のOLAPベースのシャーディングソリューションです。シャーディングされたテーブルとシャーディングされていないテーブルの組み合わせを定義できます。分割されていないテーブル(ルックアップテーブルなど)は、分割されたテーブルに自由に結合できます。分割されたテーブルは、シャードキーによって結合されている限り、相互に結合できます(シャードの境界を超えるクロスシャードまたは自己結合はありません)。Shard-QueryはOLAPソリューションであるため、通常、単純なクエリでも最小応答時間が100ミリ秒以下であるため、OLTPでは機能しません。Shard-Queryは、ビッグデータセットを並行して分析するように設計されています。
MySQLにはOLTPシャーディングソリューションも存在します。クローズドソースソリューションには、ScaleDB、DBShardsが含まれます。オープンソースのOLTPソリューションには、JetPants、CubridまたはFlock / Gizzard(Twitterインフラストラクチャ)が含まれます。
もちろんアプリケーションレベル。
私がこの本で見つけた今までで最高のアプローチ
高性能MySQL http://www.amazon.com/High-Performance-MySQL-Jeremy-Zawodny/dp/0596003064
簡単な説明:データを多くの部分に分割し、各サーバーに最大50の部分を保存できます。これは、シャーディングの2番目に大きな問題であるリバランスを回避するのに役立ちます。それらのいくつかを新しいサーバーに移動するだけで、すべてうまくいきます:)
購入して「mysqlスケーリング」の部分を読むことを強くお勧めします。
2018年の時点では、MySqlネイティブのソリューションがあるようです。実際には少なくとも2つあります-InnoDBクラスターとNDBクラスターです(その商用バージョンとコミュニティバージョンがあります)。
MySqlコミュニティエディションを使用するほとんどの人はInnoDBエンジンに慣れているため、これを最優先事項として検討する必要があります。それは、箱から出してすぐにレプリケーションとパーティション分割/シャーディングをサポートし、さまざまなルーティング/負荷分散オプションのMySqlルーターに基づいています。
テーブル作成の構文は、たとえば次のように変更する必要があります。
CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME) PARTITION BY HASH ( YEAR(col3) );
(これは4つのパーティションタイプの 1つにすぎません)
1つの非常に重要な制限:
InnoDB外部キーとMySQLパーティショニングには互換性がありません。パーティション化されたInnoDBテーブルは、外部キー参照を持つことも、外部キーによって参照される列を持つこともできません。外部キーを持つ、または外部キーによって参照されるInnoDBテーブルはパーティション化できません。
PARTITION BY HASH(YEAR...)
がスキャンされることに注意してください。ああ。