Skip to main content

Garnet Configuration

How to Configure Garnet​

The Garnet server (GarnetServer.exe) can be configured using a configuration file (e.g. garnet.conf or redis.conf), while command line arguments can be used to override any settings specified in the file. Any settings not specified in either configuration file or command line arguments are set to default valued specified in the defaults.conf file (path to this file can be overridden via the command line arguments).

Garnet currently supports two configuration file formats:

  1. The garnet.conf file format (default) - a JSON-formatted collection of settings
  2. The redis.conf file format - a collection of settings in the Redis configuration file format:
    keyword argument1 argument2 argument3 ... argumentN
    See Redis docs for reference. Important: Not all redis.conf keywords are supported in Garnet. In order to have full configuration settings coverage, use the garnet.conf format.

Specifying a configuration file path (and a default file path) can be done via the command line parameters.

  1. For garnet.conf:
    GarnetServer.exe --config-import-path <file-path>
  2. For redis.conf:
    GarnetServer.exe --config-import-path <file-path> --config-import-format RedisConf

Note: To change the path (and/or format) of the defaults configuration file, use the config-default-import-path and config-default-import-format keywords respectively.

garnet.conf​

The default configuration file format for Garnet, which supports the full-range of configurable Garnet settings. garnet.conf is a JSON-formatted file containing a collection of configuration settings. For all the available settings, see the defaults.conf file or refer to the complete Garnet settings list.

redis.conf​

Garnet supports the redis.conf file format as a configuration file. Note that not all redis.conf keywords are supported. Please see the following list of supported redis.conf keywords:

redis.conf keywordgarnet.conf keywordNotes
bindAddressOnly the first IP address specified is used; all other addresses are ignored.
protected-modeProtectedMode
enable-debug-commandEnableDebugCommandEnable the DEBUG command for no, local, or yes (all) connections.
enable-module-commandEnableModuleCommandEnable the MODULE command for no, local, or yes (all) connections.
portPort
maxmemoryLogMemorySize
logfileFileLogger
dirCheckpointDir
cluster-enabledEnableCluster
requirepassPassword
aclfileAclFile
cluster-node-timeoutClusterTimeout
tls-portEnableTLSValue used to indicate if TLS should be used, port number is otherwise ignored
tls-cert-fileCertFileNameGarnet currently supports TLS using a .pfx file and passphrase, while Redis supports TLS using .crt and .key files. In order to use TLS in Garnet while using redis.conf, convert your certificate to .pfx format (see details in the security section), then use the .pfx file path as the tls-cert-file value. If a passphrase was used when creating the original certificate, specify it in the tls-key-file-pass parameter as you would in Redis (or via the --cert-password command line argument). When starting the server, use the --cert-subject-name command line argument to set the certificate subject name, if applicable.
tls-key-file-passCertPasswordSee tls-cert-file notes
tls-auth-clientsClientCertificateRequiredSee tls-cert-file notes
latency-trackingLatencyMonitor
commandstats-trackingCommandStatsMonitor
loglevelLogLevel
io-threadsThreadPoolMinThreads
repl-diskless-sync-delayReplicaSyncDelayMs
unixsocketUnixSocketPath
unixsocketpermUnixSocketPermission
slowlog-log-slower-thanSlowLogThreshold
slowlog-max-lenSlowLogMaxEntries
databasesMaxDatabases

Command line arguments​

Any setting in Garnet can be also configured by specifying a command line argument. If the setting is also specified in the configuration file, it will be overridden by the value specified in the command line. For all available command line settings, run GarnetServer.exe -h or GarnetServer.exe -help, or refer to the complete Garnet settings list.

Configurable Settings​

