Redis基础应用

说说你对redis的认识?

Redis(Remote Dictionary Server)是一个使用C语言编写的高性能内存数据库,基Key/Value结构存储数据, 一般会用来做缓存、消息队列,分布式锁,同时还支持事务 、持久化、主从和集群架构等。

Redis基础数据类型有哪些?

Redis基础数据类型:

  1. string以字符串形式存储数据,经常用于记录用户的访问次数、文章访问量等。
  2. hash以对象形式存储数据,比较方便的就是操作对象中的某个字段。
  3. list以列表形式存储数据,可记录添加顺序,允许元素重复。
  4. set以集合形式存储数据,不记录添加顺序,元素不能重复,也不能保证存储顺序。
  5. zset排序集合,可对数据基于某个权重进行排序。可做排行榜,取TOP N操作。

Redis过期数据的删除策略?

  1. 惰性删除
    在查询时,检测到key过期了,此时对key进行删除。这里的缺点是,假如key长时间不被访问,也就无法删除,此时就会一直占用着内存。
  2. 定期删除
    每隔一段时间对redis数据进行一次检查,删除过期key。但是这里并不会对所有key进行检查,只是随机取一些key,检查是否过期,过期了然后删除。

什么缓存穿透以及解决方案?

当访问一个缓存和数据库都不存在的 key时,请求会直接打到数据库上,并且查不到数据,没法写缓存,所以下一次同样会打到数据库上。这时缓存就好像被"穿透"了一样,起不到任何作用。假如一些恶意的请求,故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力,甚至数据库挂掉,这就叫做缓存穿透。

解决方案?

方案1:接口校验。在正常业务流程中可能会存在少量访问不存在 key 的情况,但是一般不会出现大量的情况,所以这种场景最大的可能性是遭受了非法攻击。可以在最外层先做一层校验,用户鉴权、数据合法性校验等,例如商品查询中,商品的ID是正整数,则可以直接对非正整数直接过滤等等。

方案2:缓存空值。当访问缓存和DB都没有查询到值时,可以将空值写进缓存,但是设置较短的过期时间,该时间需要根据产品业务特性来设置。

方案3:布隆过滤器。使用布隆过滤器存储所有可能访问的 key,不存在的 key 直接被过滤,存在的 key 则再进一步查询缓存和数据库。可把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

什么缓存雪崩以及解决方案?

缓存雪崩是当缓存服务器重启或者大量缓存集中在某一个时间段失效,造成瞬时数据库请求量大,压力骤增,导致系统崩溃。缓存雪崩其实有点像"升级版的缓存击穿",缓存击穿是一个热点 key,缓存雪崩是一组热点 key。

解决方案:

方案1:打散过期时间。不同的key,设置不同的过期时间(例如使用一个随机值),让缓存失效的时间点尽量均匀。

方案2:做二级缓存。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

方案3:加互斥锁。缓存失效后,通过加锁或者队列来控制写缓存的线程数量。比如对某个key只允许一个线程操作缓存,其他线程等待。

方案4:热点数据不过期。该方式和缓存击穿一样,要着重考虑刷新的时间间隔和数据异常如何处理的情况。

Redis的持久化机制

说说Redis的持久化逻辑?

Redis数据持久化从客户端发起请求开始,到服务器真实地写入磁盘,需要发生如下几件事情:

其过程描述如下:

  1. 客户端向数据库发送写命令 (数据在客户端的内存中)
  2. 数据库接收到客户端的写请求 (数据在服务器的内存中)
  3. 数据库调用系统 API将数据写入磁盘 (数据在内核缓冲区中)
  4. 操作系统将写缓冲区传输到磁盘控控制器 (数据在磁盘缓存中)
  5. 操作系统的磁盘控制器将数据写入实际的物理媒介中(数据在磁盘中)

说说Redis的持久化方式?

Redis持久化是把内存中的数据同步到硬盘文件中,当Redis重启后再将硬盘文件内容重新加载到内存以实现数据恢复的目的。具体持久化方式,分别为RDB和AOF方式。

说说Redis中RDB方式的持久化?

RDB方式的持久化是Redis数据库默认的持久化机制,是保证redis中数据可靠性的方式之一,这种方式可以按照一定的时间周期策略把内存中的数据以快照(二进制数据)的形式保存到磁盘文件中,即快照存储。对应产生的数据文件为dump.rdb。

RDB持久化方式的常用配置参数?

