什么是Redis

Redis是一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:

字符串类型 string

散列类型 Hash

列表类型 List

集合类型 set

有序集合类型 zset

为什么使用Redis

因为传统的关系型数据库如Mysql已经不能适用所有的场景了,比如秒杀的库存扣减,APP首页的访问流量高峰等等,都很容易把数据库打崩,所以引入了缓存中间件,也就是Redis,它是 开源的 高性能的 键值(Key-Value)存储数据库。主要应用:内容缓存、用于处理大量数据的高访问负载。目前市面上比较常用的缓存中间件就有 Redis ,考虑各种缓存中间件的优缺点,最后选择了Redis。

Redis有哪些优缺点

优点:

  • 性能极高,能到 100000 次/s 读写速度
  • 支持数据的持久化,对数据的更新采用Copy-on-write技术,可以异步地保存到磁盘上
  • 丰富的数据类型,String(字符串)、List(列表)、Hash(字典)、Set(集合)、Sorted Set(有序集合)
  • 原子性:Redis 的所有操作都是原子性的,多个操作通过 MULTI 和 EXEC 指令支持事务
  • 丰富的特性:key 过期、publish/subscribe、notify
  • 支持数据的备份,快速的主从复制
  • 节点集群,很容易将数据分布到多个Redis实例中

缺点:

  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写
  • 适合的场景主要局限在较小数据量的高性能操作和运算上

为什么要用 Redis /为什么要用缓存

使用缓存主要是为了提升用户体验以及应对更多的用户,使用缓存主要是为了提升用户体验以及应对更多的用户。

高性能:

假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!

高并发:

直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。

Redis的应用场景

Redis的主要应用场景还是用于做缓存,比如数据查询、新闻内容、商品内容等。其他的就是可以做排行榜、数据过期处理等。

Redis有哪些数据结构

字符串类型 string

散列类型 Hash

列表类型 List

集合类型 set

有序集合类型 zset

如果有大量的key需要设置同一时间过期,一般需要注意什么

到过期的那个时间点,Redis可能会出现短暂的卡顿现象(因为redis是单线程的),严重的话可能会导致服务器雪崩,所以我们一般在过期时间上加一个随机值,让过期时间尽量分散.

你使用过Redis分布式锁么,它是什么回事

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

使用过Redis做异步队列么,你是怎么用的

一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。

如果对方追问可不可以不用sleep呢

用 blpop/brpop 替代前面的 lpop/rpop,list 还有个指令叫 blpop阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。消息的延迟几乎为零。

Redis持久化数据和缓存怎么做扩容

使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。

什么是Redis持久化

Redis的所有数据都是保存在内存中,redis崩掉的话,会丢失。Redis持久化就是把数据保存到磁盘上(可永久保存的存储设备中),以便数据恢复。

Redis 的持久化机制是什么?各自的优缺点

  • RDB:通过快照完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘
  • AOF:一秒一次,每一次去通过一个后台的线程fsync操作,将每条写入命令,写入到日志,并作为日志。以追加的方式方式写入一个日志文件中,所以没有任何磁盘寻址的开销,所以很快。

优点

RDB:

它每次储存会生成多个数据文件,每个数据文件分别都代表了某一时刻Redis里面的数据。一旦服务挂了,我们想恢复多少分钟之前的数据,就去拷贝一份之前的数据文件就行。RDBRedis的性能影响非常小,是因为在同步数据的时候他只是fork了一个子进程去做持久化的,而且他在数据恢复的时候速度比AOF来的快。

AOF:

RDB最快是一分钟一次生成快照,AOF是一秒同步一次数据。那么最多丢一秒的数据。同时AOF在对数据文件进行操作的时候是以追加的方式方式写入,只会有一个文件,所以它的写入性能惊人,文件也不容易破损。


缺点

RDB:

都是快照文件,都是默认五分钟才会生成一次,最快一分钟。这意味着你这次同步到下次同步这中间五分钟的数据都很可能全部丢失掉。AOF则最多丢一秒的数据,数据完整性上高下立判。

AOF:

一样的数据,AOF文件比RDB还要大。

如何选择合适的持久化方式

全都使用,你单独用RDB你会丢失很多数据,你单独用AOF,你数据恢复没RDB来的快,如果出了问题,第一时间用RDB恢复,然后AOF做数据补全。

Redis持久化数据和缓存怎么做扩容

1、Redis缓存,可以使用一致性哈希实现动态扩容缩容。

2、Redis持久化数据,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定就不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。

什么是缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,我们数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。

如何解决缓存穿透

  • 在接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return,比如:id 做基础校验,id <=0的直接拦截等
  • 布隆过滤器

什么是缓存击穿

缓存击穿是指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。

如何解决缓存击穿

缓存击穿的话,设置热点数据永远不过期

Redis的过期键的删除策略有哪些

  1. 定时删除

    在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。

  2. 惰性删除

    放任过期键不管,每次从键空间中获取键时,检查该键是否过期,如果过期,就删除该键,如果没有过期,就返回该键。

  3. 定期删除

    每隔一段时间,程序对数据库进行一次检查,删除里面的过期键,至于要删除哪些数据库的哪些过期键,则由算法决定。

Redis key的过期时间和永久有效分别怎么设置

EXPIRE和PERSIST命令。

Redis是怎么持久化的?服务主从数据怎么交互的

RDB做镜像全量持久化,AOF做增量持久化。因为RDB会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要AOF来配合使用。在redis实例重启时,会使用RDB持久化文件重新构建内存,再使用AOF重放近期的操作指令来实现完整恢复重启之前的状态。

