Redis

一、Redis基本

1.概念

Redis是一种开放源代码的内存中数据结构存储,用作数据库,缓存和消息中间MQ ,它支持数据结构,例如字符串,哈希,列表,集合,带范围查询的排序集合,位图,超级日志等

2.特点

  1. 多样的数据类型
  2. 持久化
  3. 效率高
  4. 集群
  5. 事务

redis默认有十六个数据库,默认使用的是第0个。
redis是单线程的,基于内存操作的,CPU不是性能瓶颈,是根据机器的内存和网络带宽来限制的。
redis是将所有的数据全部放在内存中的,所以说使用单线程效率就是最高的,多线程的CPU上下文切换时会耗费大量时间,对于内存系统来说,如果没有上下文切换效率就是最高的。

二、数据类型

1.String(字符串)

String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M

1.使用场景

String类似的使用场景:value除了是我们的字符串还可以是数字。

  • 计数器
  • 对象缓存存储

2.List列表

  • Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
  • 它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

1.总结

  • List是一个双向链表,两边都可以插入
  • 消息队列,栈

3.Set集合

  • Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
  • Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。
  • Set中的元素是不允许重复的

4.Hash哈希

  • Redis hash 是一个键值对集合。
  • Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
  • 类似Java里面的Map<String,String>
  • 就是key-map类型,值是map集合

应用:存储关系型的数据,更适合对象的存储

5.Zset(有序集合)

  • 在Set的基础上加了一个值,用于排序
  • Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score) ,这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。
  • 因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

三、事务

1.事务

Redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,并且会按顺序执行。分为三个阶段:

  • 开启事务
    Redis事务的开始是通过执行MULTI 命令来实现,它的作用是将执行该命令的客户端从非事务状态切换至事务状态, 这一切换是通过在客户端状态的 flags 属性中打开 REDIS_MULTI 标识来完成的。
  • 命令入队
    当一个客户端出于事务状态时, 如果客户端发送的命令是 **EXEC(执行所有事务块内的命令) 、DISCARD(取消事务,放弃执行事务块内的所有命令。) 、 WATCH(监视任意数量的key ,提一下,在事务中执行这个命令会报错:ERR WATCH inside MULTI is not allowed) 、 MULTI(标记一个事务块的开始) ** 四个命令以外的其他命令,那么服务器并不立即执行这个命令,而是将这个命令放入一个事务队列里面, 然后向客户端返回 QUEUED 回复。
  • 执行事务
    当一个处于事务状态的客户端向服务器发送 EXEC 命令时, 这个 EXEC 命令将立即被服务器执行: 服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。
    (这里需要说明的一点是,Redis在处理网络请求的是单线程的,所以队列中的命令在执行期间是不会被其他客户端命令插进来的。这一点对理解Redis事务很关键)

2.乐观锁

概念:认为什么时候都不多出问题,所以不会上锁,只需要更新数据的时候去判断一下,在此期间是否有人修改过这个数据

作用: 在数据库执行数据操作时,为了保证数据的一致性,即:A用户更新数据时,B用户不能更新!

实现:在数据库中增加一个锁的处理列。

优点: 悲观锁在执行时,会将其他处理数据库的请求拦截,使其他请求等待。
乐观锁在执行时,不会将数据锁住,让其他数据库请求等待。

3.SpringBoot集成Reids

在SpringBoot 2之后,原来使用的Jedis被替换为了lettuce

  • Jedis:采用的是直连,多线程操作是不安全的,使用jedis pool连接至,类似于BIO
  • lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,类似于NIO

4.持久化

Redis是内存数据库,如果不能将内存中的数据库保存到磁盘,那么一旦服务器进程退出,数据就会丢失,所以Redis提供了持久化的功能

1.RDB(Redis DataBase)

1.RDB是什么
  • 把当前数据生成快照保存在硬盘上。
  • 在制定时间间隔内讲内存中的数据集快照写入磁盘(也就是Snapshot快照),它恢复的时是将快照文件直接读到内存里
  • Redis会单独创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失
2.如何触发RDB快照
  1. 自动
  • save规则满足时,系统会自从生成RDB快照
  • 执行flushall命令,单里面是空的,没有意义
  • 执行shutdo退出时
  1. 手动(save和bgsave)
  • save:SAVE直接调用rdbSave函数,阻塞Redis主进程,知道保存完成为止,在主进程阻塞期间,服务器不能处理客户端的任何请求。如果数据量小,用此命令可能感觉不出有什么区别,但是当数据量很大的时候,就需要谨慎使用这个命令.
  • BGSAVE 命令执行之后返回OK,然后Redis fork出一个新子进程,原来的Redis进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到自盘,然后退出

BGSAVE方式比较适合线上的维护操作

3.RDB优点+缺点

优点

  1. 适合大规模的数据回复
  2. 如果业务对数据完整性和一致性要求不高,RDB是很好的选择

缺点

  1. 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了
  2. 备份时占用内存,因为Redis在备份时会独立创建一个子进程,将数据写入到一个临时文件,最后再将临时文件替换之前的备份文件。所以要考虑大概两倍的数据大小

2.AOF(Append Only File)

1.AOF是什么

记录每次对数据的操作到硬盘上。

以日志的形式来记录每个写操作,将Redis执行过程的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

2.文件重写
  • 重写: AOF采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof。
  • 重写原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename), 遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件, 而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。
  • 触发机制:Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。
3.优点+缺点

优点

  • appendfsync always 同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好。
  • appendfsync everysec 异步操作,每秒记录 如果一秒内宕机,会发生数据丢失。
  • appendfsync no 从不同步
    缺点
  • 相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
  • Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

6.消息订阅发布

进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

1.消息订阅发布是什么

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端

四、主从复制

1. 为什么会有主从复制

  • 通过持久化功能,Redis保证了即使在服务器重启的情况下数据也不会丢失,但是由于数据是存储在一台服务器上的,所以这台服务器出现故障,比如硬盘坏了,也会导致数据的丢失
  • 所以为了避免这种故障,我们需要将数据复制多份,部署在多台不同的服务器上,如果有一台服务器出现故障,其他服务器依然可以继续提供服务
  • 这就要求当一台服务器上的数据更新后,自动将更新的数据同步到其他服务器上,这时候就用到了Redis的主从复制

2.能干什么

  • Redis提供了复制功能来自动实现多台服务器的数据同步
  • 我们可以部署多台Redis,并在配置文件中制定这几台redis之间的主从关系,主负责写入数据,同时把写入的数据同步实时到从机器,从负责读出数据,这样就实现了读写分离,减缓服务器的压力

3.搭建环境

  • 查看当前服务器的信息
  • 复制三个配置文件,并修改相应的信息:端口号,pid名字,log日志名,rdb文件名,并启动
  • 搭建一主二从(默认情况下,每台Redis服务器都是主节点,一般情况下只用配置从机就好了)

4.复制原理

从机启动成功连接到主机后会发送一个sync同步命令,主机接到命令,启动后台的存盘进程,同时手机所有接受到的用户修改数据集命令,在后台进程执行完毕之后,主机将传送整个数据文件到从机,并完成第一次完全同步。

  • 全量复制: 从机服务在接收到数据库文件数据后,将其存盘并加载到内存中
  • 增量复制: 主机继续将信的所有收集到的修改命令依次传递给从机,完成同步。

但是只要是从机重新连接主机,一次完全同步(全量复制)将自动执行

五、哨兵模式

1.概述

  • 主从切换技术的方法是:当服务器宕机后,需要手动把一台从机切换为主机,这需要人工干预,不仅费时费力而且还会造成一段时间内服务不可用。所以就有了哨兵模式
  • 能够监控后台主机是否故障,如果故障就会根据票数自动将从机变为主机

2.单哨兵模式

哨兵模式是一种特殊的模式,首先Redis提供了烧饼的命令,哨兵是一个独立的进程,它会独立运行通过发送命令,等待Redis服务器响应,从而监控多个Redis服务
在这里插入图片描述

这里的哨兵有2个作用

  • 通过发送命令来监控Redis服务器的运行状态
  • 当检测到主机宕机,会自动将某个从机切换为主机,然后通过发布订阅模式来通知其他服务器修改配置文件进行连接

3.多哨兵模式

单哨兵模式下,如果这个哨兵出现问题就GG了。所以我们用多个哨兵来进行监控,每个哨兵之间也进行监控,这样就形成了多哨兵模式
在这里插入图片描述
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线,当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵执行failover故障转移操作,切换成功后,就会通过发布订阅发布让各个哨兵把自己监控的从服务器连接到新的主机。

4.哨兵模式优缺点

优点

  • 哨兵模式就是主从复制的升级,手动到自动,更加健壮
  • 主从可以互换,故障可以专业,系统的可用性就会更好

缺点

  • Redis不好在线扩容,集群容量一旦打到上限,在线扩容就十分麻烦!
  • 实现哨兵模式的配置其实是很麻烦的,里面有很多的选择

六、缓存穿透

1.什么是缓存穿透

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

2.解决方法

1.布隆过滤器

1.布隆过滤器原理
  • 原理:很简单首先也是对所有可能查询的参数以hash形式存储,当用户想要查询的时候,使用布隆过滤器发现不在集合中,就直接丢弃,不再对持久层查询。

布隆过滤器是由一个很长的bit数组和一系列哈希函数组成的。
数组的每个元素都只占1bit空间,并且每个元素只能为0或1。
布隆过滤器还拥有k个哈希函数,当一个元素加入布隆过滤器时,会使用k个哈希函数对其进行k次计算,得到k个哈希值,并且根据得到的哈希值,在数组中把对应下标的值置位1。
判断某个数是否在布隆过滤器中,就对该元素进行k次哈希计算,得到的值在位数组中判断每个元素是否都为1,如果每个元素都为1,就说明这个值在布隆过滤器中。

2.为什么会误判
  • 当插入的元素越来越多时,当一个不在布隆过滤器中的元素,经过同样规则的哈希计算之后,得到的值在位数组中查询,有可能这些位置因为其他的元素先被置1了。
  • 所以布隆过滤器存在误判的情况,但是如果布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就一定不在。

2.缓存空对象

1.原理

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

2.方法产生的问题
  • 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
  • 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

七、缓存击穿

1.概述

缓存击穿,是指一个key非常热点,大并发的集中对这一个点进行访问,但是当redis中这个点在一个瞬间失效(缓存过期)了,那么这些大并发的访问都会直接请求数据库,给数据库瞬间造成极大的压力。

2.解决方法

  • 设置热点数据永不过期,
  • 后台定义一个job(定时任务)专门主动更新缓存数据.比如,一个缓存中的数据过期时间是30分钟,那么job每隔29分钟定时刷新数据(将从数据库中查到的数据更新到缓存中),这种方案比较容 易理解,但会增加系统复杂度。比较适合那些 key 相对固定,cache 粒度较大的业务,key 比较分散的则不太适合,实现起来也比较复杂。
  • 使用分布式锁,保证在高并发情况下每次同时只有一个线程去查询数据库,其他线程没有获得分布式锁的权限,其余的进行等待,这样就将高并发的压力转移到了分布式锁。

八、缓存雪崩

1.概述

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

2.解决方法

  • 搭建集群,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作
  • 限流降级,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待
  • 数据预热,数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值