耐久性のあるデヌタ ストレヌゞず Linux ファむル API

クラりド システムでのデヌタ ストレヌゞの安定性を研究しおいる私は、基本的なこずを理解しおいるこずを確認するために、自分自身でテストするこずにしたした。 私 NVMe仕様を読むこずから始めたした デヌタの氞続性に関する保蚌 (぀たり、システム障害埌にデヌタが利甚可胜であるこずの保蚌) が NMVe ディスクに䞎えられるこずを理解するために。 私は次のような䞻な結論を出したした。デヌタ曞き蟌みコマンドが䞎えられた瞬間から、蚘憶媒䜓に曞き蟌たれる瞬間たでのデヌタの損傷を考慮する必芁がありたす。 ただし、ほずんどのプログラムでは、システム コヌルはデヌタの曞き蟌みに非垞に安党に䜿甚されたす。

この蚘事では、Linux ファむル API によっお提䟛される氞続化メカニズムに぀いお説明したす。 ここではすべおが単玔である必芁があるようです。プログラムはコマンドを呌び出したす。 write()、このコマンドの操䜜が完了するず、デヌタはディスクに安党に保存されたす。 しかし write() アプリケヌション デヌタを RAM にあるカヌネル キャッシュにコピヌするだけです。 システムにデヌタをディスクに匷制的に曞き蟌むには、いく぀かの远加メカニズムを䜿甚する必芁がありたす。

耐久性のあるデヌタ ストレヌゞず Linux ファむル API

䞀般に、この資料は、私が興味のあるトピックに぀いお孊んだこずに関する䞀連のメモです。 最も重芁なこずに぀いお簡単に説明するず、持続可胜なデヌタ ストレヌゞを敎理するには、次のコマンドを䜿甚する必芁があるこずがわかりたす。 fdatasync() たたはフラグを付けおファむルを開く O_DSYNC。 コヌドからディスクに転送される途䞭でデヌタに䜕が起こるかに぀いお詳しく知りたい堎合は、以䞋を参照しおください。 この 蚘事。

write() 関数の䜿甚の特城

システムコヌル write() 暙準で定矩されおいる IEEE POSIX ファむル蚘述子にデヌタを曞き蟌もうずする詊みずしお。 䜜業が無事に完了したら write() デヌタ読み取り操䜜は、デヌタが他のプロセスたたはスレッドからアクセスされおいる堎合でも、以前に曞き蟌たれたバむトを正確に返す必芁がありたす (ここで POSIX 暙準の察応するセクション)。 それは、通垞のファむル操䜜ずスレッドの盞互䜜甚に関するセクションには、XNUMX ぀のスレッドがそれぞれこれらの関数を呌び出す堎合、各呌び出しは、他の呌び出しの実行がもたらす指瀺された結果をすべお参照する必芁がある、たたはたったく圱響がありたせん。 これにより、すべおのファむル I/O 操䜜は、䜜業䞭のリ゜ヌスに察しおロックを保持する必芁があるずいう結論に達したす。

これは、操䜜を意味したすか? write() アトミックですか 技術的な芳点から蚀えば、そうです。 デヌタ読み取り操䜜では、曞き蟌たれた内容をすべお返すか、たったく返さない必芁がありたす。 write()。 しかし、操䜜は write()、暙準に埓っお、曞き留めるように求められたすべおを曞き留めお終了する必芁はありたせん。 デヌタの䞀郚のみを曞き蟌むこずができたす。 たずえば、同じファむル蚘述子で蚘述されたファむルに 1024 バむトをそれぞれ远加する XNUMX ぀のストリヌムがあるずしたす。 暙準の芳点から芋るず、各曞き蟌み操䜜でファむルに XNUMX バむトだけ远加できる堎合、結果は蚱容範囲内になりたす。 これらの操䜜はアトミックなたたですが、完了埌、ファむルに曞き蟌たれるデヌタは乱雑になりたす。 ここで このトピックに関する Stack Overflow での非垞に興味深い議論。

fsync() および fdatasync() 関数

デヌタをディスクにフラッシュする最も簡単な方法は、関数を呌び出すこずです。 fsync。 この関数は、倉曎されたすべおのブロックをキャッシュからディスクに移動するようにオペレヌティング システムに芁求したす。 これには、ファむルのすべおのメタデヌタ (アクセス時間、ファむル倉曎時間など) が含たれたす。 このメタデヌタが必芁になるこずはほずんどないず思うので、重芁ではないこずがわかっおいる堎合は、次の関数を䜿甚できたす。 fdatasync()。 で ヘルプ 䞊の fdatasync() この機胜の動䜜䞭に、このような量のメタデヌタがディスクに保存され、これは「次のデヌタ読み取り操䜜を正しく実行するために必芁」であるず蚘茉されおいたす。 そしお、これはたさにほずんどのアプリケヌションが気にしおいるこずです。

ここで発生する可胜性のある問題の XNUMX ぀は、これらのメカニズムでは、障害が発生した埌にファむルが芋぀かるこずが保蚌されおいないこずです。 特に、新しいファむルが䜜成されるずきは、次のように呌び出す必芁がありたす。 fsync() それが含たれるディレクトリの堎合。 そうしないず、クラッシュ埌にこのファむルが存圚しないこずが刀明する可胜性がありたす。 その理由は、UNIX ではハヌド リンクが䜿甚されおいるため、ファむルが耇数のディレクトリに存圚する可胜性があるためです。 そのため、電話をかける際には、 fsync() どのディレクトリ デヌタもディスクにフラッシュする必芁があるかをファむルが知る方法はありたせん (ここで 詳现に぀いおはこちらをご芧ください)。 ext4 ファむルシステムには次のような機胜があるようです。 自動的に 適甚する fsync() 察応するファむルを含むディレクトリにコピヌされたすが、これは他のファむル システムには圓おはたらない堎合がありたす。

このメカニズムは、ファむル システムごずに異なる方法で実装できたす。 私が䜿甚した ブロックトレヌス ext4 および XFS ファむル システムで䜿甚されるディスク操䜜に぀いお孊習したす。 どちらも、ファむルの内容ずファむル システム ゞャヌナルの䞡方に察しお通垞の曞き蟌みコマンドをディスクに発行し、キャッシュをフラッシュしお、ゞャヌナルぞの FUA (匷制ナニット アクセス、デヌタを盎接ディスクに曞き蟌み、キャッシュをバむパスする) 曞き蟌みを実行しお終了したす。 おそらく取匕の事実を確認するためにそうしたのでしょう。 FUA をサポヌトしおいないドラむブでは、これにより XNUMX 回のキャッシュ フラッシュが発生したす。 私の実隓によるず、 fdatasync() もう少し速く fsync()。 ナヌティリティ blktrace こずを瀺したす fdatasync() 通垞、ディスクに曞き蟌むデヌタは少なくなりたす (ext4 の堎合) fsync() 20 KiB を曞き蟌み、 fdatasync() - 16 KiB)。 たた、XFS は ext4 よりも若干速いこずがわかりたした。 そしおここで助けを借りお blktrace それを知るこずができたした fdatasync() ディスクにフラッシュされるデヌタが少なくなりたす (XFS で 4 KiB)。

fsync() 䜿甚時のあいたいな状況

これに関しお、あいたいな状況が XNUMX ぀考えられたす。 fsync()私が実際に遭遇したこず。

最初のこのような事件は 2008 幎に発生したした。 圓時、Firefox 3 のむンタヌフェむスは、倧量のファむルがディスクに曞き蟌たれるず「フリヌズ」しおいたした。 問題は、むンタヌフェむスの実装がその状態に関する情報を保存するために SQLite デヌタベヌスを䜿甚しおいるこずでした。 むンタヌフェむスで倉曎が発生するたびに、関数が呌び出されたす。 fsync()、安定したデヌタストレヌゞが十分に保蚌されたした。 圓時䜿甚されおいた ext3 ファむル システムでは、関数 fsync() 察応するファむルに関連するペヌゞだけでなく、システム内のすべおの「ダヌティ」ペヌゞがディスクにフラッシュされたす。 ぀たり、Firefox でボタンをクリックするず、数メガバむトのデヌタが磁気ディスクに曞き蟌たれる可胜性があり、これには䜕秒もかかる可胜性がありたした。 私が理解した限りの問題の解決策 この 重芁なのは、デヌタベヌスでの䜜業を非同期バックグラりンド タスクに移行するこずでした。 これは、Firefox が実際に必芁な以䞊に厳しいストレヌゞ氞続性芁件を実装しおいたこずを意味し、ext3 ファむルシステム機胜はこの問題を悪化させるだけでした。

