web-dev-qa-db-ja.com

自動シャーディングpostgresql?

大量のデータ(50億行以上)をデータベースに非常に迅速にロードする必要があるという問題があり(理想的には30分未満ですが、速い方が良いです)、最近postgresqlを調べるように提案されました(mysqlで失敗しました)そしてhbase/cassandraを見ていました)。私のセットアップでは、大量のデータを生成するクラスター(現在は8台のサーバー)があり、クラスター内の各マシンでデータベースをローカルで実行して、ローカルにすばやく書き込み、最後に(またはデータ生成全体で)データを実行することを考えていました。一緒にマージされました。データは順不同なので、どの特定のサーバーにあるかは気にしません(最終的にそこにある限り)。

私の質問は、PostgreSQLの自動シャーディングについて学ぶための良いチュートリアルや場所はありますか(sykpeのような会社が自動シャーディングを行っている結果を見つけましたが、チュートリアルはありません。自分でこれを試してみたいです)?私がやろうとしていることは可能ですか?自動インクリメントID番号を使用する予定だったデータの順序が決まっていないため、データをマージすると競合が発生しますか(これはもはや大きな問題ではありません)?

更新:以下のフランクのアイデアは、私が尋ねていた自動インクリメントの競合の問題を排除しました。問題は基本的に今ですが、自動シャーディングについてどのように学ぶことができ、複数のサーバーへのデータの分散アップロードをサポートしますか?

20
Lostsoul

まず、クラスターから生成されたデータをリレーショナルデータベースに直接挿入する必要が本当にありますか?とにかく最後にマージしてもかまいませんが、なぜデータベースに挿入する必要があるのでしょうか。あなたの立場では、クラスターノードにフラットファイル(おそらくgzipで圧縮されたCSVデータ)を書き込ませます。次に、 pg_bulkload のようなツールを使用して、そのデータを一括インポートしてマージします。

リレーショナルデータベースに直接挿入する必要がある場合:それが(の一部) PgPool-II および(特に) PgBouncer の目的です。異なるノード間で負荷分散するようにPgBouncerを構成すると、ほぼソートされているはずです。

PostgreSQLは、強力なデータ耐久性が保証されたトランザクションデータベースであることに注意してください。これは、単純な方法で使用すると、小さな書き込みを大量に実行するのが遅くなる可能性があることも意味します。データの耐久性、速度、ハードウェアのコストの間でどのようなトレードオフを行うかを検討する必要があります。

極端な場合、各INSERTは、成功を返す前にディスクに同期的にコミットされる独自のトランザクションにすることができます。これにより、1秒あたりのトランザクション数がディスクサブシステムで実行できるfsync()の数に制限されます。これは、多くの場合、1秒あたり数十または数百にすぎません(バッテリーバックアップRAIDコントローラーなし)。これは、特別なことを何もせず、INSERTsをBEGINCOMMITでラップしない場合のデフォルトです。

もう一方の極端な例では、「このデータをすべて失ってもかまわない」と言って、 ログに記録されていないテーブル を使用します。あなたの挿入物のために。これは基本的に、データが正常であることを保証できない場合、たとえばOSのクラッシュ、データベースのクラッシュ、電源の喪失などの場合に、データベースにデータを破棄する許可を与えます。

中間点はおそらくあなたがなりたい場所です。これには、 非同期コミットグループコミットcommit_delay および commit_siblings )の組み合わせが含まれ、挿入をラップされたグループにバッチ処理します。明示的なBEGINENDなど。INSERTバッチ処理の代わりに、一度に数千レコードのCOPYロードを実行できます。これらはすべて、データの耐久性と速度のトレードオフです。

高速一括挿入の場合は、主キー以外のインデックスなしでテーブルに挿入することも検討する必要があります。多分それでもないでしょう。一括挿入が完了したら、インデックスを作成します。これは非常に速くなります。

14
Craig Ringer

これが役立つかもしれないいくつかのことです:

  • 各サーバーのDBには、そのサーバーの固有の特性を持つ小さなメタデータテーブルが必要です。それがどのサーバーであるかなど。サーバーには順番に番号を付けることができます。そのテーブルの内容とは別に、各サーバーのスキーマを可能な限り類似させておくのが賢明でしょう。

  • 数十億の行がある場合、bigint ID(またはUUIDなど)が必要になります。 bigintを使用すると、サーバーごとに十分な範囲を割り当て、それを使用するようにシーケンスを設定できます。例えば。サーバー1は1..1000000000000000を取得し、サーバー2は1000000000000001から2000000000000000などを取得します。

  • データが単純なデータポイントである場合(毎秒正確に10の機器からの温度読み取りなど)、より正確な(time timestamp, values double precision[])ではなく(time timestamp, instrument_id int, value double precision)列のテーブルにデータを保存することで効率が向上する可能性があります。これは、効率を高めるための明示的な非正規化です。 (私 ブログ このスキームでの私自身の経験について。)

2
Edmund

申し訳ありませんが、チュートリアルは手元にありませんが、考えられる解決策の概要は次のとおりです。

  • データの8つを各サーバーのPGインスタンスにロードします
  • 最適なロード速度を得るには、インサートを使用せずに [〜#〜] copy [〜#〜] メソッドを使用します
  • データをロードするときは、8つのデータベースを1つに結合しないでください。代わりに、 plProxy を使用して、単一のステートメントを起動し、すべてのデータベースを一度にクエリします(またはクエリを満たすための適切なステートメント)

すでに述べたように、キーが問題になる可能性があります。重複しないシーケンス、uuid、または文字列プレフィックス付きのシーケンス番号を使用してください。解決するのはそれほど難しくありません。

サーバーの1つでCOPYテストを開始し、30分の目標にどれだけ近づくことができるかを確認する必要があります。データが重要でなく、Postgresqlの最新バージョンを使用している場合は、 ログに記録されていないテーブル を使用してみてください。これははるかに高速です(ただし、クラッシュセーフではありません)。楽しいプロジェクトのようですね、頑張ってください。

1
C. Ramseyer

PostgreSQLの自動シャーディングには citus を使用します。また このリンク は役に立ちます。

1
Guido Mocha