zoukankan      html  css  js  c++  java
  • cache 访问频率的思考

    互联网的项目用户基数很大,有时候瞬间并发量非常大,这个时候对于数据访问来说是个灾难。为了应对这种场景,一般都会大量采用web服务器集群,缓存集群。采用集群后基本上就能解决大量并发的数据访问。当然这个时候内网的网速会成为缓存速度的瓶颈。

    当然我们希望能有更好的缓存结构,比如一级缓存和二级缓存。一级缓存直接缓存在宿主主机内存上,二级缓存缓存在redis集群上,如果一个缓存实例被访问的频率非常高,我们希望这个缓存实例能缓存在宿主主机内存上,如果一个实例的访问频率非常低,我们甚至可能不会为此实例进行缓存处理。

    基于这种设想,我们希望能够跟踪监视缓存实例,并根据监视结果,对实例的缓存级别进行动态调整,以达到最佳的缓存效果。(事实上dotNet4.0里面的System.Runtime.Caching.MemoryCache对此已经有很好的实现和支持了。当然我们的应用必须知道要缓存在宿主主机内存上,还是redis集群上,那就必须实现类似System.Runtime.Caching.MemoryCache的监视功能和动态调整功能)

    首先我们需要附加一些监视信息到缓存实例上,

     public class CacheAttach
        {
            public CacheAttach(string key)
            {
                this.Key = key;
                this.InsertedTime = DateTime.Now;
            }
            public string Key { get; set; }
            public DateTime InsertedTime { get; private set; }
            public int QueryTimes { get; set; }
            public int AccessTimes { get; set; }
            public override bool Equals(object obj)
            {
                if (obj == null)
                    return false;
                return obj.GetHashCode() == this.GetHashCode();
            }
            public override int GetHashCode()
            {
                return Key.GetHashCode();
            }
            public static implicit operator CacheAttach(string value)
            {
                return new CacheAttach(value);
            }
        }
        public class CacheAttachCollection : List<CacheAttach>, ICollection<CacheAttach>
        {
            public bool Contains(string Key)
            {
                return this.Find(i => i.Key == Key) == null;
            }
            public CacheAttach this[string key]
            {
                get
                {
                    CacheAttach item =this.Find(i => i.Key == key);
                    if (item == null)
                    {
                        item = new CacheAttach(key);
                        this.Add(item);
                    }
                    return item;
                }
                set
                {
                    CacheAttach item = this.Find(i => i.Key == key);
                    if (item == null)
                    {
                        item = new CacheAttach(key);
                        this.Add(item);
                    }
                    item = value;
                }
            }
        }
    

      这里采用的是一种附加形式的监视,不去破坏原来的K/V缓存方式。这个时候我们可能需要重新包装一下原有的缓存访问,使得对缓存的操作能被监视。

    public class MonitorCache: ICache
        {
            private ICache proxyCache;
            CacheAttachCollection cacheMonitor = new CacheAttachCollection();
            public MonitorCache(ICache cache)
            {
                this.proxyCache = cache;
            }
            #region ICache Implement
            public bool Set<T>(string key, T value)
            {
                cacheMonitor[key].QueryTimes++;
                cacheMonitor[key].AccessTimes++;
                return proxyCache.Set(key, value);
            }
    
            public bool Set<T>(string key, T value, DateTime absoluteTime, TimeSpan slidingTime, Action<string, T> removingHandler)
            {
                cacheMonitor[key].QueryTimes++;
                cacheMonitor[key].AccessTimes++;
                return this.proxyCache.Set(key, value, absoluteTime, slidingTime, removingHandler);
            }
    
            public object Get(string key)
            {
                cacheMonitor[key].QueryTimes++;
                cacheMonitor[key].AccessTimes++;
                return this.proxyCache.Get(key);
            }
    
            public T Get<T>(string key)
            {
                cacheMonitor[key].QueryTimes++;
                cacheMonitor[key].AccessTimes++;
                return this.proxyCache.Get<T>(key);
            }
    
            public bool Contains(string key)
            {
                cacheMonitor[key].QueryTimes++;
                return this.proxyCache.Contains(key);
            }
    
            public bool Remove(string key)
            {
                if (this.proxyCache.Remove(key))
                {
                    cacheMonitor.Remove(key);
                    return true;
                }
                return false;
            }
            #endregion
    
            public object this[string key]
            {
                get
                {
                    return this.Get(key);
                }
                set
                {
                    this.Set(key, value);
                }
            }
    
            public CacheAttachCollection Monitor
            {
                get
                {
                    return this.cacheMonitor;
                }
            }
    
        }
    

      通过对原有的缓存访问进行包装,我们已经实现对原有缓存的重构,实现监视的意图。

     public class CacheHelper : ICache
        {
            private MonitorCache level1 = null;
            private MonitorCache level2 = null;
    
            private CacheHelper()
            {
                this.level1 = new MonitorCache(new MemoryCache());
                this.level2 = new MonitorCache(new RedisCache());
            }
    
            public bool Set<T>(string key, T value)
            {
                if (this.level1.Set(key, value))
                    return true;
                if (this.level2.Set(key, value))
                    return true;
                return false;
            }
    
            public bool Set<T>(string key, T value, DateTime absoluteTime, TimeSpan slidingTime, Action<string, T> removingHandler)
            {
                if (this.level1.Set(key, value, absoluteTime, slidingTime, removingHandler))
                    return true;
                if (this.level2.Set(key, value, absoluteTime, slidingTime, removingHandler))
                    return true;
                return false;
            }
    
            public object Get(string key)
            {
                return this.level1.Get(key) ?? this.level2.Get(key) ?? null;
            }
    
            public T Get<T>(string key)
            {
                if (this.level1.Contains(key))
                    return this.level1.Get<T>(key);
                if (this.level2.Contains(key))
                    return this.level2.Get<T>(key);
                return default(T);
            }
    
            public T Get<T>(string key, Func<T> valueGetter)
            {
                var result = default(T);
                if (this.level1.Contains(key))
                    result = this.level1.Get<T>(key);
                else if (this.level2.Contains(key))
                    result = this.level2.Get<T>(key);
    
                if (result == null && valueGetter != null)
                    result = valueGetter();
                return result;
            }
    
            public bool Contains(string key)
            {
                if (this.level1.Contains(key))
                    return true;
                if (this.level2.Contains(key))
                    return true;
                return false;
            }
    
            public bool Remove(string key)
            {
                if (this.level1.Contains(key))
                    this.level1.Remove(key);
                if (this.level2.Contains(key))
                    this.level2.Remove(key);
                return true;
            }
    
            public object this[string key]
            {
                get
                {
                    return this.Get(key);
                }
                set
                {
                    this.Set(key, value);
                }
            }
            public void Trim()
            {
                //对一级缓存进行整理
                for (int i = 0, lengh = this.level1.KeyMonitor.Count; i < lengh; i++)
                {
                    CacheAttach item = this.level1.KeyMonitor[i];
    
                    //频率小于10次/秒的缓存需要移除一级缓存
                    if (item.AccessRate < 10)
                    {
                        //频率大于1次/秒的缓存移到二级缓存
                        if (item.AccessRate >= 1)
                        {
                            this.level2.Set(item.Key, this.level1[item.Key]);
                            this.level2.KeyMonitor[item.Key] = item;
                        }
                        this.level1.Remove(item.Key);
                    }
                }
    
                //对二级缓存进行整理
                for (int i = 0, lengh = this.level2.KeyMonitor.Count; i < lengh; i++)
                {
                    CacheAttach item = this.level1.KeyMonitor[i];
    
                    //频率大于等于10次/秒的缓存需要移至一级缓存
                    if (item.AccessRate >= 10)
                    {
                        this.level1.Set(item.Key, this.level2[item.Key]);
                        this.level1.KeyMonitor[item.Key] = item;
                        this.level1.Remove(item.Key);
                        continue;
                    }
                    if (item.AccessRate < 1)
                    {
                        this.level2.Remove(item.Key);
                        continue;
                    }
                }
            }
    
            private static CacheHelper _Current = new CacheHelper();
            public static CacheHelper Current
            {
                get { return _Current; }
            }
            public static CacheHelper()
            {
                System.Threading.Timer timer = new System.Threading.Timer(delegate
                {
                    Current.Trim();
                });
            }
        }
    

      

  • 相关阅读:
    Mybatis总结(mybatis plus待更新)
    maven配置(IDEA)quickstart,IDEA上maven细节配置
    (已解决)C3P0数据库使用配置文件链接,报错:com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
    angular--ng-template&ngTemplateOutlet的用法

    Array.from()和Array.of()用法
    Object.create()
    继承
    Object类型
    剩余参数
  • 原文地址:https://www.cnblogs.com/Linjianyu/p/5673022.html
Copyright © 2011-2022 走看看