Couchbase Server consists of various services and components that have different storage requirements. Each component uses the optimized storage engine purpose-built and configured for the workload of relevant components.
As an administrator, you can independently control data and index storage paths within the filesystem on a per node basis. This ensures data and index storage can utilize separate I/O subsystems to enable independent tuning and isolation. There are multiple storage engines in use in Couchbase Server:
Data Service and Couchstore
For core data operations, Couchbase Server uses Couchstore. Each vBucket is represented as a separate Couchstore file in the file system. Couchstore uses a B+tree structure to quickly access items through their keys. For efficient writes, Couchstore uses an append-only write model for each file for efficient and safe writes.
Index Service and ForestDB
For indexing with GSI in the Index service, Couchbase Server uses ForestDB. With ForestDB, each index is represented as a separate ForestDB file in the file system. Unlike Couchstore, ForestDB uses a B+trie structure to quickly access item through its index key. B+trie provides a more efficient tree structure compared to B+trees and ensures a shallower tree hierarchy to better scale large item counts and very large index keys. ForestDB, like Couchstore, uses an append-only write model for each file for efficient writes which also requires compaction for cleanup. For more information on ForestDB and B+Trie, see \https://github.com/couchbase/forestdb.
Couchbase Server uses multiple storage engines to optimize specific I/O patterns required by the services. Couchstore is used for storage under data service for both database engine and for view engine. ForestDB is used by the index service for storage of global secondary indexes.
There are a few similarities between Couchstore and ForestDB.
Both use an append-only write approach.
Both storage engines perform compression using the SNAPPY library when persisting.
Both storage engines require compaction to periodically clean up orphaned pages.
There are a few important differences between Couchstore and ForestDB.
Tree Structure: Unlike Couchstore, ForestDB does not maintain a B+tree structure. ForestDB uses an optimized tree structure called B+Trie. B+Trie can handle large keys much more efficiently. This helps in cases where a large set of attributes or a single large attribute in the document need to be indexed. B+tree with large index keys can end up with many levels in the tree. The depth of the tree impacts the write amplification and access times to get to the leaf of the tree during scans. With a B+Trie, the same key size can achieve much shallower tree structure reducing both write amplification and retrieval times.
Caching: Unlike Couchstore, ForestDB maintain its own cache. This cache holds the mutations before they are persisted to disk.
As mutations arrive, the writes append new pages to the end of the file and invalidate links to previous versions of the updated pages. With these append-only write models, a compaction process is needed to clean up the orphaned or fragmented space in the files.
In Couchbase Server, the compaction process reads the existing file and writes a new contiguous file that no longer contains the orphaned items. The compaction process runs in the background and is designed to minimize the impact on the front end performance.
The compaction process can be manual, scheduled, or automated based on percentage of fragmentation. Compaction of an entire dataset is parallelized across multiple nodes as well as multiple files within those nodes.
In the figure below, as A’’, B’ and D is received by Couchbase Server, previous versions such as A’, A and B are orphaned. After compaction, the orphaned references are removed and a continuous file is created.