All Projects → thepirat000 → Cachingframework.redis

thepirat000 / Cachingframework.redis

Licence: other
Distributed caching based on StackExchange.Redis and Redis. Includes support for tagging and is cluster-compatible.

Projects that are alternatives of or similar to Cachingframework.redis

Redisson
Redisson - Redis Java client with features of In-Memory Data Grid. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Publish / Subscribe, Bloom filter, Spring Cache, Tomcat, Scheduler, JCache API, Hibernate, MyBatis, RPC, local cache ...
Stars: ✭ 17,972 (+8499.04%)
Mutual labels:  redis, cache, redis-client, redis-cluster
Redis
Vapor provider for RediStack
Stars: ✭ 434 (+107.66%)
Mutual labels:  redis, cache, redis-client
Redis Plus Plus
Redis client written in C++
Stars: ✭ 428 (+104.78%)
Mutual labels:  redis, redis-client, redis-cluster
Redis Py Cluster
Python cluster client for the official redis cluster. Redis 3.0+.
Stars: ✭ 934 (+346.89%)
Mutual labels:  redis, redis-client, redis-cluster
Fastoredis
FastoRedis is a crossplatform Redis GUI management tool.
Stars: ✭ 316 (+51.2%)
Mutual labels:  redis, redis-client, redis-cluster
Lettuce Core
Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
Stars: ✭ 4,319 (+1966.51%)
Mutual labels:  redis, redis-client, redis-cluster
Iodine
iodine - HTTP / WebSockets Server for Ruby with Pub/Sub support
Stars: ✭ 720 (+244.5%)
Mutual labels:  redis, redis-client, pubsub
Pottery
Redis for humans. 🌎🌍🌏
Stars: ✭ 204 (-2.39%)
Mutual labels:  redis, cache, redis-client
Php Redis Client
RedisClient is a fast, fully-functional and user-friendly client for Redis, optimized for performance. RedisClient supports the latest versions of Redis starting from 2.6 to 6.0
Stars: ✭ 112 (-46.41%)
Mutual labels:  redis, redis-client, redis-cluster
Redis Game Transaction
在大型游戏中经常使用分布式,分布式中因为游戏逻辑会经常游戏事务,借助redis特性我们可以实现分布式锁和分布式事务。很多redis集群不支持redis的事务特性。 这个框架用来解决分布式服务器下redis集群事务失效的情况下,基于分布式锁完成分布式事务。支持独占锁,共享锁,读写锁,并且支持事务提交失败情况下的回滚操作,让开发者可以有更多时间侧重游戏逻辑.
Stars: ✭ 124 (-40.67%)
Mutual labels:  redis, redis-client, redis-cluster
Csredis
.NET Core or .NET Framework 4.0+ client for Redis and Redis Sentinel (2.8) and Cluster. Includes both synchronous and asynchronous clients.
Stars: ✭ 1,714 (+720.1%)
Mutual labels:  redis, redis-client, redis-cluster
Xredis
Redis C++ client, support the data slice storage, support redis cluster, thread-safe,multi-platform,connection pool, read/write separation.
Stars: ✭ 285 (+36.36%)
Mutual labels:  redis, redis-client, redis-cluster
Redis
Type-safe Redis client for Golang
Stars: ✭ 13,117 (+6176.08%)
Mutual labels:  redis, redis-client, redis-cluster
Stackexchange.redis.extensions
Stars: ✭ 419 (+100.48%)
Mutual labels:  redis, cache, redis-client
salad
Asynchronous Scala Redis Client supporting Sentinel and Redis Cluster
Stars: ✭ 14 (-93.3%)
Mutual labels:  cache, redis-cluster, redis-client
Quick redis blog
QuickRedis is a free forever Redis Desktop manager. It supports direct connection, sentinel, and cluster mode, supports multiple languages, supports hundreds of millions of keys, and has an amazing UI. Supports both Windows, Mac OS X and Linux platform.
Stars: ✭ 594 (+184.21%)
Mutual labels:  redis, redis-client, redis-cluster
Ioredis
🚀 A robust, performance-focused, and full-featured Redis client for Node.js.
Stars: ✭ 9,754 (+4566.99%)
Mutual labels:  redis, redis-client, redis-cluster
Overlord
Overlord是哔哩哔哩基于Go语言编写的memcache和redis&cluster的代理及集群管理功能,致力于提供自动化高可用的缓存服务解决方案。
Stars: ✭ 1,884 (+801.44%)
Mutual labels:  redis, cache, redis-cluster
Camellia
camellia framework by netease-im. provider: 1) redis-client; 2) redis-proxy(redis-sentinel/redis-cluster); 3) hbase-client; 4) others
Stars: ✭ 146 (-30.14%)
Mutual labels:  redis, redis-client, redis-cluster
Study
全栈工程师学习笔记;Spring登录、shiro登录、CAS单点登录和Spring boot oauth2单点登录;Spring data cache 缓存,支持Redis和EHcahce; web安全,常见web安全漏洞以及解决思路;常规组件,比如redis、mq等;quartz定时任务,支持持久化数据库,动态维护启动暂停关闭;docker基本用法,常用image镜像使用,Docker-MySQL、docker-Postgres、Docker-nginx、Docker-nexus、Docker-Redis、Docker-RabbitMQ、Docker-zookeeper、Docker-es、Docker-zipkin、Docker-ELK等;mybatis实践、spring实践、spring boot实践等常用集成;基于redis的分布式锁;基于shared-jdbc的分库分表,支持原生jdbc和Spring Boot Mybatis
Stars: ✭ 159 (-23.92%)
Mutual labels:  redis, cache

CachingFramework.Redis

Gitter issues-open issues-closed

.NET Redis client library based on StackExchange.Redis adding some interesting features like an extensible serialization strategy, a tagging mechanism to group keys, hash fields and set members, and a fetching mechanism to support atomic add/get operations, all being cluster-compatible.

Features

Usage

NuGet

To install the package run the following command on the Package Manager Console:

PM> Install-Package CachingFramework.Redis

Context

The RedisContext class provides all the functionality divided into five categories, each of which is exposed as a property with the following names:

  • Cache
  • Collections
  • GeoSpatial
  • PubSub
  • KeyEvents

Default configuration

Connect to Redis on localhost port 6379:

var context = new RedisContext();

Custom configuration

var context = new RedisContext("10.0.0.1:7000, 10.0.0.2:7000, connectRetry=10, abortConnect=false, allowAdmin=true");

The constructor parameter must be a valid StackExchange.Redis connection string. Check this for more information about StackExchange.Redis configuration options.

Custom multiplexer

You can inject your own multiplexer by using the appropiate constructor overload:

public class PooledConnectionMultiplexer : IConnectionMultiplexer
{
    // ...
}

var myMultiplexer = new PooledConnectionMultiplexer(Common.Config);
var context = new RedisContext(myMultiplexer);

IMPORTANT NOTE:

The RedisContext object should be shared and reused between callers. It is not recommended to create a RedisContext per operation. Please check StackExchange.Redis documentation for more information.

Serialization

Different serialization mechanisms are provided:

Serializer Data Configuration
BinarySerializer All types are serialized using the .NET BinaryFormatter and GZIP compressed. Default for .Net Framework
JsonSerializer Data is stored as Json using System.Text.Json. Serialization can be configured with JsonSerializerOptions. Default for .Net Core
RawSerializer The simple types are serialized as UTF-8 strings. Any other type is serialized using the default serializer. Serialization can be set-up per type using SetSerializerFor()
NewtonsoftJsonSerializer Data is stored as Json using Newtonsoft.Json. Serialization can be configured with JsonSerializerSettings. NuGet Package CachingFramework.Redis.NewtonsoftJson
MsgPackSerializer Data is stored as MessagePack via MsgPack.Cli. NuGet Package CachingFramework.Redis.MsgPack

The RedisContext class has constructor overloads to supply the serialization mechanism, for example:

var context = new RedisContext("localhost:6379", new JsonSerializer());

Default serialization method

You can change the default serialization mechanism by setting the static property RedisContext.DefaultSerializer. This default is used when creating RedisContext without an explicit serializer.

Of course you must do this before any context creation, for example on your application startup:

RedisContext.DefaultSerializer = new JsonSerializer();

NOTE: If you don't explicitly set the serializer, it will default depending on the framework: .NET Framework version will default to BinarySerializer and .NET Core to JsonSerializer.

If you plan to consume data from different framework versions, make sure all of them are using the same serialization method.

Custom serialization

To provide a custom serialization mechanism, implement the ISerializer interface. For example:

public class MySerializer : ISerializer
{
    public RedisValue Serialize<T>(T value)
    {
        return value.ToString();
    }
    public T Deserialize<T>(RedisValue value)
    {
        return (T)Convert.ChangeType(value.ToString(), typeof(T));
    }
}

Raw serializer

The RawSerializer allows to dynamically override the serialization/deserialization logic per type with the method SetSerializerFor<T>().

For example, to allow the serialization of a StringBuilder as an UTF-8 encoded string:

// On your startup logic:
RedisContext.DefaultSerializer = new RawSerializer()
    .SetSerializerFor<StringBuilder>
    (
        sb => Encoding.UTF8.GetBytes(sb.ToString()), 
        b => new StringBuilder(Encoding.UTF8.GetString(b))
    );

Typed cache

Any primitive type or serializable class can be used as a cache value.

For example:

[Serializable]
public class User
{
    public int Id { get; set; }
    public string UserName { get; set; } ...
}

Note: The Serializable attribute is needed by the default serialization method binary serializer. If you use, for example, the json serializer, this attribute becomes unnecessary. See Serialization section for more information.

Add a single object to the cache:

string redisKey = "user:1";
User value = new User() { Id = 1 };  // any serializable object 
context.Cache.SetObject(redisKey, value);

Add a single object with TTL

Add a single object to the cache with a Time-To-Live of 1 day:

context.Cache.SetObject(redisKey, value, TimeSpan.FromDays(1));

Get a single object

User user = context.Cache.GetObject<User>(redisKey);

Remove a key

context.Cache.Remove(redisKey);

Fetching mechanism

Shortcut methods are provided for atomic add/get operations (see Cache-Aside pattern). Image of Fetching Mechanism

Fetch an object

Try to get an object from the cache, inserting it to the cache if it does not exists:

var user = context.Cache.FetchObject<User>(redisKey, () => GetUserFromDatabase(id));

The method GetUserFromDatabase will only be called when the value is not present on the cache, in which case will be added to the cache before returning it.

Fetch an object with a time-to-live:

var user = context.Cache.FetchObject<User>(redisKey, () => GetUserFromDatabase(id), TimeSpan.FromDays(1));

The TTL value is set only when the value is not present on the cache.


Hashes

Hashes are maps composed of fields associated with values, like .NET dictionaries.

Image of hashes

Set hashed objects

Set an object on a redis key indexed by a field key (sub-key):

void InsertUser(User user)
{
    var redisKey = "users:hash";
    var fieldKey = "user🆔" + user.Id;
    context.Cache.SetHashed(redisKey, fieldKey, user);
}

Get hashed object

Get an object by the redis key and a field key:

User u = context.Cache.GetHashed<User>("users:hash", "user🆔1");

Get all the objects in a hash

IDictionary<string, User> users = context.Cache.GetHashedAll<User>("users:hash");

Objects within a hash can be of different types.

Scan fields by pattern

Incrementally iterate over the hash members by matching a glob-style pattern with the field names.

For example, to iterate over the members of a hash whose field names starts with "user:".

var scan = context.Cache.ScanHashed<User>("users:hash", "user:*");
foreach (var item in scan)
{
    string key = item.Key;
    User value = item.Value;
    // ...
}

Remove object from hash

context.Cache.RemoveHashed("users:hash", "user🆔1");

Fetch a hashed object

var user = context.Cache.FetchHashed<User>("users:hash", "user🆔1", () => GetUser(1));

The method GetUser will only be called when the value is not present on the hash, in which case will be added to the hash before returning it.

Hash as a .NET Dictionary

Hashes can be handled as .NET Dictionaries by using the GetRedisDictionary method on RedisContext.Collections, for example:

var dict = context.Collections.GetRedisDictionary<string, User>("users:hash");
dict.Add("user🆔1", user);

For more information about collections, please see COLLECTIONS.md.


Tagging mechanism

Cluster compatible tagging mechanism where tags are used to group keys, hash fields, set members, sorted set members and geospatial members, so they can be retrieved or invalidated at the same time. A tag can be related to any number of keys, hash fields, or set members.

Image of Tagging Mechanism

Add a single object related to a tag

Add a single object to the cache and associate it with tags red and blue:

context.Cache.SetObject("user:1", user, new[] { "red", "blue" });

Add a hashed object related to a tag

Tags can point to a field in a hash.

context.Cache.SetHashed("users:hash", "user🆔1", value, new[] { "red" });

Add a member to a redis set related to a tag:

Add a single member to a redis set and associate the member to the tag red:

context.Cache.AddToSet("users:set", value, new[] { "red" });

Add a member to a redis sorted set related to a tag:

Add a single member to a redis sorted set and associate the member to the tag blue:

context.Cache.AddToSortedSet("users:sortedset", 100.00, value, new[] { "blue" });

Relate an existing key to a tag

Relate the key to the green tag:

context.Cache.AddTagsToKey("user:1", new [] { "green" });

Relate an existing hash field to a tag

Relate the hash field to the green tag:

context.Cache.AddTagsToHashField("users:hash", "user🆔1", new[] {"green"});

Relate an existing member of a redis set to a tag

Relate a set member to the blue tag:

context.Cache.AddTagsToSetMember("users:set", "user🆔1", new[] { "blue" });

The same method can be used to relate tags to Sorted Set members and GeoSpatial index members.

Remove a tag from a key

Remove the relation between the key and the tag green:

context.Cache.RemoveTagsFromKey("user:1", new [] { "green" });

Remove a tag from a hash field

Remove the relation between the hash field and the tag green:

context.Cache.RemoveTagsFromHashField("users:hash", "user🆔1", new [] { "green" });

Remove a tag from a redis set

Remove the relation between a set member and the tag green:

context.Cache.RemoveTagsFromSetMember("users:set", "user🆔1", new[] { "green" });

The same method can be used to remove tags from Sorted Set members and GeoSpatial index members.

Get objects by tag

Get all the objects related to red and/or green:

IEnumerable<User> users = context.Cache.GetObjectsByTag<User>("red", "green");

This assumes all the keys related to the tags are of the same type.

Determine if member is tagged

Determines whether a redis string key is included on a given tag:

bool x = context.Cache.IsStringKeyInTag("key", "blue");

Determines whether a redis hash field is included on a given tag:

bool x = context.Cache.IsHashFieldInTag("users:hash", "user🆔1", "blue");

Determines whether a redis set member is included on a given tag:

bool x = context.Cache.IsSetMemberInTag("users:set", user, "red");

Invalidate keys by tags

Remove all the keys, hash fields, set members and sorted set members related to blue and/or green tags:

context.Cache.InvalidateKeysByTag("blue", "green");

Get members in tag

Get all the members (keys, hash fields and set members) related to a particular tag:

IEnumerable<TagMember> members = context.Cache.GetMembersByTag("blue");
foreach (TagMember member in members)
{
    var key = member.Key;
    var type = member.MemberType;
    var user = member.GetMemberAs<User>();
}

TagMember contains the Redis Key on its Key property and the member type on MemberType property. If the member type is not a redis string, you can get the member value pointed by the tag by calling the GetMemberAs<T> method.

The MemberType is one of StringKey, HashField, SetMember or SortedSetMember.

Get keys by tag

Get all the keys, hash fields and set members related to the given tags:

ISet<string> keys = context.Cache.GetKeysByTag(new [] { "green" });

