RocksDB Block Cache memory growth with shared Column Families
0 reputation · 30 Oct 2023, 19:12 UTC
0 reputation · 30 Oct 2023, 19:12 UTC
RocksDB allows multiple Column Families to share a single Block Cache to optimize memory utilization. While the cache is governed by a size limit and an LRU eviction policy, the interaction between the Block Cache and MemTable memory limits can create ambiguity regarding the total process memory footprint.
Under high concurrency and heavy random read patterns across diverse Column Families, there is uncertainty regarding how effectively memory is reclaimed when the shared cache reaches its capacity. Specifically, the discrepancy between internal rocks.block_cache_usage metrics and the system resident set size (RSS) suggests potential overhead or fragmentation issues during eviction cycles.
35275 reputation · 31 Oct 2023, 01:21 UTC
The shared Block Cache does enforce the configured capacity for the data it tracks, and moving to per-Column Family caches changes isolation at the cost of overhead. The RSS vs rocks.block_cache_usage gap you see is expected and is not a failure of eviction.
BlockBasedTableOptions.block_cache is a single cache instance referenced by multiple Column Families. Insert charge is the block size plus internal overhead, and eviction is global LRU across all CFs.rocks.block_cache_usage reports the sum of charges held in the cache. It does not include MemTable memory, WAL, or process allocator overhead.Under high concurrency and heavy random reads across diverse Column Families, simultaneous insertions cause rapid LRU churn. The cache enforces the size limit on a per-insert basis, so eviction does occur, but:
rocks.block_cache_usage oscillates near the cap.rocks.block_cache_pinned_usage, temporarily holds blocks outside normal LRU accounting.Isolated caches per Column Family prevent one CF from evicting another CF's hot data and make per-CF limits explicit. The trade-off is higher total overhead because each cache maintains its own LRU lists, hash tables and allocator arenas. Total RSS often rises with isolation, even though per-CF predictability improves.
cat /proc/self/status | grep -E 'VmRSS|VmHWM'
Compare with rocks.block_cache_usage and rocks.block_cache_pinned_usage from RocksDB statistics.options.allow_mmap_reads and allocator settings only after a baseline is captured.rocks.block_cache_hit_rate, rocks.block_cache_index_usage, and eviction counts per CF. High pinned usage indicates reads are holding memory.One diagnostic detail that changes the recommendation: which allocator RocksDB is built with and whether Cache::NewLRUCache is configured with strict capacity and no high-priority partition. The allocator determines how quickly RSS can fall after eviction, and high-priority partitions can make the cache appear to exceed the nominal limit.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 30 Oct 2023, 19:38 UTC
While the shared cache enforces charges per insertion, the configured capacity behaves as a soft target under concurrency. Simultaneous inserts across column families can cause transient overage before eviction catches up, so reported cache usage may briefly exceed the limit during read bursts.
For total process memory, block cache and memtable/write-buffer limits are independent controls. Without a write buffer manager coordinating stalls, the effective footprint is roughly the sum of both limits plus overhead. Enabling a strict capacity limit changes insertion behavior when the cache is full, but that behavior is configuration- and version-sensitive and can affect read latency. Verify the exact option names and defaults against your RocksDB version before relying on them.