sql 复制代码
# 这里表示每隔60s,如果有超过1000个key发生了变更,就执行一次数据持久化。 
# 这个操作也被称之为snapshotting(快照)。 save 60 1000 
# 持久化 rdb文件遇到问题时,主进程是否接受写入,yes 表示停止写入, 
# 如果是no 表示redis继续提供服务。 stop-writes-on-bgsave-error yes 
# 在进行快照镜像时,是否进行压缩。yes:压缩, 
# 但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间。 rdbcompression yes 
# 一个CRC64的校验就被放在了文件末尾,当存储或者加载rbd文件的时候 
# 会有一个10%左右的性能下降,为了达到性能的最大化,你可以关掉这个配置项。 rdbchecksum yes 
# 快照的文件名 dbfilename dump.rdb 
# 存放快照的目录 dir /var/lib/redis

什么情况下会触发RDB持久化?

  1. 基于配置文件中的save规则周期性的执行持久化。
  2. 手动执行了shutdown操作会自动执行rdb方式的持久化。
  3. 手动调用了save或bgsave指令执行数据持久化。
  4. 主从复制架构下Slave连接到Master时,Master会对数据持久化,然后全量同步到Slave。

save和bgsave有什么不同?

SAVE生成 RDB 快照文件,但是会阻塞主进程,服务器将无法处理客户端发来的命令请求,所以通常不会直接使用该命令。 BGSAVE指令会fork 子进程来生成 RDB 快照文件,阻塞只会发生在 fork 子进程的时候,之后主进程可以正常处理请求。

RDB方式持久化有哪些优势?

  1. RDB 文件是压缩的二进制文件,占用空间小,保存的是某个时间点的数据,适合做备份。
  2. RDB 适用于灾难恢复,它只有一个文件,文件内容都非常紧凑,方便传送到其它数据中心。
  3. RDB 持久化性能较好,可由子进程处理保存工作,父进程无须执行任何磁盘 I/O 操作。

RDB方式持久化有哪些缺点?

1、RDB方式在服务器故障时容易造成数据的丢失。

实际项目中,我们可通过配置来控制持久化的频率。但是,如果频率太频繁,可能会对 Redis 性能产生影响。所以通常可能设置至少5分钟才保存一次快照,这时如果 Redis 出现宕机等情况,则意味着最多可能丢失5分钟数据。

2、RDB 方式使用 fork 子进程进行数据的持久化。

子进程的内存是在fork操作时父进程中数据快照的大小,如果数据快照比较大的话,fork 时开辟内存会比较耗时,同时这个fork是同步操作,所以,这个过程会导致父进程无法对外提供服务。

3、RDB持久化过程中的fork操作,可能会导致内存占用加倍。

Linux系统fork 子进程采用的是 copy-on-write 的方式(写时复制,修改前先复制),在 Redis 执行 RDB 持久化期间,如果 client 写入数据很频繁,那么将增加 Redis 占用的内存,最坏情况下,内存的占用将达到原先的2倍。

如何理解AOF方式的持久化?

Redis中AOF方式的持久化是将Redis收到的每一个写命令都追加到磁盘文件的最后,类似于MySQL的binlog。当Redis重启时,会重新执行文件中保存的写命令,然后在内存中重建整个数据库的内容。

AOF 持久化默认是关闭的,可以通过配置appendonly yes 开启。当 AOF 持久化功能打开后,服务器在执行完一个写命令之后,会将被执行的写命令追加到服务器端 aof 缓冲区(aof_buf)的末尾,然后再将 aof_buf 中的内容写到磁盘。

Linux 操作系统中为了提升性能,使用了页缓存(page cache)。当我们将 aof_buf 的内容写到磁盘上时,此时数据并没有真正的落盘,而是存在在 page cache 中,为了将 page cache 中的数据真正落盘,需要执行 fsync / fdatasync 命令来强制刷盘。这边的文件同步做的就是刷盘操作,或者叫文件刷盘可能更容易理解一些。

AOF持久化方式有什么优势?

  • AOF方式 比 RDB方式的持久化更加可靠。

你可以设置不同的 fsync 策略(no、everysec 和 always)。默认是 everysec,在这种配置下,redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据。

  • AOF文件是一个基于纯追加模式的日志文件。

即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机等等), 我们也可以使用 redis-check-aof 工具也可以轻易地修复这种问题。

  • AOF文件太大时,Redis 会自动在后台进行重写。

重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。整个重写是绝对安全,因为重写是在一个新的文件上进行,同时 Redis 会继续往旧的文件追加数据。当新文件重写完毕,Redis 会把新旧文件进行切换,然后开始把数据写到新文件上。

  • AOF 文件以Redis协议的格式有序地保存了对数据库执行的所有写操作,可读性好。

对如果你不小心执行了 FLUSHALL 命令把所有数据刷掉了,但只要 AOF 文件没有被重写,那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF持久化方式有什么劣势?

  • 对于相同的数据集,AOF 文件的大小一般会比 RDB 文件大。

