百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

redis分布式锁及ZK锁的区别?缓存穿透、击穿、雪崩及布隆过滤器

mhr18 2024-12-13 12:59 30 浏览 0 评论

1、使用redis如何设计分布式锁?

(1)最普通的实现方式,就是在redis里创建一个key来加锁。

语法:SET my:lock 随机值 NX PX 30000

用这个命令就ok,这个NX的意思就是只有key不存在的时候才会设置成功,PX 30000的意思是30秒后锁自动释放。别人创建的时候如果发现已经有了就不能加锁了。

释放锁就是删除key,但是一般可以用lua脚本删除,判断value一样才删除。

如:

if redis.call("get",KEYS[1]) == ARGV[1] then

return redis.call("del",KEYS[1])

else

return 0

end

为啥要用随机值呢?

因为如果某个客户端获取到了锁,但是阻塞了很长时间才执行完,此时可能已经自动释放锁了,此时可能别的客户端已经获取到了这个锁,要是你这个时候直接删除key的话会有问题,所以得用随机值加lua脚本来释放锁。

但是这样是肯定不行的。因为如果是普通的redis单实例,那就是单点故障。或者是redis普通主从,那redis主从异步复制,如果主节点挂了,key还没同步到从节点,此时从节点切换为主节点,别人就会拿到锁。

(2)RedLock算法有效防止单点故障

这个场景是假设有一个redis cluster,有5个redis master实例。然后执行如下步骤获取一把锁:

1)获取当前时间戳,单位是毫秒。

2)跟上面类似,轮流尝试在每个master节点上创建锁,过期时间较短,一般就几十毫秒。

3)尝试在大多数节点上建立一个锁,比如5个节点就要求是3个节点(n / 2 +1)。

4)客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了。

5)要是锁建立失败了,那么就依次删除这个锁。

6)只要别人建立了一把分布式锁,你就得不断轮询去尝试获取锁。

(3)集成redisson,用redisson的api进行操作

代码原理就是基于lua脚本加监听机制(watchdog监听)来实现的,就不用文字描述了,以下流程是看源码所画,如下,按序号进行查看,虚线为备注:


redisson的实现RedLock的方式,如下:



关于redisson的更多锁实现方式及如果看不清楚,可私信我获取。

2、redis分布式锁和zk分布式锁的对比

redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。

zk分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小

另外一点就是,如果是redis获取锁的那个客户端出bug了或者挂了,那么只能等待超时时间之后才能释放锁;而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁。

至于ZK的加锁方式,后面会进行分享。

3、缓存穿透

正常情况下,我们去查询数据都是存在的。那么请求去查询一条压根数据库中根本就不存在的数据,也就是说缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。这种查询不存在数据的现象我们称为缓存穿透

解决办法:

1、那么我们就可以为这些key 设置的值设置为null ,并且设置过期时间丢到缓存里面去。后面再出现查询这个key 的请求的时候,直接返回null ,就不用在到数据库中。但这种可能会存在空间的浪费。

2、采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的BitSet中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查询压力。

布隆过滤器

布隆过滤器是Burton Howard Bloom在1970年提出来的,一种空间效率极高的概率型算法和数据结构,主要用来判断一个元素是否在集合中存在。因为他是一个概率型的算法,所以会存在一定的误差,如果传入一个值去布隆过滤器中检索,可能会出现检测存在的结果但是实际上可能是不存在的,但是肯定不会出现实际上不存在然后反馈存在的结果。因此,Bloom Filter不适合那些"零错误"的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter 通过极少的错误换取了存储空间的极大节省。

bitmap

所谓的Bit-map就是用一个bit位来标记某个元素对应的Value,通过Bit为单位来存储数据,可以大大节省存储空间。

所以我们可以通过一个int型的整数的32比特位来存储32个10进制的数字,那么这样所带来的好处是内存占用少、效率很高(不需要比较和位移)比如我们要存储5(101)、3(11)四个数字,那么我们申请int型的内存空间,会有32个比特位。这四个数字的二进制分别对应从右往左开始数,比如第一个数字是5,对应的二进制数据是101, 那么从右往左数到第5位,把对应的二进制数据存储到32个比特位上。


第一个5就是 00000000000000000000000000101000

输入3时候 00000000000000000000000000001100


布隆过滤器原理

有了对位图的理解以后,我们对布隆过滤器的原理理解就会更容易了,以40亿数据为案例,假设这40亿数据为某邮件服务器的黑名单数据,邮件服务需要根据邮箱地址来判断当前邮箱是否属于垃圾邮件。原理如下 :

假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候同样的方法将W通过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1则可以判断该元素一定不存在集合中反之,如果3个点都为1,则该元素可能存在集合中。


接下来按照该方法处理所有的输入对象,每个对象都可能把bitMap中一些白位置涂黑,也可能会遇到已经涂黑的位置,遇到已经为黑的让他继续为黑即可。处理完所有的输入对象之后,在bitMap中可能已经有相当多的位置已经被涂黑。至此,一个布隆过滤器生成完成,这个布隆过滤器代表之前所有输入对象组成的集合。

如何去判断一个元素是否存在bit array中呢? 原理是一样,根据k个哈希函数去得到的结果,如果所有的结果都是1,表示这个元素可能假设某个元素通过映射对应下标为4,5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都是1存在。 如果一旦发现其中一个比特位的元素是0,表示这个元素一定不存在。

至于k个哈希函数的取值为多少,能够最大化地降低错误率(因为哈希函数越多,映射冲突会越少),这个地方就会涉及到最优的哈希函数个数的一个算法逻辑。

4、缓存击穿

缓存击穿是在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key 正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们成为击穿。会造成某一时刻数据库请求量过大,压力剧增。

如何解决

上面的现象是多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个互斥锁(同一个客户端可有用双简锁的方式来实现,如集群方试,可用分布式锁)来锁住它。其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。

5、缓存雪崩

缓存雪崩是在用缓存的情况下,当某一时刻发生大规模的缓存失效的情况。比如你的缓存服务过期或宕机了,会有大量的请求进来直接打到DB上面。结果就是DB 撑不住挂掉。

解决办法

事前:使用集群缓存,保证缓存服务的高可用。

事中:使用 ehcache 本地缓存 + Hystrix 限流&降级 ,避免 MySQL 被打死的情况发生。

事后:开启 Redis 持久化机制,尽快恢复缓存集群。

1. 对缓存的访问,如果发现从缓存中取不到值,那么通过加锁或者队列的方式保证缓存的单进程操作,从而避免失效时并发请求全部落到底层的存储系统上;但是这种方式会带来性能上的损耗。

2. 将缓存失效的时间分散,降低每一个缓存过期时间的重复率。

3. 如果是因为缓存服务器故障导致的问题,一方面需要保证缓存服务器的高可用、另一方面,应用程序中可以采用多级缓存。

热点数据集中失效问题怎么解决

我们在设置缓存的时候,一般会给缓存设置一个失效时间,过了这个时间,缓存就失效了。对于一些热点的数据来说,当缓存失效以后会存在大量的请求过来,然后打到数据库去,从而可能导致数据库崩溃的情况。

解决办法:

设置不同的失效时间或加互斥锁。

相关推荐

外贸独立站卡成PPT?你可能用错了对象缓存!

最近帮一个上海的电子元器件客户优化网站,发现他的WooCommerce后台操作要等5秒才能响应——查了下服务器日志,MySQL查询每秒炸出200+次!原来他的"高性能"主机根本没用对象...

搭建N8N

一、概述n8n是一款强大的工作流自动化工具,它允许用户通过可视化界面创建自动化工作流,无需编写复杂代码。作为一个开源的自动化平台,N8N支持连接各种服务和应用程序,实现数据流转和任务自动化。核心特点...

性能优化!7个策略,让Spring Boot 处理每秒百万请求

首先,我需要确定这个问题的背景。可能用户是在处理高并发的系统,或者正在设计一个需要应对大流量的应用。他们的身份可能是后端开发工程师,或者是系统架构师,对性能优化有较高需求。接下来,我要想,处理百万级的...

定时任务优化总结(从半个小时优化到秒级)

整体优化思路:1.按需查询、2.分小批次游标查询、3.JED场景下按数据库分片分组更新、4.精准定位要处理的数据、5.负载均衡业务背景:站外广告投放平台在做推广管理状态优化重构的时候,引入了...

跨境电商建站隐藏技巧:Redis缓存,让站点“记住”用户更高效

用户登录后,每次刷新页面都要重新验证身份,有时候还会出现“会话丢失”,用户不得不重新登录,体验很差找我们帮忙后,我们建议用Redis缓存会话数据。简单来说,Redis就像站点的“临时记事本”,用户登...

服务架构性能优化与Java实现

服务架构性能优化大全(附Java代码实现)一、缓存核心思想:将高频访问数据存储在高速存储中,减少慢速存储(如数据库)访问场景:读多写少的数据(用户信息、配置数据)Java实现:使用Caffeine缓存...

百万并发不是梦!Nginx高并发优化配置与性能调优全解

Nginx的最大转发能力受硬件、配置和系统参数影响,处理超高并发请求时需多维度优化和扩展。以下是具体分析和解决方案:一、Nginx最大转发能力的关键因素硬件资源CPU:Nginx依赖多核CPU,...

面试官:工作中优化MySQL的手段有哪些?

MySQL是面试中必问的模块,而MySQL中的优化内容又是常见的面试题,所以本文来看“工作中优化MySQL的手段有哪些?”。工作中常见的MySQL优化手段分为以下五大类:索引优化:确保高频查...

万字长文|RAG优化全攻略:微服务部署+动态权重策略,代码级详解

本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在官网-聚客AI学院大模型应用开发微调项目实践课程学习平台从理论到实践,全面解析RAG性能瓶颈与高阶优化方案。一、RAG核心架...

在Windows环境下,本地部署和启动开源项目Ragflow的源代码

在当前AI领域中,基于检索增强生成(RAG)的应用备受关注,而开源项目RAGFlow因其灵活性和功能性成为了一个热门选择。不过,由于其快速的版本迭代,可能会存在一些Bug,并且在实际项目落地时通常需要...

这款 .NET 9 + React 后台权限管理系统太强了!支持多租户、按钮权限(简单易用且文档齐全)

前言在数字化转型浪潮中,高效且安全的权限管理是后台系统的核心基石。传统方案或依赖臃肿的三方框架,或难以满足细粒度权限需求。今天推荐一款完全独立开发、基于前沿技术栈开发的RBAC权限系统。它摒弃了现成A...

开源声明:只是一个随便写写的管理系统(认真脸)

最近微信公众号和技术博客都断更了,最近2了两周时间撸了一套管理系统的脚手架。原因是因为最近项目需要用到,但是找了一圈Github或者Gitee,基本都不合适。要么有前端,配套后端是Node而...

「第七期」深信服go实习一面二面HR面

一面面试时长:1h自我介绍channel知识点协程goroutinemysql的两种存储引擎InnoDB索引redis使用单线程还是多线程?有多少个库?redis持久化有哪些?各自优势?谁更常用?P...

Go中使用sync.Map实现线程安全的缓存

不依赖外部库,在Go中实现自己的线程安全缓存照片来源:PossessedPhotography在Unsplash缓存是优化现代应用程序性能的关键方面。它允许您存储并快速检索昂贵操作的结果或经常访...

Redis中RedisTemplate 和 StringRedisTemplate

前言:RedisTemplate和StringRedisTemplate都是Spring提供的操作Redis的模板类,但它们之间在序列化方式和使用场景上有显著区别。序列化方式不同Redi...

取消回复欢迎 发表评论: