Photo by Shubham Dhage on Unsplash
Tombstone TTL and Distributed Delete Propagation
The Problem With Deleting in Distributed Systems
Deleting data seems simple in a single-node database. You remove the record, reclaim the space, and move on. But in a distributed system with eventual consistency, deletion becomes surprisingly complex. The core challenge: how do you ensure a delete operation propagates to all replicas when nodes might be temporarily offline, partitioned, or receiving concurrent writes?
The standard solution is the tombstone—a special marker that indicates a delete occurred. Instead of immediately removing data, the system writes a tombstone that supersedes the original value. When replicas sync, they see the tombstone and know to discard their copies of that key. This ensures deletes propagate correctly even when nodes are temporarily unreachable.
Why Tombstones Need Expiration
Tombstones solve the propagation problem but create a new one: they accumulate. Every deleted key leaves behind a marker that consumes storage and gets included in compaction operations, anti-entropy repairs, and read paths. In systems with high churn—where keys are frequently created and deleted—tombstone accumulation degrades performance and wastes disk space.
The solution is tombstone time-to-live (TTL): automatically removing tombstones after a configured duration. The assumption is that after enough time has passed, all replicas have seen the tombstone and processed the deletion. Once that window closes, the tombstone itself can be safely removed.
The Tombstone TTL Dilemma
Choosing the right TTL involves a fundamental tradeoff. Set it too short, and you risk resurrection: a node that was offline during the TTL window comes back online, sees no tombstone, and reintroduces the deleted data during anti-entropy repair. Set it too long, and tombstones accumulate, degrading read performance and consuming storage.
The TTL must be longer than the maximum time any replica might be offline while still participating in the cluster. For systems designed for high availability with aggressive failure detection, this might be hours or days. For systems that tolerate longer maintenance windows or slower repairs, it might be weeks.
Cassandra defaults to 10 days. Riak allows per-bucket configuration. The choice depends on operational patterns: how quickly failed nodes are replaced, how long maintenance might take, and how much resurrection risk is acceptable.
Compaction and Tombstone Visibility
Tombstones interact with storage engine compaction in critical ways. In LSM-tree-based systems, tombstones must be preserved across compaction operations until their TTL expires. A tombstone in a newer SSTable must shadow older instances of the same key in older SSTables, even during major compactions that span multiple levels.
The storage engine must track tombstone creation timestamps and check them against the TTL during compaction. Only when a tombstone is older than the TTL—and crucially, when the compaction can verify that all older data for that key has been eliminated—can the tombstone itself be dropped.
Some systems add a grace period beyond the configured TTL to add safety margin. Others require manual intervention to purge tombstones in pathological cases, such as after bulk deletes that create millions of markers.
Range Tombstones and Efficiency
Individual key tombstones are expensive when deleting large ranges. Some systems support range tombstones: a single marker indicating that all keys in a range are deleted. This is far more space-efficient than individual tombstones for each key.
Range tombstones introduce their own complexity. During reads, the system must check whether each key falls within a deleted range. During compaction, range tombstones must be carefully merged and split as SSTables are reorganized. The implementation requires careful ordering and merging logic to ensure correctness.
Operational Considerations
Monitoring tombstone accumulation is critical. High tombstone ratios in read queries indicate either misconfigured TTLs or access patterns that frequently scan deleted data. Some systems expose metrics for tombstone counts per query, tombstone-to-live-data ratios, and tombstone eviction rates.
In extreme cases, expired tombstones that cannot be safely removed—because older data might still exist in deep compaction levels—can trigger manual repair operations. Operators might need to force major compactions, remove and rebuild nodes, or adjust TTL settings and wait for the change to take effect.
The delete propagation problem has no perfect solution. Tombstone TTLs represent a practical compromise: accept bounded storage overhead and resurrection risk in exchange for eventual consistency and operational simplicity. The key is matching the TTL to cluster dynamics and monitoring for the inevitable edge cases.