2011-01-26 2 views
2

私は、シーケンシャルに整数を生成する非常にレイテンシに敏感なルーチンを持っていますが、クラッシュや再起動の際に最後に生成されたものをディスクに格納する必要があります。32ビット整数をディスクに格納するための絶対的な最速の方法は?

現在、ファイルの先頭にシークしてから整数を書き出し、新しいintが生成されるたびにフラッシュします。書き込みは、少なくともバッテリバックアップのコントローラキャッシュに当たるようにフラッシュが必要です。

シークはかなりコストがかかるので、私はちょうど4バイトを追加することを考えていました。そして、リカバリが必要であれば、最後まで探して最後の4バイトを読みます。この前のステートメントは、明らかに、他のディスクアクティビティがあまり起こっていないと仮定しているため、書き込みヘッドは理想的にはファイルの最後にとどまるべきです。

数字は通常10,000,000を上回らないので、40MBはそれほど悪くありません。

完全性を犠牲にすることなく最小待ち時間を達成する方法についてのアドバイスはありますか? Linuxの2.6+

+0

は、データベースのトランザクションログとまったく同じように聞こえます。あなたは確かにあなたは車輪を再発明しようとしていないのですか? –

+0

ディスクハードウェアに非常に近い「組み込みシステム」で動作している場合を除き、ヘッドがディスク上の特定の場所に留まることは保証されません。 Linuxでは、ディスク全体を割り当ててrawデバイスファイルに書き込むことで、これを実現できます。しかし、@Mitchが指摘しているように、あなたは古い車輪を再発明しているように聞こえます。 –

+2

4バイトのシークはドライブにヒットしません。多かれ少なかれカーネルの減算にすぎません。 – nos

答えて

8

これを行う最も簡単な方法は、mmap/msync-mmap 1ページのファイルをメモリに保存し、そのページに値を格納することです。値が変更されると、msync(2)を呼び出してページをディスクに強制的に戻します。この方法では、ストアごとに1つのシステムコールしか必要ありません。

+0

私はこのアイデアが大好きです。私はリチャード・スティーブンスの本を引き出して、mmap機能の詳細を学んでいます。 – chriskirk

2

CまたはC++私はどのようにメモリマップドファイルを使用する方法について、正しく読めば?割り当てられたアドレスに番号を書き込むだけで、ファイルに表示されます。これは、必要に応じてOSがキャッシュをディスクに強く書き込むことを前提にしていますが、試してみる価値があるかもしれません。

int len = sizeof(unsigned); 
int fildes = open(...) 
void* address = mmap(0, len, PROT_READ, MAP_PRIVATE, fildes, 0) 
unsigned* mappedNumber = (unsigned*)(address); 

* mappedNumberは今、あなたの整数を含めることができます。

+1

は、値が変更されるたびにアドレスでmsyncを呼び出す必要があります。また、RAM内でのみ変更されます。電源が切れた場合、新しい値が失われます。 –

+0

4行目にアドレスをキャストする必要はありません。 – user562374

2

測定。

あなたはハードウェアに対してどれだけのコントロールを持っていますか? が完全未満の場合、保証はありません。

Linuxでは、おそらくファイルシステムを使用しなくても、最高の優先度で書き込みを行うカーネルドライバを作成しようとします。

しかし、理論的には...コントローラのキャッシュに達するだけであれば、ディスクに何かをフラッシュするたびにデータがヒットします。つまり、ドライブ内に物理的なシークがあるかどうかにかかわらず、データは既にそこに存在します。また、他のアプリケーションが何をするのか、またディスクの回転速度が決まらないため、ファイルの先頭または末尾に論理ファイルハンドルを保持しても、シークはランダムになります。

あなたはいつでもフラッシュドライブを使用するようにユーザーに求めることができます。

+0

フラッシュドライブであっても、データはまだしばらくRAMにキャッシュされます。ディスクにフラッシュするにはfsync/msyncが必要です。 –

+0

@Chris Dodd、確かに、fsyncは強制的にドライブに追い込み、フラッシュドライブはシーク時間がはるかに長くなります。 – liori

+0

私はハードウェアにかなり近づくことができますが、この特定のアプリケーションを実行するマシンは必ずしも同質ではありません。一部のものには、大量のキャッシュを持つRAIDコントローラがあります。いくつかはしません。いつかはフラッシュドライブを持っているかもしれません... – chriskirk

1

ファイルを書き込む最も速い方法は、そのファイルをメモリにマップし、char配列として扱うことです。

OSクラッシュを気にしない場合(Linuxは本番環境では決してクラッシュしません)、ファイルを同期する必要はありません。すべての書き込みはカーネルを迂回するファイルマッピング、つまり実際のゼロコピー(標準ハードウェア上のソケットではこれを行うことはできません)に移動します。メモリにレコードを書き込む際にアプリケーションがクラッシュした場合に備えて、いくつかのレコードが書き込まれたヘッダーをそのファイルに保存する必要があります。私。レコードを書き、それ以降はレコードカウンタをインクリメントします。このファイルのサイズを変更

は少し時間がかかりすぎることがありftruncate()/remap()シーケンスを必要とするので、あなたはそれがオーバーフローしたときにstd::vector<>push_back()に1.5のサイズによって成長のように、係数でファイルを成長させることによって、リサイズ最小限にすることをお勧めします。スループットとレイテンシの要件に応じて、最適化を適用することができます。

カーネルは、(アプリケーションにディスクへの書き込み専用の別のスレッドがあるかのように)ディスクへのファイルマッピングを非同期で書き込みます。 msync()を使用して、必要に応じてディスクへの書き込みを強制する方法があります。ただし、OSのクラッシュに耐えたい場合にのみ必要です。しかし、OSのクラッシュから生き残るには、とにかく洗練されたアプリケーション設計が必要です。実際には、アプリケーションのクラッシュから生き残るだけで十分です。

+0

一般的なアドバイスは良いですが、 "アプリケーションのクラッシュで生き残っている"ということは、業界やシステムなどに大きく依存しています。関連する質問をしなくても、また、ハードウェア、環境(電源、エアー、洪水、火)、ヒューマンエラー(間違ったケーブルの抜き差し、誤ったスイッチのフリック)など、OSとアプリだけではありません。 –

+0

非常に良いアドバイス。問題のアプリケーションでは、2つのシーケンス番号を追跡する必要があります.1つは近似値(最後の数回の更新を失う可能性があります)ですが、もう1つはカーネルの障害を除いて保証する必要があります。私はあなたが両方の文脈に非常によく適応したと思います。ありがとうございました。 – chriskirk

1

なぜアプリケーションは書き込みが完了するのを待たなければならないのですか?

データを非同期で、または別のスレッドから書き込みます。

ハードドライブには、低レベルの制御はほとんどありません。一度に小さなデータを書いている限り、高価なシークがたくさん発生します。しかし、クラッシュの場合に復旧するための "チェックポイント"としてしか使用していないため、書き込みが非同期的には発生しない理由はないようです。

+0

「別のスレッド」は、プログラムがクラッシュするとすぐに分割されます。 「別のプロセス」が機能するかもしれませんが、その時点で、カーネルに依存して他のプロセスになっている可能性があります。 – Tom

+0

なぜ正確に?起こる可能性のある最悪の事態は、最新のチェックポイントを失い、プロセスが再開したときにもう少し作業をしなければならないことです。だから何?これらのチェックポイントをディスクに頻繁に書き込んでください。実際には、別のスレッドで実行している場合は、*常に*書くことができるので、クラッシュのため最後のものを失う場合は*重要ではありません。 – jalf

+0

私のポイントは、最新のチェックポイントを失う危険があるということです。質問は、整合性を犠牲にすることなく待ち時間を最小化することを指定しています。データがOSに渡される前にプロセスが停止する可能性があるため、同じプロセス内の別のスレッドへのI/Oの延期は整合性を犠牲にします。 mmapのアプローチは、 "他のスレッド"をカーネルにすることができます( 'pdflush'と私は思っていますが、間違っている可能性があります)。プロセスが終了すると死ぬことはありません。 – Tom

0

intを格納すると、ブロックサイズに関係なく、ディスク上で1ブロックしか使用されません。したがって、1つのブロックをディスクに同期させなければならず、時間がかかりますが、それを速くするために何もできません。

fdatasync()は他に何があっても、時間をとってキラーになります。 1つのブロックを(バッテリバックアップされたRAID)コントローラに同期させます。

ある種の不揮発性RAMがないかぎり、すべての(賢明な)メソッドは、すべてが1つのブロックをsync'dする必要があるため、まったく同じになります。

シークシステムコールを実行することは、ハードウェアに影響を与えないので、何の違いもありません。いずれにしても、pwrite()を使用すると回避できます。

0

「4バイトを追加する」とは何を意味しますか。ディスクはファイルやバイトを格納しません。彼らはクラスターとそれらの固定数を格納します。ファイルの概念は、OSによって作成されます。ファイルシステムテーブルにいくつかのクラスタを割り当て、ファイルの正確な位置を追跡します。今、4バイトを追加することは、少なくとも4バイトをクラスタに書き込むことを意味します。しかし、それはまた、どのクラスタを決定するのかを意味します。既存のファイルサイズは?新しいクラスタが必要ですか?そうでない場合は、最後のクラスタを読み取り、正しい位置に4バイトをパッチし、クラスタを書き戻してから、ファイルシステムのファイルサイズを更新する必要があります。新しいクラスタを追加する場合は、4バイトの後にゼロを書き込むことができます(古い値は必要ありません)が、ファイルにクラスタを追加するためには多くの簿記を行う必要があります。

したがって、絶対的な最速の方法では4バイトを追加することはできません。 は、は既存の4バイトを上書きする必要があります。好ましくは、あなたがすでに記憶しているセクターで。他の人はすでにmmap/msyncでこれを達成できると指摘しています。

明らかに、現在のSSDと開発者の価格と40 MBの制限があれば、SSDを使用することになります。あなたが1時間を節約すれば、それは自分のために払います。したがって、シーク時間は無関係です。 SSDには物理的な頭がありません。

+0

mmap/msyncを使用して、コントローラカードにバッテリバックアップされたキャッシュがある場合、物理的な媒体は多かれ少なかれ無関係ですか?私の理解から、msyncを呼び出すとコントローラカードにヒットします。メモリが不揮発性のままである限り、媒体はそれが気にするすべてのテープであってもよい。思考? – chriskirk

+1

@chriskirk:バッテリーが十分に大きければ、石タブレットの第2レベルはOKです。本質的に、不揮発性ソリッドステートストレージの1つのレベルが必要です。 – MSalters

0

mmap()について何か修正があるかのように多くの人が話していますが、のシステムオーバーヘッドは基本的にディスク書き込みオーバーヘッドに比べてゼロです。ファイルへの追加または書き込みは、とにかくinode(mtime、filesize)を更新する必要があることを忘れないでください。

ディスク以外の整数を格納することをお勧めします。たとえば

  • は(。組込みシステム上など)あなたがコントロールするいくつかのNVRAMに書き込みます。 (あなたのRAIDコントローラが書き込みのためにnvramを持っているなら、あなたのためにこれを行うかもしれませんが、もしこの質問をしているのであれば、おそらくそうではありません)。0120 PCハードウェア上)。

  • ネットワーク上の別のマシン(速いネットワークの場合)に書き込み、確認するようにしてください。

  • すべてのトランザクションの後ではなく、n回のトランザクションごとに同期を解除できるようにアプリケーションを再設計します。これは毎回行うよりも約n倍高速です。

  • 整数を紛失した場合、最新のトランザクションからの変更がであるようにアプリケーションを再設計します。技術的に整数更新を失ったという事実は問題ではありません。再起動すると、増分しないかのようになりますので、そこから再開できます。

この動作が必要な理由について説明していません。正直言って、もしあなたのアプリがこれを必要とするなら、あなたのアプリケーションはおそらくとてもうまく設計されていないように思えます。たとえば、ある人はデータベースを使用するように提案しました。なぜなら、このようなことをいつもしているからです。真実ですが、データベースは遅い(毎回ディスクを同期させる)ことによって、を実行します。を最初に作成しないと、「トランザクションをコミットする」ときだけディスクを同期させる必要があります。しかし、すべての整数の後に必ず同期を取らなければならない場合は、常にトランザクションをコミットし、データベースはそれを保存できません。少なくともfdatasync()を行わない限り、データベースがデータを失わないことを保証する魔法の方法はありません。

関連する問題