• Redis进阶


    什么是redis?它是用来做什么的?

    Redis是一个c语言编写的nosql的数据库,支持网络,可基于内存也可持久化的,key-value类型的数据库。 与一般数据库不同的是,redis是存储在内存中的,他的读写速度非常快,常常被广泛应用到缓存之中。

    redis除了用作缓存,还可以干什么?

    1. 计数器
    2. 排行榜 (排序)
    3. 数据排重 (重复数据)
    4. 可以发布、订阅的实时消息系统
    5. 消息队列 (list先进先出)
    6. 分布式锁

    一、Redis 线程模型

    1、Redis是单线程模型还是多线程模型

    redis6.x版本之前,属于彻彻底底的单线程,redis中监听客户端连接、读写数据操作,都是由一个单线程来完成的,效率低。

    redis6.x之后,引入了多线程。将客户端网络请求,由多线程来负责完成,数据读写操作仍然是单线程。(单线程操作不会出现并发安全问题,保证了操作的原子性)

    2、为什么设计为单线程模型速度也很快?
    1. Redis是基于内存操作的,所有的运算都是内存级别的,所以性能比较高
    2. 底层是一个hash表结构,查找和操作的时间复杂度是O(1)
    3. IO多路复用和非阻塞 I/O(后面会补充,属于操作系统级别的IO)
    4. 单线程避免了线程间的切换

    redis的瓶颈不是cpu,而是内存大小、网络速度,本身速度就很快。

    3、全局hash表

    Redis底层是一个hash表结构,时间复杂度是O(1)

    hash可以在O(1)的时间内计算出hash值并且找到对应的entry位置,entry里面是一个一个key指针和value指针,其实还有其他信息。这也是redis之所以性能高的原因之一。

    二、Redis数据持久化

    因为redis数据平常存储在内存中,一旦机器故障可能数据就会丢失。Redis还提供了数据持久化的机制,把内存中的数据,根据一定规则写入到硬盘中的文件,分别是RDB和AOF。

    • 点赞-->存储在redis内存中--->定期的将数据写入到文件中。定时任务:每天晚上0点,把redis的数据写入到mysql

    在我们安装了redis之后,所有的配置都是在redis.conf文件中,里面保存了RDB和AOF两种持久化机制的各种配置。当符合一定条件时,Redis会自动将内存中的数据进行快照并持久化到硬盘。

    1、RDB方式(Redis DataBase)

    在redis.conf文件中可以进配置,是否开启rdb持久化。在满足一定的条件时,定期的将redis中的数据(数据快照)保存到一个dump.rdb文件中,在redis 重新启动时,会将数据还原回来,将键值存储到rdb文件中。

    数据快照:内存中有许多key-value、key1-value1---->存储在dump.rdb文件

    rdb方式是redis默认的持久化方式,不需要配置开启,默认是支持的。

    redis.conf文件中有触发rdb保存快照的条件

    save:这里是用来配置触发Redis的RDB持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如"save m n"。表示m秒内数据集存在n次。修改时,自动触发bgsave。

    如下配置:

    • save 900 1:表示900秒钟内至少1个键被更改则进行快照。
    • save 300 10:表示300秒内至少10个键被更改则进行快照。
    • save 60 10000:表示60秒内至少10000个键被更改则进行快照。

    如果不需要持久化,那么你可以注释掉所有的save行来停用保存功能。

    退出redis,也会产生 rdb 文件, 命令: shutdown save。在Redis客户端模式下,关闭Redis服务时会保存快照,重新启动Redis服务时,会将dump.rdb文件中的数据还原回来。

    2、AOF方式(Append Only File)

    日志的方式来记录所有写操作的命令(读操作不记录)。redis重启的话,会还原数据,会将日志文件中写命令从前到后执行一次。

    set name jim

    set name tom

    如果是RDB方式,最终记录name的值为tom;而AOP方式记录所有的

    Redis默认是关闭的,修改redis.conf配置文件,来开启AOF机制

    appendonly no #默认是不开启aof模式的,改为yes开启。

    appendfilename appendonly.aof #默认的文件名是 appendonly.aof,可以通过appendfilename参数修改 AOF 同步机制。

    appendfsync always #每次修改都会同步,消耗性能。

    appendfsync everysec #每秒会同步一次,可能会丢失这1s的数据(默认)

    appendfsync no #不同步

    修改完之后,重启redis才生效。

    三、Redis事务

    redis事务:是将多条命令打包为一个整体执行(在同一个事务中),这样执行的过程中其他客户端命令就不能执行了。但是不保证命令的原子性(中间有一条命令报错,不影响其他命令的执行)。

    redis 的事务操作:

    • 开启事务(multi)
    • 执行命令, 命令入队(把命令加入到一个队列中,并没有立即执行)
    • 执行前可以放弃事务(discard)
    • 执行事务(exec)

    实例:

    • multi 开启事务
    • set a aa 添加命令
    • set b bb 添加命令
    • incr b 添加命令
    • exec 执行事务

    但是事务不保证同一事物中多条命令执行的原子性,即使命令有错误也会添加到队列中,执行报错也不影响其他命令执行。  

    1. redisTemplate.multi();//开启事务
    2. ValueOperations valueOperations = redisTemplate.opsForValue();
    3. valueOperations.set(a,aa);
    4. valueOperations.set(b,bb);
    5. redisTemplate.exec();//执行事务

    四、主从复制

    主从复制,是指将一台Redis服务器的数据复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主机到从机。

    redis集群--->多台服务构成

    Redis为了数据能够备份,实现读写分离(写命令找主机,读命令找从机)。有一台服务作为主机、多台服务作为从机,一台Redis服务器的数据复制到其他的Redis服务器。主机负责写数据,将数据备份到多台从机,从机负责读操作。

    即使期间,有一台服务器出现问题,其他redis服务也可以正常工作。当有问题的服务故障排除后,可以继续在集群中工作。即使是主机故障,也可以从多台从机中,选举出一台服务作为主机(哨兵机制)

    主从复制的作用主要包括:
    1. 必将存在数据冗余、服务冗余。主机的数据备份到从机中。
    2. 负载均衡(有多台服务,有很多请求到达后,可以根据一些机制让多个请求到达不同的服务器),读写分离,多台从机分担读操作。
    3. 实现高可用,是哨兵和集群实施的基础。
    主从复制配置

    主从复制时只需要配置从库即可,其默认为主库模式。打开redis客户端登录,使用命令info replication查看。

    主从复制可以搭建真集群,也可以搭建伪集群。

    真集群:有多台主机、每台主机安装一个 redis。

    redis伪集群:可以在一台机器上,配置多个redis端口,启动多个redis实例。配置方式两者相同。

    主从复制实例

    1.复制多份配置文件,一主二从

    主机配置

    • bind 0.0.0.0 #任何 ip 都可以访问
    • daemonize yes #后台运行
    • pidfile /var/run/redis_6379.pid #进程号文件
    • logfile "6379.log" #日志文件 注意文件名修改只是为了区分
    • dbfilename dump6379.rdb #数据文件
    • requirepass root #主机密码

    从机配置

    • #bind 注释
    • daemonize yes #后台运行
    • port 6380 #修改端口
    • pidfile /var/run/redis_6380.pid #进程号文件
    • logfile "6380.log" #日志文件
    • dbfilename dump6380.rdb #数据文件
    • replicaof 主机ip 主机端口
    • masterauth 主机密码

    从机进入客户端模式 ./redis-cli -p 从机端口

    主机  

    测试主写从读

    五、哨兵机制

    哨兵是一个独立的进程,独立运行。

    哨兵定期的向redis集群中发送请求,等待Redis服务器响应。如果收不到回复,就说明redis服务有问题,会通过一套选举机制,在多台从机中选取一台作为主机;当主机故障恢复后,临时主机又变为从机角色。

    单哨兵

    哨兵集群  

     

    六、Key过期策略(删除策略)

    Redis中的key,是可以设置有效时间的。不是时间到期后就会自动删除的;当时间到了后,redis中有一套机制来删除过期的key。

    Redis提供了两种删除策略:

    1、惰性删除

    key到期后不立即删除,只是使用一个字典记录此key已经过期,在下次使用此key时才会删除。

    浪费内存空间,但节省CPU

    2、定时删除

    每隔指定的时间后,字典中记录过期的key,定期的删除过期的key。

    redis使用的过期键值删除策略是:惰性删除加上定期删除,两者配合使用

    七、如何保证Redis和mysql数据一致

    采用延时双删机制:先删除Redis数据,再更新Mysql,延迟几百毫秒再删除Redis数据。这样就算在更新Mysql时,有其他线程读了没有更新的Mysql数据,把老数据读到了Redis中,那么也会被删除掉,从而保持数据一致。

    (第一个线程要对mysql进行操作的时候,要先把Redis数据删掉,去更新mysql,在此没有实际更新之前,另一个线程看Redis中没有,去mysql中拿到没有更新的数据,写到Redis中。但是没有关系,在mysql更新之后立即把Redis数据删掉,这样保证Redis和mysql数据一致)

    八、跳表

    Redis数据类型(String、哈希、list、set、zset)

    跳表是zset的底层实现之一,是一种将有序链表改造为支持近似"折半查找"算法。查询一个元素时,不需要从头一个一个查询,先确定元素在调表中的区间范围,可以提高查询效率。

    先分成大区间,再分成小区间  

    九、缓存穿透、缓存击穿、缓存雪崩

    redis可以用来缓存数据,访问量大的时候可以缓解mysql的压力。如果Redis使用不当,也会造成新的问题。

    缓存处理流程

    前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存并返回结果,数据库没取到直接返回空结果。

    1、缓存穿透

    数据在mysql中本身就不存在,这样redis中也没有,每次查询时,都会访问mysql,大量访问会压垮mysql。

    解决办法:

    1. 在Redis中设置一个key为null的键值 -1:null。下次再请求的时候,就可以从缓存里边获取了。这种情况我们一般会将空对象设置一个较短的过期时间。
    2. 对参数进行校验,不合法参数进行拦截。
    2、缓存击穿

    mysql中有数据,在Redis中的某个时刻key到期了。此时刚好有大量请求到达,这时没有做任何的控制,大量请求查询redis,但是redis中没有数据,请求到达mysql,导致mysql被压垮。

    解决办法:

    1. 合理设置key的过期时间
    2. 加锁,查询mysql时,进行加锁处理
    3、缓存雪崩

    大量的key过期或者Redis服务器出现故障,导致大量的请求到达mysql(更严重的击穿)。

    解决办法:

    1. 随机设置key失效时间,避免大量key集体失效。setRedis(Key,value,time+Math.random() * 10000);
    2. 把热点key放在不同的从机。
    3. 不设置过期时间。
    4. 定时任务,将快过期的key,重新放入到缓存。
  • 相关阅读:
    基于TensorRT部署和C++推理目前最SOTA的图像降噪网络
    python sqlalchemy(ORM)- 01 简单使用
    要素类WKT文本获取
    云计算学习笔记——第四章 存储虚拟化
    Spring 的面向切面编程(AOP)的使用场景有哪些?
    自制操作系统番外2:编程语言中函数参数的传递
    overflow:auto的用法
    JavaGUI——Java图形用户界面
    python迭代器
    云原生专栏博客汇总
  • 原文地址:https://blog.csdn.net/m0_73503454/article/details/133691310