根据所使用的 fsync 策略,AOF 的速度可能会比 RDB 慢。通常 fsync 设置为每秒一次就能获得比较高的性能,而关闭 fsync 可以让 AOF 的速度和 RDB 一样快。

  • AOF 可能会因个别命令的原因,导致 AOF 文件在重新载入时,无法将数据恢复到原样。

虽然这种 bug 在 AOF 文件中并不常见, 但是相较而言, RDB 几乎是不可能出现这种 bug 的。

如何理解Redis的混合持久化?

混合持久化并不是一种全新的持久化方式,而是对已有方式的优化。混合持久化只发生于 AOF 重写过程。使用了混合持久化,重写后的新 AOF 文件前半段是 RDB 格式的全量数据,后半段是 AOF 格式的增量数据。

开启:混合持久化的配置参数为 aof-use-rdb-preamble,配置为 yes 时开启混合持久化,在 redis 4 刚引入时,默认是关闭混合持久化的,但是在 redis 5 中默认已经打开了。

关闭:使用 aof-use-rdb-preamble no 配置即可关闭混合持久化。混合持久化本质是通过 AOF 后台重写(bgrewriteaof 命令)完成的,不同的是当开启混合持久化时,fork 出的子进程先将当前全量数据以 RDB 方式写入到新的 AOF 文件,然后再将 AOF 重写缓冲区(aof_rewrite_buf_blocks)的增量命令以 AOF 方式写入到文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

优点:结合 RDB 和 AOF 的优点, 更快的重写和恢复。

缺点:AOF 文件里面的 RDB 部分不再是 AOF 格式,可读性差。

Redis为什么要AOF重写?

AOF持久化是通过保存被执行的写命令来记录数据库状态的,随着写入命令的不断增加,AOF文件中的内容会越来越多,文件的体积也会越来越大。如果不加以控制,体积过大的 AOF 文件可能会对 Redis 服务器、甚至整个宿主机造成影响,并且 AOF 文件的体积越大,使用 AOF 文件来进行数据还原所需的时间就越多。

举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。为了处理这种情况, Redis 引入了 AOF 重写,可以在不打断服务端处理请求的情况下, 对 AOF 文件进行重建(rebuild)。

描述一下AOF重写的过程?

Redis中的AOF重写是 生成新的 AOF 文件来代替旧 AOF 文件,这个新的 AOF 文件包含重建当前数据集所需的最少命令。具体过程是遍历所有数据库的所有键,从数据库读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令。

命令:有两个 Redis 命令可以用于触发 AOF 重写,一个是 BGREWRITEAOF(底层fork子进程来重写) 、另一个是 REWRITEAOF 命令(会阻塞主进程);

开启:AOF 重写由两个参数共同控制,auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size,同时满足这两个条件,则触发 AOF 后台重写 BGREWRITEAOF。例如:

// 当前AOF文件比上次重写后的AOF文件大小的增长比例超过100 auto-aof-rewrite-percentage 100 // 当前AOF文件的文件大小大于64MB auto-aof-rewrite-min-size 64mb

关闭:auto-aof-rewrite-percentage 0,指定0的百分比,以禁用自动AOF重写功能。

AOF 后台重写存在的问题?

AOF 使用子进程进行重写,解决了主进程阻塞的问题,但是仍然存在另一个问题,那就是子进程在进行 AOF 重写期间,服务器主进程还需要继续处理命令请求,新的命令可能会对现有的数据库状态进行修改,从而使得当前的数据库状态和重写后的 AOF 文件保存的数据库状态不一致。

Redis常用拓扑结构?

Redis为了实现其高可用性,基于需求不同定义了如下几种架构形式:

  • 主从架构(一主一从,一主多从,一主多从从)
  • 主从及哨兵架构
  • 多节点集群架构

3.2 Redis数据同步方式?

Redis数据同步分为全量同步和增量同步。

  • 全量同步

全量同步发生在slave第一次连接master时,其同步过程如下:

1)slave连接master。

2)主节点会执行bgsave指令,对数据进行持久化。

3)主节点将rdb文件发送给从节点.

4)从节点基于rdb文件恢复数据。

可能存在的问题:

对于全量同步,RDB文件生成时,Redis主进程可能还在接收写操作,这样会导致master和slave数据的不一致。还有假如RDB文件比较大,同步给slave时,因网络阻塞或中断,可能会有部分数据的丢失。

  • 增量同步

全量同步出现了中断或全量同步之后,Master又有新的写入操作,此时会触发增量同步。

其同步过程如下:

  1. 从节点会继续发送同步请求。

  2. 主节点基于数据同步请求将写指令同步到从节点。

  3. 从节点执行指令进行数据更新。

Redis主从复制可能存在的问题?

主节点故障需要手动将从节点(Slave)升级为主节点(Master),主节点的写操作及存储将受到单机节点的限制。

3.4 如何理解Redis中的哨兵?

Redis中的哨兵本质上是一个服务(Redis哨兵节点),用于监控Redis数据节点,然后进行故障自动转移,实现高可用。

3.5 Redis中哨兵实现的底层原理?

Redis中的哨兵起到了一个定时监控的功能,每隔1秒会向数据节点发送心跳,检测网络和节点状态,然后还会每隔10秒向数据节点发送info命令获取新的拓扑结构。

假如在响应时间超过了哨兵配置的down-after-milliseconds值(默认30秒),则sentinel节点会认为该节点下线了。这种下线为主观下线,当某个sentinel认为一个数据主节点主观下线了,这个哨兵(sentinel)还会与其它sentinel进行通讯,询问这个主节点的状态,假如有多个sentinel节点(具体几个可以通过配置实现,一般默认是一半)认为这个主节点有问题,此时sentinel会对主节点做出客观下线的决定。此时,Sentinel节点之间会有一个领导的选举工作,它们会从中选择一个Sentinel节点作为领导者进行故障转移工作。

从slave节点中选举一个节点作为新的主节点(Master),sentinel会向其它从节点发送命令,让他们成为新的主节点的从节点,sentinel会将原有主节点更新为从节点,假如故障恢复了,让此节点连接新的主节点。

Redis新的主节点选举过程?

第一步:过滤不健康节点(ping不通)。

第二步:选择优先级最高的从节点。

第三步:假如优先级都一样,选择数据最完整。

第四步:选择runid最小的(每个redis实例启动后都会随机生成一个40位的runid)。

Redis集群要解决什么问题?

第一、Redis集群要解决数据分区(分片)存储,增加存储容量、提高读写响应速度。

第二、Redis集群支持高可用,实现主从节点的自动故障转移。

3.8 Redis集群如何实现故障转移的?

第一、集群中每个节点都会定期向其它节点发送ping消息,回复为pong。

第二、当发送ping消息的节点没有收到pong回复时,则主观认为节点下线。

第三、集群内当半数以上持有槽节点认为节点主观下线,则触发客观下线流程。

第四、如果客观下线的节点是主节点,则从它的从节点中选出一个节点作为主节点。

Redis集群是如何实现数据分区的?

1、方案1:节点取余hash(key)%n

  1. 优点:简单、适合节点数量比较稳定的场景。

  2. 缺点:节点数量发生变化时,数据和节点映射关系发生变化。导致数据需要重新迁移。

2、方案2: 一致性哈希 分区

此方案基于节点IP求hash值,然后基于IP的hash值构建虚拟环,最后将key/value存储到虚拟环上的节点中(顺时针方向按区间存储)。

  1. 优点:节点数量发生变化时,只影响hash环中相邻的两个节点。

  2. 缺点:圆环上的节点分配不均匀,一个节点故障,顺时方向的下一个节点读写压力就会变大

3、方案3:虚拟槽分区(redis)

将redis集群设置多个虚拟槽(总计0~16383个槽),每个虚拟槽会对应一个数据集(一个范围值),基于对key进行CRC16(key)&16383计算结果进行数据存储。

优点:数据分配均匀,通过槽实现了数据和实际节点之间的解耦,节点数量发生了变化(扩容、缩容)对整个系统的影响很小(只需要对槽进行重新分配即可)。

相关推荐
nongcunqq26 分钟前
abap 操作 excel
java·数据库·excel
rain bye bye1 小时前
calibre LVS 跑不起来 就将setup 的LVS Option connect下的 connect all nets by name 打开。
服务器·数据库·lvs
Kiri霧2 小时前
Rust开发环境搭建
开发语言·后端·rust
阿里云大数据AI技术2 小时前
云栖实录|MaxCompute全新升级:AI时代的原生数据仓库
大数据·数据库·云原生
不剪发的Tony老师3 小时前
Valentina Studio:一款跨平台的数据库管理工具
数据库·sql
间彧3 小时前
Spring事件监听与消息队列(如Kafka)在实现解耦上有何异同?
后端
间彧3 小时前
Java如何自定义事件监听器,有什么应用场景
后端
叶梅树3 小时前
从零构建A股量化交易工具:基于Qlib的全栈系统指南
前端·后端·算法
间彧3 小时前
CopyOnWriteArrayList详解与SpringBoot项目实战
后端
间彧3 小时前
SpringBoot @FunctionalInterface注解与项目实战
后端