就目前的大環境來講,說到緩存,可能大部分小夥伴第一反應就會是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
固然,可能有人會提出問題,若是在程序啓動的時候,緩存沒能正確的寫入,好比從數據庫讀數據的時候引起了異常,或者其餘緣由致使沒能寫進去。
這裏也給出下面幾個解決方案:
文中示例代碼: