What Is a Near Cache?

A near cache is a small local cache held inside the application process, sitting in front of a shared distributed cache. Reads are served from local memory and only cross the network on a miss. What makes it a near cache rather than a plain local cache is the invalidation channel: when an entry changes, every instance holding a copy is told.

The mental model, stated once: a near cache is a local cache, plus a distributed cache, plus an invalidation channel between them. Remove the channel and you have two independent caches that quietly disagree.

The term comes from the in-memory data grid world — Oracle Coherence has shipped one since the early 2000s, Hazelcast since the late 2000s, and Apache Ignite since it graduated at Apache in 2015 — but the pattern applies to any remote cache, including Redis and Valkey.

How a Near Cache Differs From Both

A near cache is not a third alternative to the other two — it is the two of them stacked, which is why its properties are a mixture rather than a compromise.

Local cacheDistributed cacheNear cache
Where the data livesApplication heap onlyA separate cache tierBoth — hot copy local, authoritative copy remote
Read on a hitNanoseconds, no networkA network round trip plus deserializationNanoseconds when the local copy is warm
Read on a missGoes to the databaseGoes to the databaseGoes to the shared cache first, database second
On a write elsewhereNothing. This instance never finds outNothing to do — there is one copyAn invalidation message drops or replaces the local copy
ConsistencyNone across instancesStrong, for reads against the primaryEventually consistent, bounded by invalidation latency
Heap costThe whole working set, on every instanceNoneOnly the hot subset, on every instance
Survives a restartNoYesThe shared copy does; the local one rebuilds
Cost of a writeFreeOne round tripOne round trip plus an invalidation broadcast

Read the last row carefully, because it is where near caching stops being free. Every write now costs a message to every other instance. On a read-heavy workload that is a rounding error against the reads you saved. On a write-heavy one it is a tax you pay forever.

App A App B App C near cache price = 12 near cache entry dropped near cache entry dropped reads never leave the JVM 1. write shared distributed cache · Redis or Valkey price = 12 2. invalidate A wrote, so A already has the new value · B and C reload on next access the window between step 1 and step 2 is the staleness window

How Near Cache Invalidation Works

Every implementation answers the same question — how does an instance learn a copy it holds is no longer good? — and there are only two families of answer.

Broadcast invalidation. The instance performing the write publishes on a channel every other instance subscribes to. The server is a relay; it neither knows nor cares who is caching what. Simple, protocol-version agnostic, and one message per write regardless of who held the entry.

Server-tracked invalidation. The server records which clients read which keys and notifies only those holding a copy. In Redis this is CLIENT TRACKING, and it is more precise — no wasted messages to instances that never read the key. Our page on Redis client-side caching covers the protocol.

That looks like a straightforward precision-versus-simplicity trade. It is not, because of granularity — per-entry versus per-object is the distinction that actually matters, and the one most discussions skip. A tracking invalidation names the key that changed, which for a Map stored as a single Redis hash means it names the whole Map and says nothing about which field moved. The only safe response is to discard the entire structure: change one product price in a 10,000-entry catalog and every instance drops all 10,000 entries and reloads them.

Redisson ships a warning about exactly this, in the javadoc of its own tracking-based API:

NOTE: client side caching feature invalidates whole Map per entry change
which is ineffective. Use local cached Map, JSON Store instead.

A broadcast implementation can do better, because it controls the payload. If the message carries a hash of the changed key rather than just the object name, receivers can evict one entry and leave the rest warm. That is why mature near caches for map-like structures are usually broadcast-based even where a tracking protocol is available.

Invalidate or update. Once notified, a peer can either drop the entry and reload it lazily, or accept a pushed copy of the new value. Dropping is the safer default: it is idempotent, it carries no payload beyond a key hash, and an entry nobody reads again is never reloaded at all. Pushing avoids the reload but broadcasts the full value to every instance whether they want it or not, and races with concurrent writers.

Either way, no near cache is strictly consistent. Between a write committing and the invalidation arriving, other instances serve the old value. With unbatched broadcast invalidation on a healthy network that window is sub-millisecond — but implementations that batch invalidations make it far larger, and it is unbounded when a message is lost.

Near Cache in Ignite, Hazelcast and Coherence

Near caching is not new. The in-memory data grid vendors have shipped it for years, and their designs are worth knowing — both because they are the prior art and because a team evaluating Redis is often migrating from one of them.

