Redis

本文详细介绍了NOSQL数据库中的Redis,包括其特点、数据类型(如String、哈希、列表、集合和有序集合)、线程模型、持久化策略(RDB和AOF)、事务处理以及主从复制和哨兵机制。此外,还讨论了缓存问题及其解决方案:缓存穿透、击穿和雪崩。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NOSQL(Not Only SQL)

NoSQL泛指非关系型数据库,区别于关系型数据库(使用标准的sql语言进行操作)

关系型数据库&非关系型数据库

优点: 易扩展、高性能、灵活的数据模型

关系型数据库:

采用关系模型组织数据的数据库

优点:

  • 容易理解
  • 易于维护,其完整性大大降低了数据冗余和数据不一致的概率缺点

缺点:

  • IO瓶颈
  • 海量数据查询效率低
  • 横向扩展困难,无法简单的通过添加硬件和服务节点来扩展性能和负载能力

非关系型数据库

非关系型,分布式,一般不保证遵循 ACID 原则的数据存储系统。键值对存储,结构不固定

优点:

  • 结构简单易扩展
  • 高性能
  • 数据模型灵活

缺点:

  • 存储简单数据
  • 不适合复杂查询数据

Redis是什么

是一个开源的,使用C语言编写;是键值对存储在内存中,也可以存储在硬盘上,存储结构简单、性能高、易于扩展、支持多语言、保证操作原子性、支持多种数据类型

redis主要用来做数据缓存,数据也保存在内存中,一般将redis称为中间件

Redis数据类型

redis是以键值对进行存储的,键都是String

五种基本常用类型

redis支持多种类型的数据类型,五种数据类型指的是String(字符串)、Hash(哈希)、List(列表)、Set、Zset(有序)

在这里插入图片描述

底层数据结构6种

简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组

在这里插入图片描述

全局哈希表:在这里插入图片描述

底层结构是hash结构,可以通过key值计算出位置,将key-value都存储在此位置

  • 哈希冲突问题:

    提供两块内存空间,相当于扩容,将原来的映射渐进式的复制到扩容的哈希表中,然后释放之间的空间

String(字符串)

String是redis最基本的类型,一个key对应value

单值缓存

例:

  • set key value
  • get key
  • del key

对象缓存(不对对象中数据操作时可以使用)

set user : 1 value(json格式数据)

计数器

例:

  • set news_views : 1 0 设置文章访问量
  • incr news_views : 1 文章访问量+1
  • decr news_views : 1 文章访问量-1
  • get news_views : 1 获得值

Web集群session共享

session + redis 实现 session 共享

Hash(哈希)

redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象(对对象中的数据发生修改情况)。 存的是字符串和字符串值之间的映射,比如要存储用户购物车等信息

  • hset key 属性 值 存储一个哈希表key的键值。
  • hmset key 属性1 值1 属性2 值2
  • hmget key 属性1 属性2
  • hdel key 属性 获取哈希表key对应的属性键值
  • hlen key 返回哈希表key中的属性的数量
  • hgetall key 返回哈希表key 中所用的键值
  • hincrby key 属性 增加的值(减少给负数)

List(列表)

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

  • lpush key value[value…] 将一个或多个值插入到 key 列表的表头(最左边)
  • rpush key value[value…] 将一个或多个值插入到 key 列表的表尾(最右边)
  • lpop key 移除并返回 key 列表的头元素
  • rpop key 移除并返回 key 列表的尾元素
  • lrange key start stop 返回列表key中指定区间内的元素,区间以偏移量start和 stop

Set(集合)

Redis的Set是无序集合

  • sadd key member[member…] 往集合 key 中存入元素,元素存在则忽略,若 key 不存在则新建
  • srem key member[member…] 从集合 key 中删除元素
  • smembers key 获取集合 key 中所有元素
  • scard key 获取集合 key 的元素个数

Zset(sorted set :有序集合)

redis zset 也是不允许重复的成员,但是是有序的。不同的是每个元素都会关联一个double类型的分数,而redis正是通过这样的分数来为集合中的成员进行从小到大的排序

zset的成员是唯一的,但是分数(score)是可以重复的

Redis线程模型

redis是单线程模式还是多线程模式?

不同的版本有区别:

6.x之前是是真正意义上的单线程:处理客户端的连接和执行操作的命令,都是由一个线程来完成的

6.x之后引入多线程:处理客户端请求是由专门的线程处理,执行命令还是单线程

