Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Best Practices and Pitfalls

This chapter provides a collection of best practices, advanced techniques, and common pitfalls to help you build robust, production-ready layers on FoundationDB.

Transaction Management

Use Timeouts and Retry Limits

Most language bindings provide a run or transact method that automatically handles the retry loop for you. However, to prevent transactions from running indefinitely, it is critical to configure two options:

  • Timeout: Set a timeout in milliseconds. If the transaction takes longer than this to commit, it will be automatically cancelled. This is a crucial backstop for preventing stuck application threads.
  • Retry Limit: Set a maximum number of retries. This prevents a transaction from retrying endlessly in the case of a persistent conflict or a live-lock scenario.

These options should be set on every transaction to ensure your application remains stable under load.

Set Transaction Priority

FoundationDB supports transaction priorities to help manage workloads.

  • Default: The standard priority for most latency-sensitive, user-facing operations.
  • Batch: A lower priority for background work, such as data cleanup or analytics. Batch priority transactions will yield to default priority transactions, ensuring that they don't interfere with your main application workload.
  • System Immediate: The highest priority, which can block other transactions. Its use is discouraged outside of low-level administrative tools.

Observability

Tag Your Transactions

FoundationDB allows you to add a byte-string tag to any transaction. This is an invaluable tool for observability and performance management. You can use tags to identify different types of workloads (e.g., user_signup, post_comment). The fdbcli tool can then be used to monitor the rate of transactions with specific tags and even throttle them if they are causing excessive load.

See the official documentation on Transaction Tagging for more details.

Enable Client Trace Logs

By default, clients do not generate detailed trace logs. To debug performance issues, you can enable them by setting the TraceEnable database option. You can then add a DebugTransactionIdentifier to a specific transaction and set the LogTransaction option to get detailed, low-level logs about its execution, including all keys and values read and written.

Advanced Techniques

The metadataVersion Key

The special key \xFF/metadataVersion is a cluster-wide version counter that can be used to implement client-side caching. Its value is sent to clients with every read version, so reading it does not require a round-trip to a storage server. A layer can watch this key to know when to invalidate a local cache.

Note: If you write to the metadataVersion key, you cannot read it again in the same transaction.

The TimeKeeper

The Cluster Controller maintains a map of recent read versions to wall-clock times. This can be accessed by scanning the key range beginning with \xFF\x02/timeKeeper/map/. This can be useful for approximating a global clock.

Special Keys

Keys prefixed with \xFF\xFF are “special” keys that are materialized on-demand when read. The most common example is \xFF\xFF/status/json, which returns a JSON document containing the cluster's status.

See the official documentation on Special Keys for more details.

Common Pitfalls: The Directory Layer

The Directory Layer is a powerful tool, but it has several sharp edges that developers must be aware of:

  • Concurrent Mutations: Modifying the same directory (e.g., creating two different subdirectories within it) in multiple, concurrent transactions is not safe and can lead to corruption.
  • Metadata Hotspots: Opening a directory with a long path requires one read per path element for every transaction. This can create a hotspot on the directory's internal metadata subspace.
  • Multi-Cluster Deployments: The directory prefix allocator is not safe for multi-cluster deployments and can allocate the same prefix in different clusters, leading to data corruption if the data is ever merged.
  • Redwood and Prefix Compression: The Redwood storage engine (new in 7.0) provides native key-prefix compression. This offers many of the same space-saving benefits as the Directory Layer without the associated complexity and caveats. For new projects, especially those using Redwood, consider whether you can use subspaces with descriptive prefixes directly instead of relying on the Directory Layer.