http_cache_store_memory

http_cache_store_memory is an in-memory LRU cache that can be used as a backend for http_cache. It implements the http_cache_store behaviour.

It supports:

It uses Erlang's capabilities and doesn't require external stores (Redis, memcached, DB...). Under the hood, it uses ETS tables, system monitor and Erlang's distribution.

For on-disk caching, see: http_cache_store_disk.

http_cache* pro versions

Advanced HTTP caching features are available as licensed packages:

Refer to these links for technical insights and license information.

Support

OTP25+

Usage

This is an OTP application, and automatically starts.

Configuration parameters

All are environment parameters.

All are read at runtime (and can be changed dynamically) except cluster_enabled.

Installation

Erlang (rebar3):

{deps, [{http_cache_store_memory, "~> 0.3.0"}]}.

Elixir:

{:http_cache_store_memory, "~> 0.3.0"}

Telemetry

Architecture

This application uses 3 ETS tables:

The configuration table is used to store when the limit is reached, so as to discard immediately requests to cache HTTP responses.

The object and LRU tables store the following tuples:

Object table: {ObjectKey, VaryHeaders, UrlDigest, Response, RespMetadata, Expires, SeqNumber}

LRU table: {{LastUsedTime, ObjectKey, SeqNumber}}. Note there's only one 3-tuple entry.

Both are ordered_set tables, so that:

Also note that the ObjectKey of the object table is a {RequestKey, VaryHeadersHash} tuple. Indeed, the same URL and HTTP verb can have different HTTP responses, depending on the vary header and we need to return all of them to http_cache to select the correct one. Fortunately, matching on the first term of a compound key in an ordered_set table is very efficient.

Whenever http_cache:notify_response_used/2 is called, a new entry is added in the LRU table with the current time, object key and a SeqNumber. This sequence number is a random integer and is also updated in the object table along with the cached HTTP response. When nuking older entries, we then can use this sequence number to determine if the cached response was used since (the SeqNumber between the 2 tables don't match) or not (they do match).

At startup, some processes are launched:

Screenshot of the supervision tree

http_cache_store_memory_table_holder holds the ETS tables.

http_cache_store_memory_worker_sup is a supervisor responsible for spawning workers that insert or update new HTTP responses into the ETS object table, invalidate entries, and process cluster work. It is used for backpressure, as there's a maximum number of tasks that can be run at the same time (except for invalidation requests).

http_cache_store_memory_stats collects stats about memory, emits telemetry events related to it and provides with helper function to calculate how much allocated memory is used, depending on the configuration.

http_cache_store_memory_cluster_mon handles communication with the other members of the cluster, by:

Then we have 3 sweeper processes: