当前位置: 首页 > news >正文

Review --- Redis

Redis

在这里插入图片描述

redis是什么?

Redis是一个开源的,使用C语言编写的,支持网络交互的,key-value数据结构存储系统,支持多种语言的一种非关系型数据库,它可以用作数据库(存储一些简单的数据,例如新闻点赞量),**缓存(秒杀的商品数量信息)**和消息中间件(两个项目间交换数据)

mysql在硬盘上存储数据:客户端不断刷新会攻击mysql,redis缓存则可以抵挡,同一请求不断刷新时就从redis读取数据返回给客户端,不跟mysql进行交互

Redis特点

  1. Redis 将数据存储在内存中,也支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
  2. 性能极高 , Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s 。
  3. Redis 供 list,set,zset,hash 等数据结构的存储来进行存储数据。
  4. 原子 – Redis 的所有操作都是原子性的,同时 Redis 还支持对几个操作全并后的原子性执行。
  5. Redis 分布式集群化扩展性极,高即 master-slave(主-从)模式。

为什么使用Redis?

​ 随着 web3.0(支持大量用户使用添加,全民参与,例如头条、抖音 用户量很大,大量用户来连接数据库 【链接太多,IO瓶颈】 为了缓解关系型数据库的压力,可以将数据暂时存储在redis中,甚至有些数据直接存储在redis中,从而实现对关系型数据库的保护) 的时代到来,传统的关系型数据库在大量的访问压力出现了一些性能问题,如连接数量问题,IO瓶颈问题等,此时需要使用redis对部分数据进行缓存,或者将某些数据直接存储在 redis 中,以减少对关系型数据库的访问压力.

当然 redis 数据库也是不能完全替代关系型数据库的,他们是相互依赖的.

Redis安装(通过docker)

在这里插入图片描述

在这里插入图片描述

Redis中的五种数据存储结构(值)

redis中键都是string类型的,没有其它数据结构

五种数据结构:

  1. String:redis最基本类型,单值存储(存一个具体值,也可以存储一个java中的对象,对象是被序列化为json格式的字符串)一个值最大存储512MB

    ​ 计数器:

    ​ set news_views 0

    ​ incr news_views (+1)

    ​ decr news_views (-1)

    ​ get news_views (获得值)

  2. Hash: 是一个string类型的属性和值的映射表,hash特别适合存储对象

    新闻点赞

    新闻收藏

    hset key 属性 值

    hget key 属性

    hdel key 属性

    hlen key

    hgetall key 返回key下所有属性值

  3. List(列表):Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 有添加顺序

    lpush list名 值

    rpush list名 值

    rpop list名

    lpop list名

    lrange list名 start stop(索引从0开始)

  4. Set(集合):Redis 的 Set 是无序集合。

    sadd set名 值

    srem set名

    smembers set名 (查看指定set名下所有的元素)

    scard set名(查看指定set下元素个数)

  5. zset(有序集合):有排序

    zadd key 分数 值

    zrem key 值

    zscore key 值(返回值的分数)

    zcard key(查看key下元素个数)

java程序连接redis

  1. 使用官方提供的Jedis类实现连接

    通过Jedis对象调用各种方法

  2. 使用springboot对jedis的封装实现

    1. 管理连接redis对象,提供数据库连接池功能
    2. 针对每种数据结构分别封装不同的实现类
    3. 事务(跳过)
    4. 提供了对键值序列化,反序列化操作
  3. 具体搭建

Redis缓存(穿透、击穿、雪崩)

1.**缓存穿透:**请求访问不存在的数据,redis查不到就请求直接落在了mysql数据库上了,mysql查不到数据,就没给缓存同步数据,大量访问不存在数据的请求直接落在数据库上,数据库可能崩溃宕机。
解决方法:1)每次mysql根据id查出空值也同步到缓存,这样该请求再次过来就会落在redis而不对数据库进行操作

​ 2)缓存预热时候,启动布隆过滤器,客户端请求过来后先到布隆过滤器,如果该数据存在就将该请求传到缓存,不存在就直接返回
在这里插入图片描述

布隆过滤器依赖于位图(bitmap)

在这里插入图片描述

2.**缓存击穿:**一个热点key过期了,恰巧这时候有大量请求过来请求这个数据,由于key过期了,大量请求直接落在了mysql数据库上,有可能导致mysql宕机罢工

解决方法:1)逻辑过期,将热点key创建时候设置为永不过期,设置一个过期时间字段,确保数据就算过期了也可以查询到.一个请求过来查询数据发现过期了,则开启一个线程并获加锁到数据库重新查询数据 重置缓存.在这个重置缓存过程中 第一个请求会接受过期数据.如果这个时候另一个请求过来也查询这个数据,那么它会获取锁失败,然后直接返回现在的缓存数据

​ 2)给查询方法加互斥锁,发现数据过期时,启动重置缓存方法并获取锁,这个时候其他线程查询这个数据时候,获取锁失败,休眠一会,继续查询缓存中是否存在该数据,直至缓存重置线程完

3.缓存雪崩: 同一时间大量热点key过期了/Redis服务宕机,所有热点key的请求落在了数据库,数据库可能宕机

解决方法: 1)针对第一种情况在原有设置过期时间上再随机加一个过期时间;

​ 2)针对第二种情况 :

  • 利用redis集群提高服务的可用性,比如哨兵模式、集群模式.
  • 在设计这个业务系统时候添加降级限流策略,如nginx或者微服务项目的话使用spring cloud gateway网关中设置限流的规则.
  • 给业务添加多级缓存,一级使用Guava或Caffeine,二级使用redis缓存

降级限流可作为系统的保底策略,适用于缓存穿透、缓存击穿、缓存雪崩

双写一致性

概念:当修改了数据库数据后,要更改缓存数据,确保数据库和缓存数据一致

读操作: 缓存命中,直接返回;缓存未命中查询数据库数据,写入缓存,设置超时时间

写操作: 延时双删(先删除缓存还是先修改数据库都会出现问题),所以采用删除两次缓存,延时是因为数据库是主从模式,数据从主节点同步到从节点需要时间.

一般放入缓存中的数据都是读多写少,写多读少的话直接操作数据库

1.一致性要求高的

1)互斥锁

2)共享锁readLock(读读不互斥,写互斥)和排他锁(读写、读读都互斥)writeLock也叫独占锁,加锁之后阻塞其它线程读写操作,避免其它线程读脏数据

2.允许延迟一致(短暂的不一致)

1)使用MQ异步通知保证数据的最终一致性,需要保证MQ的可靠性.更新数据之后,通知缓存删除

2)利用canal(监听MySQL的binlog),基于mysql的主从进行实现.不需要修改业务代码,伪装为mysql的一个从节点,canal通过读取binlog数据更新缓存


在这里插入图片描述

Redis持久化存储

RDB和AOF

在这里插入图片描述

一、RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照.简单来说就是把内存中的所有数据都记录到磁盘中.当Redis实例故障重启后,从磁盘读取快照,恢复数据

save #由Redis主进程来执行RDB,会阻塞所有命令

bgsave #开启子进程执行RDB,来避免主进程收到影响

Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:

#900秒内,囡至少一个key被修改,则执行basave

save 900 1

save 300 1

save 60 10000

RDB的执行原理是什么?

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据.完成fork后读取内存数据并入RDB文件

如果子进程在持久化数据时候,主进程也在对数据进行操作,可能会出现脏数据的问题,实际上fork主进程得到子进程中,fork采用的是copy-on-write技术:

​ 当主进程执行读操作时,访问共享内存;

​ 当主进程执行写操作时,则会拷贝一份数据,执行操作后再进行数据替换

​ (fork时候会把共享数据标记为read-only)

二、AOF全称为Append Only File(追加文件). Redis处理的每一个写命令都会记录在AOF文件中,可以看作是命令日志文件.

AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:

#是否开启AOF功能,默认是no

appendonly yes

#AOF文件的名称

appendfilename “appendonly.aof”

在这里插入图片描述

AOF因为是记录命令,AOF文件会比RDB文件大得多.而且AOF会记录对同一个key的多次写操作,但是只有最后一次写操作才有意义.通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果

在这里插入图片描述

Redis的数据过期策略

Redis的key过期后,会立即删除吗?

惰性删除:key过期后不管,访问key的时候,判断key是否过期,过期则删除 反之则返回key对应的value

定期删除:定期检查一定量的key是否过期(SLOW模式+FAST模式)

  • SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf的hz选项来调整这个次数

  • FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms

​ 优点:可以通过限制删除操作执行的时长和频率来减少删除操作对CPU的影响.另外定期删除,也能有效释放过期键占用的内存.

​ 缺点:难以确定删除操作执行的时长和频率.

Redis的过期删除策略:惰性删除+定期删除两种数据过期策略配合使用

Redis的数据淘汰策略

假如缓存过多,内存是有限的,内存被占满了怎么办?

数据的淘汰策略: 当Redis中的内存不够用时, 此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略

Redis中支持8种不同策略来选择要删除的key:

  • noeviction: 不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略.
  • volatile-ttl: 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰
  • allkeys-random: 对全体key,随机进行淘汰
  • volatile-random: 对设置了TTL的key, 随机进行淘汰.
  • allkeys-lru: 对全体key, 基于LRU算法进行淘汰
  • volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰
  • allkeys-lfu: 对全体key,基于LFU算法进行淘汰
  • volatile-lfu: 对设置了TTL的key,基于LFU算法进行淘汰

LRU(Least Recently Used) 最近最少使用. 用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高.

LFU(Least Frequently Used) 最少频率使用. 会统计每个key的访问频率,值越小淘汰优先级越高.

Redis分布式锁,是如何实现的?

需要结合项目中的业务进行回答,通常情况下,分布式锁使用的场景:

集群情况下的定时任务、抢单、幂等性场景

抢券场景:

​ 单体情况

在这里插入图片描述

​ 只适用于单体项目这样写

​ 集群部署

在这里插入图片描述

synchronized锁是服务本地的锁,属于jvm,每个微服务都有一个自己的jvm

服务集群情况下就不能使用本地锁解决,只能用外部锁(分布式锁)解决并发

Redis分布式锁

Redis实现分布式锁主要利用Redis的setnx命令. sentx是SET if not exits (如果不存在,则SET)的简写.

  • ​ 获取锁:

获取锁的过程需要满足以下条件:

  1. 锁的键不存在时才能成功设置锁。
  2. 设置锁时需要指定一个唯一的值(通常是客户端的唯一标识),以避免误删其他客户端的锁。
  3. 设置锁的同时需要指定一个超时时间,防止死锁(例如某个客户端在持有锁后崩溃(服务器宕机),无法释放锁)。

​ # 添加锁,lock_key: 锁的键名,用于标识锁。unique_value: 锁的值,通常是一个唯一的标识符(如客户端 ID 或 UUID),用于区分不同的客户端。 NX是互斥 表示只有当键不存在时才设置键, EX是设置超时时间

​ SET lock_key unique_value NX EX 10 (过期时间单位为秒)

  • ​ 释放锁:

释放锁时需要注意以下几点:

  1. 只有持有锁的客户端才能释放锁。
  2. 为了避免误删其他客户端的锁,释放锁时需要检查锁的值是否与当前客户端的唯一标识匹配。
  3. 使用 Lua 脚本可以保证操作的原子性。

​ # 释放锁,删除即可

​ DEL lock_key

redisson实现的分布式锁-执行流程

在这里插入图片描述

线程二有等待阈值,一般达不到

在这里插入图片描述

redisson实现的分布式锁-可重入

同一个线程才可以重入,不是同一个线程互斥

在这里插入图片描述

redisson实现的分布式锁-主从一致性

在这里插入图片描述

Redis整体思想是AP思想,优先考虑高可用性.

