首页 > 数据库 >速通Redis

速通Redis

时间:2024-08-18 18:07:32浏览次数:11  
标签:缓存 速通 redis Redis master key 线程 节点

redis问题总结

缓存问题:

1.缓存穿透

查询一个不存在的数据,MySQL中也查询不到而且也写不进缓存,就导致每次请求都查询数据库

解决方案

  • 缓存空数据,查询返回数据为空时把空结果缓存:缺点是内存开销变大
  • 布隆过滤器:通过哈希检测一个元素是否存在于集合中:在缓存预热时同时预热过滤器,将传进来的key通过相应的hash将数据存入bitmap中,在查询时使用相同的hash查看对应位置。缺点是可能会存在误判的情况。

2.缓存击穿

热点key突然失效,大量并发请求过来瞬间压垮DB

解决方案

  • 互斥锁:查询未命中会建立互斥锁,然后再写入缓存,写期间其他线程不可以抢夺锁,需要等待,完成后释放锁。其他线程等待休眠重试(强一致性,低可用性)
  • 逻辑过期:热点key不设置实际过期时间,但设置逻辑过期时间。当key逻辑过期后,第一个请求会获取互斥锁,新开辟一个线程来重写缓存并重置过期时间。重写过程中原线程会直接返回过期数据,其他线程请求时,由于获取互斥锁失败,也会直接返回过期数据。当写缓存线程完成时会释放互斥锁,这时其他线程可正常访问(高可用,性能好)

3.缓存雪崩

同一时段内大量key同时失效,或者redis宕机了,导致请求都打在DB上

解决方案

给不同key的ttl设随机值

设计redis集群:哨兵模式集群模式

给缓存添加降级限流策略

添加多级缓存

4.双写一致性(这里要根据简历上的业务来选择一致性再选择下列方案)

强一致性:

  • 写操作采用延迟双删:删除缓存------>修改数据库------>(延时)-------->删除缓存:在高并发的情况下,不论是先删数据库还是先删缓存都会出现脏数据。延时双删能有效控制脏数据产生的问题
  • 采用分布式锁:redisson提供了读写锁,在写操作的时候上写锁

最终一致性:

  • 采用异步通知
  • 通过阿里的canal

5.持久化

RDB,就是把内存中的所有数据都记录在磁盘中。采用bgsave命令,使用子进程异步完成

AOF,记录每一次执行命令,相对于RDB记录较为,但是磁盘空间占的多,数据安全性更高

6.数据过期策略

惰性删除:访问key的时候再看是否过期,如果过期就删除

定期删除:定期检查一定量key是否过期(分为fast和slow两种,fast频率不固定,耗时和间隔都极短;slow则是定时任务,具有默认频率)一般情况下是使用fast+slow模式

7.数据淘汰策略

默认是不淘汰任何key,但是内存满了之后不会允许新数据写入。allkeys / volatile-lru 对所有key/有ttl的key基于LRU淘汰,allkeys / volatile-lfu 对所有key/有ttl的key基于LFU淘汰

 

分布式锁问题:

传统的synchronized只能管控当前进程,一旦进入分布式集群就会容易失效;分布式锁的解决了这个问题

  • setnx:(set if not exists)获取锁:SET lock value NX EX 10(NX:只有不存在的时候才可以set,EX为过期时间);释放锁:del lock。
    • 为什么要加过期时间:防止死锁(业务超时或者服务宕机)
    • 为什么要用一条指令而不是setnx+过期时间:为了保证原子性
    • 锁的有效时长如何控制:1.根据业务评估锁的时间(较难)2.给锁续期(需要新开一个线程,比较麻烦)
  • redisson:通过setnx加锁,另开一个线程watchdog进行监控,他会不断监控锁给锁续期。当释放锁的时候也会通知watchdog,告诉他锁释放了。当新线程企图获取锁时,他会一直while循环等待锁释放再加锁,不过循环也是有阈值的
    • 如何使用redisson:
      • 通过RLock lock=redissonClient.getLock("key")获取锁
      • 通过boolean isLock=lock.tryLock("等待时间","失效时间","时间的单位")     (如果这里不传任何值,那么就默认用watchdog续期)
      • isLock为true的时候就是锁获取成功了
      • 注意:这里的加锁,过期时间都是通过lua脚本实现的,使用lua脚本是为了保持原子性
    • redisson支持在同一个线程内可重入锁(锁里还能再加相同的锁)
    • redisson的主从一致性:redisson通过红锁redlock实现了主从一致性,他要求至少要在n/2+1的节点上有创建锁。但是红锁性能差,运行复杂,官方都不建议使用。redis主要是基于AP思想,追求的是高可用;如果需要强一致性那么需要选择基于CP思想的zookeeper    

