Home

Awesome

NebulexLocalMultilevelAdapter

A variation of Multilevel adapter that assumes Level 1 being Local cache running in a distributed cluster.

Installation

Add nebulex_local_multilevel_adapter to your list of dependencies in mix.exs:

def deps do
  [
    {:nebulex_local_multilevel_adapter, "~> 0.2.0"}
  ]
end

Usage

<!-- MDOC -->

NebulexLocalMultilevelAdapter setup resembles Nebulex.Adapters.Multilevel with two exceptions: model option is always :inclusive and the first level is autocreated:

defmodule MyApp.Cache do
  use Nebulex.Cache,
    otp_app: :slab,
    adapter: NebulexLocalMultilevelAdapter
end

# This can be shared cache, e.g. Partitioned, Replicated, Memcached
defmodule MyApp.Cache.Redis do
  use Nebulex.Cache,
    otp_app: :slab,
    adapter: NebulexRedisAdapter
end

Then configure MyApp.Cache levels just like normal Multilevel:

config :my_app, MyApp.Cache,
  local_opts: [],
  levels: [
    {MyApp.Cache.Redis, []},
  ]

The adapter will automatically create MyApp.Cache.Local L1 cache using options provided in local_opts.

How it works

LocalMultilevelAdapter is different from Nebulex.Adapters.Multilevel in a couple of ways:

  1. L1 is created automatically and uses Nebulex.Adapters.Local adapter
  2. Other levels must be global for nodes, meaning they behave like a shared storage. The simplest example is NebulexRedisAdapter, but Replicated and Partitioned should work too.
  3. All write operations are asynchronously broadcasted to other nodes which invalidate affected keys in their local L1 caches.

Race conditions {: .warning}

There are several important things to keep in mind when working with a multilevel cache in a clustered environment:

  1. Always update the underlying storage (e.g. Ecto repo) first and invalidate the cache after to avoid a potential race condition when another client can write a stale value to the cache. The adapter follows this pattern moving from higher to lower levels with deletes.
  2. Keep in mind that invalidation messages are broadcasted without any confirmation from recipient nodes, so there is always a small chance of reading a stale value from the cache.
<!-- MDOC -->

Development

NebulexLocalMultilevelAdapter relies on shared test code from Nebulex repository, so you'll need to fetch it first

export NEBULEX_PATH=nebulex
mix nbx.setup

make sure epmd is running:

epmd -daemon

From this it should be business as usual:

mix deps.get
mix test