garnet.conf
keyword
Command line keyword(s)TypeValid ValuesDescription
Port--portintInteger in range:
[0, 65535]
Port to run server on
Address--bindstringIP Address in v4/v6 formatWhitespace or comma separated string of IP addresses to bind server to (default: any)
ClusterAnnouncePort--cluster-announce-portintInteger in range:
[0, 65535]
Port that this node advertises to other nodes to connect to for gossiping.
ClusterAnnounceIp--cluster-announce-ipstringIP Address in v4/v6 formatIP address that this node advertises to other nodes to connect to for gossiping.
ClusterAnnounceHostname--cluster-announce-hostnamestringHostname that this node advertises to other nodes to connect to for gossiping.
ClusterPreferredEndpointType--cluster-preferred-endpoint-typeClusterPreferredEndpointTypeip, hostname, unknownDetermines the endpoint type to be advertised to other nodes. (value options: ip, hostname, unknown)
LogMemorySize-m
--memory
stringMemory sizeTotal main-log memory (inline and heap) to use, in bytes. Does not need to be a power of 2
PageSize-p
--page
stringMemory sizeSize of each main-log page in bytes (rounds down to power of 2; minimum 512).
PageCount--pagecountintInteger in range:
[0, MaxValue]
Number of main-log pages (rounds down to power of 2). This allows specifying less pages initially than LogMemorySize divided by PageSize.
SegmentSize-s
--segment
stringMemory sizeSize of each main-log segment in bytes on disk (rounds down to power of 2)
ObjectLogSegmentSize--object-log-segmentstringMemory sizeSize of each object-log segment in bytes on disk (rounds down to power of 2)
IndexMemorySize-i
--index
stringMemory sizeStart size of hash index in bytes (rounds down to power of 2)
IndexMaxMemorySize--index-max-sizestringMemory sizeMax size of hash index in bytes (rounds down to power of 2)
UseNativeAllocator--use-native-allocatorboolRoute large memory regions (log pages / hash index / recovery frames) through a native (off-managed-heap) direct-VM allocator (mmap/VirtualAlloc) instead of the GC heap. No native library is required. When enabled, size GCHeapHardLimit to leave headroom and monitor 'native_allocator_bytes' in INFO memory.
UseLegacyBufferPool--use-legacy-buffer-poolboolSelect the per-level ConcurrentQueue SectorAlignedBufferPool instead of the default origin-return (per-thread) pool. The origin-return pool returns each buffer to the thread that allocated it, so it scales with concurrent IO-completion threads under a per-pool byte budget.
BufferPoolMemoryBudget--buffer-pool-memory-budgetstringMemory sizePer-pool managed byte budget for the default origin-return SectorAlignedBufferPool (ignored when --use-legacy-buffer-pool is set). Bounds total cacheable buffer bytes across all IO-completion threads, reserving 25% for small size-classes and 75% for large. Requests above the pooled ceiling, or beyond the budget, allocate on demand and free on return. Set to 0 to disable buffer caching entirely (applies to both pool backends). E.g. 1g, 8g.
MutablePercent--mutable-percentintInteger in range:
[0, 100]
Percentage of log memory that is kept mutable
EnableReadCache--readcacheboolEnables read cache for faster access to on-disk records.
ReadCacheMemorySize--readcache-memorystringMemory sizeTotal readcache-log memory (inline and heap) to use if readcache is enabled, in bytes. Does not need to be a power of 2
ReadCachePageSize--readcache-pagestringMemory sizeSize of each read cache page in bytes (rounds down to power of 2; minimum 512).
ReadCachePageCount--readcache-pagecountintInteger in range:
[0, MaxValue]
Number of readcache-log pages (rounds down to power of 2). This allows specifying less pages initially than ReadCacheMemorySize divided by ReadCachePageSize.
EnableStorageTier--storage-tierboolEnable tiering of records (hybrid log) to storage, to support a larger-than-memory store. Use --logdir to specify storage directory.
CopyReadsToTail--copy-reads-to-tailboolWhen records are read from the store's in-memory immutable region or storage device, copy them to the tail of the log.
LogDir-l
--logdir
stringStorage directory for tiered records (hybrid log), if storage tiering (--storage-tier) is enabled. Uses current directory if unspecified.
CheckpointDir-c
--checkpointdir
stringStorage directory for checkpoints. Uses logdir if unspecified.
Recover-r
--recover
boolRecover from latest checkpoint and log, if present.
DisablePubSub--no-pubsubboolDisable pub/sub feature on server.
PubSubPageSize--pubsub-pagesizestringMemory sizePage size of log used for pub/sub (rounds down to power of 2)
DisableObjects--no-objboolDisable support for data structure objects.
EnableCluster--clusterboolEnable cluster.
CleanClusterConfig--clean-cluster-configboolStart with clean cluster config.
ParallelMigrateTaskCount--pmtintInteger in range:
[0, 16384]
Number of parallel migrate tasks to spawn when SLOTS or SLOTSRANGE option is used.
FastMigrate--fast-migrateboolWhen migrating slots 1. write directly to network buffer to avoid unnecessary copies, 2. do not wait for ack from target before sending next batch of keys.
AuthenticationMode--authGarnetAuthenticationModeNoAuth, Password, Aad, ACL, AclWithAadAuthentication mode of Garnet. This impacts how AUTH command is processed and how clients are authenticated against Garnet. Value options: NoAuth, Password, Aad, ACL
Password--passwordstringAuthentication string for password authentication.
ClusterUsername--cluster-usernamestringUsername to authenticate intra-cluster communication with.
ClusterPassword--cluster-passwordstringPassword to authenticate intra-cluster communication with.
AclFile--acl-filestringExternal ACL user file.
AclStrictCustomCommands--acl-strict-custom-commandsboolIf true (default), the server refuses to start when an ACL rule references a custom (extension) command name that no loaded module has registered. Set to false to load unresolved names as-is and log warnings.
AadAuthority--aad-authoritystringThe authority of AAD authentication.
AadAudiences--aad-audiencesstringThe audiences of AAD token for AAD authentication. Should be a comma separated string.
AadIssuers--aad-issuersstringThe issuers of AAD token for AAD authentication. Should be a comma separated string.
AuthorizedAadApplicationIds--aad-authorized-app-idsstringThe authorized client app Ids for AAD authentication. Should be a comma separated string.
AadValidateUsername--aad-validate-acl-usernameboolOnly valid for AclWithAAD mode. Validates username - expected to be OID of client app or a valid group's object id of which the client is part of.
EnableAOF--aofboolEnable write ahead logging (append-only file).
AofMemorySize--aof-memorystringMemory sizeTotal AOF memory buffer used in bytes (rounds down to power of 2) - spills to disk after this limit. Must be at least twice AofPageSize.
AofPageSize--aof-page-sizestringMemory sizeSize of each AOF page in bytes (rounds down to power of 2). Must be at least twice the main-log PageSize, since an AOF entry can be as large as the underlying main-log record being written; object commands like LPUSH/HSET can push this even higher. When you raise this, also raise --aof-memory to at least 2x this value.
AofSegmentSize--aof-segment-sizestringMemory sizeSize of each AOF segment (file) in bytes on disk (rounds down to power of 2). This is the granularity at which AOF files are created and truncated.
AofPhysicalSublogCount--aof-physical-sublog-countintInteger in range:
[1, 4]
Number of AOF physical sublogs (i.e. TsavoriteLog instances) used (=1 equivalent to the legacy single log implementation >1: sharded log implementation.
AofReplayTaskCount--aof-replay-task-countintInteger in range:
[1, 256]
Number of replay tasks per physical sublog at the replica.
AofReplayDriftThreshold--aof-replay-drift-thresholdintInteger in range:
[-1, MaxValue]
Cross-sublog replay drift, in sequence-number units, tolerated on a replica before a replay-align barrier round is triggered. -1 disables the barrier.
AofReplayDriftCheckFreq--aof-replay-drift-check-freqintInteger in range:
[0, MaxValue]
How often the cross-sublog drift is re-checked during replay, as a multiple of aof-replay-drift-threshold: one scan per (this value x threshold) sequence-number window system-wide, rotated across replay threads (window index mod virtual sublog count), firing a replay-align round when the drift exceeds the threshold. 0 = readers about to wait are the only round source.
AofReplayBarrierSpinUs--aof-replay-barrier-spin-usintInteger in range:
[-1, MaxValue]
How long a replay thread spins at the replay-align barrier before sleeping: -1 = spin forever, 0 = never spin, >0 = spin up to that many microseconds then sleep.
AofTailWitnessFreqMs--aof-tail-witness-freqintInteger in range:
[0, MaxValue]
Polling frequency of the background task responsible for moving time ahead for all physical sublogs (Used only with physical sublog value >1).
CommitFrequencyMs--aof-commit-freqintInteger in range:
[-1, MaxValue]
Write ahead logging (append-only file) commit issue frequency in milliseconds. 0 = issue an immediate commit per operation, -1 = manually issue commits using COMMITAOF command
WaitForCommit--aof-commit-waitboolWait for AOF to flush the commit before returning results to client. Warning: will greatly increase operation latency.
AofSizeLimit--aof-size-limitstringMemory sizeMaximum size of AOF (rounds down to power of 2) after which unsafe truncation will be applied. Left empty AOF will grow without bound unless a checkpoint is taken
AofSizeLimitEnforceFrequencySecs--aof-size-limit-enforce-frequencyintInteger in range:
[0, MaxValue]
Frequency (in secs) of execution of the AutoCheckpointBasedOnAofSizeLimit background task.
CompactionFrequencySecs--compaction-freqintInteger in range:
[0, MaxValue]
Background hybrid log compaction frequency in seconds. 0 = disabled (compaction performed before checkpointing instead)
CheckpointFrequencySecs--checkpoint-freqintInteger in range:
[0, MaxValue]
Gap in seconds between automatic checkpoints of all active databases. 0 = disabled. Settable at runtime with CONFIG SET checkpoint-freq. The append-only file is not required.
ExpiredObjectCollectionFrequencySecs--expired-object-collection-freqintInteger in range:
[0, MaxValue]
Frequency in seconds for the background task to perform object collection which removes expired members within object from memory. 0 = disabled. Use the HCOLLECT and ZCOLLECT API to collect on-demand.
CompactionType--compaction-typeLogCompactionTypeNone, Shift, Lookup, ScanHybrid log compaction type. Value options: None - no compaction, Shift - shift begin address without compaction (data loss), Lookup - lookup each record in compaction range, for record liveness checking using hash chain (no data loss; recommended for production use), Scan - scan old pages and move live records to tail (no data loss; NOT RECOMMENDED - builds a temporary parallel KV index proportional to the keyspace, causing significant transient memory use; prefer Lookup)
CompactionForceDelete--compaction-force-deleteboolForcefully delete the inactive segments immediately after the compaction strategy (type) is applied. If false, take a checkpoint to actually delete the older data files from disk.
CompactionMaxSegments--compaction-max-segmentsintInteger in range:
[0, MaxValue]
Number of log segments created on disk before compaction triggers.
EnableLua--luaboolEnable Lua scripts on server.
LuaTransactionMode--lua-transaction-modeboolRun Lua scripts as a transaction (lock keys - run script - unlock keys).
GossipSamplePercent--gossip-spintInteger in range:
[0, 100]
Percent of cluster nodes to gossip with at each gossip iteration.
GossipDelay--gossip-delayintInteger in range:
[0, MaxValue]
Cluster mode gossip protocol per node sleep (in seconds) delay to send updated config.
ClusterTimeout--cluster-timeoutintInteger in range:
[0, MaxValue]
Cluster node timeout is the amount of seconds a node must be unreachable.
ClusterConfigFlushFrequencyMs--cluster-config-flush-frequencyintInteger in range:
[-1, MaxValue]
How frequently to flush cluster config unto disk to persist updates. =-1: never (memory only), =0: immediately (every update performs flush), >0: frequency in ms
ClusterTlsClientTargetHost--cluster-tls-client-target-hoststringName for the client target host when using TLS connections in cluster mode.
ServerCertificateRequired--server-certificate-requiredboolWhether server TLS certificate is required by clients established on the server side, e.g., for cluster gossip and replication.
EnableTLS--tlsboolEnable TLS.
CertFileName--cert-file-namestringTLS certificate file name. Accepts a PKCS#12/PFX file or a PEM-encoded certificate (.pem, .crt, .cer); the format is auto-detected from the file's contents (example: testcert.pfx).
CertPassword--cert-passwordstringTLS certificate password (example: placeholder). For a PEM-encoded cert-file-name, this is instead treated as the path to a separate PEM private key file, if the key isn't already included in cert-file-name.
CertSubjectName--cert-subject-namestringTLS certificate subject name.
CertificateRefreshFrequency--cert-refresh-freqintInteger in range:
[0, MaxValue]
TLS certificate refresh frequency in seconds (0 to disable).
ClientCertificateRequired--client-certificate-requiredboolWhether client TLS certificate is required by the server.
CertificateRevocationCheckMode--certificate-revocation-check-modeX509RevocationModeNoCheck, Online, OfflineCertificate revocation check mode for certificate validation (NoCheck, Online, Offline).
IssuerCertificatePath--issuer-certificate-pathstringFull path of file with issuer certificate for validation. If empty or null, validation against issuer will not be performed.
LatencyMonitor--latency-monitorboolTrack latency of various events.
LatencyMonitorPrecision--latency-monitor-precisionintInteger in range:
[0, 5]
Resolution kept by the latency histograms, in significant decimal digits (0-5). This is relative accuracy at every magnitude: percentiles are reported to within 1 part in 10^N of the value, whether that value is microseconds or seconds. 2 (default) reports to ~1% at ~32KB per histogram, 1 to ~10% at ~5KB, 3 to ~0.1% at ~225KB.
CommandStatsMonitor--commandstats-monitorboolTrack per-command usage statistics (calls, failures, rejections). Exposed via INFO COMMANDSTATS.
SlowLogThreshold--slowlog-log-slower-thanintInteger in range:
[0, MaxValue]
Threshold (microseconds) for logging command in the slow log. 0 to disable.
SlowLogMaxEntries--slowlog-max-lenintInteger in range:
[0, MaxValue]
Maximum number of slow log entries to keep.
MetricsSamplingFrequency--metrics-sampling-freqintInteger in range:
[0, MaxValue]
Metrics sampling frequency in seconds. Value of 0 disables metrics monitor task.
QuietMode-qboolEnabling quiet mode does not print server version and text art.
LogLevel--logger-levelLogLevelTrace, Debug, Information, Warning, Error, Critical, NoneLogging level. Value options: Trace, Debug, Information, Warning, Error, Critical, None
LoggingFrequency--logger-freqintInteger in range:
[0, MaxValue]
Frequency (in seconds) of logging (used for tracking progress of long running operations e.g. migration)
DisableConsoleLogger--disable-console-loggerboolDisable console logger.
FileLogger--file-loggerstringEnable file logger and write to the specified path.
ThreadPoolMinThreads--minthreadsintInteger in range:
[0, MaxValue]
Minimum worker threads in thread pool, 0 uses the system default.
ThreadPoolMaxThreads--maxthreadsintInteger in range:
[0, MaxValue]
Maximum worker threads in thread pool, 0 uses the system default.
ThreadPoolMinIOCompletionThreads--miniothreadsintInteger in range:
[0, MaxValue]
Minimum IO completion threads in thread pool, 0 uses the system default.
ThreadPoolMaxIOCompletionThreads--maxiothreadsintInteger in range:
[0, MaxValue]
Maximum IO completion threads in thread pool, 0 uses the system default.
NetworkConnectionLimit--network-connection-limitintInteger in range:
[-1, MaxValue]
Maximum number of simultaneously active network connections across all listeners, or -1 for unlimited. Equivalent to the Redis maxclients parameter, and settable at runtime with CONFIG SET maxclients. Every inbound connection counts, including replica and cluster gossip links, and at the limit those are refused along with ordinary clients -- Garnet accepts them all on one listener and cannot tell the kinds apart at accept time. Redis also counts cluster bus links against maxclients, but accepts them on a separate bus port that applies no limit. Leave headroom for peer links. Lowering it refuses new connections rather than disconnecting established ones.
UseAzureStorage--use-azure-storageboolUse Azure Page Blobs for storage instead of local storage.
AzureStorageServiceUri--storage-service-uristringThe URI to use when establishing connection to Azure Blobs Storage.
AzureStorageManagedIdentity--storage-managed-identitystringThe managed identity to use when establishing connection to Azure Blobs Storage.
AzureStorageConnectionString--storage-stringstringThe connection string to use when establishing connection to Azure Blobs Storage.
CheckpointThrottleFlushDelayMs--checkpoint-throttle-delayintInteger in range:
[-1, MaxValue]
Whether and by how much should we throttle the disk IO for checkpoints: -1 - disable throttling; >= 0 - run checkpoint flush in separate task, sleep for specified time after each WriteAsync
FastCommitThrottleFreq--fast-commit-throttleintInteger in range:
[0, MaxValue]
Throttle FastCommit to write metadata once every K commits.
NetworkSendThrottleMax--network-send-throttleintInteger in range:
[0, MaxValue]
Throttle the maximum outstanding network sends per session.
NetworkBufferMemoryBudget--network-buffer-memory-budgetstringMemory sizeProcess-wide budget for the network buffers held by live client connections, shared across all listeners. While connections are few this is slack and each connection gets the full 128k send and receive buffers; once the budget divided by the live buffer count falls below that, the base size for new buffers adapts down toward a 16k floor so the total stays near the budget. Buffers still grow on demand beyond their base size, so large requests are unaffected. Set to 0 to disable adaptation, leaving per-connection buffers unbounded.
EnableScatterGatherGet--sg-getboolWhether to use scatter-gather IO for a run of contiguous GET operations - useful to saturate disk random read IO. MGET always uses scatter-gather.
ReplicaSyncDelayMs--replica-sync-delayintInteger in range:
[0, MaxValue]
Whether and by how much (milliseconds) should we throttle the replica sync: 0 - disable throttling
AofReplayMaxLagBytes--aof-replay-max-lag-bytesintInteger in range:
[-1, MaxValue]
Throttle ClusterAppendLog when replica.AOFTailAddress - ReplicationOffset > AofReplayMaxLagBytes. 0: Synchronous replay, >=1: background replay with specified lag, -1: infinite lag
AofSyncMaxLagBytes--aof-sync-max-lag-byteslongInteger in range:
[-1, MaxValue]
Stall primary AOF appends when the replication lag exceeds this budget, divided evenly per sublog (each sublog stalls at an even 1/m share). -1: disabled, >=1: max lag in bytes.
MainMemoryReplication--main-memory-replicationboolUse main-memory replication model.
FastAofTruncate--fast-aof-truncateboolUse fast-aof-truncate replication model.
OnDemandCheckpoint--on-demand-checkpointboolUsed with fast-aof-truncate replication model. Take on demand checkpoint to avoid missing data when attaching
ReplicaDisklessSync--repl-diskless-syncboolWhether diskless replication is enabled or not.
ReplicaDisklessSyncDelay--repl-diskless-sync-delayintInteger in range:
[0, MaxValue]
Delay in diskless replication sync in seconds. =0: Immediately start diskless replication sync.
ReplicaAttachTimeout--repl-attach-timeoutintInteger in range:
[0, MaxValue]
Timeout in seconds for replication attach operation.
ReplicaSyncTimeout--repl-sync-timeoutintInteger in range:
[0, MaxValue]
Timeout in seconds for replication sync operations.
ReplicaDisklessSyncFullSyncAofThreshold--repl-diskless-sync-full-sync-aof-thresholdstringMemory sizeAOF replay size threshold for diskless replication, beyond which we will perform a full sync even if a partial sync is possible. Defaults to AOF memory size if not specified.
UseAofNullDevice--aof-null-deviceboolWith fast-aof-truncate replication, use null device for AOF. Ensures no disk IO, but can cause data loss during replication.
ConfigImportPath--config-import-pathstringImport (load) configuration options from the provided path
ConfigImportFormat--config-import-formatConfigFileTypeGarnetConf, RedisConfFormat of configuration options in path specified by config-import-path
ConfigExportFormat--config-export-formatConfigFileTypeGarnetConf, RedisConfFormat to export configuration options to path specified by config-export-path
UseAzureStorageForConfigImport--use-azure-storage-for-config-importboolUse Azure storage to import config file
ConfigExportPath--config-export-pathstringExport (save) current configuration options to the provided path
UseAzureStorageForConfigExport--use-azure-storage-for-config-exportboolUse Azure storage to export config file
UseNativeDeviceLinux--use-native-device-linuxboolDEPRECATED: use DeviceType (--device-type) of Native instead.
DeviceType--device-typeDeviceTypeDefault, Native, RandomAccess, FileStream, AzureStorage, LocalMemory, NullDevice type (Default, Native, RandomAccess, FileStream, AzureStorage, LocalMemory, Null)
DeviceIoBackend--device-io-backendIoBackendDefault, Libaio, UringLinux-only IO backend for DeviceType=Native: Default (=libaio), Libaio, or Uring (io_uring). The shipped native library is built with -DUSE_URING=ON and requires liburing.so.2 at load time for all backends; a -DUSE_URING=OFF rebuild only needs libaio.
DeviceCompletionThreads--device-completion-threadsintInteger in range:
[1, 64]
Linux-only: Number of IO completion drain threads for DeviceType=Native (default 4, max 64). Under high concurrent pending-read load a single drainer convoys on the completion-signal path and collapses throughput; 4 removes that on both backends. On io_uring this scales further/more CPU-efficiently; libaio benefits less beyond a few.
DeviceThrottleLimit--device-throttle-limitintInteger in range:
[0, 65536]
Per-device max number of in-flight IOs (IDevice.ThrottleLimit). 0 = use the device's built-in default (4096 for DeviceType=Native; 120 for the other in-box Tsavorite devices such as RandomAccess/FileStream). Raising this lets disk-bound workloads keep the queue depth high enough to saturate fast NVMe / io_uring backends. For DeviceType=LocalMemory (which has no device-wide throttle) this instead sets the per-ring in-flight capacity, rounded up to a power of two.
DeviceIoContexts--device-io-contextsintInteger in range:
[0, 4096]
Linux-only, DeviceType=Native: number of independent kernel io_contexts / io_uring rings (ring COUNT), decoupled from --device-completion-threads. Critical for io_uring: set at or above submitter concurrency (roughly your connection count) so each submitter owns a ring and io_submit is contention-free; too few rings serialize submitters on a per-ring lock and cost up to ~3x. libaio is largely indifferent. 0 = device default.
DeviceQueueDepth--device-queue-depthintInteger in range:
[0, 32768]
Linux-only, DeviceType=Native: per-ring kernel submission depth (maxEvents for io_uring_queue_init / libaio io_setup). Orthogonal to --device-io-contexts (ring count) and --device-throttle-limit (aggregate in-flight). 0 = device default. Note: for libaio, io-contexts x queue-depth is drawn from the global fs.aio-max-nr budget.
DeviceUringSqPoll--device-uring-sqpollboolLinux-only, DeviceType=Native + --device-io-backend=Uring: enable io_uring SQPOLL (IORING_SETUP_SQPOLL) so a kernel thread polls the submission queue and submissions are syscall-free. Each ring gets its own poll thread, so submission stays parallel across rings. Off by default (opt-in); ignored for libaio. Busy-polling kernel threads consume CPU, so benchmark it against the default per-submit path.
DeviceUringSqPollIdleMs--device-uring-sqpoll-idle-msintInteger in range:
[0, 600000]
io_uring SQPOLL poll-thread idle window in milliseconds (sq_thread_idle): how long the kernel poll thread spins after the last submit before parking. 0 = native default (10s). Only meaningful with --device-uring-sqpoll.
DeviceAioMaxDevices--device-aio-max-devicesintInteger in range:
[1, 4096]
Linux-only, DeviceType=Native (libaio): target number of Native devices to fit within the machine-global fs.aio-max-nr libaio budget (default 32). libaio io_setup permanently reserves io-contexts x queue-depth events from that global budget per device, so the default per-device reservation is capped at fs.aio-max-nr / this. To recover from io_setup EAGAIN, raise fs.aio-max-nr or raise this (a larger divisor shrinks each device's reservation); lower this to give each device a deeper reservation. Ignored for io_uring (no global budget) and non-Linux.
RevivBinRecordSizes--reviv-bin-record-sizesIEnumerable<int>#,#,...,#: The sizes of records in each revivification bin, in order of increasing size. Supersedes the default --reviv; cannot be used with --reviv-in-chain-only
RevivBinRecordCounts--reviv-bin-record-countsIEnumerable<int>#,#,...,#: The number of records in each bin: Default (not specified): If reviv-bin-record-sizes is specified, each bin is 256 records # (one value): If reviv-bin-record-sizes is specified, then all bins have this number of records, else error #,#,...,# (multiple values): If reviv-bin-record-sizes is specified, then it must be the same size as that array, else error Supersedes the default --reviv; cannot be used with --reviv-in-chain-only
RevivifiableFraction--reviv-fractiondoubleDouble in range:
[0, 1]
#: Fraction of mutable in-memory log space, from the highest log address down to the read-only region, that is eligible for revivification.
EnableRevivification--revivboolA shortcut to specify revivification with default power-of-2-sized bins. This default can be overridden by --reviv-in-chain-only or by the combination of reviv-bin-record-sizes and reviv-bin-record-counts.
RevivNumberOfBinsToSearch--reviv-search-next-higher-binsintInteger in range:
[0, MaxValue]
Search this number of next-higher bins if the search cannot be satisfied in the best-fitting bin. Requires --reviv or the combination of rconeviv-bin-record-sizes and reviv-bin-record-counts
RevivBinBestFitScanLimit--reviv-bin-best-fit-scan-limitintInteger in range:
[0, MaxValue]
Number of records to scan for best fit after finding first fit. Requires --reviv or the combination of reviv-bin-record-sizes and reviv-bin-record-counts 0: Use first fit #: Limit scan to this many records after first fit, up to the record count of the bin
RevivInChainOnly--reviv-in-chain-onlyboolRevivify tombstoned records in tag chains only (do not use free list). Cannot be used with reviv-bin-record-sizes or reviv-bin-record-counts.
ObjectScanCountLimit--object-scan-count-limitintInteger in range:
[0, MaxValue]
Limit of items to return in one iteration of *SCAN command
EnableDebugCommand--enable-debug-commandConnectionProtectionOptionno, local, yesEnable DEBUG command for 'no', 'local' or 'all' connections
EnableModuleCommand--enable-module-commandConnectionProtectionOptionno, local, yesEnable MODULE command for 'no', 'local' or 'all' connections. Command can only load from paths listed in ExtensionBinPaths
ProtectedMode--protected-modeCommandLineBooleanOptiontrue, false, yes, noEnable protected mode.
ExtensionBinPaths--extension-bin-pathsIEnumerable<string>List of directories on server from which custom command binaries can be loaded by admin users. MODULE command also requires enable-module-command to be set
LoadModuleCS--loadmodulecsIEnumerable<string>List of modules to be loaded
ExtensionAllowUnsignedAssemblies--extension-allow-unsignedboolAllow loading custom commands from digitally unsigned assemblies (not recommended)
IndexResizeFrequencySecs--index-resize-freqintInteger in range:
[1, MaxValue]
Hash-index resize check frequency in seconds
IndexResizeThreshold--index-resize-thresholdintInteger in range:
[1, 100]
Hash-index Overflow bucket count over total index size in percentage to trigger index resize
MaxInlineKeySize--max-inline-key-sizestringMemory sizeMaximum size of a key stored inline in the in-memory portion of the main log. Accepts a memory size (e.g. "1k", "128"). Must be in range [0, 1022] bytes; default is 1022.
MaxInlineValueSize--max-inline-value-sizestringMemory sizeMaximum size of a value stored inline in the in-memory portion of the main log. Accepts a memory size (e.g. "4k", "15m"). Must be in range [0, 16777214] bytes; default is min (1m, PageSize / 2).
InitialIORecordSize--initial-io-record-sizestringMemory sizeInitial IO read size for records on disk. Accepts a memory size (e.g. 4k, 8k). Default is 128 bytes.
FailOnRecoveryError--fail-on-recovery-errorboolServer bootup should fail if errors happen during bootup of AOF and checkpointing
LuaMemoryManagementMode--lua-memory-management-modeLuaMemoryManagementModeNative, Tracked, ManagedMemory management mode for Lua scripts, must be set to Tracked or Managed to impose script limits
LuaScriptMemoryLimit--lua-script-memory-limitstringMemory sizeMemory limit for a Lua instances while running a script, lua-memory-management-mode must be set to something other than Native to use this flag
LuaScriptTimeoutMs--lua-script-timeoutintInteger in range:
[10, MaxValue]
Timeout for a Lua instance while running a script, specified in positive milliseconds (0 = disabled)
LuaLoggingMode--lua-logging-modeLuaLoggingModeEnable, Silent, DisableBehavior of redis.log(...) when called from Lua scripts. Defaults to Enable.
UnixSocketPath--unixsocketstringUnix socket address path to bind server to
UnixSocketPermission--unixsocketpermintInteger in range:
[0, 777]
Unix socket permissions in octal (Unix platforms only)
MaxDatabases--max-databasesintInteger in range:
[1, 256]
Max number of logical databases allowed in a single Garnet server instance
ExpiredKeyDeletionScanFrequencySecs--expired-key-deletion-scan-freqintInteger in range:
[-1, MaxValue]
Frequency of background scan for expired key deletion, in seconds
ClusterReplicationReestablishmentTimeout--cluster-replication-reestablishment-timeoutintInteger in range:
[0, MaxValue]
ClusterReplicaResumeWithData--cluster-replica-resume-with-databoolIf a Cluster Replica resumes with data, allow it to be served prior to a Primary being available
EnableVectorSetPreview--enable-vector-set-previewboolEnable Vector Sets (preview) - this feature (and associated commands) are incomplete, unstable, and subject to change while still in preview
VectorSetReplayTaskCount--vector-set-replay-task-countintInteger in range:
[0, MaxValue]
Configure how many replay tasks are used to replay VectorSet operations at the replica (default: 0 uses the machine CPU count)
EnableRangeIndexPreview--enable-range-index-previewboolEnable Range Index (preview) - this feature (and associated RI.* commands) are incomplete, unstable, and subject to change while still in preview
VectorSetQuantizationTaskCount--vector-set-quantization-task-countintInteger in range:
[0, MaxValue]
Configure how many quantization tasks are used to optimize Vector Set operations (default: 0 uses the machine CPU count; maximum: the machine CPU count)

Cost of automatic checkpoints​

--checkpoint-freq is disabled by default. A value such as 300 seconds is a reasonable starting point. The interval is the gap after one checkpoint completes before the next attempt, so a slow checkpoint does not queue up another one. The first checkpoint is taken one full interval after startup or after the setting is enabled. A checkpoint is taken on every interval whether or not data has changed since the previous one. Checkpoints from SAVE, BGSAVE, or the AOF size limit do not reset the schedule. The append-only file (AOF) does not need to be enabled.

Garnet checkpoints are not deltas. Each checkpoint writes the portion of the hybrid log still in memory and not yet flushed to a storage tier. For a dataset that fits in memory, this is effectively the whole dataset each time. A hybrid-log-only checkpoint avoids rewriting the hash index but still writes that log region. Disk volume scales with resident data size divided by the interval. Checkpoint files also consume disk space, and checkpoint flushes can affect latency. --checkpoint-throttle-delay can reduce the latency impact by extending the flush. Choose the interval based on acceptable recovery data loss and available disk bandwidth.

A scheduled checkpoint covers all active databases. If one database is already being checkpointed, that database is skipped until the next interval and the others are still checkpointed. In cluster mode, only primaries act on the setting; a replica accepts the value and starts using it if it is promoted. A primary checkpoint also causes each replica to checkpoint. While one is running, SAVE and BGSAVE can return ERR checkpoint already in progress, and cluster attach or failover may need to be retried. CONFIG SET checkpoint-freq updates the interval without waiting for a running checkpoint; that checkpoint finishes normally, even when the new interval is 0. Changing the interval starts a new wait of the full new interval; setting the current value again has no effect. Shutdown waits for a running checkpoint to finish.

If --compaction-freq is 0, checkpointing runs compaction first. With AOF enabled, a completed checkpoint truncates the AOF, so enabling scheduled checkpoints changes how much AOF history is retained. Use LASTSAVE for each database and rdb_last_bgsave_status in INFO PERSISTENCE to confirm completion.


Recovery failures at startup​

When Garnet is started with --recover, it restores the store from the most recent readable checkpoint and then replays the append-only file (AOF) on top of it. --fail-on-recovery-error controls what happens when that restore cannot reproduce everything that was durably acknowledged before shutdown.

Startup is refused when all of the following hold:

  • checkpoint tokens are present in the checkpoint directory, but none of them could be read;
  • the surviving AOF cannot cover the resulting gap, because it is disabled or because it begins past the first valid log address (a completed checkpoint truncates the AOF up to the address that checkpoint covers);
  • --fail-on-recovery-error is true.

The checkpoint artifacts are left on disk so the failure can be diagnosed, and the reason is logged with the number of tokens that were found and rejected.

These cases are not treated as recovery failures and continue to start normally:

  • a fresh directory, with or without --aof;
  • an AOF-only database whose complete log begins at the first valid address;
  • an unreadable checkpoint alongside a complete AOF from the first valid address, because replaying the AOF in full reconstructs the database;
  • an AOF that begins past the first valid address with no checkpoint tokens at all, which is the normal state of a replica that was synchronized without receiving a checkpoint;
  • --fast-aof-truncate and AOF null-device configurations, which discard AOF history by design.

With --fail-on-recovery-error set to false (the default) the server still starts on whatever it managed to recover, and the incomplete recovery is logged as an error.

In cluster mode a primary refuses under the same conditions. A replica reports the same error but continues, because a full sync from its primary will reconcile it. Cluster startup never purges checkpoint artifacts when no valid checkpoint could be selected.


Cluster configuration compatibility​

Breaking change

Garnet 2.2.0 writes persisted cluster configuration in format version two. After nodes.conf has been rewritten, the node cannot be rolled back to a Garnet version earlier than 2.2.0 that only supports format version one. Back up the cluster configuration before upgrading.


Native device IO tuning (Linux)​

When --device-type Native is used on Linux (the default on x64 Linux), four orthogonal knobs size the kernel IO path. Each controls exactly one dimension:

KnobControlsGuidance
--device-io-backendLibaio (default) or Uring (io_uring)Both reach the same peak on fast NVMe when sized correctly.
--device-io-contextsRing count (independent io_uring rings / libaio io_contexts)Critical for io_uring: set at or above submitter concurrency (~your connection count) so each submitter owns a ring and submission is lock-free; too few rings serialize submitters on a per-ring lock and can cost ~3x. libaio is largely indifferent (its kernel io_context mutex is cheap), so it needs no tuning here.
--device-queue-depthPer-ring depth (kernel submission queue size)Independent of ring count. For libaio, io-contexts × queue-depth is drawn from the global fs.aio-max-nr budget, so keep the product within that limit (raise fs.aio-max-nr, or lower one factor, if device creation fails). io_uring depth is per-ring memory only.
--device-completion-threadsNumber of background completion (drain) threadsDefault 4 is sufficient on both backends; a single drainer convoys under high pending-read load.
--device-throttle-limitAggregate in-flight reads before backpressureSoftware backpressure only — it bounds pinned read-buffer memory and must stay ≤ io-contexts × queue-depth. Raise it for very high connection counts; the default saturates fast NVMe at typical thread counts.

Mental model: io-contexts = number of submission queues, queue-depth = depth of each queue, so io-contexts × queue-depth is the kernel capacity; throttle-limit is how much of that capacity the allocator keeps in flight at once. The most common tuning mistake is running the io_uring backend with too few rings — always set --device-io-contexts to cover your submitter concurrency for io_uring.