有些业务必须要强一致性则采用CP思想的zookeeper

在这里插入图片描述

Redis集群方案

  • 主从复制
  • 哨兵模式
  • 分片集群

在这里插入图片描述

主从复制

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离

一般都是一主多从,主节点负责写数据,从节点负责读数据

在这里插入图片描述

主从数据同步原理
  • 主从全量同步:

在这里插入图片描述

  • 主从增量同步:

在这里插入图片描述

哨兵的作用

Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:

在这里插入图片描述

服务状态监控

Sentinel基于心跳机制监测服务状态,每隔一秒向集群的每个实例发送ping命令:

  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。

在这里插入图片描述

Redis集群(哨兵模式)脑裂

在这里插入图片描述
在这里插入图片描述

分片集群结构

主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:

  • 海量数据存储问题
  • 高并发写的问题

使用分片集群可以解决上述问题,分片集群特征:

  • 集群中有多个master,每个master保存不同数据
  • 每个master都可以有多个slave节点
  • master之间通过ping监测彼此健康状态
  • 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
    在这里插入图片描述
分片集群结构-数据读写

​ Redis分片集群引入了哈希槽的概念,Redis集群有16384个哈希槽,将16384个插槽分配到不同的实例。每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。

​ 根据key的有效部分计算哈希值,对16384取余(有效部分,如果key前面有大括号,大括号的内容就是有效部分,如果没有,则以key本身作为有效部分)余数作为插槽,寻找插槽所在的实例。

Redis是单线程的,为什么还那么快?

  • Redis是纯内存操作,执行速度非常快
  • 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题
  • 使用I/O多路复用模型,非阻塞IO

可以解释下I/O多路复用模型?

Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,I/O多路复用模型主要就是实现了高效的网络请求
在这里插入图片描述

在这里插入图片描述
可以看到,非阻塞IO模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高。而且忙等机制会导致CPU空转,CPU使用率暴增。

在这里插入图片描述
在这里插入图片描述

http://www.xdnf.cn/news/317827.html

相关文章:

  • 金融企业如何借力运维监控强化合规性建设?
  • 【hot100】bug指南记录1
  • Qt界面设计时窗口中各控件布局及自适应方法
  • [250507] 小米发布首个推理模型 MiMo,70亿参数展现卓越性能
  • 使用 Java 11 的 HttpClient 处理 RESTful Web 服务
  • 【Linux】Linux环境基础开发工具
  • 精益数据分析(46/126):深入剖析用户生成内容(UGC)商业模式
  • 并发设计模式实战系列(17):信号量(Semaphore)
  • 解构与重构:自动化测试框架的进阶认知之旅
  • Spring Boot 为 MongoDB 自动配置了哪些核心 Bean?
  • Make:独立创造者手册——从0到1的商业自由之路
  • 任意文件读取漏洞
  • 阿里联合北大开源数字人项目FantasyTalking,输出内容更加动态化~
  • HarmonyOS Next~HarmonyOS应用测试全流程解析:从一级类目上架到二级类目专项测试
  • 游戏引擎学习第262天:绘制多帧性能分析图
  • 标量/向量/矩阵/张量/范数详解及其在机器学习中的应用
  • MCP 入门指南
  • Kubernetes生产环境实战:深度排查Pod内存溢出(OOM)问题指南
  • 优选算法系列(8.多源BFS)
  • Vue3响应式:effect作用域
  • linux命令>/dev/null 2>1的含义
  • 【北京迅为】iTOP-4412精英版使用手册-第七章 Android 4.0/Linux源码编译
  • 在 Vue 2 中使用 qrcode 库生成二维码
  • Python 识别图片上标点位置
  • CSDN文章都是VIP
  • Ubuntu 使用dotfiles个性化配置模板
  • 使用 Apache POI 生成包含文本和图片的 Word 文档
  • 【MCP】从0到1实现一个MCP Client
  • 【Python类(Class)完全指南】面向对象编程入门
  • 阿里云服务器-centos部署定时同步数据库数据-dbswitch