Foreword
Slightly more complex Internet projects, technology selection may involve Redis, .NetCore ecological more perfect, more and more .NetCore support of Redis client,
The following three common Redis client, I believe we usually use some more or less, usually combined with the use of three clients, some feelings and experiences.
To more macro background:
Package Name | background | github star | Dependence on .NetStandard2.0 target frame |
Stackexchange.redis | Veteran .Net Redis client, free, unlimited, Stackoverflow endorsement | 3700 |
|
Microsoft.Extensions.Caching.StackExchangeRedis | .Netcore 2.2 for IDistributedCache Redis interface distributed cache |
|
|
CSRedisCore | Famous people achieve third-party clients, redis.io official website recommended | 894 |
|
Reviews
Three support Redis client connection string substantially the same configuration
"connectionstrings": { "redis": "localhost:6379,password=abcdef,connectTimeout=5000,writeBuffer=40960" }
StackExchange.Redis
Positioning high-performance, general-purpose Redis .Net client ; conveniently used Redis fully functional; Redis support the Cluster
- High-performance core in that the multiplexer (Redis supports efficient sharing of the plurality of connecting the calling thread)
Redis = ConnectionMultiplexer.Connect ConnectionMultiplexer ( " server1: 6379, server2: 6379 " ); // core library is the daily application of the IDatabase the IDatabase db = redis.GetDatabase (); // support Pub / Sub the ISubscriber Sub = redis.GetSubscriber ( ); sub.Subscribe ( " messages " , (Channel, Message) => { Console.WriteLine (( String ) Message); }); --- sub.Publish ( " messages " , " Hello " );
It is also because multiplexing, StackExchange.Redis unique characteristics Redis is not supported by "blocking POPs" , this feature is of critical theory RedisMQ.If you need blocking pops, StackExchange.Redis official recommended pub / sub model simulation to achieve.
- Please pay attention to the daily operation of the API IDatabase interface, support for asynchronous method, here I am [ the client operating Redis try not to use asynchronous methods do not agree with the argument], I think for the asynchronous method or comply with Microsoft best practices: For IO intensive operations , you can use asynchronous try to use asynchronous
_redisDB0.StringDecrementAsync ( " ProfileUsageCap " , ( Double ) . 1 ) // corresponding to the self-energizing redis API: DECR MyKey _redisDB0.HashGetAsync (profileUsage, eqidPair.ProfileId)) // corresponding to API redis: Key hget field1 _redisDB0.HashDecrementAsync (profileUsage, eqidPair .ProfileId, . 1 ) // corresponding to the hash redis increment api: HINCRBY myhash field -1
- ConnectionMultiplexer way to support the switch at any time Redis DB, for the operation of multiple Redis DB, I encapsulates a common Redis DB operation client.
public class RedisStore { private static Lazy<ConnectionMultiplexer> LazyConnection; private static string connectionRedis = "localhost:6379"; public RedisStore(string connectiontring) { connectionRedis = connectiontring ?? "localhost:6379"; LazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionRedis)); } public static ConnectionMultiplexer Connection => LazyConnection.Value; public RedisDatabase RedisCache => new RedisDatabase(Connection); } public class RedisDatabase { private Dictionary<int, IDatabase> DataBases = new Dictionary<int, IDatabase>(); public ConnectionMultiplexer RedisConnection { get; } public RedisDatabase(ConnectionMultiplexer Connection) { DataBases = new Dictionary<int, IDatabase>{ }; for(var i=0;i<16;i++) { DataBases.Add(i, Connection.GetDatabase(i)); } RedisConnection = Connection; } public IDatabase this[int index] { get { if (DataBases.ContainsKey(index)) return DataBases[index]; else return DataBases[0]; } } }
Microsoft.Extensions.Caching.StackExchangeRedis
It is seen from nuget doc, which depends on the component library StackExchange.Redis client; .NetCore client is provided for the distributed cache, the focus characteristic of Redis cache .
// add Redis cache service services.AddStackExchangeRedisCache(options => { options.Configuration = Configuration.GetConnectionString("redis"); options.InstanceName = "SampleInstance"; }); // Set Cache Item (by byte[]) lifetime.ApplicationStarted.Register(() => { var currentTimeUTC = DateTime.UtcNow.ToString(); byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC); var options = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromMinutes(20)); cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options); }); // Retrieve Cache Item [HttpGet] [Route("CacheRedis")] public async Task<string> GetAsync() { var ret = ""; var bytes = await _cache.GetAsync("cachedTimeUTC"); if (bytes! = null ) { right = Encoding.UTF8.GetString (bytes); _logger.LogInformation (right); } Return await Task.FromResult (right); }
① Clearly, the Cache component and can not do are free to switch Redis DB, currently available in the connection string redis -time configuration items which you want to use Redis DB
① generates key = SampleInstancecachedTimeUTC specified items in the cache redis DB (default 0)
② Redis does not support bytes [] in the form of stored value, more than byte [] Hash is actually stored in the form
CSRedisCore
var redisDB = new CSRedisClient[16]; // 多客户端 ......
services.AddSingleton(redisDB);
// ---------------------------- _redisDB[0].IncrByAsync("ProfileUsageCap", -1) _redisDB[0].HGetAsync(profileUsage, eqidPair.ProfileId.ToString()) _redisDB[0].HIncrByAsync(profileUsage, eqidPair.ProfileId.ToString(), -1);
Built-in static operation class RedisHelper, and Redis-Cli command exactly the same, so he can natively "blocking pops".
// achieve back-office services, sustainable consumption MQ message public class BackgroundJob: BackgroundService { Private Readonly CSRedisClient [] _redisDB; Private Readonly IConfiguration _conf; Private Readonly ILogger _logger; public BackgroundJob (CSRedisClient [] csRedisClients, IConfiguration conf, ILoggerFactory LoggerFactory) { _redisDB = csRedisClients; _conf = the conf; _logger = loggerFactory.CreateLogger (NameOf (BackgroundJob)); } // Background 需要实现的后台任务 protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _redisDB[0] = new CSRedisClient(_conf.GetConnectionString("redis") + ",defualtDatabase=" + 0); RedisHelper.Initialization(_redisDB[0]); while (!stoppingToken.IsCancellationRequested) { var key = $"eqidpair:{DateTime.Now.ToString("yyyyMMdd")}" ; // Blocking read from the first message right List var eqidpair RedisHelper.BRPop = ( . 5 , Key); // the TODO the Message Handler the else the await Task.Delay ( 1000 , stoppingToken); } } } ----- RedisMQ producer --- // one or more msg header inserted List RedisHelper.LPush (redisKey, eqidPairs.ToArray ()) ;
Redis little experience:
- Logarithmic time complexity Redis API's own heart must be used, try not to use long-running commands such as keys *, which can be observed by redis.io SlowLog command command takes a long time
- Redis Key in accordance with ":" string has separated defined business significance, such as NewUsers: 201909: 666666 (Redis UI may be some friendly and intuitive view of the service)
- Suitable Key-Value determined size: Redis more friendly for small value, if the value is large, taking into multiple key
- About cache penetration, the interview will ask themselves searching Bloom filter.
- Although there are redis persistence mechanism, but in practice it will be key-value persisted to a relational database, because for some structured query, SQL more efficient.