karpetrosyan / hishel

An elegant HTTP Cache implementation for HTTPX and HTTP Core.
https://hishel.com
BSD 3-Clause "New" or "Revised" License
158 stars 19 forks source link

Control memory use of InMemoryStorage #225

Open douglas-raillard-arm opened 5 months ago

douglas-raillard-arm commented 5 months ago

InMemoryStorage allows controlling the number of cached request but not the size of the cached data. A single GET request with a large file (a few GB) seems to be consuming unreasonable amounts of memory, which cannot be controlled with the number of cached requests.

karpetrosyan commented 4 months ago

We definitely need some memory control here, so I think that would be great.

Before we begin, we should have answers to the following questions:

Simon-Will commented 2 months ago

I think there's two aspects to this:

In fact, even the storage doesn't have complete information about how much space a cached response will really take to store because the cache "backend" (LFUCache, SQLite, file system) will probably take a bit more space than just the number of bytes of the serialized response. E.g., a file system cache will always take up a multiple of the block size plus the necessary inodes. SQLite needs to integrate it into its index. The dict in the LFUCache needs to store pointers to the stored responses and an entry in the self.freq_count dict, etc. So, in a perfect implementation, the storage could ask its backend how much more space will be taken up if a response were stored. Implementing this would probably get pretty complex and maybe brittle.

Since it's only requested here for the InMemoryStorage and that's probably where it's most relevant, we could implement the following naive version:

What do you think? Should I try including a max_cached_response_size?

Apart from that, maybe we should advise people using Redis that they should set maxmemory and maxmemory-policy?

douglas-raillard-arm commented 2 months ago

I think it would be reasonable to have something like that:

Having the storage report the space left might work quite well with an implementation that tries to preserve some headroom, and will adapt to changing conditions in shared storage situation (e.g. a filesystem).