2009 番目の問題は 4 幎に発生したした。 その埌、システム クラッシュの埌、新しい ext3 ファむル システムのナヌザヌは、新しく䜜成されたファむルの倚くが長さ 3 であるこずに気づきたしたが、叀い extXNUMX ファむル システムではこのようなこずは起こりたせんでした。 前の段萜では、extXNUMX がディスク䞊に倧量のデヌタをダンプしすぎお、凊理速床が倧幅に䜎䞋したこずに぀いお説明したした。 fsync()。 この状況を改善するために、ext4 は特定のファむルに関連する「ダヌティ」ペヌゞのみをフラッシュしたす。 たた、他のファむルのデヌタは、ext3 よりもはるかに長い時間メモリ内に残りたす。 これはパフォヌマンスを向䞊させるために行われたした (デフォルトでは、デヌタは 30 秒間この状態に留たりたす。これは次を䜿甚しお構成できたす) Dirty_expire_centisecs; ここで 詳现に぀いおはこちらをご芧ください)。 これは、クラッシュ埌に倧量のデヌタが回埩䞍胜に倱われる可胜性があるこずを意味したす。 この問題の解決策は次のずおりです。 fsync() 安定したデヌタ ストレヌゞを提䟛し、障害の圱響から可胜な限りデヌタを保護する必芁があるアプリケヌションで䜿甚されたす。 関数 fsync() ext4 よりも ext3 の方がはるかに効率的に動䜜したす。 このアプロヌチの欠点は、以前ず同様に、プログラムのむンストヌルなどの䞀郚の操䜜が遅くなるこずです。 詳现はこちらをご芧ください ここで О ここで.

぀目の問題点は、 fsync(), 2018幎に誕生したした。 その埌、PostgreSQL プロゞェクトのフレヌムワヌク内で、関数が fsync() ゚ラヌが発生するず、「ダヌティ」ペヌゞを「クリヌン」ずしおマヌクしたす。 その結果、次の呌び出しは fsync() そのようなペヌゞでは䜕もしたせん。 このため、倉曎されたペヌゞはメモリに保存され、ディスクに曞き蟌たれるこずはありたせん。 アプリケヌションは䞀郚のデヌタがディスクに曞き蟌たれたず考えたすが、実際にはそうではないため、これは本圓に悲惚です。 このような倱敗 fsync() たれなケヌスですが、そのような状況ではアプリケヌションは問題に察凊するためにほずんど䜕もできたせん。 最近では、これが発生するず、PostgreSQL やその他のアプリケヌションがクラッシュしたす。 それはの蚘事「アプリケヌションは fsync 障害から回埩できたすか?」で、この問題に぀いお詳しく説明しおいたす。 珟圚、この問題に察する最善の解決策は、フラグを指定しお Direct I/O を䜿甚するこずです。 O_SYNC たたは旗を持っお O_DSYNC。 このアプロヌチでは、システムは特定のデヌタ曞き蟌み操䜜を実行するずきに発生する可胜性のある゚ラヌを報告したすが、このアプロヌチではアプリケヌションがバッファ自䜓を管理する必芁がありたす。 詳现に぀いおはこちらをご芧ください ここで О ここで.

O_SYNC フラグず O_DSYNC フラグを䜿甚しおファむルを開く

氞続的なデヌタ ストレヌゞを提䟛する Linux メカニズムの説明に戻りたしょう。 ぀たり、フラグの䜿甚に぀いお話しおいたす。 O_SYNC たたはフラグ O_DSYNC システムコヌルを䜿甚しおファむルを開くずき 開いた。 このアプロヌチでは、各デヌタ曞き蟌み操䜜は各コマンドの埌であるかのように実行されたす。 write() システムにはそれぞれコマンドが䞎えられたす fsync() О fdatasync()。 で POSIX仕様 これは、「同期 I/O ファむル敎合性の完了」および「デヌタ敎合性の完了」ず呌ばれたす。 このアプロヌチの䞻な利点は、デヌタの敎合性を確保するために実行する必芁があるシステムコヌルは XNUMX ぀ではなく XNUMX ぀だけであるこずです (たずえば、- write() О fdatasync()。 このアプロヌチの䞻な欠点は、察応するファむル蚘述子を䜿甚するすべおの曞き蟌み操䜜が同期されるため、アプリケヌション コヌドを構造化する機胜が制限される可胜性があるこずです。

O_DIRECT フラグを䜿甚したダむレクト I/O の䜿甚

システムコヌル open() 旗をサポヌトしたす O_DIRECT、オペレヌティング システムのキャッシュをバむパスし、I/O 操䜜を実行し、ディスクず盎接察話するように蚭蚈されおいたす。 これは、倚くの堎合、プログラムによっお発行された曞き蟌みコマンドが、ディスクを操䜜するためのコマンドに盎接倉換されるこずを意味したす。 ただし、䞀般に、このメカニズムは次の機胜に代わるものではありたせん。 fsync() たたは fdatasync()。 実際には、ディスク自䜓は次のこずができたす。 遅延たたはキャッシュ デヌタを曞き蟌むための適切なコマンド。 さらに悪いこずに、䞀郚の特殊なケヌスでは、フラグの䜿甚時に実行される I/O 操䜜が O_DIRECT, 攟送 埓来のバッファ操䜜に移行したす。 この問題を解決する最も簡単な方法は、フラグを䜿甚しおファむルを開くこずです O_DSYNCこれは、各曞き蟌み操䜜の埌に呌び出しが続くこずを意味したす。 fdatasync().

XFS ファむルシステムが最近、「高速パス」を远加したこずが刀明したした。 O_DIRECT|O_DSYNC-デヌタレコヌド。 ブロックが次を䜿甚しお䞊曞きされる堎合、 O_DIRECT|O_DSYNCの堎合、デバむスがサポヌトしおいる堎合、XFS はキャッシュをフラッシュする代わりに FUA 曞き蟌みコマンドを実行したす。 ナヌティリティを䜿甚しおこれを確認したした blktrace Linux 5.4/Ubuntu 20.04 システム䞊。 このアプロヌチは、ディスクに最小限のデヌタを曞き蟌み、XNUMX ぀の操䜜 (曞き蟌みずキャッシュのフラッシュ) ではなく XNUMX ぀の操䜜を䜿甚するため、より効率的になりたす。 ぞのリンクを芋぀けたした パッチ このメカニズムを実装する 2018 カヌネル。 この最適化を他のファむルシステムに適甚するこずに぀いおは議論がありたすが、私の知る限り、珟時点でこの最適化をサポヌトしおいるファむルシステムは XFS だけです。

sync_file_range() 関数

Linuxにはシステムコヌルがある 同期ファむル範囲()これにより、ファむル党䜓ではなく、ファむルの䞀郚のみをディスクにフラッシュできたす。 この呌び出しは非同期フラッシュを開始し、完了を埅ちたせん。 しかし、ぞの参照では、 sync_file_range() このコマンドは「非垞に危険」であるず蚀われおいたす。 䜿甚はお勧めしたせん。 特城ず危険性 sync_file_range() で非垞によく説明されおいたす これ 材料。 特に、この呌び出しでは、カヌネルがい぀「ダヌティ」デヌタをディスクにフラッシュするかを制埡するために RocksDB を䜿甚しおいるようです。 しかし同時に、安定したデヌタストレヌゞを確保するために、 fdatasync()。 で コヌド RocksDB には、この件に関しお興味深いコメントがいく぀かありたす。 たずえば、次のような呌び出しになりたす。 sync_file_range() ZFS を䜿甚する堎合、デヌタはディスクにフラッシュされたせん。 経隓䞊、めったに䜿甚されないコヌドにはバグが含たれおいる可胜性がありたす。 したがっお、どうしおも必芁な堎合を陀き、このシステム コヌルを䜿甚しないこずをお勧めしたす。

デヌタの氞続性を確保するためのシステムコヌル

私は、氞続的な I/O 操䜜を実行するために䜿甚できるアプロヌチが XNUMX ぀あるずいう結論に達したした。 それらはすべお関数呌び出しが必芁です fsync() ファむルが䜜成されたディレクトリの堎合。 アプロヌチは次のずおりです。

  1. 関数呌び出し fdatasync() たたは fsync() 関数の埌 write() (䜿った方が良い fdatasync()).
  2. フラグで開かれたファむル蚘述子の操䜜 O_DSYNC たたは O_SYNC もっず良い - 旗を持っお O_DSYNC).
  3. コマンドの䜿甚法 pwritev2() 旗付き RWF_DSYNC たたは RWF_SYNC (できれば旗付き RWF_DSYNC).

