Document

.netcore入门18:aspnetcore分布式缓存(分布式内存、sqlserver、redis)

环境:

aspnetcore 3.1.1
vs2019 16.4.5
.netcore的本地缓存请参考:.net core中使用缓存之MemoryCache(本机内存)

一、分布式缓存介绍
分布式的缓存由多个应用程序服务器共享,缓存中的信息不存储在单独的 Web 服务器的内存中,并且缓存的数据可用于所有应用服务器。这具有几个优点:

所有 Web 服务器上的缓存数据都是一致的。
缓存的数据在 Web 服务器重新启动后和部署后仍然存在。
对数据库的请求变的更少 。
aspnetcore框架定义了分布式缓存的接口IDistributedCache,我们在自己的代码中应该与这个接口做交互,同样,aspnetcore平台上的所有分布式缓存实现也应该实现这个接口。我们来看下这个接口定义的方法:

Get,GetAsync :
接受字符串键,并检索缓存项作为 byte[] 数组(如果在缓存中找到)。
Set,SetAsync:
使用字符串键将项(作为 byte[] 数组)添加到缓存中。
Refresh,RefreshAsync :
基于其键刷新缓存中的项,并重置其可调过期超时值(如果有)。
Remove,RemoveAsync:
会根据其字符串键删除缓存项。
aspnetcore已经内置了分布式内存缓存,并以nuget包形式提供了分布式 SQL Server 缓存和分布式 Redis 缓存的实现,下面具体看一下:

二、分布式内存缓存:
aspnetcore提供的这个缓存实现是为了开发测试用的,其实它并没有实现真正的分布式。你观察它的源码后会发现,它内部调用的还是IMemoryCache。下面看一下它的使用方式:

2.1 第一步:向容器注册服务
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
}

2.2 第二步:Controller中调用
namespace _2webapidemo.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
private readonly ILogger<WeatherForecastController> _logger;
private readonly IDistributedCache distributedCache;
public WeatherForecastController(ILogger<WeatherForecastController> logger,/* IMemoryCache cache, */IDistributedCache distributedCache)
{
_logger = logger;
this.distributedCache = distributedCache;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
#region 测试分布式内存缓存
var key = Guid.NewGuid().ToString();
var message = "Hello, World!";
var value = Encoding.UTF8.GetBytes(message);
Console.WriteLine("Connecting to cache");
Console.WriteLine("Connected");
Console.WriteLine("Cache item key: {0}", key);
Console.WriteLine($"Setting value '{message}' in cache");
await distributedCache.SetAsync(key,value,new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(10)));
Console.WriteLine("Set");
Console.WriteLine("Getting value from cache");
value = await distributedCache.GetAsync(key);
if (value != null)
{
Console.WriteLine("Retrieved: " + Encoding.UTF8.GetString(value, 0, value.Length));
}
else
{
Console.WriteLine("Not Found");
}
Console.WriteLine("Refreshing value in cache");
await distributedCache.RefreshAsync(key);
Console.WriteLine("Refreshed");
Console.WriteLine("Removing value from cache");
await distributedCache.RemoveAsync(key);
Console.WriteLine("Removed");
Console.WriteLine("Getting value from cache again");
value = await distributedCache.GetAsync(key);
if (value != null)
{
Console.WriteLine("Retrieved: " + Encoding.UTF8.GetString(value, 0, value.Length));
}
else
{
Console.WriteLine("Not Found");
}
#endregion

var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}

上面代码的控制台输出如下图:


三、分布式SqlServer缓存
aspnetcore框架提供的这个实现可以让我们很方便的把sqlserver当成一个缓存容器,它的源码也很简单,就是对一张缓存表的增删改查。我们看一下它的源码文件:

有兴趣的可以点开看看里面的内容,里面操作数据库没有依赖EFCore,而是直接使用的SqlConnection、SqlCommand等这些原始对象。下面来看一下它的使用步骤:

3.1 第一步:准备sqlserver数据库
你可以手动建表或者是使用dotnet sql-cache工具自动建表,两种方法任选其一,但是要注意三个名称“数据库名称”、“模式名称”和“表名称”,因为这三个名称要在代码中进行配置。下面以数据库test的dbo下的表global_cache为例说明两种方案:

3.1.1 方案1:手动建表
直接执行下面脚本即可:

--****************<global_cache>**************
if exists (select 1
from sysobjects
where id = object_id('global_cache')
and type = 'U')
begin
drop table global_cache
print '已删除表:global_cache'
end
go
create table [global_cache] (
[Id] nvarchar(449) not null unique,
[Value] varbinary(max) not null ,
[ExpiresAtTime] datetimeoffset(7) not null ,
[SlidingExpirationInSeconds] bigint ,
[AbsoluteExpiration] datetimeoffset(7)
)
ALTER TABLE [global_cache] ADD CONSTRAINT PK_gene_global_cache_Id PRIMARY KEY(Id)
--************索引<Index_ExpiresAtTime>*****************
CREATE NONCLUSTERED INDEX Index_ExpiresAtTime ON global_cache(ExpiresAtTime)
--************索引</Index_ExpiresAtTime>*****************
print '已创建:global_cache'
--****************</global_cache>**************

3.1.2 方案2:使用dotnet sql-cache工具:
这种方法是微软官方提供的(参考:分布式 SQL Server 缓存)

1)、首先,你要确保你电脑中安装了sql-cache工具,如果没有的话,在cmd中执行如下命令安装:

dotnet tool install --global dotnet-sql-cache --version 3.1.1
1
注意,sql-cache的版本要和.netcore的版本保持一致,否则,建议卸载重装,卸载的命令如下:

dotnet tool uninstall dotnet-sql-cache --global
1
2)、然后, 执行如下命令建表

dotnet sql-cache create "Data Source=.;Initial Catalog=test;User ID=sa;Password=xxxxxx;" dbo global_cache
1
执行完后提示:“Table and index were created successfully.” 则表示建表成功!

3.3 第二步:引入nuget包
虽然微软默认提供了分布式SqlServer缓存的实现,但并没有集成到aspnetcore框架中,所以我们需要将nuget包引入进来:


3.2 第二步:向容器注册服务
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedSqlServerCache(options=>
{
options.ConnectionString = "Data Source=.;Initial Catalog=test;User ID=sa;Password=sa;";
options.SchemaName = "dbo";
options.TableName = "global_cache";
});
services.AddControllers();
}

3.3 第三步:Controller中调用
同分布式内存。

附:程序运行过程中sqlserver数据库中存储的情况:


四、分布式Redis缓存
redis服务器搭建参考:redis入门(1): linux下安装redis与简单配置。
redis客户端下载地址:
链接:https://pan.baidu.com/s/1l2NPkhgVdnEM89vpJIwGfA
提取码:beg4
说明:
aspnetcore中分布式Redis缓存的源码很简单,因为它对redis的操作依赖于StackExchange.Redis,先来看看它的源码文件有哪些:

可以看到源码非常少。我们知道redis中有五大数据类型:string(字符串)、hash(哈希)、list(列表)、set(集合)和zset(sorted set:有序集合),这个分布式缓存实现的时候仅使用了hash(哈希)这一种格式进行存储。下面直接看使用步骤:

4.1 第一步:准备redis服务
假设你已经准备好了redis服务为:
ip:192.168.3.28
port:6379
password:123456

4.2 第二步:引入nuget包
虽然微软默认实现了分布式redis缓存,但是并未将程序集集成在aspnetcore框架里面,所以需要我们手动添加上去:


4.3 第三步:向容器注册服务
public void ConfigureServices(IServiceCollection services)
{
services.AddStackExchangeRedisCache(options =>
{
//options.Configuration = "192.168.3.28:6379";
options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions()
{
EndPoints = { { "192.168.3.28", 6379 } },
Password = "123456"
};
options.InstanceName = "TestRedisCache";
});
services.AddControllers();
}

4.4 第四步:Controller中调用
同分布式内存缓存

附:代码运行过程中redis存储数据截图

从上面的截图中可以看到,存储的时候八absexp和sldexp也存储了进去,也就是一个缓存项被当成一个hash存储了起来。

五、总结
从上面的介绍中可以看到,虽然我们分别使用了Sqlserver、Redis缓存方式但调用代码不用做任何改变,而这正是由于我们调用的是IDistributedCache接口提供的服务。

posted @ 2021-09-25 18:00  从未被超越  阅读(502)  评论(0)    收藏  举报