StackExchange.Redis.Extensions

repository·master·Indexed 20 days ago

https://github.com/imperugo/stackexchange.redis.extensions

A high-level wrapper for StackExchange.Redis that simplifies working with complex .NET objects through automatic serialization, connection pooling, and advanced features. It provides the IRedisDatabase interface for operations including Distributed Locking, Pub/Sub, Redis Streams, GeoSpatial Indexes, and Hash Field Expiry. The library supports multiple serializers (System.Text.Json, Newtonsoft, MemoryPack, MsgPack, Protobuf) and transparent compression (GZip, Brotli, LZ4, Snappy, Zstandard), with dedicated integration for ASP.NET Core.

Tokens
45.9K
Snippets
141
Records
194
Agent score
70%

What's inside StackExchange.Redis.Extensions

  1. Explore available Redis features and operations

    master

    StackExchange.Redis.Extensions provides high-level implementations for various Redis data structures and features:

    • Object Management: Add, retrieve, replace, and remove complex objects.
    • Hashes: Standard hash operations and Hash Field Expiry (requires Redis 7.4+).
    • Advanced Data Types:
      • GeoSpatial Indexes for location-based data.
      • VectorSet for AI/ML similarity search (requires Redis 8.0+).
      • Redis Streams for message streaming.
      • HyperLogLog for probabilistic cardinality estimation.
      • Bitmaps for bit-level analytics and feature flags.
    • Messaging & Scripting:
      • Pub/Sub Messaging.
      • Lua Scripting for server-side execution.
    • Concurrency: Distributed Lock implementation using IAsyncDisposable.
  2. Available features in StackExchange.Redis.Extensions

    master

    The library extends standard Redis capabilities with the following features:

    • Complex Objects: Add, retrieve, and remove complex objects.
    • Object Management: Replace objects and work with multiple items.
    • Customization: Use custom serializers and optional compression.
    • Messaging: Pub/Sub events.
    • Advanced Operations:
      • Search keys into Redis
      • Store multiple objects with a single roundtrip
      • Get Redis Server information
      • Set operations (Add / Remove / Member)
      • Geo commands
      • Stream commands
      • Hash commands (including Hash Field Expiry)
      • Tag-based operations
    • Infrastructure Support:
      • Async methods
      • Keyspace isolation
      • Support for multiple databases
  3. Use HyperLogLog for approximate cardinality estimation

    master

    HyperLogLog is a probabilistic data structure used to estimate the cardinality (unique count) of a set with minimal memory (~12 KB per key). It is ideal for high-scale scenarios like counting unique visitors or events where an approximate count is acceptable.

    Key characteristics:

    • Memory Efficiency: Constant memory usage regardless of the number of elements.
    • Accuracy: Standard error rate of approximately 0.81%.
    • Serialization: Values are processed through the configured ISerializer before being added to the structure.
  4. How compression works in StackExchange.Redis.Extensions

    master

    Compression is applied transparently to all cached data. The library uses a decorator pattern where a CompressedSerializer wraps an ISerializer and an ICompressor.

    Data Flow:

    1. Write: Your Object $\rightarrow$ ISerializer (byte array) $\rightarrow$ ICompressor (compressed bytes) $\rightarrow$ Redis.
    2. Read: Redis $\rightarrow$ compressed bytes $\rightarrow$ ICompressor (byte array) $\rightarrow$ ISerializer (Your Object).

    This reduces Redis memory usage and network bandwidth by compressing data after serialization but before storage.

  5. How KeyPrefix affects Pub/Sub channels

    master

    If a KeyPrefix is configured in your Redis settings, it is automatically applied to Pub/Sub channels using the underlying ChannelPrefix mechanism.

    Important: Do not manually add the prefix to your channel names in your code; the library handles this automatically. For example, if KeyPrefix is set to "myapp:", publishing to "orders" will actually target the Redis channel "myapp:orders".

    // Config: KeyPrefix = "myapp:"
    await redis.PublishAsync("orders", message);
    // Actual Redis channel: "myapp:orders"
  6. How StackExchange.Redis.Extensions architecture works

    master

    The library follows a layered architecture designed for dependency injection and connection pooling:

    1. Application Layer: Your code interacts with high-level abstractions.
    2. DI Layer: ASP.NET Core DI manages the lifecycle of clients.
    3. Factory Layer: IRedisClientFactory produces either a default IRedisClient or specific named instances.
    4. Client Layer: IRedisClient provides access to the database.
    5. Database Layer: IRedisDatabase is the primary interface for operations. It utilizes a Connection Pool Manager to manage multiple connections (using strategies like LeastLoaded or RoundRobin) to the Redis server.
    6. Serialization Layer: IRedisDatabase uses an ISerializer (which can be a CompressedSerializer wrapping an inner serializer like System.Text.Json or Newtonsoft) to handle object conversion before sending data to the Redis server.
  7. How GeoSpatial indexing works in StackExchange.Redis.Extensions

    master

    The library wraps Redis's native GeoSpatial commands.

    • Data Model: Geo members are string identifiers (e.g., IDs or names). Coordinates are stored internally by Redis as sorted set scores.
    • Complex Objects: Since members are strings, if you need to associate complex objects with a location, you should store those objects under a separate Redis key derived from the member name.
    • Command Mapping:
      • GeoAddAsync $\rightarrow$ GEOADD (uses Redis Sorted Sets)
      • GeoSearchAsync $\rightarrow$ GEOSEARCH
      • GeoDistanceAsync $\rightarrow$ GEODIST
      • GeoPositionAsync $\rightarrow$ GEOPOS
  8. Important considerations for Distributed Locks

    master

    When using Redis-based distributed locking, keep the following in mind:

    • Holder Identity: The lock value acts as a holder identifier. Only the holder with the matching value can release or extend the lock.
    • Automatic Values: LockAcquireAsync generates a random GUID as the lock value automatically.
    • Retry Defaults: The default retry delay is 200ms with 3 retries.
    • Failure Handling: LockAcquireAsync returns null (not an exception) when the lock cannot be acquired.
    • Deadlock Prevention: Always set a reasonable expiry to prevent deadlocks if the holder crashes.
    • Cluster Support: This is a single-instance lock implementation. For multi-instance Redis (Cluster), consider using the Redlock algorithm.
  9. Choose a Serializer for Redis objects

    master

    The library supports multiple serialization formats to handle complex objects in Redis. You should select the one that best fits your performance and compatibility requirements:

    • System.Text.Json (Recommended)
    • Newtonsoft Json.NET
    • MemoryPack
    • MsgPack
    • Protobuf

    You can also implement a Custom Serializer if the built-in options do not meet your needs.

  10. Important behaviors and constraints in StackExchange.Redis.Extensions

    master

    When using the library, be aware of the following operational behaviors:

    • Serialization: All values are processed through ISerializer. This means strings are JSON-encoded (e.g., "hello" becomes "\"hello\"").
    • Raw Access: For operations not covered by the extensions, use redis.Database directly.
    • KeyPrefix: The configured KeyPrefix is applied to both Redis keys and Pub/Sub channels.
    • Compression: If a compressor is configured, it wraps the ISerializer transparently; all operations benefit from compression automatically.
    • Bitmap Operations: These do NOT use serialization; they operate directly on bit offsets.
    • Distributed Locks: Locks use a GUID as the holder value. Only the specific holder that acquired the lock can release or extend it.
    • Lock Acquisition: LockAcquireAsync returns null if the lock cannot be acquired, rather than throwing an exception.
    • Lua Scripts: To ensure cluster compatibility, always use KEYS[n] and ARGV[n] in Lua scripts instead of hardcoding key names.
    • Read-Only Scripts: Use ScriptEvaluateReadOnlyAsync to utilize EVALRO, which allows the command to be routed to Redis replicas.
  11. Understand Connection Pooling strategies

    master

    The library manages a pool of connections. When an operation requests a connection via GetConnection(), it uses one of two strategies:

    • LeastLoaded (default): Picks the connected connection with the fewest outstanding commands.
    • RoundRobin: Randomly selects among connected connections.

    The pool automatically skips disconnected connections and falls back gracefully when all connections are down.