The previous article has introduced the Memorycache,memorycache storage data type is object, also said Redis support v data type of storage, but Microsoft's Redis cache component only implemented hash type of storage. Before you analyze the source code, learn a few commands about Redis operations.
One, Redis command
All Redis commands are described in detail on the http://doc.redisfans.com/. Here are a few common commands for hash types.
Hset: For adding a cache
Usage: Hset key field value.
return value: Iffieldis a new domain in the hash table, and the value is set successfully, return1.
If the domain in the hash tableFieldalready exists and the old value has been overwritten by the new value, returning0。 For example: Hset user Name microheart hset user age Hmset: for adding multiple
Usage: Hmset key [field value Field1 value1 ...]
Return value: ReturnsOKif the command executes successfully.
WhenKeyis not a hash table (hash) type, an error is returned. Example: Hmset user1 Name microheart age hget: Get field value
Usage: Hget key field
Return value: The value of the given field.
ReturnsNilif the given domain does not exist or if a givenkeydoes not exist
Example: Hget user Name ( Note Redis is case sensitive )
Hmget: Get the values of multiple fields
Usage: Hmget key [Field1,field2]
Return value: A table that contains the associated values for a given field, and the table values are arranged in the same order as the request order for the given domain parameters.
Example: Hmget user Name Age
EXPIRE: Setting the cache Expiration time
Usage: EXPIRE key seconds
Return value: The setting returned successfully to1.
WhenKeyDoes not exist or cannot beKeyWhen you set the time to live (for example, in Redis under 2.1.3, you try to updateKeyTime of Life), return0。 For example: EXPIRE user TTL: Indicates the remaining time to live. 57 means 57 seconds before this cache expires. When it expires, Redis is automatically deleted. In the Redis 2.4 release, the delay in the expiration time is within 1 seconds--that is, even ifKeyhas expired, but it may be accessed within one second of expiration, and in the new Redis 2.6 release, the latency is reduced to 1 milliseconds. Ii. using Redis components in. Net Core
The Redis cache feature is added first in the Startup class. The value of the instancename set in the configured option is used as part of the key. For example, set the InstanceName to test, the code set a cache key is user, the actual key stored in Redis is testuser.
Public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDistributedRedisCache(option =>
{
option.Configuration = "121.41.55.55:6379"; / / connection string
option.InstanceName = "test";
});
}
Then inject the idistributedcache where it is needed. As shown in the following:
Public class ValuesController : Controller
{
Private readonly IDistributedCache redisCache;
Public ValuesController(IDistributedCache redisCache)
{
this.redisCache = redisCache;
}
[HttpGet]
Public IEnumerable<string> Get()
{
redisCache.SetAsync("key1", Encoding.UTF8.GetBytes("value1"), new DistributedCacheEntryOptions()
{
AbsoluteExpiration = DateTime.Now.AddSeconds(10)//Set the expiration time, the time is removed as soon as the cache is removed.
});
redisCache.SetString("key2", "value2");//The cache expiration time is not set, indicating that it is a permanent cache.
Return new string[] { "value1", "value2" };
}
}
Third, source code analysis
Source code in the Github.com/aspnet/caching,redis source is relatively simple, mainly because many are directly using the Stackexchange.redis API.
Rediscacheoptions class: Mainly Redis configuration related.
Configuration: Set up Redis configuration, such as connection string, time-out, etc., and eventually be replaced with Configurationoptions in Stackexchange.redis
InstanceName: Instance name. And the key set in the code is joined to the key in Redis.
Rediscacheservicecollectionextensions class: Associated with service injection.
For a method Adddistributedrediscache, rely on an instance of injected Idistributedcache.
public static IServiceCollection AddDistributedRedisCache(this IServiceCollection services, Action<RedisCacheOptions> setupAction)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (setupAction == null)
{
throw new ArgumentNullException(nameof(setupAction));
}
services.AddOptions();
services.Configure(setupAction);
services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCache>());//注入一个单例
return services;
}
Rediscache class: The most important class, the cache operation-related class.
The method of inserting and retrieving data is more important.
3.1 The Set method, insert the data.
Public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
{
/ / Omit some logic judgment
Connect();
Var creationTime = DateTimeOffset.UtcNow;
/ / For a cache can be set to the absolute expiration time, relative to the current time expiration time and sliding expiration time (in the previous article has an example), in fact, the first two types of time can be converted to each other.
//The following step is if the absolute expiration time is set or the expiration time relative to the current time is set, the replacement is the absolute expiration time.
Var absoluteExpiration = GetAbsoluteExpiration(creationTime, options);
/ / Called the StackExchange.Redis API insert cache
Var result = _cache.ScriptEvaluate(SetScript, new RedisKey[] { _instance + key }, / / The key here is the key in the instance name +key=Redis. Of course, when we look up the cache, we don't need to manually stitch it. Just pass the key we copied, no need for instance name
New redisValue[]
{
absoluteExpiration?.Ticks ?? NotPresent,
options.SlidingExpiration?.Ticks ?? NotPresent,
// If the absolute expiration time and the sliding expiration time are set for a cache at the same time, the time that is about to expire, that is, the minimum time, is taken.
GetExpirationInSeconds(creationTime, absoluteExpiration, options) ?? NotPresent,
Value
});
}
If both Absexp and sldexp do not have a value set, the default is-1, which means never expires, the cache time is taken from the set absolute expiration and sliding expiration time, and when the time is up, Redis automatically deletes the expired cache, which is not the same as memorycache. Memorycahe is in the cache operation, will scan the entire cache delete, there is a large delay, and Redis uses the following three strategies to clean up expired key:
- Passive deletion: When reading/writing a key that has expired, the lazy delete policy is triggered, and the expired key is deleted directly
- Active deletion: Due to the lazy deletion policy cannot guarantee that cold data is deleted in time, so Redis will periodically proactively eliminate a batch of expired key
- Active cleanup policy is triggered when current memory exceeds maxmemory limit
This ensures that the expiration cache is cleaned up in a timely manner. The strategy for Redis cleanup expired key can be seen in this article.
When inserting a hash type of data, open Redismanager will see the following, Absexp: Absolute Expiration time, sldexp: Sliding expiration Time, data: is the value set in our code.
In the 3.2 get method, the implementation of the main fetch function calls the following code.
In the above add cache, script insert is used.
Private const string SetScript = (@"
Redis.call('HMSET', KEYS[1], 'absexp', ARGV[1], 'sldexp', ARGV[2], 'data', ARGV[4])//Set key, absolute expiration time, sliding Expiration time, and value of value
If ARGV[3] ~= '-1' then
Redis.call('EXPIRE', KEYS[1], ARGV[3])//Set the cache time
End
Return 1");
The Remove method calls the Stackexchange API directly, which is not explained here.
Compared to MemoryCache code, the Redis code is relatively simple, mainly Microsoft developers "Jerry-building" (I feel), many important methods, such as Redis connection, add, set the expiration time, have called the Stackexchange API, Did not implement its own link pool and so on. More like a re-encapsulation of the hash type in STACKEXCHANGEAPI.