Refactor cache logic for configurable backends

I plan to implement rate-limiting using a redis backend for a distributed setup with local caches.

As a preparation for that I've refactored the current cache-related code into a `CacheBackend` class, and added a setting to specify a custom backend (defaults to the cache backend of course).