Redis  

What is Redis and how does it fit into Clean Architecture in a .NET application

Introduction

Redis (Remote Dictionary Server) is an open-source, in-memory NoSQL data platform designed to deliver ultra-fast read and write performance—often below 1 millisecond. It can function as a cache, a distributed database, and a lightweight message broker. Redis supports advanced data structures such as strings, hashes, lists, sets, sorted sets, streams, bitmaps, HyperLogLogs, and more.

Because Redis stores data directly in RAM rather than on disk, it is thousands of times faster than traditional relational databases. This makes it ideal for building high-performance, real-time applications, including:

  • Microservices

  • Chat applications

  • Leaderboards and gaming systems

  • Analytics dashboards

  • Distributed locks

  • Session storage

  • Rate limiting and throttling

Redis is trusted by major organizations such as Netflix, Spotify, Microsoft, Stack Overflow, Amazon, and GitHub, and it plays a critical role in modern, scalable .NET systems.

Core Features of Redis

In-Memory Storage

Traditional SQL databases perform read and write operations on disk, which introduces latency. Redis operates entirely in memory and is capable of handling millions of operations per second.

Why It Matters in C# Applications

  • Extremely fast loading of dashboards, profiles, menus, and home pages

  • Reduces database overload and prevents SQL deadlocks

  • Ideal for API caching, real-time chat, and session storage

Rich Data Structures

Redis behaves like a compact NoSQL system by offering multiple optimized data structures.

Redis TypeUse CaseExample
StringCache a single value"User:100:name" = "Mohan"
HashStore object-like dataproduct: { name, price, stock }
ListQueue / FIFO tasksEmail queue, background jobs
SetUnique values onlyCategory tags
Sorted SetRanking by scoreGame leaderboard
StreamEvent logsOrder status stream

Example C# Usage

IDatabase db = RedisConnection.Connection.GetDatabase();

// String
db.StringSet("user:1:name", "Mohan Veer");
string name = db.StringGet("user:1:name");

// Hash
db.HashSet("product:101", new HashEntry[]
{
    new("name", "Keyboard"),
    new("price", "1200"),
    new("brand", "Dell")
});

var product = db.HashGetAll("product:101");

// List
db.ListLeftPush("emailQueue", "[email protected]");
string nextEmail = db.ListRightPop("emailQueue");

// Sorted Set
db.SortedSetAdd("game:scoreboard", "player1", 500);
db.SortedSetAdd("game:scoreboard", "player2", 1200);
var topPlayers = db.SortedSetRangeByScore(
    "game:scoreboard",
    order: Order.Descending
);

Persistence (Data Durability)

Although Redis is primarily an in-memory system, it also supports data persistence to ensure data is not lost during crashes or restarts. In managed services such as Azure Cache for Redis, persistence is enabled by default.

Persistence Modes

ModeDescription
RDB SnapshotPeriodically saves the entire database
AOF LogLogs every write operation
Hybrid ModeCombination of RDB and AOF

Pub/Sub Messaging System

Redis can function as a lightweight messaging system, similar to RabbitMQ or Kafka.

Common Use Cases

  • Sending notifications to multiple microservices

  • Real-time dashboard updates

  • Chat applications

  • Triggering workflows without a dedicated queue server

Example (C#)

var redis = RedisConnection.Connection;
var sub = redis.GetSubscriber();

await sub.PublishAsync("order_channel", "Order Created #1001");

await sub.SubscribeAsync("order_channel", (channel, message) =>
{
    Console.WriteLine("Received => " + message);
});

Distributed Cache (Shared Across Servers)

Redis enables a single shared cache across multiple application instances.

  • Essential for Kubernetes, cloud scaling, and microservices architectures

  • Sessions remain intact even if an application server restarts

High Availability and Clustering

Redis supports multiple high-availability and scaling modes.

ModeExplanation
Primary–ReplicaWrites to primary, reads from replicas
ClusterData is automatically sharded across nodes
SentinelAutomatic failure detection and failover

Benefits

  • Zero downtime

  • No cache loss

  • High performance under heavy load

These features make Redis suitable for e-commerce flash sales, high-frequency trading systems, and gaming platforms.

TTL – Auto-Expiring Keys

Redis allows keys to expire automatically after a specified duration.

db.StringSet("otp:9876", "4567", TimeSpan.FromMinutes(2));

This is ideal for OTPs, login sessions, and temporary API cache data.

Lua Scripting and Atomic Operations

Redis supports Lua scripting to execute atomic operations safely.

Typical use cases include:

  • Wallet balance deduction

  • Preventing duplicate order placement

  • Safe queue processing across multiple servers

Security

Redis provides multiple security mechanisms:

  • Password-based authentication

  • TLS/SSL encryption (mandatory for cloud deployments)

  • VNet isolation using Azure Private Link

  • Role-based access control in Redis Enterprise

For production-grade .NET applications, SSL should always be enabled.

Redis Installation and Client Setup

Install Redis Locally Using Docker

docker run --name redis-dev -p 6379:6379 -d redis

Install Redis Client NuGet Package

dotnet add package StackExchange.Redis

Single ConnectionMultiplexer (Recommended)

public class RedisConnection
{
    private static readonly Lazy<ConnectionMultiplexer> lazyConnection =
        new(() => ConnectionMultiplexer.Connect("localhost:6379"));

    public static ConnectionMultiplexer Connection => lazyConnection.Value;
}

Redis in Clean Architecture

A common mistake in .NET applications is accessing Redis directly from controllers. This violates Clean Architecture principles and makes unit testing difficult.

Recommended Approach

  • Redis logic should reside in the Infrastructure layer

  • Define an ICacheService interface in the Application layer

  • Controllers should not be aware of Redis

  • Cache implementation can be swapped easily

Flow:

Controller → Application Service → ICacheService → RedisCacheService

Interface (Application Layer)

public interface ICacheService
{
    Task<T?> GetAsync<T>(string key);
    Task SetAsync<T>(string key, T value, TimeSpan? expiry = null);
    Task RemoveAsync(string key);
}

Implementation (Infrastructure Layer)

public class RedisCacheService : ICacheService
{
    private readonly IDatabase _db;

    public RedisCacheService(IConnectionMultiplexer connection)
        => _db = connection.GetDatabase();

    public async Task<T?> GetAsync<T>(string key)
        => JsonSerializer.Deserialize<T>(await _db.StringGetAsync(key));

    public async Task SetAsync<T>(string key, T value, TimeSpan? expiry = null)
        => await _db.StringSetAsync(
            key,
            JsonSerializer.Serialize(value),
            expiry
        );

    public async Task RemoveAsync(string key)
        => await _db.KeyDeleteAsync(key);
}

Best Practices for Real .NET Systems

  • Always set a TTL (expiry) for cached data

  • Avoid storing objects larger than 1–2 MB

  • Use JSON compression for large payloads

  • Use Azure Redis for production workloads

  • Use a singleton ConnectionMultiplexer

  • Monitor using RedisInsight, INFO, and SLOWLOG

Summary

Redis is a powerful performance accelerator for .NET applications. It enables systems to handle millions of requests per second, significantly reduces database load, prevents concurrency issues, supports distributed communication, and delivers fast, scalable, cloud-ready user experiences.