数据库通关整理3-Redis基础、RDB、AOF、发布订阅、主从复制、哨兵模式、缓存穿透、缓存击穿、缓存雪崩

网上收集整理,仅供笔记参考学习

数据库通关整理1-索引、聚簇索引、非聚簇索引、MyISAM和InnoDB存储引擎、范式

数据库通关整理2-事务、并发问题、事务隔离级别、锁(S锁、X锁`)、乐观锁、悲观锁、sql注入、内连接、外连接

数据库通关整理3-Redis基础(数据库、缓存、消息中间件)、RDB、AOF、发布订阅、主从复制、哨兵模式、缓存穿透、缓存击穿、缓存雪崩


基础

为什么要用Nosql

发展历程:
1.单机MySQL
在这里插入图片描述

2.Memcached(缓存) + MySQL + 垂直拆分(读写分离)
在这里插入图片描述

3.分库拆表 + 水平拆分 + MySQL集群

在这里插入图片描述
4.关系型数据库不够用!数据很多,变化很快

为什么要使用NoSQL!
用户的个人信息、社交网络、地理位置。用户自己产生的数据,用户日志等等爆发式增长!
这时候我们就就需要使用NoSQL数据库,NoSQL可以很好的处理以上的情况

Redis

Redis(Remote Dictionary Server),即远程字典服务

Redis 是速度非常快的非关系型(NoSQL)数据库,可基于内存亦可持久化的日志型、Key-Value数据库。可以用作数据库缓存消息中间件MQ

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

Redis使用场景

- (数据库、缓存、消息中间件)

1、内存存储、持久化、内存中是断电即失、所以说初九话很重要(RDB、AOF)
2、效率高、可以用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器、计数器(浏览量)
6、…

特性:
1、多样的数据类型
2、持久化
3、集群
4、事务

Redis基础知识

1、默认是16个数据库
2、Redis是单线程的
3.为什么是单线程还这么快?
误区1:高性能的服务器一定是多线程的
误区2:多线程(CPU上下文切换)一定比单线程效率高
核心:redis是将所有数据放在内存中的,所以说使用单线程去操作效率最高。多线程(CPU上下文切换:耗时)

五种数据类型

string (字符串)

string 是 redis 最基本的类型,一个 key 对应一个 value。
string 类型的一个键最大能存储 512MB。

redis 127.0.0.1:6379> SET runoob “Helloworld”
OK
redis 127.0.0.1:6379> GET runoob
“Helloworld”

场景:计数器、统计多单位的数量

Hash(哈希)

Map集合,key-value中的value 是一个Map
hash 是一个value键值(key=>value)对集合。
hash 是一个 string 类型的 field 和 value 的映射表.

redis 127.0.0.1:6379> HMSET runoob field1 “Hello” field2 “World”

  • hash变更的数据 user name age,尤其是用户信息之类,经常变动的值
  • hash更加适合对象的存储,string更适合字符串的存储
List(列表)

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

redis 127.0.0.1:6379> lpush runoob redis

  • 实际是一个双向链表,before Node after , left, right都可插入
  • 如果key不存在,新增链表
  • 如果key存在,新增内容
  • 如果移除所有值,空链表,也表示不存在
  • 在连边插入或者改动之,效率最高!中间元素,相对来说效率会低一点
  • 消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)
Set(集合)

Redis 的 Set 是 string 类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

redis 127.0.0.1:6379> sadd runoob redis

  • 微博,A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
  • 共同关注,共同爱好,二度好友,推荐好友!(六度分隔理论)
Zset(有序集合)

在 set 的基础上,增加一个值(分数),然后可以进行排序
关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

redis 127.0.0.1:6379> zadd runoob 0 redis

  • 案例思路:set 排序 存储班级成绩表,工资表排序!
  • 普通消息、重要消息,带权重判断
  • 排行榜实现,取top N测试

三种特殊数据类型

范围查询

Geospatial(地理位置)

朋友的定位,附近的人,打车距离计算
这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人
只有6个命令

  • 附近的人?(获得所有附近的人的地址,定位!),通过半径来查询
  • 获得指定数量的人
Hyperloglog(不重复数)

什么是基数?A {1,3,3,5,7}
不重复的元素个数 = 4,可以接受误差

Hyperloglog数据结构,Hyperloglog 基数统计的算法
网页的UV(一个人访问一个网站多次,但是还是算作一个人!)
传统的方式,set保存id,统计set中数量作为标准判断。如果保存大量的id,就比较麻烦!我们的目的是计数,不是保存数据id

优点:占用内存是固定的,2^64不同的元素的技术,只需要废12kb内存,如果要从内存角度上来说,Hyperloglog是首选
0.81%错误率!统计UV任务,可以忽略不记

Bitmap(位图)

位存储
统计用户信息,活跃,不活跃!登录,未登录!打卡【0 1 代替】

Bitmap位图,数据结构!操作二进制位来进行记录,只有0/1两个状态

事务

Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺寻执行!

  • Redis 单条命令是保证原子性,但是Redis的事务是不保证原子性的
  • Redis的事务没有隔离级别的概念!
    所有的命令在事务中,并没有直接执行!只有发起执行命令才会执行 Exec

redis事务:

  • 开启事务(multi)
  • 命令入队()
  • 执行事务(exec)

放弃事务:
-discard
异常:

  • 编译时异常。代码有误,事务所有的命令都不会被执行!
  • 运行时异常(1/0)。错误命令抛出异常,其他命令正常执行!
监控-悲观锁、乐观锁《面试常问》

悲观锁

  • 很悲观,认为什么时候都会出现问题,无论做什么都会加锁!

redis可以实现乐观锁----watch,类似对比version版本号
解锁unwatch

乐观锁

  • 很乐观,认为什么时候都不会出问题,所以不会上锁!在提交数据的时候,需要判断一下,在此期间,数据是否被其他改动。
  • 获取version
  • 更新的时候比较version
  • watch命令可以当成redis的乐观锁操作!

Jedis

import redis.clients.jedis.Jedis;
 
public class RedisStringJava {
    public static void main(String[] args) {
        //连接本地的 Redis 服务
        Jedis jedis = new Jedis("localhost");
        //如果有密码,输入
        // jedis.auth("123456"); 
        System.out.println("连接成功");
        //设置 redis 字符串数据
        jedis.set("runoobkey", "www.runoob.com");
        // 获取存储的数据并输出
        System.out.println("redis 存储的字符串为: "+ jedis.get("runoobkey"));
    }
}

SpringBoot整合

SpringBoot操作数据:spring-data jpa mongodb redis
SpringData也是和SpringBoot齐名的项目!

  • 说明在SpringBoot2.x之后,原来使用的jedis被替换为了lettuce
  • jedis:底层采用的是直连,多个线程操作的话,是不安全的,如果想要避免不安全,使用jedis pool连接池!更像BIO模式!
  • lettuce:底层采用的是netty,实力可以在多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据,更像NIO模式!

1、导入依赖

<!-- 操作redis -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置连接

# 配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

3、测试
在这里插入图片描述
在这里插入图片描述

  • 在企业开发中,80%的情况下,都不会使用这个原生的方式来编写代码
  • 在我们真实的开发中,一般可以看到一个公司自己封装的RedisUtils工具类

进阶

Redis.conf

快照

  • 持久化,在规定的时间内,执行了多少次操作,则会持久化到 .rdb .aof
  • redis是内存数据库,如果没有持久化,那么数据断电即失
    .rdb文件

300秒内,如果至少有 10 个 key 的值变化,则进行持久化操作

  • save 300 10

安全

  • 可以设置redis的密码,默认没有密码

aof配置 -APPEND ONLY 模式

  • appendonly no
    默认是不开启aof模式的,默认是使用rdb方式持久化,在大多数情况在,rdb而完全够用
  • appendonly.aof 持久化的文件名字

三种配置方式:appendfsync everysec 相对常用

  • appendfsync always 每次修改都会sync。消耗性能
  • appendfsync everysec 每秒执行一次sync。可能会丢失这一秒的数据!
  • appendfsync no 不执行sync。这时候操作系统自己同步数据,速度最快

具体的配置,在持久化中

Redis持久化

RDB

流程
(1)redis根据配置自己尝试去生成rdb快照文件

(2)fork一个子进程出来

(3)子进程尝试将数据dump到临时的rdb快照文件中

(4)完成rdb快照文件的生成之后,就替换之前的旧的快照文件

dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照
在这里插入图片描述

rdb保存的文件是dump.rdb,有时候在生产环境下,我们需要备份这个文件

  • 触发机制
    1、save的规则满足的情况下,会自动出发rdb规则
    2、执行flushall命令,也会出发我们的rdb规则
    3、退出redis,也会产生rdb文件
    备份就自动生成一个dump.rdb

  • 如何恢复rdb文件
    1、只需要将rdb文件放在我们redis启动目录就可以了。redis启动的时候救护i自动检查dump.rdb恢复其中的数据!
    2、查看需要存放的位置

config get dir
“dir”
“/usr/local/bin” 如果在这个目录下的dump.rdb文件没启动就会自动恢复其中的数据

  • 优点
    1、适合大规模的数据恢复!dump.rdb
    2、对数据要求不高!
  • 缺点
    1、需要一定的时间间隔进程操作,如果redis意外宕机,最后一个修改的数据就没有了。
    2、fork进程的时候,需要占用一定的空间
AOF

流程
(1)redis fork一个子进程

(2)子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志

(3)redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件

(4)子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中

(5)用新的日志文件替换掉旧的日志文件

在这里插入图片描述

将我们的所有命令都记录下来,恢复的时候就把这个文件全部执行一遍

  • aof保存的是appendonly.aof文件。记录我们的所有写操作
  • 默认不开启,需要手动开启配置appendonly改为yes就可以了

如果aof文件有错误,redis重启时就会拒绝恢复数据

  • redis提供redis-check-aof --fix 命令可以修复aof文件

如果文件正常,直接重启数据就恢复了

  • 优点
    1、每一次修改都同步,文件的完整性会更好
    2、每秒同步一次,最多只会丢失一秒的数据
    3、从不同步,效率最高
  • 缺点
    1、相对数据文件来说,aof远远大于rdb,修复的数据速度也比rdb慢
    2、aof运行的效率比rdb慢,所以redis里面默认的

AOF重写机制

redis中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在redis内存中,所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,到很大很大,所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,

  • redis2.4之后,就会自动进行rewrite操作

上一次AOF rewrite之后,是128mb。然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite但是此时还要去跟min-size,64mb去比较,256mb > 64mb,才会去触发rewrite

Redis发布订阅

Redis发布订阅是一种消息通信模式:发送者发布信息,订阅者接收信息。微信、微博、关注系统!
Redis客户端可以定语任意数量的频道

订阅/发布图:

第一个:消息发送者;第二个:频道;第三个消息订阅者
在这里插入图片描述

  • 命令被广泛用到构建即时通信应用,比如网络聊天室和实时广播、实时提醒
  • 使用场景
    1、实时消息系统!
    2、实时聊天()频道当作聊天室,将消息回显给所有人即可
    3、订阅,关注系统都是可以
  • 稍微复杂的场景我们就会使用消息中间件MQ()

Redis主从复制

数据的复制是单向的,只能由主节点到从节点。

主从复制的作用主要包括:

1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

4、高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

环境搭建

复制三个redis配置文件,然后修改对应的信息
1、端口
2、pid名字
3、log
4、dump.rdb文件名
修改完毕后,启动三个redis服务器,可以通过进程信息查看

一主二从

默认情况下,每台Redis服务器嗾使主节点,一般情况下配从机就可以了。
认老大!

命令配置

  • 从机配置:SLAVEOF 127.0.0.1 6379
    真实的从主配置应该在配置文件中配置,这样就是永久的,命令配置是暂时的。

细节

  • 主机可以写,从机不能写只能读。主机中的信息和数据,都会被从机保存。

测试:主机断开连接,从机依旧连接到主机的,但是没有写操作,此时,如果主机回来了,从机一九可以直接获取到主机写的信息!

如果是使用命令行配置的主从,如果从机重启,则默认变回主机!只要重新设置为从机,立马就可以从主机中获取到值。

复制原理
Slave启动成功连接到Master后,会发送一个sync(同步)命令

  • 全量复制
  • 增量复制

只要重新连接master,一次完全同步(全量复制)会被自动执行,数据一定可以在从机中看到!

层层链路

一个接一个

如果主机宕机,或者没有主机,可手动选择老大!

谋财篡位

  • 如果主机断开连接,我们可以使用SLAVEOF no one,手动让自己变为主机,其他节点就可以连接到最新的这个主节点(手动命令)
  • 如果这时候老大回来了,需要重新配置
哨兵模式(Sentinel)-重点

主从切换技术方法:当主服务器宕机之后,需要手动把其中的一台从服务器切换成主服务器,需要人工命令干预设置,这样费时费力,还会造成一段时间内服务不可用。 这不是一种推荐的方式,更多的时候,优先考虑哨兵模式。

基础模式:
在这里插入图片描述

  • 这里哨兵的两个作用
    1、通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
    2、当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

谋财篡位的自动版,可以后台监控主机是否故障,若故障就会根据票数自动将从机转换为主机。

多哨兵模式:
一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

在这里插入图片描述

  • 优点
    1、哨兵集群,基于主从复制模式,所有的主从配置优点,它都有
    2、主从可以切换,故障可以转移,系统的可用性就会更好
    3、哨兵模式就是主从复制的升级,手动到自动回滚,更加健壮
  • 缺点
  • 1、Redis不好在线扩容,集群容量一旦达到上限,在线扩容九十分麻烦!
  • 2、实现
    哨兵模式的配置很麻烦,里面的选择有很多

故障切换(failover)的过程描述。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。

Redis缓存穿透和雪崩(面试高频,工作常用)

作为一个内存数据库,redis也总是免不了有各种各样的问题

缓存穿透(查不到)

概念

用户想要查询一个数据时,发现redis内存数据库中没有,也就是缓存没有命中,于是向持久化数据库查询。发现也没有,语事本次查询失败。当用户很多时,缓存都没有命中(),语事都去请求持久数据库。 这会给持久数据库造成很大的压力,是时候就相当于缓存穿透。

解决方案

布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,当用户想要查询的时候,使用布隆过滤器发现不在集合中,就直接丢弃,不再对持久层查询。

所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

在这里插入图片描述

缓存空对象

当首次持久存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后在访问这个数据就可以在缓存智官获取,保护了后端数据库

  • 问题/缺点
    1、需要更多的空间存储更多空值的键
    2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口不一致,这对保持一致性的业务有影响
缓存击穿(量不大,缓存过期)

微博服务器宕机
集中访问缓存中的一个key

概述

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

缓存击穿,是指一个key(或者某些key)非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

解决方案

设置热点数据不过期
加互斥锁

加锁只保证只有一个进程到服务器查询,其余等待,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。

缓存雪崩

概念

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

缓存雪崩是指,缓存层出现了错误,不能正常工作了。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

在这里插入图片描述

在一定时间内,缓存几种过期失效,redis宕机。
比如说双十一前一个小时的抢购,快到1点时,缓存集体过期

  • 更致命的时服务器某个节点宕机或者断网

双十一:停掉退款服务

  • 解决方案
    1、redis高可用
    思想含义:既然redis有可能挂掉,那就多增设几台redis,这样一台挂掉之后,其他的还可以继续工作。其实就是搭建集群。(异地多活!)
    2、限流降级
    思想:在缓存失效后,通过加索或者队列来空值读数据库写缓存的线程数量。比如对某个key只允许一个线程进行查询数据和写缓存,其他线程等待。
    3、数据预热
    数据加热的含义就是在正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到内存。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀

高可用:
通过设计减少系统不能提供服务的时间。增加容错性。如:主从复制、集群

猜你喜欢

转载自blog.csdn.net/weixin_45773603/article/details/108186631