Cache Patterns
Cache Patterns
This page outlines common caching patterns with Morphium and when to use them.
- Read‑through entity cache (default)
- Use
@Cacheon entities to enable read cache for queries and ID cache - Choose a clear strategy that matches your write rate and consistency needs
@Cache(timeout = 30_000, clearOnWrite = true, strategy = Cache.ClearStrategy.LRU, syncCache = Cache.SyncCacheStrategy.CLEAR_TYPE_CACHE)
public class Product { ... }
When to use
- Most read‑heavy entities, where occasional stale reads for up to the TTL are acceptable
- Precise invalidation per entity (remove or update)
- Reduce blast radius on writes by removing/updating only affected IDs instead of clearing the whole type cache
@Cache(timeout = 60_000, clearOnWrite = true, syncCache = Cache.SyncCacheStrategy.REMOVE_ENTRY_FROM_TYPE_CACHE)
public class User { ... }
or
@Cache(timeout = 60_000, clearOnWrite = true, syncCache = Cache.SyncCacheStrategy.UPDATE_ENTRY)
public class User { ... }
Notes
- With
UPDATE_ENTRY, other nodes re‑read the updated document (slightly higher cost, but fewer cache misses)
- Cluster‑wide synchronization via messaging
- Ensure every node runs messaging and attach a
MessagingCacheSynchronizer
MorphiumMessaging messaging = morphium.createMessaging();
messaging.start();
new MessagingCacheSynchronizer(messaging, morphium);
When to use
- Multi‑node deployments that need consistent caches after writes
- TTL tuning and hot‑set sizing
- Keep
@Cache.timeoutsmall enough to minimize staleness, large enough to reduce DB load - Use
maxEntriesandstrategyto control memory use and eviction behavior
@Cache(timeout = 15_000, maxEntries = 50_000, strategy = Cache.ClearStrategy.LRU)
public class Article { ... }
- JCache integration and layering
- Use
MorphiumCacheJCacheImplto adopt javax.cache - Optionally back it with an external provider for cross‑JVM cache layers
MorphiumCacheJCacheImpl jcache = new MorphiumCacheJCacheImpl();
cfg.cacheSettings().setCache(jcache);
- Avoiding cache stampede
- For heavy queries, consider:
- Pre‑warming popular keys at startup
- Adding small jitter to TTL at application level if you implement explicit invalidation
- Using
UPDATE_ENTRYto keep hot IDs fresh without clearing type cache
- Eventual vs strong consistency
- Read‑through caching is eventually consistent between nodes
- To minimize staleness:
- Use smaller TTLs
- Prefer
REMOVE_ENTRY_FROM_TYPE_CACHEorUPDATE_ENTRY - Ensure messaging is available and responsive (replica set + change streams is preferred)
- Batching and write buffering
- Global write buffering and async writes reduce DB pressure under load
cfg.cacheSettings().setAsyncWritesEnabled(true);
cfg.cacheSettings().setBufferedWritesEnabled(true);
Trade‑off
- Buffering can delay writes; choose TTLs and cache sync strategies accordingly
- Manual controls for maintenance
// Clear one type
morphium.clearCachefor(Product.class);
// Clear all types on all nodes
new MessagingCacheSynchronizer(messaging, morphium).sendClearAllMessage("maintenance");
- Query‑result cache keys
- Morphium computes a deterministic key for queries (criteria + sort + projection + paging)
- Prefer projections to keep cached result documents small
See also