互联网的项目用户基数很大,有时候瞬间并发量非常大,这个时候对于数据访问来说是个灾难。为了应对这种场景,一般都会大量采用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();
});
}
}

  

cache 访问频率的思考的更多相关文章

  1. Django Rest Framework(认证、权限、限制访问频率)

    阅读原文Django Rest Framework(认证.权限.限制访问频率) django_rest_framework doc django_redis cache doc

  2. RestFramework自定制之认证和权限、限制访问频率

    认证和权限 所谓认证就是检测用户登陆与否,通常与权限对应使用.网站中都是通过用户登录后由该用户相应的角色认证以给予对应的权限. 权限是对用户对网站进行操作的限制,只有在拥有相应权限时才可对网站中某个功 ...

  3. Django rest framework 限制访问频率(源码分析)

    基于 http://www.cnblogs.com/ctztake/p/8419059.html 当用发出请求时 首先执行dispatch函数,当执行当第二部时: #2.处理版本信息 处理认证信息 处 ...

  4. Django Rest Framework用户访问频率限制

    一. REST framework的请求生命周期 基于rest-framework的请求处理,与常规的url配置不同,通常一个django的url请求对应一个视图函数,在使用rest-framewor ...

  5. IP访问频率限制不能用数组循环插入多个限制条件原因分析及解决方案

    14.IP频率限制不能用数组循环插入多个限制条件原因分析及解决方案: define("RATE_LIMITING_ARR", array('3' => 3, '6' => ...

  6. 从FBV到CBV四(访问频率限制)

    比如我们有一个用户大转盘抽奖的功能,需要规定用户在一个小时内只能抽奖3次,那此时对接口的访问频率限制就显得尤为重要 其实在restframework中已经为我们提供了频率限制的组件 先捋一下请求到AP ...

  7. web系统访问频率限制

    无论是spring mvc还是struts,都可以为controller或者aciton执行前,增加拦截器. 通过拦截器中的逻辑控制,可以实现访问频率的限制. 首先构造访问频率数据类 class Fr ...

  8. C# 站点IP访问频率限制 针对单个站点

    0x00 前言 写网站的时候,或多或少会遇到,登录,注册等操作,有时候,为了防止别人批量进行操作,不得不做出一些限制IP的操作(当前也可以用于限制某个账号的密码校验等). 这样的简单限制,我们又不想对 ...

  9. nginx lua redis 访问频率限制(转)

    1. 需求分析 Nginx来处理访问控制的方法有多种,实现的效果也有多种,访问IP段,访问内容限制,访问频率限制等. 用Nginx+Lua+Redis来做访问限制主要是考虑到高并发环境下快速访问控制的 ...

随机推荐

  1. Centos7.0进入单用户模式修改root密码

    启动Centos7 ,按空格让其停留在如下界面. 按e进行编辑 在UTF-8后面输入init=/bin/sh 根据提示按ctrl+x 得如下图 输入mount -o remount,rw /  然后输 ...

  2. [ 9.26 ]CF每日一题系列—— 771B递推问题

    Description: 给定你命名的规律,1-10个字符,开头必须大写,最多有50个名字,然后告诉你有n个人,判断区间长度为k,那么你将得到n - k + 1个答案(YES or NO) 表示1 - ...

  3. SDWebImage之SDImageCache

    SDImageCache和SDWebImageDownloader是SDWebImage库的最重要的两个部件,它们一起为SDWebImageManager提供服务,来完成图片的加载.SDImageCa ...

  4. vue-cli脚手架项目按需引入elementUI

    https://www.jianshu.com/p/40da0ba35ac1 Couldn't find preset "es2015" relative to directory ...

  5. ie被hao.360劫持的解决方法

    概述 之前无意中发现ie被hao.360劫持了,只要打开网址就会跳到hao.360,然后显示网络错误.网上试了几种解决方法,都不行,最后被我用重置ie浏览器的方法解决了.我总结了一下,把各种方案都记下 ...

  6. Linux下解压.tar.xz格式文件的方法

    前言 对于xz这个压缩相信很多人陌生,但xz是绝大数linux默认就带的一个压缩工具,xz格式比7z还要小. 今天在下载Node.js源码包的时候遇到的这种压缩格式.查了一下资料,这里进行一下记录,分 ...

  7. LeetCode: 107_Binary Tree Level Order Traversal II | 二叉树自底向上的层次遍历 | Easy

    本题和上题一样同属于层次遍历,不同的是本题从底层往上遍历,如下: 代码如下: struct TreeNode { int val; TreeNode* left; TreeNode* right; T ...

  8. python(leetcode)-350两个数组的交集

    给定两个数组,编写一个函数来计算它们的交集. 示例 1: 输入: nums1 = [1,2,2,1], nums2 = [2,2] 输出: [2,2] 示例 2: 输入: nums1 = [4,9,5 ...

  9. 记hangfire后台任务运行一段时间后不运行了。

    什么是Hangfire Hangfire 是一个开源的.NET任务调度框架,目前1.6+版本已支持.NET Core.个人认为它最大特点在于内置提供集成化的控制台,方便后台查看及监控. https:/ ...

  10. 让Java线程池实现任务阻塞执行的一种可行方案

    Java的线程池一般是基于concurrent包下的ThreadPoolExecutor类实现的, 不过当我们基于spring框架开发程序时, 通常会使用其包装类ThreadPoolTaskExecu ...