这里很好理解,把RDB理解为一整个表全量的数据,AOF理解为每次操作的日志就好了,服务器重启的时候先把表的数据全部搞进去,但是他可能不完整,你再回放一下日志,数据不就完整了嘛。不过Redis本身的机制是 AOF持久化开启且存在AOF文件时,优先加载AOF文件;AOF关闭或者AOF文件不存在时,加载RDB文件;加载AOF/RDB文件城后,Redis启动成功; AOF/RDB文件存在错误时,Redis启动失败并打印错误信息

对方追问那如果突然机器掉电会怎样

取决于AOF日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。

对方追问RDB的原理是什么

你给出两个词汇就可以了,fork和cow。fork是指redis通过创建子进程来进行RDB操作,cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

注:回答这个问题的时候,如果你还能说出AOF和RDB的优缺点,我觉得我是面试官在这个问题上我会给你点赞,两者其实区别还是很大的,而且涉及到Redis集群的数据同步问题等等。想了解的伙伴也可以留言,我会专门写一篇来介绍的。

Redis的同步机制了解么

Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将RDB文件全量同步到复制节点,复制节点接受完成后将RDB镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过AOF日志同步即可,有点类似数据库的binlog。

主从之间的数据怎么同步的

我先说下为啥要用主从这样的架构模式,前面提到了单机QPS是有上限的,而且Redis的特性就是必须支撑读高并发的,那你一台机器又读又写,这谁顶得住啊,不当人啊!但是你让这个master机器去写,数据同步给别的slave机器,他们都拿去读,分发掉大量的请求那是不是好很多,而且扩容的时候还可以轻松实现水平扩容。

img

回归正题,他们数据怎么同步的呢?

你启动一台slave 的时候,他会发送一个psync命令给master ,如果是这个slave第一次连接到master,他会触发一个全量复制。master就会启动一个线程,生成RDB快照,还会把新的写请求都缓存在内存中,RDB文件生成后,master会将这个RDB发送给slave的,slave拿到之后做的第一件事情就是写进本地的磁盘,然后加载进内存,然后master会把内存里面缓存的那些新命名都发给slave。

Redis的内存淘汰策略有哪些

当客户端会发起需要更多内存的申请,Redis检查内存使用情况,如果实际使用内存已经超出maxmemory,Redis就会根据用户配置的淘汰策略选出无用的key;

  1. volatile-lru:从设置过期时间的数据集(server.db[i].expires)中挑选出最近最少使用的数据淘汰。没有设置过期时间的key不会被淘汰,这样就可以在增加内存空间的同时保证需要持久化的数据不会丢失。

  2. volatile-ttl:除了淘汰机制采用LRU,策略基本上与volatile-lru相似,从设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰,ttl值越大越优先被淘汰。

  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。当内存达到限制无法写入非过期时间的数据集时,可以通过该淘汰策略在主键空间中随机移除某个key。

  4. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰,该策略要淘汰的key面向的是全体key集合,而非过期的key集合。

  5. allkeys-random:从数据集(server.db[i].dict)中选择任意数据淘汰。

  6. no-enviction:禁止驱逐数据,也就是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失,这也是系统默认的一种淘汰策略。

MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的

数据都是热点数据

计算20w的热点数据占据内存的大小。然后在Redis中,配置最大内存容量,在redis.conf文件maxmemory 标签中配置。
当redis内存数据大小上升到一定大小的时候,就会施行数据淘汰策略。
Redis中提供了6中数据淘汰策略:

  1. volatitle-lru 从设置了过期时间的数据集中,选择最近最少使用的数据删除
  2. volatitle-ttl 从设置了过期时间的数据集中,选择将要过期的数据删除
  3. volatitle-random 从设置了过期时间的数据中,随机选择数据进行删除
  4. Allkeys-lru 从数据集中挑选最近最少使用的数据删除
  5. Allkeys-random 从数据集中随机挑选数据进行淘汰
  6. no-enviction(驱逐):禁止淘汰数据

因为我们的应用保存热点数据,也就是对缓存的访问符合幂律分布,所以应该选择Allkeys-lru淘汰策略。存放热点数据,不能为数据设置过期时间,设置过期时间也会占用内存。

Redis的内存用完了会发生什么?

Redis 的默认回收策略是 noenviction,当内存用完之后,写数据会报错。

  • volatitle-lru 从设置了过期时间的数据集中,选择最近最少使用的数据删除
  • volatitle-ttl 从设置了过期时间的数据集中,选择将要过期的数据删除
  • volatitle-random 从设置了过期时间的数据中,随机选择数据进行删除
  • Allkeys-lru 从数据集中挑选最近最少使用的数据删除
  • Allkeys-random 从数据集中随机挑选数据进行淘汰
  • no-enviction(驱逐):禁止淘汰数据

什么是事务?

事务由单独单元的一个或者多个sql语句组成,在这个单元中,每个mysql语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条sql语句一旦执行失败或者产生错误,整个单元将会回滚,也就是所有受到影响的数据将会返回到事务开始以前的状态;如果单元中的所有sql语句均执行成功,则事务被顺利执行,数据才会发生修改。

概述事务管理(ACID)

A:原子性(Atomicity)  

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。可以理解为针对过程。

C:一致性(Consistency)

一致性是指事务前后的完整性必须保持一致。可以理解为针对结果。

I:隔离性(Isolation)

隔离性是指多个用户并发访问数据库时,数据库为每一个用户开启的事务不能被其他事物的操作所干扰,多个并发事务之间要相互隔离。即在事务提交之前对其他事务不可见。

D:持久性(Durability)

持久性是指一个事务一旦被提交,他对数据库中数据的改变是永久的,接下来即使数据库发生故障也不应该对其有任何影响。

Redis事务支持隔离性吗

支持,事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断

Redis事务保证原子性吗,支持回滚吗

不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制

PS:在redis中的命令语句中,命令是忽略大小写的,而key是不忽略大小写的。