集群问题:

主从复制:提高读写性能。主负责写操作,从负责读操作:读写分离。一般情况下1主1从+哨兵集群就够用了

  • 如何保证数据同步:两个前提概念:replication_id:master有唯一的replicationId,而slave会复制master的id,因此同一个集群的ID肯定是一样的,offset:偏移量
    • 全量同步(第一次请求,replicationID不一致):从节点执行replicaof与主节点建立连接,如果是第一次同步则返回主节点版本信息,此时主节点执行bgsave将生成的rdb发送给从节点,从节点删除本地数据后加载rdb。执行期间的命令主节点也会打包成日志,发送给从节点执行。
    • 增量同步(非第一次请求,携带的replicationID一致):从节点重启或数据变化会发生增量同步:携带replication和offset,只有在replicationId一致的时候才会继续。在repl_baklog取出offset后的数据,发送命令让从节点执行

哨兵模式:保证主从集群的高可用,实现集群的自动恢复并且会给客户端实时推送故障转移的消息

  • sentinel通过redis的pingpong来对节点进行主观下线检测,如果超过配置数量的redis都检测不到对应节点,那就是客观下线,说明redis挂了
  • 恢复:判断主从节点断开的时长,超过指定值则排除该节点;判断从节点的slave-priority,值越小优先级越高,相同的则判断offset,越大优先级越高;最后是判断slave的运行id,越小优先级越高
  • 脑裂:master,slave,sentinel处于不同的网络分区:主节点没挂,还能正常用;但是由于网络问题被sentinel判定为挂了,这时会出现两个master并且数据依旧会写入老master。当网络恢复后,老master会成为slave,由于主从复制,新写入的数据会全部丢失(被新master里的旧数据覆盖了)
  • 有两个配置可以解决该问题:
    • min-replicas-to-writes 1 #表示至少要有一个slave,master才能写
    • min-replicas-max-lag 5 #表示数据复制和同步延时不能超过5秒

集群模式:

  • 海量数据存储与高并发写:集群中有多个master,每个master可以有多个slave,master互为sentinel监测是否存活
  • 通过引入哈希槽的概念,每个节点负责一部分哈希,对应的key通过计算hash值后会放入对应的master

 

redis为什么这么快:

1.redis是纯内存操作

2.采用单线程,避免了上下文切换,而且不用考虑线程安全问题

3.使用I/O多路复用模型+事件派发

redis的性能瓶颈不在于执行速度,而是网络延迟,而IO多路复用模型主要是实现了高效的网络请求

 

用户空间和内核空间:用户空间:只能执行部分命令; 内核空间:执行特权命令,调用一切系统资源。

三种常见的IO模型

  • 阻塞IO模型(BIO):
    • 一阶段:用户进程尝试读取数据,数据尚未到达内核需要阻塞等待
    • 二阶段:数据到达并拷贝到内核缓冲区,内核缓冲区再拷贝到用户缓冲区,拷贝完成后进程才会停止阻塞,处理数据
  • 非阻塞IO模型(NIO):
    • 一阶段:用户进程尝试读取数据,数据尚未到达内核,会直接给用户返回异常,用户会开启轮询
    • 二阶段:内核数据拷贝到用户缓冲区,拷贝完成后进程停止阻塞,处理数据
    • 第一阶段虽然是非阻塞的,但是由于忙等机制会使CPU使用率暴增
  • IO多路复用模型:
    • 利用单线程监听多个socket,在某个socket可读可写时通知,避免无效等待。
    • 其中select和poll模式只会通知用户进程有socket就绪,需要用户进程逐个遍历socket来确认;而epoll会在通知的同时把已就绪的socket写入用户空间,下面以select为例
      • 一阶段:用户进程调用select,指定要监听的socket集合,有socket数据就绪即返回readable,此过程中用户进程阻塞;
      • 二阶段:用户找到就绪的socket,依次调用revcvfrom读取数据,内核将数据拷贝至用户空间

 

事件派发:

redis中提供了多个事件处理器,处理器分别用于实现不同的网络通信请求。

最经典的三个是:

  • 连接应答处理器(处理客户端请求应答)
  • 命令回复处理器(处理客户端响应)
  • 命令请求处理器(接收数据,把数据转为redis命令,再把结果写入缓冲队列,再通过命令回复处理器处理客户端响应)

redis6.0引入了多线程,为了命令回复处理器以及命令请求处理器的解析部分添加了多线程。

标签:缓存,速通,redis,Redis,master,key,线程,节点
From: https://www.cnblogs.com/kun1790051360/p/18348926

相关文章

  • 基于SpringBoot3框架-数据库乐观锁、悲观锁、Redis、Zookeeper分布式锁的简单案例实现
    1.分布式锁的定义分布式锁是一种在分布式系统中用来协调多个进程或线程对共享资源进行访问的机制。它确保在分布式环境下,多个节点(如不同的服务器或进程)不会同时访问同一个共享资源,从而避免数据不一致、资源竞争等问题。2.分布式锁的工作原理分布式锁的工作原理与单机锁......
  • Java面试题———Redis篇①
    目录1、项目中为什么用Redis2、Redis的数据类型有哪些3、Redis为什么这么快4、Redis的过期删除策略有哪些5、Redis的内存淘汰策略有哪些6、Redis的RDB和AOF区别7、RDB期间可以同时处理写请求吗8、Redis集群有哪些方案1、项目中为什么用Redis我们项目中之所以选择R......
  • Redis可视化工具Redis: Desktop Manager for mac
    RedisDesktopManager是一款适用于MacOSX、Windows和Linux的跨平台Redis数据库管理工具。它具有以下功能特色:Redis可视化工具中文激活版下载地址直观易用:提供了一个易于使用的图形用户界面(GUI),方便用户查看、编辑和管理Redis数据库中的数据。支持大数据库:即便Red......
  • Redis实现分布式锁
    Redis分布式锁是一种在分布式系统中协调多个进程对共享资源访问的同步机制。在单机系统中,可以使用传统的锁机制来保证同一时间只有一个线程访问某个资源。然而,在分布式系统中,由于多个进程可能在不同的服务器上运行,传统的锁机制就不再适用。这时就需要一种跨多个进程的锁机制,即......
  • [Redis]缓存穿透/缓存击穿/缓存雪崩
    缓存穿透用户访问一些不存在的数据,redis没有,于是去mysql查询也没有,这样就发生了两次无效的查询。缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,缓存永远不会生效。这样,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的......
  • [Redis]延迟消息队列
    延迟消息队列redis数据结构,用什么结构实现延迟消息队列延迟消息队列是一种消息队列系统,它允许消息的发布者在消息发送时指定消息的投递时间,使消息在未来的某个预定时间点被消费者接收。这种机制对于需要在稍后执行的任务或具有特定延迟需求的应用非常有用。对于实现延迟消息队......
  • Redis中Big Key该如何解决?
    目录1、BigKey的产生2、BigKey场景分析3、BigKey的危害4、检测BigKey 5、解决BigKey问题BigKey拆分(1)按时间/业务拆分(2)按哈希(Hash)拆分(3)按前缀树拆分BigKey定期清理Bigkey压缩BigKey批处理优化持久化配置6、总结 BigKey问题是指某个键(key)的值(value)......
  • Redis 数据类型详解
    Redis是一个开源的内存数据结构存储系统,广泛应用于缓存、消息队列、实时数据分析等场景。Redis提供了多种数据类型,本文将详细介绍Redis的五种主要数据类型及其应用场景,并从概述、基本操作、应用场景和数据结构等方面进行深入探讨。1.字符串(String)概述字符串是Redis......
  • Redis中Set数据类型常用命令
    目录1.添加元素2.移除元素3.检查成员是否存在4.获取集合成员5.获取集合成员数量6.随机获取集合中的一个成员7.集合运算8.集合的移值9.提供集合的随机元素在Redis中,Set是一种无序且不重复的字符串集合。1.添加元素SADDkeymember[member...]:向集......
  • Redis中Sorted Set数据类型常用命令
    目录1.添加元素2.获取成员3.获取成员的分数4.删除元素5.获取集合的大小6.获取成员的排名7.按分数范围获取成员8.按排名范围获取成员9.增减分数10.删除指定分数范围的成员11.获取分数的范围在Redis中,SortedSet(有序集合)是一种重要的数据类型,它的每......