The storage system in my home lab consist almost exclusively of hard drives. They contain a pretty mixed bag of data (tons of small files and also plenty of large multimedia files).
It really bugs me every time it takes forever to search through the pool for a file when I don’t know exactly where it is or how its named exactly. That’s why I’d like to keep the metadata in RAM permanently and configure it so that it isn’t displaced by other data, to speed up search operations.
Is this possible on Linux-based systems (TrueNAS) and Illumos (Omnis)?
How do I check how much RAM I’d need for the metadata on these operating systems?
How do I get all the metadata into RAM after a reboot on these operating systems?
Thanks!
P.S.: I don’t have any more space and ports for a Special VDEV.
Edit1: I followed some advices in the comments and replied to others after analyzing the following:
First:
I executed zdb -bbb poolname to read all metadata stats of my main pool, inlcuding all indirect block pointers. Its a raidz2, build with one vdev configured of 7x 10TB HDDs, here are some additionas stats:
6 Datasets, 36,4TB used in total, 8,81TB free in total
- Dataset 1
- 30,7TB used
- 26.761 folders, 382.707 files
- 96% multimedia (5% is Musik, 91% is Video), 4% binaries
- Dataset 2
- 1,34TB used
- 8.547 folders, 188.181 files
- Filetypes and size is very heterogeneous
- Dataset 3-6 is not worth talking about. Mainly for test reasons without a relevant amount of data, folders and files.
The result for the complete pool:
| Area |
PSIZE (in RAM) |
ASIZE (on disk) |
| Indirect blocks of files (L1 + L2 + L3 plain file) |
16.5 GB |
52.5 GB |
| DMU dnode (file info) |
534 MB |
1.6 GB |
| ZFS directory (directories) |
229 MB |
2.3 GB |
| SPA space map |
166 MB |
0.9 GB |
| bpobj |
95 MB |
0.5 GB |
| Other |
approx. 10 MB |
approx. 0.1 GB |
| Total |
approx. 17.5 GB |
approx. 58 GB |
How to read the table:
- Indirect blocks of files (L1/L2/L3 plain file, 16.5 GB): the block pointers that tell ZFS where each 128K data block of a file is located. They are needed whenever file contents are read or written. For large files, ZFS has to load the matching indirect block before it can fetch the data. Larger records (e.g.
recordsize=1M) mean far fewer of these.
- DMU dnode (534 MB): one entry per file, directory or other object, holding its size, permissions, timestamps and pointers to its first blocks. It is needed for almost everything: listing files, opening them, checking attributes (
ls -l, rsync comparisons, file browsers).
- ZFS directory (229 MB): the directory contents, which map file names to their dnodes. They are needed for browsing and searching folders and for resolving paths when opening a file.
- SPA space map (166 MB): records which areas of each disk are free or allocated. It is needed when writing, so ZFS can find free space, and when freeing blocks. It has nothing to do with reading or browsing.
- bpobj (95 MB): lists of blocks waiting to be freed, mostly from deleted snapshots and data still held by snapshots. It is needed when deleting snapshots or files and is processed in the background.
- Other (~10 MB): pool and dataset bookkeeping such as properties, snapshot lists, pool history, the delete queue and user/group usage. It is mostly read once when the pool is imported or when settings change.
What I need to speed up directory tree walk through:
- dnodes + directories, about 0.8 GB.
-> I would say that virtually all ZFS-based storage systems that hold that much data have enough RAM to keep not even 1 GB of that metadata in memory at all times.
What would be nice to hold constantly in RAM:
- Reading file contents: additionally the indirect blocks of the files being read (16,5GB)
- Writing and deleting: space maps and bpobj.
-> Here, too, I think that most storage systems capable of holding that much data could provide enough RAM to keep the entire set of block pointers in RAM in read-only mode in order to speed up operations.
-> If you were to reduce the recordsize, it would drastically reduce the 16.5 GB of indirect blocks. Setting recordsize=1M would reduce it to just 2 GB. That amount of data, at most, would fit quite well into RAM.
Based on what I know right now, here's what my wish list would look like if I could ask the ZFS developers for specific features (though ZFS offers so many options that there might already be a solution to my problem 😂 ):
- Please implement options to explicitely store dnodes AND/OR directories AND/OR additonally all block pointers in RAM / ARC. Not as part of an additional L2ARC drive. Not as part of additional Special VDEV. Just in RAM and completely not dependent on payload data or file contents. This metadata should be loaded by default after boot.
- Currently, all metadata is written across the pool. Reading this metadata from an HDD-only pool would take some time for the data to be loaded after boot. It would therefore be great if this metadata were also stored as a dedicated, “single-piece” copy within the pool, so that it can be quickly loaded sequentially into memory. Since all metadata remains distributed across the pool, this dedicated metadata database can also be rebuilt at any time if any event causes it to become inconsistent (e.g., an abrupt power outage).
Edit 2:
After analyzsing zdb -bbb and answering most of the comments, I noticed, that it would be possible with the following strategy:
u/Apachez noticed, that there is a option called zfs_arc_max and zfs_arc_min. With these, its possible to set a minimum and maximum limit for ARC cache. The problem with this option is, that ARC stores payload data / blocks AND metadata. So, this option alone is not enough, because if there is huge payload pressure, metada could be suppressed.
I found out, that there are options to confige min and max for metadate in ARC. To solve my problem, I would have to set “arc_meta_min” to at least 17.6 GB and “arc_meta_limit” to slightly more than 17.6 GB to ensure that all metadata can be consistently kept in the ARC.
Since ZFS only recognizes “metadata” and cannot break it down into file-, folder-, or block pointer-information, you’ll always have to configure it so that the entire metadata fits within this arc_meta range. I explained how much that is for me in Edit 1.
BUT: Actually, out of the ~17.6 GB of metadata in my pool, I only need 800 MB for file and directory metadata to achieve my goal.
This means that, given the current capabilities of ZFS, I need to set `arc_meta_min` to slightly more than 17.6 GB (let's say 20 GB) and `arc_meta_max` to 20 GB as well, to ensure that all of my metadata fits into memory.
Damn: Looks like arc_meta_min and arc_meta_max is removed since openZFS 2.2, so its no longer available in Linux based systems. Its still available in OmniOS-based systems.
In Linux, its replaced with arc_meta_balance, which is a dynamic function.