未解決
Community Manager
•
3.1K メッセージ
0
384
【Coffee Break】DBのスナップショットをとって、それって使えるの?
この投稿は「ちょっとしたストレージ関連技術のTIPSを思いついたら書いてみる」というコンセプトで、デル・テクノロジーズ社内のTeamsグループ/チームでゆる~く運営されている「Coffee Break」からの情報抜粋です。今回はDBスペシャリストからの投稿を抜粋しました。
データベースに対してストレージスナップショットを取得した場合、そのスナップショットはちゃんと使えるの?という話を聞くことがあります。
一般論としては、ちゃんとしたRDBMSであれば戻せます、というのが回答になるかと思います。
(正式にサポートするか?というのは別問題なので、実際の回答は難しいですが・・・)
きちんとしたDBであれば、いわゆるACID特性を満たしているはずであり、そのうちのD:Durability を備えているという意味になります。
(参考Wikiページ: Durability)
これはトランザクションがきちんと完了したら、その結果は永続的であるということです。システム障害においても、です。たとえばDBサーバが突然ダウンした場合でも、次回起動したらCOMMITされていたトランザクションの結果は消えていてはいけない、ということです(起動しなかったとしても、ディスクがあればそこから復元できる)。
このDを実現するために、多くのDBではトランザクションの操作をログとして不揮発領域(ストレージとか)に記録し、なにか異常があった場合にはこのログから復旧する、ということをします。ちょっと思いつくだけでも、Oracle, SQL, PostgreSQLなどはみなそうしています。
トランザクションの操作をまずログに記録し、データの更新は後回しという実装になっています。操作の記録がログにあるので、データに何かがあってもログから復元できる、という考え方です。トランザクションの結果を確実にログに反映させるため、ログを書き込む際はOSから同期書き込みをします。COMMIT操作をしたら、そのログが不揮発領域に書き込み完了するまで次の操作はできない、ということです。性能的には不利ですがDを実現するためには仕方なし、というところです。当然ながらDBMSは通常はOS上で動くアプリケーションですので、アプリケーションとしてできる範囲で最大限頑張る、という話にはなってしまうかと思います。
ストレージスナップである瞬間のLUNの断面を記録するというのは、DBの都合はお構いなしにLUNの状態だけを保存するという意味合いになります。そこだけ見るとDBサーバダウンのときと似たような状態と言えるかと思います。
DBサーバのHAクラスタ、いわゆるActive/Standbyのクラスタを思い浮かべてください。OracleでもSQLでもPostgreSQLでも構成できます。これらのクラスタの謳い文句は「Activeノードに何かあったら、Standbyに切り替わります」だと思います。
ストレージスナップショットを心配する人が、このHA構成を心配しないのが私は不思議です。Activeノードに何かあって異常終了したとしても、Standby が同じディスクをマウントすれば起動する、と思えるのは、ここまで述べてきたDBの永続性を暗黙のうちに信用しているからにほかなりません。
我々の(ブロック)ストレージでは、スナップショットにおいてサーバからのIOの書き込み順を崩すことはありません。そのため、異常終了したサーバが残したディスクの状態よりも、よほど整合性的には信用できる状態ではないかと個人的に思います。
蛇足ながらストレージスナップを使っても、DB製品として正式に保証すると謳っているのは私の知る限りOracleのみです。いかなる場合でも、とはいきませんが、正式なサポート文書としてサポートする旨や、サポートの条件が記載されています。また、12c以降だと、ストレージスナップからリカバリするためのコマンドまで用意されています。キーワードは「ストレージ・スナップショットの最適化」、"Storage Snapshot optimization" です。マニュアルにそういった章が設けてあります。
【余談】Unix/Linuxでのファイルの同期書き込みの例:C言語
fd = open("/tmp/aaa", O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0644);
のように、O_SYNC フラグをつけてファイルをオープンする。その後この fd に対して
write(fd,buf,0x500000);
のようにwrite すると、その書き込みは同期書き込みとなる。
(writeが実際にデバイスまで行って帰ってこないと、このwrite()コールも戻ってこない)
O_SYNCをつけないと、同じ write() を行っても、非同期書き込みになる。この場合はデバイスまで書き込まなくとも、OSのバッファに入った時点で write()コールが戻ってくる。
(なので、OSのバッファに入っているが、デバイスまで書かれていない状態 という状態がありうる)