【问题标题】:What Are the Patterns and Best Practices for Caching in ASP.NET?ASP.NET 中缓存的模式和最佳实践是什么?
【发布时间】:2010-12-18 08:00:47
【问题描述】:

我们正在开发一个大型遗留应用程序,并且正在重新设计业务层和数据层。我们认为现在是重新设计缓存处理方式的好时机。是否有实现缓存层(或在业务层中构建)的模式和最佳实践?

我能想到的唯一事情是使用 SQL 缓存依赖(这很难,因为我们有一个大型遗留数据库,其中有很多表并不总是对应于业务对象)并实现强类型CacheManager 类隐藏字符串键并消除类转换问题。

还有什么更复杂的我们可以做的吗?执行更新/删除时有没有办法强制缓存失效?我们是否应该以某种方式在缓存中维护单个对象并从数据库中检索始终与相同对象一起使用的 ID 列表?

基本上,您在 ASP.NET 中使用哪些缓存技术?太糟糕了,我们不能使用支持缓存的 IoC 容器或 ORM 框架:(

编辑:我更关心可维护性而不是性能。

【问题讨论】:

    标签: asp.net caching


    【解决方案1】:
    • 只需将每个查询结果保存到数据库(缓存键:您的查询,值:您的业务对象列表)
    • 在 ASP.Net 缓存旁边使用 memcached 等分布式缓存
    • 使用复杂的缓存管理器,如https://github.com/enyim/memcached-providers;可以有缓存组。有些数据必须存储很长时间,有些时间很短。有些数据必须存储在 ASP.Net 缓存等中。
    • 使用public T GetFromCache<T>(string key, Func<T> ifKeyNotFoundDelegate) 之类的包装函数执行必须存储在缓存中的调用,以确保始终使用相同的缓存。 [1]
    • 考虑何时使用 ASP.Net 缓存,何时使用分布式缓存。每次请求读取的数据都应该存储在 ASP.Net 中,比如搜索结果的大数据;有很多不同的键和数据等应该在 memcached 中。
    • 添加版本控制。为所有键加上版本号前缀,这样您在更新 Web 应用程序时就不会遇到麻烦,并且某些对象合同会发生变化。

    嗯,这涵盖了我们在网站上所做的大部分工作(20GB 内存缓存集群分布在 20 台服务器上)。

    [1] 通过使这样的函数成为在缓存中存储内容的唯一接口,您可以实现以下目的。假设我想使用缓存中的某些内容,例如函数的结果。通常你会做类似的事情

    CacheManager cm = new CacheManager(CacheGroups.Totals);
    object obj = cm.GetFromCache("function1result");
    if(obj == null)
    {
        obj = (object)DAO.Foo();
        cm.StoreInCache("function1result", obj);
    }
    return (List<MyEntity>)obj;
    

    通过使用不同的界面,您可以确保用户不会在这里出错。

    喜欢

    public T GetFromCache<T>(string key, Func<T> ifnotfound)
    {
        T obj = this.GetFromCache(key) as T;
        if(obj == default(T)) 
        { 
             obj = ifnotfound.Invoke();
             this.StoreInCache(key, obj);
        }
        return obj;
    }
    

    这样可以确保

    1. 我们始终使用正确的类型
    2. 您的用户始终以相同的方式使用缓存

    Ergo:他们犯错的可能性较小。此外:你会得到更好、更清晰的代码,例如:

    List<MyEntity> list = new CacheManager(CacheGroups.Total).GetFromCache<List<MyEntity>>("function1result", ()=>DAO.Foo());
    

    【讨论】:

    • 非常感谢您(以及所有回复的人)。您能否详细说明一下: • 使用诸如 public T GetFromCache(string key, Func ifKeyNotFoundDelegate) 之类的包装函数来执行必须存储在缓存中的调用,以确保始终使用相同的缓存。跨度>
    • 在多线程环境中,不要忘记GetFromCache()中的锁。
    【解决方案2】:

    这是一个很大的话题,但这里有一些建议:

    1. 不要缓存不太可能重复使用的数据,例如用户特定的数据
    2. 所有层级的缓存:客户端、Silverlight(隔离存储)、代理、http.sys、IIS、ASP.NET 缓存对象、ASP.NET 每个请求缓存、SQL Server
    3. 尽可能使用 SqlDependency / SqlCacheDependency,但不要过度使用
    4. 避免会话状态;尽可能使用 Cookie
    5. 利用页面和控制(片段)输出缓存
    6. 考虑在需要时使用缓存验证
    7. 考虑 ASP.NET 缓存对象的轻量级替代方案,例如弱内存引用
    8. 如果使用得当,SQL Server 可以充当大型缓存

    如果有帮助,我会在我的书中详细介绍这个主题:Ultra-Fast ASP.NET

    【讨论】:

    • 弱内存引用是什么意思?我使用的一种非常简单的缓存形式是创建一个像这样的静态变量:private static DataTable _products; public static DataTable products { get { if(_productes == null){_products = getProductsFromSQLServer();} return _products } } 这是 Kosher 吗?我通常只为非常小的记录集这样做。
    • 哇,抱歉。我所有的空白都从评论中删除了。
    • @J.Hendix:有关弱内存引用的信息,请查看 WeakReference 类(或者在 StackOverflow 上发布问题)。您的示例是一个强大的静态参考。这当然是一种有效的缓存形式。弱 ref 的优点是,如果内存压力太大,GC 可以放手,而强 ref 则不能放手。
    • 非常感谢您的回复。但是,我对模式更感兴趣,以允许我防止缓存错误、其他开发人员对缓存的错误使用、自动失效等。在这一点上,我并不是在寻找非常高性能的缓存。我更关心可维护性。
    • @Stilgar:缓存错误通常是由于架构错误或设计不正确而发生的。 Cache 对象本身是相对健壮的,除了在多线程和锁领域。如果您的网站将进行负载平衡或部署为网络花园,那么这就为许多可能的问题打开了大门。
    【解决方案3】:

    MS 模式和实践团队创建了企业库,作为对这个问题的回答,以应对一系列常见场景。 EntLib 包括缓存以及数据访问、验证、日志记录、异常处理等。我们已经使用了多年,如果没有它,我们不会考虑开始一个新项目。

    http://www.codeplex.com/entlib

    还有 P&P 主页,http://msdn.microsoft.com/en-us/practices/default.aspx

    【讨论】:

    • 缓存应用程序块从企业库 6 中排除,他们决定从 EntLib 中淘汰一些块,如 here 所述
    猜你喜欢
    • 1970-01-01
    • 2011-03-29
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-03-08
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多