就目前的大环境来讲,说到缓存,可能大部分小伙伴第一反应就会是redis。不少人每每忽视了进程内缓存这一利器。git
分布式缓存和进程内缓存的优点和劣势不用多说,你们都略知一二。github
我我的仍是更倾向于将基础数据,这些变更少的东西,丢到进程内缓存而不是放到redis中,而后定时去更新。redis
碰到的一些业务情景对这些基础数据的实时要求并不会过高,能够容忍20〜30分钟的延迟,即容许这一小段时间内的脏读,而不影响系统的总体结果。针对不一样的业务,就要视状况而定了。数据库
目前的作法是基于.NET Core的HostedService
,在程序启动的时候先把数据加载到缓存中,同时有个定时器,每隔一个时间刷新一次。api
首先是刷新缓存的后台任务缓存
public class RefreshCachingBgTask : IHostedService, IDisposable { private readonly ILogger _logger; private readonly IEasyCachingProviderFactory _providerFactory; private Timer _timer; private bool _refreshing; public RefreshCachingBgTask(ILoggerFactory loggerFactory, IEasyCachingProviderFactory providerFactory) { this._logger = loggerFactory.CreateLogger<RefreshCachingBgTask>(); this._providerFactory = providerFactory; } public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation($"Refresh caching backgroud taks begin ..."); _timer = new Timer(async x => { if (_refreshing) { _logger.LogInformation($"Latest manipulation is still working ..."); return; } _refreshing = true; await RefreshAsync(); _refreshing = false; }, null, TimeSpan.Zero, TimeSpan.FromSeconds(20)); return Task.CompletedTask; } private async Task RefreshAsync() { _logger.LogInformation($"Refresh caching begin at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); try { var cachingProvider = _providerFactory.GetCachingProvider("m1"); // mock query data from database or others var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var random = new Random().NextDouble(); // only once var dict = new Dictionary<string, string>() { { ConstValue.Time_Cache_Key, time }, { ConstValue.Random_Cache_Key, random.ToString() } }; await cachingProvider.SetAllAsync(dict, TimeSpan.FromDays(30)); //// one by one //await cachingProvider.SetAsync(Time_Cache_Key, time, TimeSpan.FromSeconds(10)); //await cachingProvider.SetAsync(Random_Cache_Key, random.ToString(), TimeSpan.FromSeconds(10)); } catch (Exception ex) { _logger.LogError(ex, $"Refresh caching error ..."); } _logger.LogInformation($"Refresh caching end at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); } public Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation($"Refresh caching backgroud taks end ..."); _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }
注: 由于是演示,全部这里设置的时间比较短,正常来讲,这里是要设置一个超长的缓存时间,以便在获取这个缓存的时候,永远能取到值。dom
在Startup
中注册EasyCaching和刷新缓存的后台任务async
public void ConfigureServices(IServiceCollection services) { services.AddEasyCaching(options=> { options.UseInMemory("m1"); }); // register backgroud task services.AddHostedService<RefreshCachingBgTask>(); // others .. }
而后是控制器中的使用分布式
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly IEasyCachingProviderFactory _providerFactory; public ValuesController(IEasyCachingProviderFactory providerFactory) { this._providerFactory = providerFactory; } // GET api/values [HttpGet] public ActionResult<IEnumerable<string>> Get() { var provider = _providerFactory.GetCachingProvider("m1"); var time = provider.Get<string>(ConstValue.Time_Cache_Key); // do something based on time ... var random = provider.Get<string>(ConstValue.Random_Cache_Key); // do something based on random ... return new string[] { time.Value, random.Value }; } }
效果大体以下:ide
固然,可能有人会提出问题,若是在程序启动的时候,缓存没能正确的写入,好比从数据库读数据的时候引起了异常,或者其余缘由致使没能写进去。
这里也给出下面几个解决方案:
文中示例代码: