Redis 学习笔记(2)

目录

  • 1 Redis的持久化
    • 1.1 RDB持久化方案
    • 1.2 AOF持久化方案
  • 2 Redis架构
    • 2.1 主从复制架构
    • 2.2 哨兵集群设计
    • 2.3 哨兵集群设计
  • 3 Redis事务机制
  • 4 Redis过期策略与内存淘汰机制
    • 4.1 过期策略
    • 4.2 内存淘汰机制
  • 5 Redis高频面试题
    • 4.1 缓存穿透
    • 4.2 缓存击穿
    • 4.3 缓存雪崩

1 Redis的持久化


由于 redis 是一个内存数据库,所有的数据都是保存在内存当中的,内存当中的数据极易丢失,所以 redis 的数据持久化就显得尤为重要,在redis当中,提供了两种数据持久化的方式,分别为RDB以及AOF,且Redis默认开启的数据持久化方式为RDB方式。

1.1 RDB持久化方案


RDB方案是Redis默认的持久化方案。

  • 按照一定的时间内,如果Redis内存中的数据产生了一定次数的更新,就将整个Redis内存中的所有数据拍摄一个全量快照文件存储在硬盘上
  • 新的快照会覆盖老的快照文件,快照是全量快照,包含了内存中所有的内容,基本与内存一致。
  • 如果Redis故障重启,从硬盘的快照文件进行恢复。

在这里插入图片描述

RDB快照存储于Redis目录下datas文件夹下dump.rdb

触发条件

  • 手动触发:当执行某些命令时,会自动拍摄快照【一般不用】
    • save:手动触发拍摄RDB快照的,将内存的所有数据拍摄最新的快照
      • 前端运行
      • 阻塞所有的客户端请求,等待快照拍摄完成后,再继续处理客户端请求
      • 特点:快照与内存是一致的,数据不会丢失,用户的请求会被阻塞
    • bgsave:手动触发拍摄RDB快照的,将内存的所有数据拍摄最新的快照
      • 后台运行
      • 主进程会fork一个子进程负责拍摄快照,客户端可以正常请求,不会被阻塞
      • 特点:用户请求继续执行,用户的新增的更新数据不在快照中
    • shutdown:执行关闭服务端命令
    • flushall:清空,没有意义
  • 自动触发:按照一定的时间内发生的更新的次数,拍摄快照
    • 配置文件中有对应的配置,决定什么时候做快照
#Redis可以设置多组rdb条件,默认设置了三组,这三组共同交叉作用,满足任何一个都会拍摄快照
save 900 1
save 300 10
save 60 10000

为什么默认设置3组?如果只有一组策略,面向不同的写的场景,会导致数据丢失。针对不同读写速度,设置不同策略,进行交叉保存快照,满足各种情况下数据的保存策略。

总结:

  • 优点
    • rdb方式实现的是全量快照,快照文件中的数据与内存中的数据是一致的
    • 快照是二进制文件,生成快照加载快照都比较快,体积更小
    • Fork进程实现,性能更好
    • 总结:更快、更小、性能更好
  • 缺点
    • 存在一定概率导致部分数据丢失
  • 应用:希望有一个高性能的读写,不影响业务,允许一部分的数据存在一定概率的丢失【做缓存】,大规模的数据备份和恢复

1.2 AOF持久化方案


RDB存在一定概率的数据丢失,如何解决?

AOF方案

  • 按照一定的规则,将内存数据的操作日志追加写入一个文件中;
  • 当Redis发生故障,重启,从文件中进行读取所有的操作日志,恢复内存中的数据;
  • 重新对Redis进行执行,用于恢复内存中的数据。

在这里插入图片描述

追加的规则

  • appendfsync always
    • 每更新一条数据就同步将这个更新操作追加到文件中
    • 优点:数据会相对安全,几乎不会出现数据丢失的情况
    • 缺点:频繁的进行数据的追加,增大磁盘的IO,导致性能较差
  • appendfsync everysec(常用)
    • 每秒将一秒内Redis内存中数据的操作异步追加写入文件
    • 优点:在安全性和性能之间做了权衡,性能要比always高
    • 缺点:有数据丢失风险 ,但最多丢失1秒
  • appendfsync no
    • 交给操作系统来做,不由Redis控制
    • 肯定不用的

总结

  • 优点:安全性和性能做了折中方案,提供了灵活的机制,如果性能要求不高,安全性可以达到最高
  • 缺点
    • 这个文件是普通文本文件,相比于二进制文件来说,每次追加和加载比较慢
    • 数据的变化以追加的方式写入AOF文件
      • 问题:文件会不断变大,文件中会包含不必要的操作【过期的数据】
      • 解决:模拟类似于RDB做全量的方式,定期生成一次全量的AOF文件
  • 应用:数据持久化安全方案,理论上绝对性保证数据的安全

持久化方案:两种方案怎么选?

  • 两种方案都可以用:默认不配置AOF,使用的RDB
  • 问题:两种都用,重启Redis加载的是谁的数据?
    • 加载AOF

2 Redis架构


  • Redis的服务只有单台机器
  • 问题1:单点故障问题,如果Redis服务故障,整个Redis服务将不可用
    • 单点故障问题
  • 问题2:单台机器的内存比较小,数据存储的容量不足,会导致redis无法满足需求
    • 单机资源不足问题
  • 解决方案:分布式

2.1 主从复制架构


在这里插入图片描述

分布式主从架构

  • Master:主节点
    • 负责对外提供数据的读写
  • Slave:从节点
    • 负责对外提供的请求
    • 负责与主节点同步数据

特点:主从节点上的数据都是一致的,连接任何一个节点实现读,默认写操作只能连接主节点

优缺点:

  • 优点:实现了读写分离,分摊了读写的压力负载,如果一台Redis的Slave故障,其他的Redis服务节点照常对外提供服务
    • 解决了Redis单点故障问题
  • 缺点:如果Master故障,整个集群不能对外提供写的操作,Master没有HA机制
    • 带来了Master单点故障问题

2.2 哨兵集群设计


主从复制集群的Master存在单点故障问题,怎么解决?

  • 类似于ZK的设计
    • 每台节点存储的数据都是一样的
    • 如果Leader故障,允许Follower选举成为Leader

哨兵设计

  • 思想:基于主从复制模式之上封装了哨兵模式,如果Master出现故障,让Slave选举成为新的Master

  • 实现哨兵进程 实现

    • 必须能发现Master的故障
    • 必须负责重新选举新的Master

在这里插入图片描述

Redis主从架构

  • 哨兵进程
    • 每个哨兵负责监听所有Redis节点和其他哨兵
    • 为什么要监听所有Redis的节点:发现所有节点是否会出现故障
      • 如果Master出现故障,会进行投票选择一个Slave来成为新的Master
    • 为什么要监听别的哨兵:如果哨兵故障,不能让这个哨兵参与投票选举等

哨兵功能

  • 集群监控:监控节点状态
  • 消息通知:汇报节点状态
  • 故障转移:实现Master重新选举
  • 配置中心:实现配置同步

流程

  • step1:如果Master突然故障,有一个哨兵会发现这个问题,这个哨兵会立即通告给所有哨兵
    • 主观性故障【sdown】
  • step2:当有一定的个数的哨兵都通告Master故障了,整体认为Master故障了
    • 客观性故障【odown】
  • step3:所有哨兵根据每台Slave通信的健康状况以及Slave权重选举一个新的Master
  • step4:将其他所有的Slave的配置文件中的Master切换为当前最新的Master

2.3 哨兵集群设计


Redis哨兵集群中的存储容量只有单台机器,如何解决大量数据使用Redis存储问题?

分片集群模式:解决了单点故障和单机资源不足的问题。

  • 将多个Redis小集群从逻辑上合并为一个大集群,每个小集群分摊一部分槽位,对每一条Redis的数据进行槽位计算,这条数据属于哪个槽位,就存储对应槽位的小集群中

分片的规则:根据Key进行槽位运算:CRC16【K】 & 16383 = 0 ~ 16383

在这里插入图片描述

在这里插入图片描述

3 Redis事务机制