InvalidationGranularityNotable limitation
Apache IgniteCluster messages from server nodes, fully transactionalPer-entryOnly two settings of its own — eviction policy and initial size; everything else is inherited from the underlying cache, including its expiry policy, so there is no independent TTL. Stores entries on-heap, unlike Ignite's main off-heap store. Not available on thin clients
HazelcastInvalidation events, batched by default — sent at 100 events, or flushed by a background task every 10 secondsPer-entryEvents are fire-and-forget and can be lost; a background reconciliation task compensates
Oracle CoherenceBack-cache map events, with five selectable strategiesPer-entryThe all strategy plus a bulk operation can, per Oracle's own docs, "cause a flood of events that may saturate the network"
Redis or Valkey clientPub/sub broadcast, or server-side CLIENT TRACKINGPer-entry with broadcast; per-object with trackingDepends entirely on the client library — Redis supplies the signal, not the cache

Coherence has the most considered model, and its vocabulary is useful even if you never run it. Its invalidation-strategy takes five values: present listens only for events on entries the front cache holds; all listens to everything, suiting heavy overlap between instances; logical listens to everything except synthetic deletes from eviction and expiry; none disables listening and relies on a short TTL; and auto, the default, an alias for present. Most systems offer one of these behaviours and call it "the" near cache.

One structural point matters a great deal if you are choosing between these products and Redis. In all three grids the near cache is bound to the vendor's own cluster. Ignite's fronts an Ignite cache, Hazelcast's fronts an IMap or JCache, Coherence's back scheme must be a Coherence cache. You can point their read-through loaders at Redis as a system of record, but a change made directly to a Redis key invalidates nothing — none of them listens to Redis keyspace notifications or CLIENT TRACKING. Only a Redis-native client can invalidate a near cache from Redis itself.

When a Near Cache Makes Things Worse

Near caching is presented almost everywhere as a free speedup. It is not, and the failure modes are specific enough to check against your own workload first.

  • Write-heavy keys. Every write broadcasts. A counter updated a thousand times a second sends a thousand invalidations a second to every instance, and is almost never read from a warm local copy because it is almost never warm. Near caching helps when reads outnumber writes by a wide margin; if your ratio is closer to even, measure before you trust it.
  • Large values. The local copy lives on your heap, on every instance. Caching 500 MB of hot data across twenty instances is 10 GB of RAM and twenty contributions to garbage collection pause times. See cache eviction for bounding it.
  • Lost invalidations. Redis pub/sub is fire-and-forget — a disconnected subscriber gets no replay. Hazelcast documents the same property unusually candidly: "Invalidation events can be lost due to the fire-and-forget fashion of the eventing system. If an event is lost, reads from Near Cache can indefinitely be stale." Note indefinitely. Without a TTL or a reconciliation mechanism, one dropped message means a wrong value served until the process restarts.
  • Reconnection. This is the one teams miss, and it deserves its own paragraph.

An instance that loses its connection for thirty seconds misses every invalidation published during those thirty seconds. On reconnect its local cache holds entries that may be arbitrarily wrong, and nothing about the reconnection tells it which. What happens next is a configuration choice — and in most libraries the default is to do nothing.

Redisson makes the choice explicit through ReconnectionStrategy, with three settings. NONE is the default: no reconnect handling, the local cache keeps serving whatever it held. CLEAR discards the entire local cache on reconnect, trading a burst of misses for correctness. LOAD is the middle path — invalidated entry hashes are retained in a log for ten minutes, so an instance that was away for less than that reconciles precisely, and one that was away longer clears everything.

If you take one configuration decision from this page, take this one. Set reconnectionStrategy deliberately. Leaving it at the default is a choice to serve potentially stale data after every network blip, and it is the most common way a correctly configured near cache still produces incorrect reads.

Finally, a near cache is eventually consistent by construction. If a read must reflect the most recent write with no window at all, the answer is not a faster cache — it is a read against the shared cache, or the database.

What Redis and Valkey Actually Provide

Redis and Valkey make good substrates for a near cache, but it is worth being precise about what they contribute, because it is less than people assume.

They provide the signal: pub/sub for broadcast, CLIENT TRACKING for per-client precision, and keyspace notifications so a client learns a key expired rather than inferring it from a local timer. They do not provide the cache — there is no local store, no eviction policy for it, no reconnection handling, and no per-entry granularity over a hash.

All of that lives in the client library, which is why near caching on the JVM is a question about your Redis client rather than your Redis deployment. A client that only sends commands leaves you hand-building a local cache, a pub/sub listener, a message format and a reconnection strategy — and owning the correctness of all four.

Near Cache in Java With Redisson

Redisson implements near caching as RLocalCachedMap — an RMap that keeps a local copy of entries on each instance and invalidates them across the cluster over pub/sub, carrying a hash of the changed key so peers evict one entry rather than the whole map.

