目錄html
緩存是分佈式系統中的重要組件,主要解決高併發,大數據場景下,熱點數據訪問的性能問題。提供高性能的數據快速訪問。git
CDN
:存放HTML、CSS、JS等靜態資源;反向代理
:動靜分離,只緩存用戶請求的靜態資源;分佈式緩存
:緩存數據庫中的熱點數據;本地緩存
:緩存應用字典等經常使用數據。必定不存在的key,採用布隆過濾器,創建一個大的Bitmap中,查詢時經過該bitmap過濾。github
布隆過濾器(Bloom Filter)是1970年由布隆提出的。它其實是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器能夠用於檢索一> 個元素是否在一個集合中。它的優勢是空間效率和查詢時間都遠遠超過通常的算法,缺點是有必定的誤識別率和刪除困難
若是想要判斷一個元素是否是在一個集合裏,通常想到的是將全部元素保存起來,而後經過比較肯定。鏈表,樹等等數據結構都是這種思路. > 可是隨着集合中元素的增長,咱們須要的存儲空間愈來愈大,檢索速度也愈來愈慢(O(n),O(logn))。不過世界上還有一種叫做散列表(又叫哈> 希表,Hash table)的數據結構。它能夠經過一個Hash函數將一個元素映射成一個位陣列(Bit array)中的一個點。這樣一來,咱們只要看看這個點是否是1就能夠知道集合中有沒有它了。這就是布隆過濾器的基本思想。redis
數據不一致的幾種狀況:算法
目前比較經常使用的數據緩存策略的是Cache Aside Pattern,更新緩存是先把數據存到數據庫中,成功後,再讓緩存失效。
這種策略下不一致產生的緣由只有更新數據庫成功,可是刪除緩存失敗。
解決方案:shell
ASP.NET Core 支持多種不一樣的緩存。包括內存緩存,分佈式緩存(Redis 和 SQL Server)。Github 開源地址 Libraries for in-memory caching and distributed caching.數據庫
IMemoryCache是把數據存儲在Web服務器的內存中。api
在 ConfigureServices 中調用 AddMemoryCache 經過依賴關係注入引用服務。緩存
public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
在控制器類中用構造器注入的方式建立 IMemoryCache 的對象。服務器
using Microsoft.Extensions.Caching.Memory; public class ValuesController : ControllerBase { private IMemoryCache _cache; public ValuesController(IMemoryCache cache) { _cache = cache; } }
建立緩存
Set()
DateTime cacheEntry1 = DateTime.Now; var cacheEntryOptions = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(3)); _cache.Set("cache1", cacheEntry1, cacheEntryOptions);
GetOrCreate()
GetOrCreateAsync
var cacheEntry = _cache.GetOrCreate("cache1", entry => { entry.SetAbsoluteExpiration(TimeSpan.FromSeconds(3)); return DateTime.Now; });
獲取緩存
Get()
var cacheEntry = this._cache.Get<DateTime?>("cache1");
TryGetValue()
DateTime cacheEntry; if (!_cache.TryGetValue("cache1", out cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now; var cacheEntryOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromSeconds(3)); _cache.Set("cache1", cacheEntry, cacheEntryOptions); }
刪除緩存
Remove()
_cache.Remove("cache1");
其餘知識點
ICacheEntry成員:Key
緩存keyValue
緩存值AbsoluteExpiration
絕對過時時間,爲null則條件無效AbsoluteExpirationRelativeToNow
相對當前時間的絕對過時時間(使用TimeSpan),爲null條件無效SlidingExpiration
滑動過時時間ExpirationTokens
提供用來自定義緩存過時PostEvictionCallbacks
緩存失效回調Priority
緩存項優先級(在緩存滿載的時候絕對清除的順序)Size
表明緩存數據的大小,在內存緩存中通常爲nullConfigureServices 方法裏面添加服務 AddDistributedRedisCache
public void ConfigureServices(IServiceCollection services) { services.AddDistributedRedisCache(options => { options.Configuration = "localhost"; options.InstanceName = "Instance1"; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
Get
,GetAsync
採用字符串鍵並以byte[]形式檢索緩存項(若是在緩存中找到)Set
,SetAsync
使用字符串鍵向緩存添加項byte[]形式Refresh
,RefreshAsync
根據鍵刷新緩存中的項,並重置其可調過時超時值(若是有)Remove
,RemoveAsync
根據鍵刪除緩存項var now = DateTime.Now; var cacheValue = System.Text.Encoding.UTF8.GetBytes(now.ToString()); var options = new DistributedCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(3)); _cache.Set("cache1", cacheValue, options); _cache.Refresh("cache1"); var value = _cache.Get("cache1"); var nowString = System.Text.Encoding.UTF8.GetString(value); _cache.Remove("cache1");
因爲自帶的 RedisCache 繼承 IDistributedCache 接口並無提供 Redis的一些高級特性好比Hash, List, Set等。
基於Stackexchange.Redis封裝一個簡單RedisHelper類:
RedisHelper 類
public class RedisHelper { private readonly RedisOptions _options; private readonly Lazy<ConnectionMultiplexer> _connectionMultiplexer; public RedisHelper(IOptions<RedisOptions> optionsAccessor) { if (optionsAccessor == null) { throw new ArgumentNullException(nameof(optionsAccessor)); } _options = optionsAccessor.Value; _connectionMultiplexer = new Lazy<ConnectionMultiplexer>(CreateConnectionMultiplexer); } public IDatabase GetDatabase() { return _connectionMultiplexer.Value.GetDatabase(); } private ConnectionMultiplexer CreateConnectionMultiplexer() { if (_options.ConfigurationOptions != null) { return ConnectionMultiplexer.Connect(_options.ConfigurationOptions); } else { return ConnectionMultiplexer.Connect(_options.Configuration); } } }
RedisOptions 配置類
public class RedisOptions : IOptions<RedisOptions> { /// <summary> /// The configuration used to connect to Redis. /// </summary> public string Configuration { get; set; } /// <summary> /// The configuration used to connect to Redis. /// This is preferred over Configuration. /// </summary> public ConfigurationOptions ConfigurationOptions { get; set; } /// <summary> /// The Redis instance name. /// </summary> public string InstanceName { get; set; } RedisOptions IOptions<RedisOptions>.Value { get { return this; } } }
RedisHelperServiceCollectionExtensions 擴展類
public static class RedisHelperServiceCollectionExtensions { public static IServiceCollection AddRedisHelper(this IServiceCollection services, Action<RedisOptions> setupAction) { if (services == null) { throw new ArgumentNullException(nameof(services)); } if (setupAction == null) { throw new ArgumentNullException(nameof(setupAction)); } services.AddOptions(); services.Configure(setupAction); services.AddSingleton<RedisHelper>(); return services; } }
在 ConfigureServices 裏面添加服務引用
public void ConfigureServices(IServiceCollection services) { var redisOptions = Configuration.GetSection("RedisOptions").Get<RedisOptions>(); services.AddRedisHelper(options => { options.Configuration = redisOptions.Configuration; options.InstanceName = redisOptions.InstanceName; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
在 Controller 裏面使用
public class ValuesController : ControllerBase { private readonly RedisHelper _redisHelper; public ValuesController(RedisHelper redisHelper) { _redisHelper = redisHelper; } // GET api/values [HttpGet] public ActionResult<IEnumerable<string>> Get() { _redisHelper.GetDatabase().StringSet("test_key_2", "test_value_2", TimeSpan.FromSeconds(60)); return new string[] { "value1", "value2" }; } }
網上一些開源的Redis擴展: