基于(Redis | Memcache)实现分布式互斥锁
设计一个缓存系统,不得不要考虑的问题就是:缓存穿透、缓存击穿与失效时的雪崩效应。
缓存击穿
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
解决方案
有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
缓存雪崩
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决方案
缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
使用互斥锁(mutex key)
业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。在redis2.6.1之前版本未实现setnx的过期时间,所以这里给出两种版本代码参考:
public String get(String key) {
String value = redis.get(key);
if (value == null) {
if (redis.setnx(key_mutex, "")) {
// 3 min timeout to avoid mutex holder crash
redis.expire(key_mutex, * )
value = db.get(key);
redis.set(key, value);
redis.delete(key_mutex);
} else {
//其他线程休息50毫秒后重试
Thread.sleep();
get(key);
}
}
}
优化后的互斥锁逻辑
public String get(key) {
String value = redis.get(key);
if (value == null) { //代表缓存值过期
//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
} else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
sleep(50);
get(key); //重试
}
} else {
return value;
}
}
下面是基于Memcache的add方法实现的分布式互斥锁
if (memcache.get(key) == null) {
// 3 min timeout to avoid mutex holder crash
if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
value = db.get(key);
memcache.set(key, value);
memcache.delete(key_mutex);
} else {
sleep(50);
retry();
}
}
参考链接:https://blog.csdn.net/zeb_perfect/article/details/54135506
基于(Redis | Memcache)实现分布式互斥锁的更多相关文章
- 基于Zookeeper实现的分布式互斥锁 - InterProcessMutex
Curator是ZooKeeper的一个客户端框架,其中封装了分布式互斥锁的实现,最为常用的是InterProcessMutex,本文将对其进行代码剖析 简介 InterProcessMutex基于Z ...
- 基于redis实现的分布式锁
基于redis实现的分布式锁 我们知道,在多线程环境中,锁是实现共享资源互斥访问的重要机制,以保证任何时刻只有一个线程在访问共享资源.锁的基本原理是:用一个状态值表示锁,对锁的占用和释放通过状态值来标 ...
- 单机Redis实现分布式互斥锁
代码地址如下:http://www.demodashi.com/demo/12520.html 0.准备工作 0-1 运行环境 jdk1.8 gradle 一个能支持以上两者的代码编辑器,作者使用的是 ...
- 基于redis的简易分布式爬虫框架
代码地址如下:http://www.demodashi.com/demo/13338.html 开发环境 Python 3.6 Requests Redis 3.2.100 Pycharm(非必需,但 ...
- 基于Redis的简单分布式锁的原理
参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的 ...
- 基于redis解决session分布式一致性问题
1.session是什么 当用户在前端发起请求时,服务器会为当前用户建立一个session,服务器将sessionId回写给客户端,只要用户浏览器不关闭,再次请求服务器时,将sessionId传给服务 ...
- 基于Redis的开源分布式服务Codis
Redis在豌豆荚的使用历程--单实例==>多实例,业务代码中做sharding==>单个Twemproxy==>多个Twemproxy==>Codis,豌豆荚自己开发的分布式 ...
- 基于 Redis 实现简单的分布式锁
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- 基于Redis实现简单的分布式锁【理论】
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
随机推荐
- a标签、img图片、iframe、表单元素、div
1.<a href="http://www.baidu.com" target=''_blank">百度</a> 超链接标签 2.<img ...
- qt使用动态库(DLL)
本文主要讲解在QT开发环境中如何使用VC生成的DLL及QT自身生成的DLL.至于其它情况本文不作讨论. 连接库分为2种 (1)动态连接库,通常有.h .lib .dll三个文件,功能实现在dll中 ( ...
- liunx系统top命令详解
ps: 1.按1可以进行 CPU各个和总CPU汇总的切换2.cpu0是最关键的,总控管理各个CPU 3.默认情况下仅显示比较重要的 PID.USER.PR.NI.VIRT.RES.SHR.S.%CPU ...
- centos7 yum搭建lamp环境
=============================================== 2018/1/14_第1次修改 ccb_warlock == ...
- 使用apt-get安装Nginx
Ubuntu 18.04,Nginx 1.14.0, 一直想在Linux上安装Nginx,一直没找到契机,很大原因是自己不熟悉,Ubuntu没安装好吧!今天下午学习了Ubuntu安装软件的一些资料,那 ...
- day9--多线程与多进程
线程: 什么是线程? 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线 ...
- ASP.NET:Forms身份验证和基于Role的权限验证
从Membership到SimpleMembership再到ASP.NET Identity,ASP.NET每一次更换身份验证的组件,都让我更失望.Membership的唯一作用就是你可以参考它的实现 ...
- 【LOJ】#2028. 「SHOI2016」随机序列
题解 我们发现只有从第一个往后数,用乘号联通的块是有贡献的 为什么,因为后面所有表达式 肯定会有 + ,还会有个-,贡献全都被抵消了 所以我们处理出前缀乘积,然后乘上表达式的方案数 答案就是\(\su ...
- 【BZOJ】4894: 天赋
题解 这道题是求一个有向图的外向生成树 入度矩阵对应着外向生成树,出度矩阵对应着内向生成树,知道了这个就可以求出基尔霍夫矩阵了,同时n - 1阶主子式一定要删掉根节点的一行一列 代码 #include ...
- hdoj2955 Robberies(01背包)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2955 题意 有n家银行,每家银行有两个属性:钱数m,概率p,p表示抢这家银行被逮着的概率.有一个人想抢 ...