CassandraのDELETEの振る舞いについて

Cassandraを障害時のバックアップとして使うにあたり、DELETE時の処理を考える過程で学んだこと。

DELETEしてもすぐには消えない

CassandraのDELETEコマンドは、RDBMSとは異なりすぐに消えるものではない。
ある行をDELETEしても、その行のデータはディスクに残り続ける。その代わり、tombstoneというフラグが立ち、ユーザが削除の指示をしたことがわかるようになっている。つまり、DELETEコマンドもまたUPDATEコマンドの一種にすぎない。

tombstoneが立った行は、スキーマでのgc_grace_secondsで指定した秒が経過して初めてディスクから消去される。
これは、大量データの処理速度を最優先させるというCassandraの設計思想に基づいたものだ。

DELETEが起こるテーブルを設計するときのポイント

この性質は、テーブルの設計をする時にも考えなければいけない。
例えば、ある行をDELETEした後、残った行をSELECTでスキャンする場合。
このとき、gc_grace_seconds以内であれば、DELETEした行はまだディスクには残っているため、当然スキャンの対象となる。「DELETEして行の数が減ったぞ」と思っていると、予想以上にSELECTに時間がかかってしまうことがある。

さらに、Cassandraはスキャンをする際に、tombstoneをコーディネーターに伝えるためメモリ上に保管しておく。このため、短時間に多くの行をDELETEしてtombstoneがたまると、パフォーマンスに影響を及ぼし、最悪の場合はサーバ上のヒープが吹っ飛ぶ可能性もある。
具体的な検証をまじえた解説は、Cassandra公式の以下のブログで行われている。

www.datastax.com

また、同じ値の主キーを何度もDELETE/INSERTする時も注意が必要になる。
これは特定の行を頻繁にUPDATEしていることと同じになる。ミリ秒単位でtimestampが同じになるほど頻繁にDELETE/INSERTをした結果、予想外の結果が返ってきたという例もあるようだ。

stackoverflow.com

もちろんgc_grace_secondsの設定があるのでtombstoneが永遠に残ることはないが、上記のようなことが短時間で頻繁に起こるのは良くない。
最も良いのは、削除したものも含めて常に主キーが一意となり、そして大量のスキャンをなるべく避けられるような設計のテーブルを作ることだろう。削除した行が再びSELECTやUPDATEの対象となる可能性を減らすことができれば、パフォーマンスへの影響も出にくくなる。