Cache¶
Cache in Knot Resolver is shared between multiple workers and stored in a file, so resolver doesn’t lose the cached data on restart or crash.
To improve performance even further the resolver implements so-called aggressive caching for DNSSEC-validated data (RFC 8198), which improves performance and also protects against some types of Random Subdomain Attacks.
Sizing¶
For personal and small office use-cases cache size around 100 MB is more than enough.
For large deployments we recommend to run Knot Resolver on a dedicated machine, and to allocate 90% of machine’s free memory for resolver’s cache.
Note
Choosing a cache size that can fit into RAM is important even if the cache is stored on disk (default). Otherwise, the extra I/O caused by disk access for missing pages can cause performance issues.
For example, imagine you have a machine with 16 GB of memory. After machine restart you use command free -m
to determine amount of free memory (without swap):
$ free -m
total used free
Mem: 15907 979 14928
Now you can configure cache size to be 90% of the free memory 14 928 MB, i.e. 13 453 MB:
-- 90 % of free memory after machine restart
cache:
size-max: 13453M
Clearing¶
There are two specifics to purging cache records matching specified criteria:
To reliably remove negative cache entries, you need to clear the subtree with the whole zone. E.g. to clear negative cache entries for the (formerly non-existent) record
www.example.com. A
, you need to flush the whole subtree starting at the zone apex example.com. or closer to the root. [1]This operation is asynchronous and might not yet be finished when the call to the
/cache/clear
API endpoint returns. The return value indicates if clearing continues asynchronously or not.
Parameters¶
Parameters for cache clearance are in JSON and are sent with the HTTP request as its body.
- "name": "<name>"¶
Optional, subtree to purge; if the name isn’t provided, whole cache is purged (and any other parameters are disregarded).
- "exact-name": true|false¶
- Default:
false
If set to
true
, only records with the same name are removed.
- "rr-type": "<rr-type>"¶
Optional, you may additionally specify the type to remove, but that is only supported with
exact-name
enabled.
- "chunk-size": <integer>¶
- Default:
100
The number of records to remove in a single round. The purpose is not to block the resolver for too long. By default, the resolver repeats the command after at least one millisecond until all the matching data is cleared.
Return value¶
The return value is an object with the following fields. The count
field is always present.
- "count": integer¶
The number of items removed from the cache by this call (may be 0 if no entry matched criteria).
Always present.
- "not_apex": true|false¶
Cleared subtree is not cached as zone apex; proofs of non-existence were probably not removed.
Optional. Considered
false
when not present.
- "subtree": "<zone_apex>"¶
Hint where zone apex lies (this is an estimation based on the cache contents and may not always be accurate).
Optional.
- "chunk_limit": true|false¶
More than
chunk-size
items needs to be cleared, clearing will continue asynchronously.Optional. Considered
false
when not present.
Persistence¶
Tip
Using tmpfs
for cache improves performance and reduces disk I/O.
By default the cache is saved on a persistent storage device so the content of the cache is persisted during system reboot. This usually leads to smaller latency after restart etc., however in certain situations a non-persistent cache storage might be preferred, e.g.:
Resolver handles high volume of queries and I/O performance to disk is too low.
Threat model includes attacker getting access to disk content in power-off state.
Disk has limited number of writes (e.g. flash memory in routers).
If non-persistent cache is desired configure cache directory to be on tmpfs filesystem, a temporary in-memory file storage. The cache content will be saved in memory, and thus have faster access and will be lost on power-off or reboot.
Note
In most of the Unix-like systems /tmp
and /var/run
are commonly mounted as tmpfs. While it is technically possible to move the cache to an existing tmpfs filesystem, it is not recommended, since the path to cache is configured in multiple places.
Mounting the cache directory as tmpfs is the recommended approach. Make sure to use appropriate size-max
option and don’t forget to adjust the size in the config file as well.
# /etc/fstab
tmpfs /var/cache/knot-resolver tmpfs rw,size=2G,uid=knot-resolver,gid=knot-resolver,nosuid,nodev,noexec,mode=0700 0 0
# /etc/knot-resolver/config.yaml
cache:
storage: /var/cache/knot-resolver
size-max: 1G
Configuration reference¶
- cache/storage: <dir>¶
- Default:
/var/cache/knot-resolver
- cache/size-max: <size B|K|M|G>¶
- Default:
100M
Note
Use B, K, M, G
bytes units prefixes.
Opens cache with a size limit. The cache will be reopened if already open. Note that the maximum size cannot be lowered, only increased due to how cache is implemented.
cache:
storage: /var/cache/knot-resolver
size-max: 400M
- cache/ttl-max: <time ms|s|m|h|d>¶
- Default:
1d
Higher TTL bound applied to all received records.
- cache/ttl-min: <time ms|s|m|h|d>¶
- Default:
5s
Lower TTL bound applied to all received records. Forcing TTL higher than specified violates DNS standards, so use higher values with care. TTL still won’t be extended beyond expiration of the corresponding DNSSEC signature.
cache:
# max TTL must be always higher than min
ttl-max: 2d
ttl-min: 20s
- cache/ns-timeout: <time ms|s|m|h|d>¶
- Default:
1000ms
Time interval for which a nameserver address will be ignored after determining that it doesn’t return (useful) answers. The intention is to avoid waiting if there’s little hope; instead, kresd can immediately SERVFAIL or immediately use stale records (with serve-stale).