为什么设计为单线程模式,速度还非常快?

  1. 数据存储在内存中,读取速度快,CPU不是性能瓶颈
  2. 结构简单,key-value底层是哈希结构,查询速度是O(1)
  3. 采用IO多路复用,非阻塞IO模型,提高连接访问效率
  4. 单线程执行命令,不存在线程切换,节省开销,而且是线程安全的

Redis持久化

IO对象持久化,对象序列化,对象信息持久保存到硬盘上

mybatis是一个Java的数据持久层款框架

redis数据是存储在内存中,内存数据是临时保存的

redis支持将数据持久化到硬盘

redis是如何进行数据持久化的?

RDB和AOF(这两种方式都在redis.conf文件可配置)

redis默认使用RDB方式

RDB: 直接将内存的数据快照(key-value)存储起来

配置触发持久化的机制:

  1. save m n save 多少秒内 多少键
  2. flushall 命令,也会触发rdb 规则
  3. 退出redis,也会产生rdb文件

备份自动生成一个 dump.rdb.

关机后下次启动 redis 会自动将文件中的数据还原到内存中.

优点:

1.适合大规模的数据恢复!

2.对数据的完整性要不高!

缺点:

需要一定的时间间隔进程操作!如果 redis 意外宕机了,这个最后一次修改数据就没有了

AOF方式

以日志的形式,将写命令存储到文件,还原时,将命令逐个执行还原数据

开启方式

AOF机制默认是不开启的

修改 redis.conf 配置文件,开启 AOF 机制

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

appendfilename appendonly.aof #默认的文件名是 appendonly.aof,可

以通过 appendfilename 参数修改

AOF 同步机制

appendfsync always #每次修改都会 sync。消耗性能

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

重启 redis 生效

Redis事务

redis在执行单条命令时,是原子性(单线程的,一次只能有一个线程执行命令),有时候,一次操作需要执行多条命令

如何保证多条命令整体执行?

可以通过redis事务实现:

开启事务:multi

添加命令:命令添加进来不会立即执行,添加到一个多列

执行exec命令时,才会将队列中的多条命令依次执行,执行一个事务中多条命令时,其他客户端会被隔离,不会交替执行,但是事务不保证多条命令执行的原子性(假如执行3条命令,其中有一条语法出错了,那么会将其他两条正确继续执行)

redis 的事务:

  • 开启事务(multi)
  • 命令入队(…)
  • 执行事务(exec)
  • 放弃事务(discard)

主从复制

主从–>主机和从机—集群架构

为什么用集群?

如果只有一台redis服务,万一服务宕机,所有的请求都会到达MySQL,导致MySQL宕机,可以搭建多台redis服务器,如果其中一台出现故障,其他服务也可以正常使用

哨兵机制

有一个单独线程,对集群中的多态服务进行监听,给每个服务发请求,如果没有响应,表明出现故障,比如主机宕机,会在从机选取一台当做主机,当原来主机恢复后,又可以当做主机继续使用。

key的过期策略

为key设置过期时间,那么时间到了后,redis如何处理过期的key?

  1. 立即删除,到期立即执行回调函数,立即释放内存,对redis性能有影响
  2. 惰性删除,根据状态(设置时会有记录)来决定是删除还是继续使用占用内存
  3. 定期删除,每隔一段时间对所有到期的键进行删除(类似于Java的垃圾回收线程)

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

缓存处理流程

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

数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

在这里插入图片描述

缓存穿透
在这里插入图片描述

所有查询的数据,在数据库中没有查询后,也不在缓存中存储,请求都会到数据库,从而可能压垮数据库。

比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库

数据库没有,缓存没有

解决办法:

  1. 本来数据库没有,将查询出来的空值放到缓冲中
  2. 对查询的参数进行验证
    缓存击穿

数据库有数据,只是某个热点key在某个时间点上过期了,此时有大量查询请求到达(查询是不加锁),这些请求发现缓存过期,一起都向数据库发起请求,导致数据库崩溃

在这里插入图片描述

解决办法:

  1. 热点数据设置永不过期
  2. 查询缓存没有后,访问数据库时可以加锁(互斥锁)

缓存雪崩

大量的热点key过期,或者redis服务故障,大量的请求到达数据库

在这里插入图片描述

解决办法:

  1. 随机设置有效时间,避免集体失效
  2. 把不同的热点key放在不同的redis服务上(集群)
  3. 不设置过期时间
  4. 在Java中设置定时任务去检测key是否过期
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值