事务定义:事务是数据库操作的最小工作单元,包含原子性、一致性、隔离性、持久性

Redis事务:Redis一般不用事务

  • Redis本身是单线程的,所以本身没有事务等概念

  • Redis 支持事务的本质是一组命令的集合事务支持一次执行多个命令,串行执行每个命令。将一组需要一起执行的命令放在multiexec之间

  • 一旦Redis开启了事务,将所有命令放入一个队列中,提交事务时,对整个队列中的命令进行执行

  • redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令

  • 没有隔离性:批量的事务命令执行前在缓存队列中,没有事务交叉,不存在脏读幻读等问题

  • 不能保证原子性:单条命令是原子性执行的,但事务不保证原子性,且没有回滚机制,事务中任意命令执行失败,其余的命令仍会被执行。

  • 过程

    • 开启事务
    • 提交命令
    • 执行事务
  • 命令

    • multi:开启事务
    • exec:执行事务
    • discard:取消事务

测试

  • 正常使用

    set user1 hadoop1
    set user2 hadoop2
    get user1
    get user2
    multi
    set user1 hadoop3
    set user2 hadoop4
    exec
    get user1
    get user2
    

都执行

  • 语法【编译】错误

    flushdb
    set user1 hadoop1
    set user2 hadoop2
    get user1
    get user2
    multi
    set user1 hadoop3
    sets user2 hadoop4
    exec
    get user1
    get user2
    

都不执行

  • 类型【运行】错误

    flushdb
    set user1 hadoop1
    set user2 hadoop2
    get user1
    get user2
    multi
    set user1 hadoop3
    lpush user2 hadoop4 # 运行错误
    exec
    get user1
    get user2
    

    user1执行,user2不执行

  • 取消事务

    flushdb
    set user1 hadoop1
    set user2 hadoop2
    get user1
    get user2
    multi
    set user1 hadoop3
    set user2 hadoop4
    discard
    get user1
    get user2
    

都不执行

总结:

  • Redis 的事务机制很弱,在事务回滚机制上,只能对基本的语法错误进行判断。
  • 事务是Redis实现在服务端的行为,用户执行multi命令时,服务器会将对应这个用户的客户端对象设置为一个特殊的状态,在这个状态下后续用户执行的命令不会被真的执行,而是被服务器缓存起来,直到用户执行exec命令为止,服务器会将这个用户对应的客户端对象中缓存的命令按照提交的顺序依次执行。

4 Redis过期策略与内存淘汰机制


Redis使用的是内存,内存如果满了,怎么解决?

4.1 过期策略


设计思想:避免内存满,指定Key的存活时间,到达存活时间以后自动删除。命令:expire/setex

  • 定时过期:指定Key的存活时间,一直监听这个存活时间,一旦达到存活时间,自动删除
    • 需要CPU一直做监听,如果Key比较多,CPU的消耗比较严重
  • 惰性过期:指定Key的存活时间,当使用这个Key的时候,判断是否过期,如果过期就删除
    • 如果某个Key设置了过期时间,但是一直没有使用,不会被发现过期了,就会导致资源浪费
  • 定期过期:每隔一段时间就检查数据是否过期,如果过期就进行删除
    • 中和的策略机制

Redis中使用了惰性过期定期过期两种策略共同作用

4.2 内存淘汰机制


设计思想:内存满了,怎么淘汰

Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据, Redis 源码中的默认配置

实际项目中设置内存淘汰策略:maxmemory-policy allkeys-lru,移除最近最少使用的key。

  • 缓存使用:allkeys-lru
  • 数据库使用:volatile-lru / noeviction

5 Redis高频面试题


在应用程序和MySQL数据库中建立一个中间层:Redis缓存,通过Redis缓存可以有效减少查询数据库的时间消耗,但是引入redis又有可能出现缓存穿透缓存击穿缓存雪崩等问题。

在这里插入图片描述

4.1 缓存穿透


缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。

总的来说,查询Key,缓存和数据源都没有,频繁查询数据源。比如用一个不存在的用户 id 获取用户信息,无论论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决缓存穿透的方案主要有两种:

  • 当查询不存在时,也将结果保存在缓存中。但是这可能会存在一种问题:大量没有查询结果的请求保存在缓存中,这时我们就可以将这些请求的key设置得更短一些;
  • 提前过滤掉不合法的请求,可以使用Redis中布隆过滤器

布隆过滤器可能存在误判,意思就是某个数据可能不存在,但是可能误判为存在。

在这里插入图片描述

4.2 缓存击穿


缓存击穿:key对应的数据库存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

总的来说,查询Key,缓存过期,大量并发,频繁查询数据源。

业界比较常用的做法:使用互斥锁。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db(查询数据库),而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,就是只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据。

在请求数据库这一步进行上锁,这个时候只有一个线程可以抢到这个锁,这个线程查询到数据库再重新将数据写入缓存,其他线程再去缓存中查询。

4.3 缓存雪崩


缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

总的来说,缓存不可用(服务器重启或缓存失效),频繁查询数据源。

与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。缓存正常从Redis中获取,示意图如下:

在这里插入图片描述

缓存失效瞬间示意图如下:

在这里插入图片描述

缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++STL 初阶(5)vector的简易实现(上)

不同于string只实现一个最简单的版本,vector在此处我们要实现的是模版类,类模版的声明和定义分离非常不方便(会在链接时报错),所以我们都只在一个vector.h下去实现声明和定义。后续我们提及到的库里面实现的vector也是…

HCIP--OSPF(笔记3)

OSPF扩展配置 手工认证 【1】接口认证 -- 直连的邻居间,设定认证口令,进行身份核实,同时对双方交互的数据进行加密保护 [r9-GigabitEthernet0/0/1]ospf authentication-mode md5 1 cipher 123456 邻居间认证模式、编号、密码必须完全一致 【…

python实训day2

1、 from ming import * # 有点像C语言中的头文件 """在Python开发环境中,封装一个函数,功能目标为:通过两个整数参数一次性获取和、差、积、商四个值 """ def calc(a, b):return a b, a - b, a * b, a / b…

apollo规划架构

算法的基本架构 我们在最开始直接给出规划决策算法架构框图,然后一一介绍每个框图结构的细节: 模块的入口是 PlanningComponent,在 Cyber 中注册模块,订阅和发布消息,并且注册对应的 Planning 类。Planning 的过程之前…

网络技术原理需要解决的5个问题

解决世界上任意两台设备时如何通讯的?? 第一个问题,pc1和pc3是怎么通讯的? 这俩属于同一个网段,那么同网段的是怎么通讯的? pc1和pc2属于不同的网段,第二个问题,不同网段的设备是…

敏捷开发笔记(第7章节)--什么是敏捷设计

目录 1:PDF上传链接 7.1: 软件出了什么错 7.2: 设计的臭味--腐化软件的气味 7.2.1: 什么激化了软件的腐化 7.2.2: 敏捷团体不允许软件腐化 7.3: “copy”程序 1: 初始设计 2: 需求在变化 3: 得寸进尺 4: 期望变化 7.3.1: “copy”程序的敏捷设计 7.3.2:…

leetcode 二分查找·系统掌握 有效的完全平方数

