缓存一致性策略和雪崩,渗透问题

发布者:上海IT外包来源:http://www.lanmon.net点击数:945

在高并发方案中首先考虑的第一层优化是增加缓存。特别是,通过Redis,将数据库中的原始数据复制到内存中,这可以减少数据库的读取操作,并减少对数据库的压力。它还将加快系统的响应速度,但它也会带来其他问题,例如需要考虑数据一致性,还要防止可能的缓存崩溃,渗透和雪崩问题。
一,缓存原理
在高并发方案中首先考虑的第一层优化是增加缓存。特别是,通过Redis,将数据库中的原始数据复制到内存中,这可以减少数据库的读取操作,并减少对数据库的压力。它还将加快系统的响应速度,但它也会带来其他问题,例如需要考虑数据一致性,还要防止可能的缓存崩溃,渗透和雪崩问题。
1.实施步骤
首先查询缓存中的数据(如果有),直接返回缓存中的数据。如果缓存中没有数据,将查询数据库,数据将更新到缓存并返回,如果数据库中没有数据,则可以返回空数据。
考虑到数据一致性,缓存中的代码逻辑更加标准化。首先,拿Redis,点击它并返回它。如果遗漏,它将通过数据库进行查询和同步。
公共结果查询(String id){
结果result=null;
//1。从Redis缓存中获取数据
Result=(Result)redisTemplate.opsForValue()。get(id);
If(null!=result){
System.out.println('获取缓存中的数据');
返回结果;
}
//2。通过DB查询,有一个同步更新redis,否则返回空
System.out.println('获取数据库中的数据');
Result=Dao.query(id);
If(null!=result){
redisTemplate.opsForValue()组(ID,结果)。
redisTemplate.expire(id,20000,TimeUnit.MILLISECONDS);
}返回结果;
}
可以通过首先清除Key下的缓存值然后执行DB操作来执行其他添加,删除和更新操作。逻辑清晰简单,维护复杂性降低,成本不止一个查询。
Public void update(Entity entity){
redisTemplate.delete(entity.getId());
Dao.update(实体);
退货实体;
}
公共实体添加(实体实体){
redisTemplate.delete(entity.getId());
Dao.insert(实体);
退货实体;
}
2.缓存更新策略
适用于缓存的方案通常是:频繁访问,更多读取场景,更少写入方案以及不太严格的数据一致性要求。如果不满足上述三个条件,那么维护一组缓存数据的意义就不大了。实际上,通常需要为业务场景选择合适的缓存方案。给出了以下四种缓存策略。下一步是从强到弱的一致性顺序。
更新策略功能适用的方案
实时更新同步更新保证了强大的一致性,与业务的强大耦合,强大的财务转移业务等。
弱实时异步更新(MQ /发布订阅/观察者模式),服务解耦,弱一致性,延迟不适合编写频繁场景
失效机制将缓存设置为无效,存在一定的延迟,可能存在雪崩,适合于较少的读写,并且可以接受一定的延迟。
任务调度通过定期任务完全更新统计服务,并定期更新。
2.缓存雪崩和故障
缓存雪崩概念
缓存雪崩意味着在设置缓存时使用相同的到期时间,导致缓存同时失败。请求全部转发给DB,DB处于压力和雪崩状态。与缓存故障不同,缓存突破并检查相同的数据。缓存雪崩是不同的数据已过期,并且无法找到许多数据来检查数据库。

分配缓存过期时间。例如,我们可以根据原始到期时间(例如1-5分钟)添加随机值,这样每个缓存到期时间的重复率将会降低,并且很难导致集体失败。事件。
通过锁定或排队来保证对高速缓存的单线程(进程)写入,从而避免大量并发请求在失败时落入底层存储系统。
第一种方案相对容易实现,第二种方法主要通过添加阻塞独占锁来实现。在高速缓存查询不可用的情况下,仅允许一个线程查询DB,从而可以避免相同的线程。大量并发ID请求属于数据库。公共结果查询(String id){
//从缓存中获取数据
结果result=null;
Result=(Result)redisTemplate.opsForValue()。get(id);
If(result!=null){
Logger.info('获取缓存中的数据');
返回结果;
}
//2。锁定队列,阻止锁定
doLock(id); //有多少个id可能有多少个锁
尝试{
//一次只有一个线程
//仔细检查,第一次得到以下内容可以直接从缓存中命中
Result=(Result)redisTemplate.opsForValue()。get(id);
If(result!=null){
Logger.info('获取缓存中的数据');
返回结果; //第二个帖子,回到这里
}
Result=dao.query(id);
//3.从数据库查询的结果不为空,然后将数据放入缓存中,方便下次查询
If(null!=result){
redisTemplate.opsForValue()组(ID,结果)。
redisTemplate.expire(id,20000,TimeUnit.MILLISECONDS);
}
返回省份;
} catch(例外e){
返回null;
} finally {
//4。开锁
RELEASELOCK(provinceid);
}
}
Private void releaseLock(String userCode){
ReentrantLock oldLock=(ReentrantLock)locks.get(userCode);
if(oldLock!=null && oldLock.isHeldByCurrentThread()){
oldLock.unlock();
}
}
Private void doLock(String lockcode){
502 Bad Gateway

502 Bad Gateway



<中心> nginx的


<! - 用于禁用MSIE和Chrome友好错误页面的填充 - >
<! - 用于禁用MSIE和Chrome友好错误页面的填充 - >
<! - 用于禁用MSIE和Chrome友好错误页面的填充 - >
<! - 用于禁用MSIE和Chrome友好错误页面的填充 - >
<! - 用于禁用MSIE和Chrome友好错误页面的填充 - >
<! - 用于禁用MSIE和Chrome友好错误页面的填充 - >
将列表数据加载到Bloom过滤器中
Private BloomFilter bf=null;
//在创建PostConstruct注释对象后自动调用此方法。
@PostConstruct
Public void init(){
//bean初始化完成后,实例化bloomFilter,并加载数据
List entities=initList();
//初始化Bloom过滤器
Bf=BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),entities.size());对于(实体实体:实体){
Bf.put(entity.getId());
}
}
??
通过Bloom过滤器访问,可以在db中查询状态
公共省份查询(String id){
//首先确定Bloom过滤器中是否存在该值,该值是否允许访问缓存和数据库
如果(!bf.mightContain(id)){
Log.info('非法访问'+ System.currentTimeMillis());
返回null;
}
Log.info('获取数据库中的数据'+ System.currentTimeMillis());
实体实体=super.query(id);
退货实体;
}
这样,当存在来自外界的恶意攻击时,可以在过滤层直接拦截不存在的数据请求,而不会影响底层数据库系统。
IT外包
>
400-635-8089
立即
咨询
电话咨询
服务热线
400-635-8089
微信咨询
微信咨询
微信咨询
公众号
公众号
公众号
返回顶部