互联网的项目用户基数很大,有时候瞬间并发量非常大,这个时候对于数据访问来说是个灾难。为了应对这种场景,一般都会大量采用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; } } private static MonitorCache _current = new MonitorCache(new MemoryCache()); public static MonitorCache Current { get { return _current; } } }
通过对原有的缓存访问进行包装,我们已经实现对原有缓存的重构,实现监视的意图。
时间: 2024-10-10 01:27:07