9

編集:これまでの回答の結果として、私が焦点を当てたいものにさらに焦点を当てたいと思います:データにアクセスするためにストレージオプションに永続性を備えたメモリ内(単純なC#コードである可能性があります)に書き込むことができるデータベースR. Redis内から、これまでのところ最も有望に見えます。また、データベースへのデータの同時書き込みを回避するために、Lockfree ++またはZeroMQに似たものを実際に使用することを検討しますが、メッセージバス/その他の実装を介してすべてを永続化データに送信し、1つの「アクター」がすべての書き込み操作を処理するようにします。インメモリデータベースまたは他のソリューションに。Redis以外のアイデア(SQLiteについて言及している人もいますが、パフォーマンスをテストする必要があります)。他に何か提案はありますか?

以下の要件のほとんどを満たす理想的なデータベース構造/ソリューションを探していますが、これまでのところ完全に失敗しました。手伝ってもらえますか?

私のタスク:.Net 4.5(C#)でプロセスを実行し、(一般的に)他のアプリケーションでさらに分析するために使用する値型を生成します。したがって、メモリ内に保持するか、ディスクに保持します。詳細は以下をご覧ください。データはさまざまなタスク/スレッド内で生成されるため、行ベースのデータ形式はこの状況にうまく適合しません(さまざまなスレッドで生成されたデータはさまざまな時間に生成されるため、整列されないため)。したがって、列型のデータ構造が適切かもしれないと思いましたが、間違っている場合は訂正してください。

例:

タスク/スレッド#1は、指定されたタイムスタンプで次のデータを生成します

datetime.ticks/出力データの値

1000000001 233.23

1000000002 233.34

1000000006234.23..。

Taks / Thread#2は、指定されたタイムスタンプで次のデータを生成します

datetime.ticks/出力データの値

1000000002 33.32

1000000005 34.34

100000001554.32..。

.Netランタイムでタイムスタンプを調整する必要はありません。何よりもまず、データを保存し、後でRまたはPython内でデータを処理します。

私の要件:

  • 高速書き込み、高速書き込み、高速書き込み:1秒あたり100,000〜1,000,000のデータポイントを生成し、データを永続化(最悪の場合)またはメモリに保持する必要がある場合があります。このプロセスがデータ生成プロセスに遅れをとることができるように、独自のスレッドで書き込みを実行しても問題ありませんが、制限は16GB RAM(64ビットコード)です。

  • 後でデータをクエリする方法に適しているため、列指向データベース形式が優先されますが、上記の例に関して意味がある場合は、他の構造を受け入れることができます(他のすべての要件があれば、ドキュメント/キー値も問題ありません)特に書き込み速度の点で満たされています)。

  • .Net内から参照できるAPI。例:HDF5は一部の人には対応可能と見なされるかもしれませんが、.Netポートはひどいものだと思います。.Netをもう少しサポートするものはプラスですが、他のすべての要件が満たされている場合は、HDF5.Netポートに似たものを処理できます。 。

  • 可能であれば同時書き込み:前述のように、異なるタスク/スレッドから同時にデータを書き込むのが好きです。

  • 私は16GBのメモリ(64ビットで.Netプロセスを実行)に制約されているため、それよりも多くのデータを生成することがあるため、純粋にメモリ内にないものを探す可能性があります。時々永続化するメモリ内の何か、または純粋な永続化モデルがおそらく望ましいでしょう。

  • 組み込みが優先されますが、クライアント/サーバーソリューションのサーバーがWindowsサービスとして実行できる場合は、問題ありません。

  • データアクセスに関しては、RとPythonのインターフェイスがすでに存在するdbソリューションを強く好みます。これは、Python内のPandaライブラリを時系列の配置やその他の分析に使用し、R内で分析を実行するためです。

  • API/ライブラリがSQL/SQLのような/Linq/のようなクエリをサポートしている場合、それは素晴らしいことですが、一般的には、開始日と終了日の間に列データをロードするなどの絶対的な必要条件が必要です(「キー」/インデックスが与えられた場合) R / Python内でクエリを分析して実行するためです)。

  • 管理コンソールまたはデータビジュアライザーが付属している場合は、プラスになりますが、必須ではありません。

  • オープンソースであるか、「リーチ」内の価格である必要があります(いいえ、KDBはその点で資格がありません;-)

OK、これが私がこれまでに持っているものです。ほとんどのdbソリューションは、書き込みパフォーマンス要件ですでに失敗しているため、これもすべてです。

  • InfobrightとDb4o。私はこれまで読んだものが好きですが、パフォーマンス統計をチェックインしていないことを認めます
  • 何かが自分でやった。値型をバイナリ形式で簡単に保存し、datetime.ticksでデータにインデックスを付けることができます。Python/Rでデータをロード/逆シリアル化するためのスクリプトを作成する必要があります。しかし、並行性、クエリエンジン、およびその他の機能を追加したい場合は、膨大な作業になります。したがって、私はすでにそこにある何かを探します。
4

5 に答える 5

13

コメントできません-低担当者(私はここで新しいです)-代わりに完全な答えが得られます...

まず、データベースが必要ですか?書き込み速度の高速化とRへの移植性が最大の懸念事項である場合、フラットファイルメカニズムを検討したことがありますか?あなたのコメントによると、あなたは書き込みをバッチ処理する用意がありますが、永続性が必要です。それらが私の要件である場合、非常に高速なディスクに直接接続するバッファリングシステムを作成し、ディスクファイルを定期的に取得してRのデータストアに移動する別のタスクを作成します。これは、Rがフラットを読み取る場合のみです。そもそもファイルは十分ではありませんでした。

事後にアラインメントを実行できる場合は、メインの並列ループ内のファイルを分離するスレッドを作成し、各ファイルを頻繁に切り取り、アラインメントとデータベースのロードをサブプロセスに任せることができます。

したがって、(くだらない疑似コードで)、backgroundworkerなどで呼び出すスレッドプロセスを構築し、各ワーカー、つまり各ファイルストリーム(タスク/スレッド)を一意に識別するスレッド名文字列を含めます。

