[answered] Does caddy file_server do any caching?

Just a quick Q…

I am using the file_server directive. My entire website compressed is less than 1MB. It occurred to me that file_server could very comfortably cache my entire pre-compressed website in memory and never request from storage.

Does caddy have any file caching for file_server requests? I looked around here and it looks like it always opens files, maybe Go has a good file cache?

I know it is problematic, because what if the files change? But it seems like you could define a cache refresh frequency or always refresh on reload. Then installation of updated files could always initiate a caddy reload.

Thanks!

file_server doesn’t do its own caching, no.

But you can build Caddy with this plugin to do so:

2 Likes

FWIW… I believe Go uses sendfile when the io.Reader is a *os.File and the writer is a network socket: go/sendfile_linux.go at 412f659280607b06de9b25569cf668ea8f23dd57 · golang/go · GitHub

This should be very efficient, as the kernel does the file copy directly without going between user-kernel spaces.

And you don’t have to worry about a cache.

If you’re running Linux and aren’t super tight on memory, the kernel likely already is doing this for you at a lower level via the page cache. Matt already linked to Go’s use of the sendfile syscall. The kernel will use its page cache instead of reading a file from disk whenever possible.

You can see this in practice pretty well:

# create a random 5GB file and start caddy
❯ head -c 5G /dev/urandom > 5g.txt
❯ caddy file-server --listen :3000

# evict file from page cache (since it's there from the write) and confirm it's not in memory
❯ vmtouch -qe 5g.txt
❯ vmtouch 5g.txt
           Files: 1
     Directories: 0
  Resident Pages: 0/1310720  0/5G  0%
         Elapsed: 0.043495 seconds
 
# request it via curl and measure time
❯ curl -H 'Connection: Close' -o /dev/null -w "ttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" -s localhost:3000/5g.txt
ttfb: 0.001941s
total: 6.327979s

# confirm file now is fully loaded into page cache
❯ vmtouch 5g.txt
           Files: 1
     Directories: 0
  Resident Pages: 1310720/1310720  5G/5G  100%
         Elapsed: 0.06651 seconds

# measure transfer time again
❯ curl -H 'Connection: Close' -o /dev/null -w "ttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" -s localhost:3000/5g.txt
ttfb: 0.001743s
total: 2.010325s

# and if you really don't trust me, evict it from cache and watch again :)
❯ vmtouch -qe 5g.txt
❯ curl -H 'Connection: Close' -o /dev/null -w "ttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" -s localhost:3000/5g.txt
ttfb: 0.010259s
total: 6.635756s
❯ curl -H 'Connection: Close' -o /dev/null -w "ttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" -s localhost:3000/5g.txt
ttfb: 0.001448s
total: 1.987854s

You can see after the file has been loaded into memory, the subsequent transfer time decreases from 6 seconds to 2 seconds. So if your goal is to prevent unnecessary disk reads, you don’t need to do anything since the kernel is already doing so.

5 Likes

This topic was automatically closed after 30 days. New replies are no longer allowed.