解决方案:
1.布隆过滤器 把所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉
2.如果一个查询返回的数据是空的,无论数据是否存在,还是系统故障,我们仍然将这个空结果进行缓存,但设置很短的过期时间
解决方案
1.用加锁或者队列的方式保证缓存的单线程写,避免失效时大量的并发请求落到底层的存储系统上
2.将缓存的失效时间分散开,在原来失效时间的基础上加上一个随机值,比如说1-5分钟的随机,这样每一个缓存过期时间的重复率就会降低,很难引起集体失效的事件。
解决方案
String get(String key){ String value = reids.get(key); if(value == null){ if(redis.setnx(key_mutex,"1")){ reids.expire(key_mutex,3*60); value = db.get(key); redis.set(key,value); redis.delete(key_mutex); }else{ //其他线程休息50ms后重试 Thread.sleep(50); get(key); } } }
2.设置热点数据永不过期
a.从redis上来看,确实不设置过期时间,保证不会出现热点key过期的问题,也就是物理上的不过期
String get(final String key){ V v = redis.get(key); String value = v.getValue(); long timeout = v.getTimeout(); if(v.timeout <= System.currentTimeMillis()){ //异步更新后台异常执行 threadPool.execute(new Runnable(){ public void run(){ String keyMutex = "mutex:"+key; if(redis.setnx(keyMutex,"1")){ //设置三分钟的超时 redis.expire(keyMutex,3*60); String dbValue = db.get(key); redis.set(key,dbValue); redis.delete(keyMutex); } } }); } }
v = mem***.get(key); if(v==null){ if(mem***.add(key_mutex,3*60*1000) == true){ value = db.get(key); mem***.set(key,value); mem***.delete(key_mutex); }else{ sleep(50); retry(); }else{ if(v.timeout <= now()){ if(mem***.add(key_mutex,3*60*1000) == true){ v.timeout += 3*60*1000; mem***.set(key,v,KEY_TIMEOUT*2); //从数据库加载最新的数据 v = db.get(key); v.timeout = KEY_TIMEOUT; mem***.set(key,value,KEY_TIMEOUT*2); mem***.delete(key_mutex); }else{ sleep(50); retry(); } } } }