题目: 题解: 就是一个非常普通的二分查找,但是需要注意的是查找的上下界,因为是完全平方,所以可以把上界设为这个数的一半,但是要特殊处理num等于1的时候。 bool isPerfectSquare(int num) {if(num1)retur…

element-plus form表单组件之el-date-picker日期选择器组件

el-date-picker日期选择器组件可根据年,月,日期,时间范围来进行选择,可以自定义日期格式,和样式,还提供多种内置事件。 主要属性如下 属性名说明类型可选值默认值model-value / v-model绑定值&#xff0c…

qt开发-11_Dialog 仿苹果支付界面

QDialog 是 Qt 框架中用于创建对话框的一个基类。对话框是一种特殊类型的窗口,通常用于短暂的交互和信息交换,如接收用户输入、显示消息、询问用户决定等。QDialog 提供了一种方便的方式来实现这些功能,并能够控制用户与其他窗口的交互性&…

自动更新阿里云CDN SSL证书

deploy-certificate-to-aliyun 随着各大CA机构开始收割用户,云厂商们提供的免费SSL证书也由之前的12个月变成现在的3个月。笔者一直使用阿里云的OSS作为图床,说实话在如果继续在阿里云上三个月免费一换也太频繁了 笔者在这里使用github action来每隔两个…

C++ (week9):Git

文章目录 1.git介绍2.git安装3.git配置4.获取自己的SSH公钥5.新建仓库6.邀请开发者7.克隆远程仓库到本地8.在本地进行开发9.本地项目推送到远程仓库10.git的工作原理11.分支管理(1)合作开发的方式(2)分支管理(3)分支合并的原理、冲突管理 12.git 与 svn 的区别13.设置alias别名…

内容安全复习 8 - 视觉内容伪造与检测

文章目录 研究背景内容伪造方法虚假人脸生成人脸替换属性编辑表情重演跨模态人脸编辑 伪造检测方法眨眼检测交互式人脸活体检测一些了解方法挑战 研究背景 图像内容篡改造成新闻报道的偏颇易导致社会和公共秩序的不安,对公共安全产生不良影响。 造成的影响&#x…

达梦8 通过日志解释数据守护系统的关闭顺序

关闭守护系统时,必须按照一定的顺序来关闭守护进程和数据库实例。特别是自动切换 模式,如果退出守护进程或主备库的顺序不正确,可能会引起主备切换,甚至造成守护进程 DM 数据守护与读写分离集群组分裂。 官方推荐通过在监视器执行…

macbook配置adb环境和用adb操作安卓手机

(参考:ADB工具包的安装与使用_adb工具箱-CSDN博客) 第一步:从Android开发者网站下载Android SDK(软件开发工具包)。下载地址为: 第二步:解压下载的SDK压缩文件到某个目录中。 进入解…

现在的Android程序员为什么会感到焦虑?焦虑的源头在哪里?该怎么去缓解焦虑呢?——没有无中生有的贩卖焦虑,只有你的挣扎和不甘。

二、知识为何产生焦虑 先说两个世界,知识的世界和现实的世界。 知识的世界,由承载知识的那些载体组成,比如图书、音视频、报刊、自媒体等。 现实的世界,就是我们每天生活的、做出各种行为的世界。 学习的目的是什么呢&#xff1…

[spring] Spring MVC Thymeleaf(下)

[spring] Spring MVC & Thymeleaf(下) 上篇笔记讲了一下怎么使用 thymeleaf 作为 HTML 模板,与 Spring MVC 进行沟通,这里主要说一下验证的部分 常用表单验证 一些 Spring MVC 内置的常用验证注解如下: Annota…

[面试题]MongoDB

[面试题]Java【基础】[面试题]Java【虚拟机】[面试题]Java【并发】[面试题]Java【集合】[面试题]MySQL[面试题]Maven[面试题]Spring Boot[面试题]Spring Cloud[面试题]Spring MVC[面试题]Spring[面试题]MyBatis[面试题]Nginx[面试题]缓存[面试题]Redis[面试题]消息队列[面试题]…

uniapp运行到模拟器(联想模拟器)

记录一下uniapp项目运行到联想模拟器的流程 先配置一下模拟器端口 填写对应的adb路径,也就是模拟器安装路径下的adb.exe的路径 然后打开模拟器的设置,搜索版本找到版本号,多次点击打开开发者模式 进入开发者选项,打开USB调试 …

Android实战之app版本更新升级全文章(二)

BaseAndroid.checkUpdate(MainActivity.this, 2, “http://f5.market.mi-img.com/download/AppStore/0f4a347f5ce5a7e01315dda1ec35944fa56431d44/luo.footprint.apk”, “更新了XXX\n修复OOO”, false); 看看效果图 界面有点丑,自己修改下吧 当然啦&#xff0c…

Golang | Leetcode Golang题解之第167题两数之和II-输入有序数组

题目&#xff1a; 题解&#xff1a; func twoSum(numbers []int, target int) []int {low, high : 0, len(numbers) - 1for low < high {sum : numbers[low] numbers[high]if sum target {return []int{low 1, high 1}} else if sum < target {low} else {high--}}r…