19

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

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

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

4

5 に答える 5

14

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

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

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

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

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

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

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

于 2012-04-26T03:22:02.657 に答える
2

役立つ可能性のあるいくつかのことを次に示します。

  • 各サーバーの 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). これは、効率を高めるための明示的な非正規化です。(私は、このスキームに関する私自身の経験についてブログに書きました。)

于 2012-04-25T20:51:51.617 に答える
1

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

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

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

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

于 2012-04-26T00:03:21.237 に答える