Choosing a Second‑Level Cache Provider for NHibernate 5.x: SysCache, Redis, Memcached, or In‑Memory
Choosing the right second‑level cache provider for NHibernate 5.x is critical for read‑heavy workloads. This guide compares SysCache, Redis, Memcached, and InMemory, explains trade‑offs, and walks through a concrete Redis implementation with validation steps.
22 Dec 2025, 00:17 UTC

Decision Overview
When building a read‑heavy application with NHibernate 5.x, the second‑level cache can dramatically reduce database round‑trips. The choice of provider—built‑in InMemory, AppFabric’s SysCache, Redis, or Memcached—depends on deployment topology, eviction needs, and operational complexity. This guide helps you decide which provider best fits your environment and shows how to implement and validate a Redis‑based solution.
Constraints & Decision Criteria
- Deployment topology: single‑node vs. distributed cluster.
- Eviction policy: LRU, TTL, or both.
- Operational overhead: external infrastructure, libraries, and monitoring.
- Data consistency requirements: stale reads tolerance.
- Version support: NHibernate 5.x compatibility and provider maintenance status.
Provider Comparison
| Provider | Distribution | Eviction Policies | Dependencies | Typical Use Case |
|---|---|---|---|---|
| SysCache (AppFabric) | Single‑node (Windows Server) | LRU, TTL, region‑based | Microsoft.AppFabric.Caching | Legacy on‑prem Windows apps |
| Redis (NHibernate.Caches.Redis) | Distributed (cloud, containers) | TTL, LRU via Redis eviction, pub/sub invalidation | StackExchange.Redis 2.x | High‑availability, multi‑instance workloads |
| Memcached (NHibernate.Caches.Memcached) | Distributed (simple cluster) | TTL only (no LRU) | EnyimMemcached | Low‑cost, horizontal scaling |
| InMemory (NHibernate.Cache.Default) | Single‑node (per AppDomain) | None (in‑process dictionary) | None | Dev/test, single‑instance apps |
Trade‑offs
- SysCache is tied to the now‑deprecated Windows AppFabric, making it unsuitable for new deployments.
- Redis offers distributed caching and pub/sub invalidation, but requires a Redis server and the StackExchange.Redis client. It supports TTL, LRU (via Redis eviction policies), and region mapping via key prefixes.
- Memcached is lightweight but only supports TTL; it lacks native region support, so NHibernate regions are simulated by key prefixes.
- InMemory is the simplest but has no eviction and cannot be shared across processes, leading to duplicate data and potential memory exhaustion.
- Using
read-writeornonstrict-read-writecaching requires a version or timestamp column for optimistic concurrency. The former guarantees consistency at the cost of higher write traffic; the latter allows stale reads but is faster.
Concrete Implementation – Redis
Prerequisites
- NHibernate 5.x (5.4+ for improved Redis support)
- Redis server (local or cloud) with port 6379 reachable
- NuGet packages:
- NHibernate.Caches.Redis
- StackExchange.Redis (2.x)
Configuration
Add the following to hibernate.cfg.xml (or equivalent programmatic config). Replace {redisConnectionString} with your server details.
NHibernate.Caches.Redis.RedisCacheProvider, NHibernate.Caches.Redis
{redisConnectionString}
true
true
Annotate your entity with a cache region and usage mode:
[Cache(Usage = CacheUsage.NonstrictReadWrite, Region = "Products")]
public class Product
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual decimal Price { get; set; }
public virtual DateTime LastUpdated { get; set; } // for versioning
}
Enable statistics to monitor cache activity:
cfg.SetProperty("generate_statistics", "true");
Validation
- Verify cache hits – Run a load test that loads the same
Productentity twice. Inspect NHibernate logs (DEBUG level) forCache hitvsCache miss. Also checksessionFactory.Statistics.SecondLevelCacheHitCountandMissCount. - Inspect Redis keys – Use the Redis CLI:
This confirms the key prefix and TTL.redis-cli KEYS "NHibernate:*" redis-cli TTL "NHibernate:Products:42" - Simulate cache invalidation – Update a
Productthrough another session. The Redis pub/sub channelNHibernate:Productswill receive an invalidation message. Verify that subsequent reads fetch from the database and repopulate the cache. - Network partition test – Stop the Redis server temporarily. NHibernate should fall back to the database, logging a warning about the cache provider being unreachable. After restart, cache should resume normal operation.
Practical Checklist
- Confirm that the chosen provider’s NuGet package is compatible with your .NET runtime.
- Ensure that entity classes used with
read-writeornonstrict-read-writehave aVersionorTimestampproperty. - Verify region names in annotations match those in the cache configuration; mismatches silently disable caching for that entity.
- Monitor Redis or Memcached metrics (hits, misses, evictions) during load tests to fine‑tune TTL and eviction policies.
- Plan for failover: in a multi‑node environment, ensure that the cache provider is highly available or that your application tolerates temporary cache outages.
Conclusion
For new NHibernate 5.x projects that require a distributed, scalable cache, Redis is the most versatile choice. It supports TTL, LRU eviction, and pub/sub invalidation, and integrates cleanly with the ISecondLevelCacheProvider interface. Memcached is a lightweight alternative if TTL suffices, while InMemory is suitable only for development or single‑instance scenarios. Legacy SysCache should be avoided due to its deprecation. By following the configuration and validation steps above, you can confidently deploy a second‑level cache that meets your read‑heavy workload needs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.