file_name = threadname + '0001.csv' // or something
open(file_name for writing)
while(generating_data) {
    generate_data()
    while (buffer_not_full and very_busy) {
        write_data_to_buffer
        generate_data()
    }
    flush_buffer_to_disk(file_name)
    if(file is big enough or enough time has passed or we're not too busy) {
        close(file_name)
        move(file_name to bob's folder)
        increment file_name
        open(file_name for writing)
    }
)

効率的でスピーディーなファイルI/Oとバッファリングは、簡単で一般的な問題です。これより速くなるものはありません。次に、データベースのロードを実行するための別のプロセスを記述し、そこでパフォーマンスを低下させないようにすることができます。

while(file_name in list of files in bob's folder sorted by date for good measure)
{
    read bob's file
    load bob's file to database
    align dates, make pretty
}

そして、その部分をC#で記述せず、バッチスクリプトを作成し、データベースのネイティブローダーを使用します。これは、最初から構築できるものと同じくらい高速です。

同じハードウェアで実行している場合は、2つのループがあまり干渉しないことを確認する必要があります。つまり、タスクスレッドをより高い優先度で実行するか、いくつかのミューテックスまたはパフォーマンスリミッターを組み込んで、スレッドの実行中にデータベースの負荷がリソースを占有しないようにします。フラットファイルへのファイルI/Oが損なわれないように、データベースサーバーとハードウェアを確実に分離します。

Unixを使用している場合、FIFOキューは機能しますが、そうではありません。:-)

また、ハードウェアはデータベースエンジンよりもパフォーマンスに大きな影響を与えると思います。予算が限られている場合は、COTSハードウェアを使用していると思います。そのため、ソリッドステートドライブを使用すると、パフォーマンスがかなり安く向上する可能性があります。私が言ったように、フラットファイルストレージからDBストレージを分離することは助けになり、R、データベース、およびスレッドのCPU/RAMはすべて理想的に分離されるべきです。

私が言っているのは、あなたがたくさんのお金を使わない限り、DBベンダーの選択はおそらくあなたの最大の問題ではないということです。それ以外の場合は、ほとんどの場合ハードウェアに縛られます。データベースの調整は芸術であり、トップエンドでパフォーマンスのわずかな向上を確認できますが、優れたデータベース管理者がいると、パフォーマンスのためにほとんどのデータベースを同じ球場に保つことができます。RとPythonが何をうまくサポートしていて、あなたが快適であるかを見ていきます。列形式で考える場合は、RとC#によるCassandra(私の投票)、Hana、Lucid、HBase、Infobright、Verticaなどのサポートを確認し、価格とサポートに基づいて1つを選択してください。単一のコモディティマシン上の従来のデータベースの場合、MySQLで処理できないものは見たことがありません。

于 2012-11-08T16:01:38.917 に答える
2

これは私自身の質問に答えるためではなく、これまでにテストしたすべてのデータベースと、それらが(まだ)要件を満たしていない理由を追跡するためです。100万個の単一オブジェクト(1つのロング、2つのフロート)を書き込もうとするたびにデータベースに。ooDBの場合、オブジェクトをコレクションに貼り付けてコレクション自体を作成しました。これは、Redisなどのキー/値の場合と同様の話ですが、InfoBrightなどの列型データベースに単純なint(1mil)を作成しようとしました。

  • Db4o、書き込みが非常に遅い:コレクション内の1milオブジェクトは約45秒かかりました。後でコレクション構造を最適化し、各オブジェクトを個別に作成しました。ここではあまり好きではありません。
  • InfoBright:同じことですが、書き込み速度の点で非常に遅いので、データを列形式で整理するのでかなり驚きましたが、「ナレッジツリー」は、フラットなデータ構造/テーブルを保存するときではなく、データをクエリするときにのみ起動すると思います-構造のように。
  • Redis(BookSleeve経由):.Net用の優れたAPI:完全なRedis機能(ただし、WindowsマシンとLinuxまたはUnixボックスでサーバーを実行する場合のいくつかの欠点があります)。パフォーマンスは非常に速かった...毎秒100万アイテムの北。Protocol Buffers(protobuf-net、どちらもMarc Gravellによって作成された)を使用してすべてのオブジェクトをシリアル化しましたが、ライブラリでさらに多くのことを行う必要がありますが、RとPythonはどちらもRedisDBに完全にアクセスできます。これは大きな利点です。これまでのところそれが大好きです。MarcがRedisの基本関数について書いたAsyncフレームワークは素晴らしく、本当にすっきりしていて、これまでのところ機能しています。これまではバイト配列にしかシリアル化されていなかったので、Redisリスト/コレクションタイプについてももう少し時間をかけて実験したいと思います。
  • SqLite:純粋にメモリ内で実行し、約3秒で100万の値型要素を書き込むことができました。純粋なRDBMSにとっては悪くありませんが、明らかにインメモリオプションは実際に処理を高速化します。1つの接続、1つのトランザクション、1つのコマンド、1つのパラメーターを作成し、ループ内でパラメーターの値を調整し、各反復でExecuteNonQueryを実行しただけです。次に、トランザクションコミットがループの外側で実行されました。
  • HDF5:.Netポートがあり、RからHDF5ファイルを処理するためのライブラリもありますが、そうすることは強くお勧めしません。その純粋な悪夢。.Netポートは非​​常にひどく書かれています、一体、HDF5の概念全体は疑わしい以上のものです。それは非常に古く、私の意見では、ベクトル化/列化されたデータを格納するためのソリューションは大きくなりませんでした。これは1995年ではなく2012年です。以前に保存されていたファイルからデータセットとベクトルを完全に削除できない場合、私はそれを煩わしいとは言いませんが、大きな設計上の欠陥と呼びます。一般的なAPI(.Netだけでなく)は非常にひどく設計され、私見で書かれています。ファイル構造の研究に何時間も費やさなければ、誰も使用方法を理解できないクラスオブジェクトがたくさんあります。それは、そこにある非常にまばらな量のドキュメントとサンプルコードによっていくらか証明されていると思います。さらに、h5r Rライブラリはドラマであり、絶対的な悪夢です。その書き込みも悪く(多くの場合、フラッシュの失敗のために書き込み時にファイルが正しく閉じられず、ファイルが破損します)、ライブラリには32ビットOSに適切にインストールすることさえ問題があります...そしてそれは継続します。私はHDF5について最も多くのことを書いています。なぜなら、私はほとんどの時間をこの作品に費やし、そして最も欲求不満に終わったからです。Rと.Netからアクセスできる高速の列型ファイルストレージシステムを用意するというアイデアは魅力的でしたが、APIの統合と使いやすさ、またはその欠如という点で約束したものを実現できませんでした。その書き込みも悪く(多くの場合、フラッシュの失敗のために書き込み時にファイルが正しく閉じられず、ファイルが破損します)、ライブラリには32ビットOSに適切にインストールすることさえ問題があります...そしてそれは継続します。私はHDF5について最も多くのことを書いています。なぜなら、私はほとんどの時間をこの作品に費やし、そして最も欲求不満に終わったからです。Rと.Netからアクセスできる高速の列型ファイルストレージシステムを用意するというアイデアは魅力的でしたが、APIの統合と使いやすさ、またはその欠如という点で約束したものを実現できませんでした。その書き込みも悪く(多くの場合、フラッシュの失敗のために書き込み時にファイルが正しく閉じられず、ファイルが破損します)、ライブラリには32ビットOSに適切にインストールすることさえ問題があります...そしてそれは継続します。私はHDF5について最も多くのことを書いています。なぜなら、私はほとんどの時間をこの作品に費やし、そして最も欲求不満に終わったからです。Rと.Netからアクセスできる高速の列型ファイルストレージシステムを用意するというアイデアは魅力的でしたが、APIの統合と使いやすさ、またはその欠如という点で約束したものを実現できませんでした。

更新:R内からデータベースにアクセスするためのアダプターが利用できないため、velocityDBのテストを中止しました。私は現在、作成されたバイナリファイルから生成されたデータにアクセスするか、ブローカーレスメッセージバス(zeroMQ)を介して送信するか、LockFree ++を介して「actor」(私のGUI)に送信するチャートライブラリを使用して独自のGUIを作成することを検討しています。次に、C#内からRを呼び出して、結果をGUIに返すことができます。それはおそらく私に最も柔軟性と自由を与えるでしょうが、明らかにコード化するのに最も退屈なことでもあります。私はテスト中にますます多くの制限に直面しており、各dbテストでこのアイデアをますます友好的にしています。

結果:ご参加いただきありがとうございます。結局、私はチップモンキーに賞金を授与しました。彼は、私の問題の解決策の重要なポイントを部分的に提案したからです(最終的には独自の異なる解決策を選択しましたが)。結局、メモリストレージ内のRedisと、.NetからR.dllへの直接呼び出しのハイブリッドになりました。Redisは、さまざまなプロセスによってメモリに保存されているデータへのアクセスを許可します。これにより、データをキー/値としてRedisにすばやく保存し、Rから同じデータにアクセスできる便利なソリューションになります。さらに、データを直接送信し、.dllと優れたR.Netライブラリを介してRの関数を呼び出します。100万の値型のコレクションをRに渡すのに、私のマシンでは約2.3秒かかります。これは、データを渡すだけの便利さを考えると、十分に高速です。

于 2012-11-09T06:58:05.307 に答える
0

私は永続ストレージ(私は個人的にdb4oを好みますが、上記と同様にファイルを使用できます)を組み合わせて、次のようにオブジェクトをメモリに格納する方法を採用します。

BlockingCollection <T>を使用してオブジェクトをメモリに格納し(オブジェクトをメモリに格納するよりも1000000 / sの方がパフォーマンスが向上すると思います)、オブジェクトを消費して永続データベースに格納する1つ以上の処理スレッドを使用します。

// Producing thread
for (int i=0; i<1000000; i++)
    blockingCollection.Add(myObject);

// Consuming threads
while (true)
{
      var myObject = blockingCollection.Take();
      db4oSession.Store(myObject); // or write it to the files or whathever
}

BlockingCollectionは、生産者/消費者ワークフローをほぼ解決します。それらの複数のインスタンスを使用し、AddToAny / TakeFromAnyを使用する場合は、あらゆる種類のマルチスレッドパフォーマンスに到達できます。

消費するスレッドごとに異なるdb4oセッション(ファイル)を使用して、目的のパフォーマンスを実現できます(db4oはシングルスレッドです)。

于 2012-11-10T22:21:30.903 に答える
0

注:私はかつて、delphiフォーラムの仲間から同様の問題が投稿されました。当時書いた単純なID-key-valueデータベースバックエンド(NoSQLエンジンの一種)で彼を助けることができました。基本的に、Bツリーを使用してトリプレット(32ビットObjectID、32ビットPropertyKey、64ビット値)を格納します。リアルタイムで約500k/秒の値を節約することができました(約5年前)。もちろん、データは3つの値(ID、プロパティID、値)すべてにインデックスが付けられました。値インデックスを無視することで、これを最適化できます。

私がまだ持っているソースはDelphiにありますが、C#を使用してそのようなものを実装することを考えます。パフォーマンスのニーズを満たすかどうかはわかりませんが、他のすべてが失敗した場合は、試してみてください。バッファ書き込みを使用すると、パフォーマンスも大幅に向上します。

于 2012-11-10T18:20:04.313 に答える
-1

ZeroMQを使用したいので、Redisではなくmemcacheを使用してみませんか?
ZeroMQは、私が知る限り、永続性を提供しません。Memcacheも永続性を提供せず、Redisよりも少し高速です。
または、おそらく逆に、Redisを使用している場合は、beanstalk MQを使用しないのはなぜですか?
(永続性のために)Redisを使用する場合は、ZeroMQからbeanstalk MQに切り替えることをお勧めします(これもメモリキュー内で高速ですが、ロギングによる永続性もあります)。BeanstalkにはC#ライブラリもあります。

于 2012-11-14T17:27:20.413 に答える