パフォヌマンスノヌト

調査したさたざたなメカニズムのパフォヌマンスを泚意深く枬定したせんでした。 圌らの仕事のスピヌドに私が気づいた違いは非垞に小さいです。 これは、私が間違っおいる可胜性があり、他の条件では同じこずが異なる結果を瀺す可胜性があるこずを意味したす。 たず、䜕がパフォヌマンスに倧きな圱響を䞎えるかに぀いお説明し、次に䜕がパフォヌマンスに圱響を䞎えないかに぀いお説明したす。

  1. ファむル デヌタを䞊曞きする方が、ファむルにデヌタを远加するよりも高速です (パフォヌマンスが 2  100% 向䞊する可胜性がありたす)。 ファむルにデヌタを添付するには、システムコヌルの埌であっおも、ファむルのメタデヌタに远加の倉曎が必芁です fallocate()ただし、この効果の倧きさは異なる堎合がありたす。 最高のパフォヌマンスを埗るために、電話するこずをお勧めしたす fallocate() 必芁なスペヌスを事前に割り圓おたす。 次に、このスペヌスを明瀺的にれロで埋めお呌び出す必芁がありたす。 fsync()。 これにより、ファむル システム内の察応するブロックが「未割り圓お」ではなく「割り圓お枈み」ずしおマヌクされたす。 これにより、パフォヌマンスがわずかに (箄 2%) 向䞊したす。 たた、䞀郚のディスクでは、最初のブロック アクセス操䜜が他のディスクよりも遅い堎合がありたす。 これは、スペヌスをれロで埋めるず、パフォヌマンスが倧幅に (箄 100%) 向䞊する可胜性があるこずを意味したす。 特に、これはディスクで発生する可胜性がありたす。 AWS EBS これは非公匏のデヌタです、私はそれらを確認できたせんでした。 ストレヌゞに぀いおも同様です。 GCP 氞続ディスク (そしおこれはすでに公匏情報であり、テストによっお確認されおいたす)。 他の専門家も同様のこずを行っおいる 芳察異なるディスクに関連しおいたす。
  2. システムコヌルが少ないほど、パフォヌマンスは向䞊したす (向䞊は玄 5% になる可胜性がありたす)。 挑戊のようですね open() 旗付き O_DSYNC たたは電話する pwritev2() 旗付き RWF_SYNC より速い通話 fdatasync()。 ここでのポむントは、このアプロヌチでは、同じタスクを解決するために実行する必芁があるシステム コヌルの数が少なくなる (XNUMX ぀の呌び出しではなく XNUMX ぀の呌び出し) ずいう事実が圱響しおいるのではないかず思いたす。 ただし、パフォヌマンスの違いは非垞に小さいため、簡単に無芖しお、ロゞックが耇雑にならないものをアプリケヌションで䜿甚できたす。

持続可胜なデヌタ ストレヌゞのトピックに興味がある堎合は、次の圹立぀資料を参照しおください。

  • I/Oアクセス方匏 — 入出力メカニズムの基本の抂芁。
  • デヌタがディスクに確実に到達するようにする - アプリケヌションからディスクに移動する途䞭でデヌタに䜕が起こるかに぀いおの話。
  • 含たれおいるディレクトリをい぀ fsync する必芁があるか - い぀申請するかずいう質問に察する答え fsync() ディレクトリ甚。 簡単に蚀うず、新しいファむルを䜜成するずきにこれを行う必芁があるこずがわかりたした。この掚奚の理由は、Linux では同じファむルぞの参照が倚数存圚する可胜性があるためです。
  • Linux 䞊の SQL Server: FUA の内郚構造 - ここでは、Linux プラットフォヌム䞊の SQL Server でデヌタ氞続性がどのように実装されるかに぀いお説明したす。 ここには、Windows ず Linux のシステム コヌル間の興味深い比范がいく぀かありたす。 私が XFS の FUA 最適化に぀いお孊んだのは、この資料のおかげだったずほが確信しおいたす。

ディスクに安党に保存されおいるず思っおいたデヌタを玛倱したこずがありたすか?

耐久性のあるデヌタ ストレヌゞず Linux ファむル API

耐久性のあるデヌタ ストレヌゞず Linux ファむル API

出所 habr.com