I have done this, so I know how it is optimally done. The idea is to use a hash function such as SipHash to calculate a hash value for the IP address. Then you use a token bucket algorithm for each hash bucket: have e.g. 100 initial tokens in each hash bucket, add 10 tokens per second up to a maximum of 100 tokens, and remove one token every time you get a request, or else if there are no tokens, reject the request. This would allow 10 requests per second with a maximum burst size of 100.
Theoretically, it is possible that two IP addresses hash to the same bucket, but that is not a problem in this use case, if you have enough hash buckets.
As for updating the buckets, you can do them using batch timers. E.g. for 131072 buckets, you could update e.g. 4096 buckets per each timer and then have 32 timers evenly expiring within a second. So, at 1/32 seconds, you update the first 4096 buckets, at 2/32 seconds, you update the next 4096 buckets, etc. The data structure for maintaining timers is optimally a priority queue such as a binary heap.
When implemented this way, if somebody floods your system by numerous forged source IP addresses, your memory doesn't get filled.
The memory used by this approach uses 8, 16 or 32 bits per each hash bucket if you use an integer array. The integer size comes from your requirements: e.g. 8 bits cannot support more than burst sizes of 255. Similarly, 16 bits allow burst sizes of at most 65535. So, e.g. 8 bits or 1 byte per bucket and 131072 buckets takes 128 kilobytes of memory. Nowhere close to being a problem. A good machine has at least 2 GB of memory, meaning over 15 000 times the amount you require for this system.
You need to consider memory bandwidth as well: if each bucket is updated once per second, the bandwidth required is 128 KB/s. Good computers support over 5 GB/s read+write bandwidth, or over 40 000 times what this proposal of mine uses.
Do save the cache into RAM. Don't use a database or disk file for it. If your system crashes, well, then you just initialize all buckets to the initial value.