If the tag is related to a hash field, the string returned will be in the form:

{hashKey}:$_->_$:{field}

If the tag is related to a set, sorted set or geospatial index the string returned will be in the form:

{setKey}:$_-S>_$:{member}

For example:

users#️⃣$_->_$:user:id:1 means the field user🆔1 of hash users:hash.

users:set:$_-S>_$:user:id:2 means the member user🆔2 of set users:set.


Pub/Sub API

A strongly typed Publish/Subscribe mechanism is provided.

Subscribe to a channel

Listen for messages of type User on the channel users:

context.PubSub.Subscribe<User>("users", user => Console.WriteLine(user.Id));

Publish to a channel

Publishes a messages of type User to the channel users:

context.PubSub.Publish<User>("users", new User() { Id = 1 });

Unsubscribe from a channel

context.PubSub.Unsubscribe("users");

Pattern-matching subscriptions

Redis Pub/Sub supports pattern matching in which clients may subscribe to glob-style patterns to receive all the messages sent to channel names matching a given pattern.

Subscribe using channel pattern

context.PubSub.Subscribe<User>("users.*", user => Console.WriteLine(user.Id));

This will listen to any channel whose name starts with "users.".

Unsubscribe using channel pattern

context.PubSub.Unsubscribe("users.*");

Example - Naïve 4-lines chat application

static void Main()
{
    var context = new RedisContext("10.0.0.1:7000");
    context.PubSub.Subscribe<string>("chat", m => Console.WriteLine(m));
    while (true)
    {
        context.PubSub.Publish("chat", Console.ReadLine());
    }
}

Geospatial API

The Geospatial Redis API consists of a set of commands that add support for storing and querying pairs of longitude/latitude coordinates into Redis keys.

The Geospatial API is available from Redis version >= 3.2.0.

Add a Geospatial item

Add a user to a geospatial index by its coordinates:

string redisKey = "users:geo";
context.GeoSpatial.GeoAdd<User>(redisKey, new GeoCoordinate(20.637, -103.402), user);

Add a Geospatial item related to a tag

Add a user to a geospatial index and relate it to a tag:

string redisKey = "users:geo";
context.GeoSpatial.GeoAdd<User>(redisKey, new GeoCoordinate(20.637, -103.402), user, new[] { "tag" });

Get the coordinates for an item

GeoCoordinate coord = context.GeoSpatial.GeoPosition(redisKey, user);
var lat = coord.Latitude;
var lon = coord.Longitude;

Get the distance between two items

Get the distance in Kilometers between two user items:

double dist = context.GeoSpatial.GeoDistance(redisKey, user1, user2, Unit.Kilometers);

Get the items within the radius of a center location

Get the users within a 100 Km radius:

string redisKey = "users:geo";
var center = new GeoCoordinate(20.553, -102.925);
double radius = 100;
var results = context.GeoSpatial.GeoRadius<User>(redisKey, center, radius, Unit.Kilometers);

The results includes the position and the distance from the center:

foreach (var r in results)
{
    double dist = r.DistanceToCenter;
    GeoCoordinate pos = r.Position;
    User user = r.Value;
    ...
}

Example - Get the distance between two cities

Get the distance (in kilometers) between two addresses by using GoogleMaps.LocationServices:

private Context _context = new RedisContext();
private GoogleLocationService _location = new GoogleLocationService();
        
public double Distance(string address1, string address2)
{
    var redisKey = "dist";
    var loc1 = _location.GetLatLongFromAddress(address1);
    var loc2 = _location.GetLatLongFromAddress(address2);
    _context.GeoSpatial.GeoAdd(redisKey, new[]
    {
      new GeoMember<string>(loc1.Latitude, loc1.Longitude, address1),
      new GeoMember<string>(loc2.Latitude, loc2.Longitude, address2)
    });
    return _context.GeoSpatial.GeoDistance(redisKey, address1, address2, Unit.Kilometers);
}

For example:

double km = Distance("London", "Buenos Aires");

HyperLogLog API

The Redis HyperLogLog implementation provides a very good approximation of the cardinality of a set using a very small amount of memory.

