• 热缓存 IHotCache --ESBasic 可复用的.NET类库(19)


    1.缘起:

        假设我们有一个订单系统,现在这个系统要增加一个功能――允许客人查核他认为有问题的订单的详细信息。当客人觉得自己的某个订单不对劲时,他首先会从订单系统查询这个订单的详细信息,然后打电话告诉我们的客服有问题的订单的编号,客服再去查核,如果属实,客服还要进一步上报,如果该订单非常重要,则可能需要更进一步上报复查等。

        从这个需求我们看到,同一个订单可能会在比较短的时间内查询数次甚至数十次,所以我们可以称这个订单为“热点”订单。而其它的成千上万的订单可能在一个月内都不被查询一次。

        我设计热缓存ESBasic.ObjectManagement.Cache. IHotCache就是缓存类似“热点”订单的这些对象。

    热缓存的形象示意图如下:

    2.适用场合:

    根据上述的描述,我们可以总结一下热缓存IHotCache的使用场合:

    (1)根据我们系统的需求,目标对象群中的某些对象的“热”的程度可以明显地与其它对象区分开来。

    (2)加载某一类型的对象到我们的系统中需要花费比较大的气力(比如加载速度很慢、加载过程很繁琐),而且一旦加载就会被经常使用。

    (3)在指定的时间周期内不被访问的对象可以被卸载掉。如果一个“热”对象变“冷”了,那么我们就可以将其从热缓存中移除。

    (4)当然,要被缓存的对象必须有唯一的ID

    3.设计思想与实现

    IHotCache的接口定义如下:

        /// <summary>
        
    /// IHotCache 用于缓存那些活跃的对象,并定时删除不活跃的对象。该接口的实现必须是线程安全的。
        
    /// </summary>    
        public interface IHotCache<TKey, TObject> where TObject : class
        {
            
    /// <summary>
            
    /// DetectSpanInSecs 多长时间检测一次对象是否活跃,单位:秒。
            
    /// </summary>
            int DetectSpanInSecs { set; }

            
    /// <summary>
            
    /// MaxMuteSpanInMinutes 对象最大的沉默时间(分钟)。如果一个对象在MaxMuteSpanInMinutes时间间隔内都不被访问,则将被从缓存中清除。
            
    /// 如果该属性的值被设置为小于或等于0,则表示永远不会从缓存中清除。
            
    /// </summary>
            int MaxMuteSpanInMinutes { set; }

            
    /// <summary>
            
    /// MaxCachedCount 最多缓存的对象个数。当超过此个数时,不再缓存新的对象。
            
    /// </summary>
            int MaxCachedCount { getset; }

            
    IObjectRetriever<TKey, TObject> ObjectRetriever { set; }
            
    int Count { get; }
            
    long RequestCount { get; } //请求次数
            long HitCount { get; }//命中的次数
            DateTime LastReadTime { get; }        

            
    void Initialize();
            
    void Clear();
            
    void Add(TKey id, TObject obj);
            
    void Remove(TKey id);
            
            
    /// <summary>
            
    /// Get 如果缓存中存在目标则直接返回,否则通过ObjectRetriever提取对象并缓存。
            
    /// </summary>      
            TObject Get(TKey id);

            
    IList<TObject> GetAll();

            
    event CbSimple CacheContentChanged;
        }

    注意这个接口的泛型参数TObject有一个泛型约束,其表明TObject必须是一个引用类型,这表示我们不能使用热缓存来缓存那些值类型的对象。

    当你向IHotCache请求一个对象时,如果对象不在热缓存中(有可能是从来还未加载进缓存,也有可能是因为对象变“冷”后被移除缓存了),则会加载该对象到热缓存中并返回。我们是借助前面介绍的对象获取器IObjectRetriever来获取目标对象的。

        热缓存会每隔一段时间检测一次缓存中的对象是否已经变“冷”――即在MaxMuteSpanInMinutes时间段内都没有被访问过。这个定时检测就是使用循环引擎AgileCycleEngine来做到的。如果一个对象已经变“冷”,则会将其移除热缓存――热缓存只缓存那些“热”的东西,所以放“冷”了的就必须把它移除掉。

          RequestCountHitCount分别表示热缓存接收到的请求对象的次数,和缓存命中的次数――即无需IObjectRetriever加载而直接从缓存中返回对象的次数。这两个属性提供一些统计数据,以反映我们当前使用热缓存的价值究竟有多大,以此我们可以判断这个地方是否真的需要使用热缓存。

        关于HotCache的具体实现,还需要注意以下几个方面:

    (1)为了允许在多线程的环境中使用热缓存,所以HotCache必须在对内部的dictionary操作的时候进行加锁控制。

    (2)热缓存在初始化(Initialize方法)时,启动循环引擎来定时检测缓存的每个对象的冷热程度。

    (3)使用CachePackage类来封装每个被缓存的对象,其中主要是记录了被封装对象的最后一次访问时间。

    (4)如果缓存中不存在目标对象、IObjectRetriever也加载不到目标对象,Get方法将返回null

    4. 使用时的注意事项

    (1)有两种方式可以将对象添加到热缓存中,一种是热缓存借助IObjectRetriever自动加载对象;另一种是通过调用其Add方法加入。如果我们已经预计到某个对象是“热”对象,那么就可以先将其Add到热缓存中以备用。特别是,当IObjectRetriever获取这个对象比较费气力时:)。

    (2)热缓存加速了对“热”对象的访问,但是这是以占用内存为代价的。如果你的对象访问比较平均,没有凸显出特别“热”的对象,那么使用热缓存的作用就不大了。

    (3)当你确定不会再使用某个对象时,可以立即调用Remove方法将其从热缓存中手动移除,而不是等到其变“冷”后才被热缓存自动移除。当这样的对象比较多,而且对象比较大时,这样做可以立即释放比较大的内存空间。

    (4)如果某个对象已经被判定为无效或者已被外界修改(缓存中的对象的数据已经是老版本),则可以调用Remove方法将其从热缓存中移除。

    (5)MaxMuteSpanInMinutes属性设置为多少比较合适,取决于你的具体应用,也许是10分钟,也有可能是24小时。如果这个属性和DetectSpanInSecs属性、MaxCachedCount属性能进行合理搭配设置,则可以使得热缓存的运行价值最大化。

    5.扩展

    热缓存IHotCache暂时没有任何扩展。

     

    注: ESBasic已经开源,点击这里下载源码。
        
    ESBasic开源前言

  • 相关阅读:
    virtmanager 的 internal error Cannot find suitable emulator for x86_64 错误
    django 判断mysql中的bit(1)
    eucalyptus volume 的一些创建流程以及理解
    将eucalyptus数据库更改为Mysql
    ftp虚拟用户添加
    通过shell读取mysql数据
    Java webservice
    axis2之webservice
    基础巩固(二) log4j的使用
    基础巩固(一)
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/1639445.html
Copyright © 2020-2023  润新知