LocalCachedMapOptions<String, Product> options = LocalCachedMapOptions.<String, Product>name("products")
        .cacheSize(10_000)
        .evictionPolicy(EvictionPolicy.LRU)
        .syncStrategy(SyncStrategy.INVALIDATE)
        .reconnectionStrategy(ReconnectionStrategy.CLEAR)   // the default is NONE
        .timeToLive(Duration.ofMinutes(10));

RLocalCachedMap<String, Product> cache = redisson.getLocalCachedMap(options);

cache.put("sku-1", product);
Product p = cache.get("sku-1");   // served from this instance's memory, no network hop

Five settings carry most of the behaviour:

  • syncStrategyINVALIDATE (the default) broadcasts a 16-byte key hash and peers drop that entry; UPDATE broadcasts the full key and value so peers replace it in place; NONE disables synchronization, appropriate only for data that never changes.
  • evictionPolicyNONE (the default), LRU, LFU, or the reference-based SOFT and WEAK, which hand eviction to the garbage collector rather than a size bound. NONE still honours timeToLive and maxIdle; it only disables size-driven eviction.
  • reconnectionStrategyNONE, CLEAR or LOAD, as described above. Set it.
  • storeModeLOCALCACHE_REDIS (the default) keeps data in both tiers, a true near cache. LOCALCACHE keeps data only in the JVM and uses Redis purely as an invalidation bus.
  • cacheProviderREDISSON (the default) or CAFFEINE. If you were going to put Caffeine in front of Redis by hand, this is that, with the invalidation channel already built and tested.

The edition line is worth knowing before planning an integration. RLocalCachedMap is in the free edition, fully configurable, as is the CLIENT TRACKING-based API for whole-object caching. So are the base framework integrations — Spring Cache, Hibernate second-level cache, JCache, MyBatis, Micronaut and Quarkus all have free implementations. What Redisson PRO adds is the near-cached and partitioned versions of all of it: local caching combined with data partitioning across cluster shards, the clustered and V2 map variants, the JSON store, and a local-cached variant of each framework integration above. Redisson publishes read speedups of up to 45x for local caching against the equivalent non-local-cached map; PRO can be evaluated with a free trial.

For a runnable walkthrough alongside the other caching approaches, see Distributed Caching in Java with Valkey and Redis; for migrations, the guides for Hazelcast and Apache Ignite cover moving an existing near cache across.

Near Cache: Frequently Asked Questions

What Is a Near Cache?

A near cache is a small local cache held inside the application process, in front of a shared distributed cache. Reads are served from local memory and only cross the network on a miss. An invalidation channel tells every instance holding a copy when an entry changes, which is what separates it from an ordinary local cache.

What Is the Difference Between a Near Cache and a Local Cache?

A local cache is unaware of anything outside its own process, so when another instance updates the data its copy silently goes stale. A near cache is a local cache plus an invalidation channel: it is told when an entry changes and drops or replaces its copy. A near cache also has a shared cache behind it to fall back to on a miss.

How Does a Near Cache Stay in Sync?

Two mechanisms. With broadcast invalidation, the instance performing a write publishes a message on a channel every other instance subscribes to. With server-tracked invalidation, the server records which clients read which keys and notifies only those clients — in Redis, the CLIENT TRACKING command. Broadcast can carry a key identifier and evict one entry; tracking typically invalidates a whole object.

Does Redis Support Near Caching?

Redis and Valkey provide the invalidation signal — pub/sub, CLIENT TRACKING, and keyspace notifications — but not the local cache itself. The cache, its eviction policy, its reconnection handling and its invalidation granularity all live in the client library, so near caching on Redis is determined by your client. In Java, Redisson provides it as RLocalCachedMap.

When Should You Not Use a Near Cache?

When writes are frequent relative to reads, because every write costs an invalidation broadcast to every instance. When cached values are large, because each instance pays heap for its copy and lengthens its garbage collection pauses. And when a read must always reflect the latest write, because a near cache is eventually consistent by construction and has a staleness window between the write and the invalidation.

What Is the Difference Between a Near Cache and Client-Side Caching?

They describe the same idea from different angles. "Near cache" is the architectural pattern — a local tier in front of a remote one. Client-side caching usually refers to the specific Redis protocol feature, CLIENT TRACKING, that lets a server notify clients when keys they have read change. Client-side caching is one way to implement a near cache; broadcast invalidation over pub/sub is another.

Is a Near Cache Consistent?

No — it is eventually consistent. There is always a window between a write committing and the invalidation reaching other instances, during which they serve the previous value. That window is sub-millisecond with unbatched broadcast invalidation, larger where invalidations are batched, and unbounded if a message is lost or an instance is disconnected — which is why a TTL and a deliberate reconnection strategy matter.

Similar terms