Add elements

To add elements to the HLL, use the HyperLogLogAdd method:

bool result = context.Cache.HyperLogLogAdd<string>("key", "10.0.0.1");

The method returns True if the underlying HLL count was modified.

To get the cardinality (the count of unique elements) use the HyperLogLogCount method:

long count = context.Cache.HyperLogLogCount("key");

Example - Count unique logins per day

Considering a unique login as the Username + IP address combination.

Each time a user login, add the element to the HLL with the HyperLogLogAdd method:

public void OnLogin(string userName, string ipAddress)
{
    var info = new LoginInfo(userName, ipAddress);
    var key = "logins:" + DateTime.Now.ToString("yyyyMMdd");
    context.Cache.HyperLogLogAdd(key, info);
}

To get the unique login count for a specific date, use the HyperLogLogCount method:

public long GetLoginCount(DateTime date)
{
    var key = "logins:" + date.ToString("yyyyMMdd");
    return context.Cache.HyperLogLogCount(key);
}

Keyspace Notifications API

Subscribe to keyspace events to receive events affecting the Redis data. See the Redis notification documentation.

Server configuration

By default keyspace events notifications are disabled. To enable notifications use the notify-keyspace-events of redis.conf or via the CONFIG SET, for example:

redis> CONFIG SET notify-keyspace-events KEA

Usage

To access the Keyspace Notifications API, use the Subscribe/Unsubscribe methods on the context's KeyEvents property.

The subscribe method callback in an Action<string, KeyEvent> where the first parameter is the Redis key affected, and the second is the operation performed.

Examples

Receive all the commands affecting a specific key:

context.KeyEvents.Subscribe("user:1", (string key, KeyEvent cmd) =>
{
    if (cmd == KeyEvent.Delete)
    {
        //Key "user:1" was deleted
    }
    Console.WriteLine("command " + cmd);
});

Receive a specific command affecting any key:

context.KeyEvents.Subscribe(KeyEvent.PushLeft, (key, cmd) =>
{
    Console.WriteLine("key {0} received an LPUSH", key);
});

Receive any command affecting any key:

context.KeyEvents.Subscribe(KeyEventSubscriptionType.All, (key, cmd) =>
{
    Console.WriteLine("key {0} - command {1}", key, cmd);
});

Stop receiving all commands affecting the given key:

context.KeyEvents.Unsubscribe("user:1");

Stop receiving LPUSH commands affecting any key:

context.KeyEvents.Unsubscribe(KeyEvent.PushLeft);

Why some Redis commands are not implemented?

Some Redis commands were omitted by design falling into these two categories:

  • Commands that operates on multiple keys are not included because they are incompatible with a cluster topology. (i.e. MGET, SINTER, SUNION)

  • Commands that assumes a format on the Redis value were omitted because the library doesn't make assumptions on the serialization method. (i.e. INCRBY, APPEND.) (Except for the collections RedisBitmap, RedisLexicographicSet and RedisString)

You can still call these commands via StackExchange.Redis API, accesing the ConnectionMultiplexer by calling the GetConnectionMultiplexer() method on the RedisContext (see next section).


StackExchange.Redis API

To use the StackExchange.Redis API, call the GetConnectionMultiplexer() method on the RedisContext.

For example:

var context = new RedisContext();
var multiplexer = context.GetConnectionMultiplexer();	// SE.Redis Connection Multiplexer
multiplexer.GetDatabase().StringIncrement("key", 1);    // SE.Redis API

.NET Collections

You can handle Redis Lists as IList<T>, Hashes as IDictionary<K, V>, Sets, Lex Sets and Bitmaps as ICollection<T>, and more.

Access these objects by the Collections property on RedisContext.

For example:

var hash = context.Collections.GetRedisDictionary<int, User>("users:hash");
hash.Add(1, new User() { Id = 1 }, new [] { "tag" });

For details please see COLLECTIONS.md documentation file

Contribute

If you like this project please contribute in any of the following ways:

Share this package on Facebook Tweet this package

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].