日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一篇短文带您了解一下EasyCaching

發布時間:2023/12/4 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一篇短文带您了解一下EasyCaching 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

從2017年11月11號在Github創建EasyCaching這個倉庫,到現在也已經將近一年半的時間了,基本都是在下班之后和假期在完善這個項目。

由于EasyCaching目前只有英文的文檔托管在Read the Docs上面,當初選的MkDocs現在還不支持多語言,所以這個中文的要等它支持之后才會有計劃。

之前在群里有看到過有人說沒找到EasyCaching的相關介紹,這也是為什么要寫這篇博客的原因。

下面就先簡單介紹一下EasyCaching。

什么是EasyCaching

EasyCaching,這個名字就很大程度上解釋了它是做什么的,easy和caching放在一起,其最終的目的就是為了讓我們大家在操作緩存的時候更加的方便。

它的發展大概經歷了這幾個比較重要的時間節點:

  • 18年3月,在茶叔的幫助下進入了NCC

  • 19年1月,鎮汐大大提了很多改進意見

  • 19年3月,NopCommerce引入EasyCaching (可以看這個?commit記錄)

  • 19年4月,列入awesome-dotnet-core(自己提pr過去的,有點小自戀。。)

  • 在EasyCaching出來之前,大部分人應該會對CacheManager比較熟悉,因為兩者的定位和功能都差不多,所以偶爾會聽到有朋友拿這兩個去對比。

    為了大家可以更好的進行對比,下面就重點介紹EasyCaching現有的功能了。

    EasyCaching的主要功能

    EasyCaching主要提供了下面的幾個功能

  • 統一的抽象緩存接口

  • 多種常用的緩存Provider(InMemory,Redis,Memcached,SQLite)

  • 為分布式緩存的數據序列化提供了多種選擇

  • 二級緩存

  • 緩存的AOP操作(able, put,evict)

  • 多實例支持

  • 支持Diagnostics

  • Redis的特殊Provider

  • 當然除了這8個還有一些比較小的就不在這里列出來說明了。

    下面就分別來介紹一下上面的這8個功能。

    統一的抽象緩存接口

    緩存,本身也可以算作是一個數據源,也是包含了一堆CURD的操作,所以會有一個統一的抽象接口。面向接口編程,雖然EasyCaching提供了一些簡單的實現,不一定能滿足您的需要,但是呢,只要你愿意,完全可以一言不合就實現自己的provider。

    對于緩存操作,目前提供了下面幾個,基本都會有同步和異步的操作。

    • TrySet/TrySetAsync

    • Set/SetAsync

    • SetAll/SetAllAsync

    • Get/GetAsync(with data retriever)

    • Get/GetAsync(without data retriever)

    • GetByPrefix/GetByPrefixAsync

    • GetAll/GetAllAsync

    • Remove/RemoveAsync

    • RemoveByPrefix/RemoveByPrefixAsync

    • RemoveAll/RemoveAllAsync

    • Flush/FlushAsync

    • GetCount

    • GetExpiration/GetExpirationAsync

    • Refresh/RefreshAsync(這個后面會被廢棄,直接用set就可以了)

    從名字的定義,應該就可以知道它們做了什么,這里就不繼續展開了。

    多種常用的緩存Provider

    我們會把這些provider分為兩大類,一類是本地緩存,一類是分布式緩存。

    目前的實現有下面五個

    • 本地緩存,InMemory,SQLite

    • 分布式緩存,StackExchange.Redis,csredis,EnyimMemcachedCore

    它們的用法都是十分簡單的。下面以InMemory這個Provider為例來說明。

    首先是通過nuget安裝對應的包。

    dotnet add package EasyCaching.InMemory

    其次是添加配置

    public void ConfigureServices(IServiceCollection services)
    {

    services.AddEasyCaching(option =>
    {

    option.UseInMemory("default");
    });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {

    app.UseEasyCaching();
    }

    配置文件的示例

    "easycaching": {
    "inmemory": {
    "MaxRdSecond": 120,
    "EnableLogging": false,
    "LockMs": 5000,
    "SleepMs": 300,
    "DBConfig":{
    "SizeLimit": 10000,
    "ExpirationScanFrequency": 60
    }
    }
    }

    關于配置,這里有必要說明一點,那就是MaxRdSecond的值,因為這個把老貓子大哥坑了一次,所以要拎出來特別說一下,這個值的作用是預防在同一時刻出現大批量緩存同時失效,為每個key原有的過期時間上面加了一個隨機的秒數,盡可能的分散它們的過期時間,如果您的應用場景不需要這個,可以將其設置為0。

    最后的話就是使用了。

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {

    private readonly IEasyCachingProvider _provider;

    public ValuesController(IEasyCachingProvider provider)
    {
    this._provider = provider;
    }


    [HttpGet]
    [Route("sync")]
    public string Get()
    {
    var res1 = _provider.Get("demo", () => "456", TimeSpan.FromMinutes(1));
    var res2 = _provider.Get<string>("demo");

    _provider.Set("demo", "123", TimeSpan.FromMinutes(1));

    _provider.Remove("demo");


    return "sync";
    }


    [HttpGet]
    [Route("async")]
    public async Task<string> GetAsync(string str)
    {
    var res1 = await _provider.GetAsync("demo", async () => await Task.FromResult("456"), TimeSpan.FromMinutes(1));
    var res2 = await _provider.GetAsync<string>("demo");

    await _provider.SetAsync("demo", "123", TimeSpan.FromMinutes(1));

    await _provider.RemoveAsync("demo");


    return "async";
    }
    }

    還有一個要注意的地方是,如果用的get方法是帶有查詢的,它在沒有命中緩存的情況下去數據庫查詢前,會有一個加鎖操作,避免一個key在同一時刻去查了n次數據庫,這個鎖的生存時間和休眠時間是由配置中的LockMs和SleepMs決定的。

    分布式緩存的序列化選擇

    對于分布式緩存的操作,我們不可避免的會遇到序列化的問題.

    目前這個主要是針對redis和memcached的。當然,對于序列化,都會有一個默認的實現是基于BinaryFormatter,因為這個不依賴于第三方的類庫,如果沒有指定其它的,就會使用這個去進行序列化的操作了。

    除了這個默認的實現,還提供了三種額外的選擇。Newtonsoft.Json,MessagePack和Protobuf。下面以在Redis的provider使用MessagePack為例,來看看它的用法。

    services.AddEasyCaching(option=>
    {

    option.UseRedis(config =>
    {
    config.DBConfig.Endpoints.Add(new ServerEndPoint("127.0.0.1", 6379));
    }, "redis1")

    .WithMessagePack();
    });

    不過這里需要注意的是,目前這些Serializer并不會跟著Provider走,意思就是不能說這個provider用messagepack,那個provider用json,只能有一種Serializer,可能這一個后面需要加強。

    多實例支持

    可能有人會問多實例是什么意思,這里的多實例主要是指,在同一個項目中,同時使用多個provider,包括多個同一類型的provider或著是不同類型的provider。

    這樣說可能不太清晰,再來舉一個虛構的小例子,可能大家就會更清晰了。

    現在我們的商品緩存在redis集群一中,用戶信息在redis集群二中,商品評論緩存在mecached集群中,一些簡單的配置信息在應用服務器的本地緩存中。

    在這種情況下,我們想簡單的通過IEasyCachingProvider來直接操作這么多不同的緩存,顯然是沒辦法做到的!

    這個時候想同時操作這么多不同的緩存,就要借助IEasyCachingProviderFactory來指定使用那個provider。

    這個工廠是通過provider的名字來獲取要使用的provider。

    下面來看個例子。

    我們先添加兩個不同名字的InMemory緩存

    services.AddEasyCaching(option =>
    {

    option.UseInMemory("m1");


    config.UseInMemory(options =>
    {
    options.DBConfig = new InMemoryCachingOptions
    {
    SizeLimit = 100
    };
    }, "m2");
    });

    使用的時候

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
    private readonly IEasyCachingProviderFactory _factory;

    public ValuesController(IEasyCachingProviderFactory factory)
    {
    this._factory = factory;
    }


    [HttpGet]
    [Route("")]
    public string Get()
    {

    var provider_1 = _factory.GetCachingProvider("m1");

    var provider_2 = _factory.GetCachingProvider("m2");




    return $"multi instances";
    }
    }

    上面這個例子中,provider_1和provider_2是不會互相干擾對方的,因為它們是不同的provider!

    直觀感覺,有點類似區域(region)的概念,可以這樣去理解,但是嚴格意義上它并不是區域。

    緩存的AOP操作

    說起AOP,可能大家第一印象會是記錄日志操作,把參數打一下,結果打一下。

    其實這個在緩存操作中同樣有簡化的作用。

    一般情況下,我們可能是這樣操作緩存的。

    public async Task<Product> GetProductAsync(int id)
    {
    string cacheKey = $"product:{id}";

    var val = await _cache.GetAsync<Product>(cacheKey);

    if(val.HasValue)
    return val.Value;

    var product = await _db.GetProductAsync(id);

    if(product != null)
    _cache.Set<Product>(cacheKey, product, expiration);

    return val;
    }

    如果使用緩存的地方很多,那么我們可能就會覺得煩鎖。

    我們同樣可以使用AOP來簡化這一操作。

    public interface IProductService
    {
    [EasyCachingAble(Expiration = 10)]
    Task<Product> GetProductAsync(int id);
    }

    public class ProductService : IProductService
    {
    public Task<Product> GetProductAsync(int id)
    {
    return Task.FromResult(new Product { ... });
    }
    }

    可以看到,我們只要在接口的定義上面加上一個Attribute標識一下就可以了。

    當然,只加Attribute,不加配置,它也是不會生效的。下面以EasyCaching.Interceptor.AspectCore為例,添加相應的配置。

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
    services.AddScoped<IProductService, ProductService>();

    services.AddEasyCaching(options =>
    {
    options.UseInMemory("m1");
    });

    return services.ConfigureAspectCoreInterceptor(options =>
    {


    options.CacheProviderName = "m1";
    });
    }

    這兩步就可以讓你在調用方法的時候優先取緩存,沒有緩存的時候會去執行方法。

    下面再來說一下三個Attritebute的一些參數。

    首先是三個通用配置

    CacheKeyPrefix指定生成緩存鍵的前綴,正常情況下是用在修改和刪除的緩存上
    CacheProviderName可以指定特殊的provider名字
    IsHightAvailability緩存相關操作出現異常時,是否還能繼續執行業務方法

    EasyCachingAble和EasyCachingPut還有一個同名和配置。

    EasyCachingEvict有兩個特殊的配置。

    IsAll這個要搭配CacheKeyPrefix來用,就是刪除這個前綴的所有key
    IsBefore在業務方法執行之前刪除緩存還是執行之后

    支持Diagnostics

    為了方便接入第三方的APM,提供了Diagnostics的支持,便于實現追蹤。

    下圖是我司接入Jaeger的一個案例。

    二級緩存

    二級緩存,多級緩存,其實在緩存的小世界中還算是一個比較重要的東西!

    一個最為頭疼的問題就是不同級的緩存如何做到近似實時的同步。

    在EasyCaching中,二級緩存的實現邏輯大致就是下面的這張圖。

    如果某個服務器上面的本地緩存被修改了,就會通過緩存總線去通知其他服務器把對應的本地緩存移除掉

    下面來看一個簡單的使用例子。

    首先是添加nuget包。

    dotnet add package EasyCaching.InMemory
    dotnet add package EasyCaching.Redis
    dotnet add package EasyCaching.HybridCache
    dotnet add package EasyCaching.Bus.Redis

    其次是添加配置。

    services.AddEasyCaching(option =>
    {

    option.UseInMemory("m1");
    option.UseRedis(config =>
    {
    config.DBConfig.Endpoints.Add(new Core.Configurations.ServerEndPoint("127.0.0.1", 6379));
    config.DBConfig.Database = 5;
    }, "myredis");


    option.UseHybrid(config =>
    {
    config.EnableLogging = false;

    config.TopicName = "test_topic";

    config.LocalCacheProviderName = "m1";

    config.DistributedCacheProviderName = "myredis";
    });


    option.WithRedisBus(config =>
    {
    config.Endpoints.Add(new Core.Configurations.ServerEndPoint("127.0.0.1", 6379));
    config.Database = 6;
    });
    });

    最后就是使用了。

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
    private readonly IHybridCachingProvider _provider;

    public ValuesController(IHybridCachingProvider provider)
    {
    this._provider = provider;
    }


    [HttpGet]
    [Route("")]
    public string Get()
    {
    _provider.Set(cacheKey, "val", TimeSpan.FromSeconds(30));

    return $"hybrid";
    }
    }

    如果覺得不清楚,可以再看看這個完整的例子EasyCachingHybridDemo。

    Redis的特殊Provider

    大家都知道redis支持多種數據結構,還有一些原子遞增遞減的操作等等。為了支持這些操作,EasyCaching提供了一個獨立的接口,IRedisCachingProvider。

    這個接口,目前也只支持了百分之六七十常用的一些操作,還有一些可能用的少的就沒加進去。

    同樣的,這個接口也是支持多實例的,也可以通過IEasyCachingProviderFactory來獲取不同的provider實例。

    在注入的時候,不需要額外的操作,和添加Redis是一樣的。不同的是,在使用的時候,不再是用IEasyCachingProvider,而是要用IRedisCachingProvider。

    下面是一個簡單的使用例子。

    [Route("api/mredis")]
    public class MultiRedisController : Controller
    {
    private readonly IRedisCachingProvider _redis1;
    private readonly IRedisCachingProvider _redis2;

    public MultiRedisController(IEasyCachingProviderFactory factory)
    {
    this._redis1 = factory.GetRedisProvider("redis1");
    this._redis2 = factory.GetRedisProvider("redis2");
    }


    [HttpGet]
    public string Get()
    {
    _redis1.StringSet("keyredis1", "val");

    var res1 = _redis1.StringGet("keyredis1");
    var res2 = _redis2.StringGet("keyredis1");

    return $"redis1 cached value: {res1}, redis2 cached value : {res2}";
    }
    }

    除了這些基礎功能,還有一些擴展性的功能,在這里要非常感謝yrinleung,他把EasyCaching和WebApiClient,CAP等項目結合起來了。感興趣的可以看看這個項目EasyCaching.Extensions。

    寫在最后

    以上就是EasyCaching目前支持的一些功能特性,如果大家在使用的過程中有遇到問題的話,希望可以積極的反饋,幫助EasyCaching變得越來越好。

    如果您對這個項目有興趣,可以在Github上點個Star,也可以加入我們一起進行開發和維護。

    前段時間開了一個Issue用來記錄正在使用EasyCaching的相關用戶和案例,如果您正在使用EasyCaching,并且不介意透露您的相關信息,可以在這個Issue上面回復。

    原文地址:https://www.cnblogs.com/catcher1994/p/10806607.html

    .NET社區新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?

    總結

    以上是生活随笔為你收集整理的一篇短文带您了解一下EasyCaching的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。