Redis面试知识扫盲

Redis简介

Redis是一个把数据存在内存中的数据库,因此读写速度非常快,被广泛用于缓存方向。此外Redis还可用来做分布式锁。Redis提供了多种数据类型来支持不同的业务场景。redis支持事务 持久化 lua脚本 LRU事件驱动 多种集群方案

为什么要用redis/为什么要用缓存?

使用缓存可以带来两个好处:高性能与高并发。

高性能

如果用户是第一次访问数据库中的数据,这个过程是比较慢的,因为是从磁盘上读取数据的。如果将访问的数据放入缓存,下次读取就直接可以从缓存中读取,会更快。如果对应数据库中的数据改变了,只需对应改变缓存中的数据即可。

高并发

直接操作缓存能够承受的请求时远远大于直接操作数据库的,所以把数据库中部分数据转移到缓存中,这样就可以是的用户的一部分的请求会直接去缓存请求而不用请求数据库,减轻数据库的请求压力。

为什么要用redis而不用map/guava做缓存?

缓存分为本地缓存与分布式缓存。map/guava是本地缓存,有点是轻量高速,生命周期随着JVM的销毁而结束。在多实例情况下,每个实例都要保存自己独立的缓存,缓存不具有数据一致性。

redis与memcached是属于分布式缓存,在多实例情况下,多个实例共用一个缓存,缓存具有一致性。但是为了保证redis与memcached服务的高可用性,程序的架构比较复杂。

redis与memcached的区别

  1. redis支持更多的数据类型(也就是支持更复杂的业务场景):redis不仅支持简单的key/value类型的数据,同时还提供list,set,zset与hash等复杂数据结构。memcached支持简单的数据类型(文本型与二进制类型)
  2. Redis支持数据的持久化(RDB,与AOF),可以将内存中的数据存在磁盘中,重启时可以再次加载到内存中进行使用,memcached吧数据全部存在内存之中
  3. 集群模式:Redis支持原生的集群模式。而memcached不支持原生的cluster,需要依靠客户端来首先往集群中分片写入数据。
  4. redis是单线程多路io复用模型,memcached是多线程,非阻塞io复用模型

Redis常见数据结构以及使用场景的分析

1.String

常用命令: set,get,decr,incr,mget 等。

简单的key/value类型,value可以是字符串也可以是数字。

2.Hash

常用命令: hget,hset,hgetall 等。

hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以 hash 数据结构来存储用户信息,商品信息等等。比如下面我就用 hash 类型存放了我本人的一些信息:

key=JavaUser2748234783
value={“id”: M20187336,“name”: “BOB LUO”,“age”: 22,“location”: “Wuhan, Hubei”
}

3.List

常用命令: lpush,rpush,lpop,rpop,lrange等

list 就是链表,Redis list 的应用场景非常多,也是Redis最重要的数据结构之一,比如微博的关注列表,粉丝列表,消息列表等功能都可以用Redis的 list 结构来实现。

Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。

另外可以通过 lrange 命令,就是从某个元素开始读取多少个元素,可以基于 list 实现分页查询,这个很棒的一个功能,基于 redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西(一页一页的往下走),性能高。

4.Set

常用命令:** sadd,spop,smembers,sunion 等

set 对外提供的功能与list类似是一个列表的功能,特殊之处在于 set 是可以自动排重的。

当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。

比如:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程,具体命令如下:

sinterstore key1 key2 key3     将交集存在key1内

5.Sorted Set

常用命令: zadd,zrange,zrem,zcard等

和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。

举例: 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 Sorted Set 结构进行存储

redis设置过期时间

Redis可以设置过期时间,这其实是很有用的,可以用于一些token或者验证码信息,提高项目的性能(不用自己实现验证码过期)

假设设置了一批key过期时间为30s,30s后,redis是怎样删除他们的。

有两种策略,惰性删除定期删除

  • 定期删除:redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查他们是否过期,过期则删除。
  • 惰性删除:定期删除可能导致很多过期的key没有被删除。所以就使用惰性删除,就是系统查询对应key事,才会被redis删除。

可以感觉到这两种删除还是有可能导致很多过期的key仍在内存中。这个时候就需要使用redis的内存淘汰机制了。

Redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)

redis 配置文件 redis.conf 中有相关注释,我这里就不贴了,大家可以自行查阅或者通过这个网址查看: http://download.redis.io/redis-stable/redis.conf

其实就是一些常用的淘汰策略LRU,LFU等

redis 提供 6种数据淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

4.0版本后增加以下两种:

  1. volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
  2. allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key

redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)

什么是持久化

狭义的理解: “持久化”仅仅指把域对象永久保存到数据库中;广义的理解,“持久化”包括和数据库相关的各种操作。

● 保存:把域对象永久保存到数据库。

● 更新:更新数据库中域对象的状态。

● 删除:从数据库中删除一个域对象。

● 加载:根据特定的OID,把一个域对象从数据库加载到内存。

● 查询:根据特定的查询条件,把符合查询条件的一个或多个域对象从数据库 加载内在存中

很多时候我们需要持久化数据也就是将内存中的数据写入到硬盘里面,大部分原因是为了之后重用数据(比如重启机器、机器故障之后恢复数据),或者是为了防止系统故障而将数据备份到一个远程位置。

Redis不同于Memcached的很重一点就是,Redis支持持久化,而且支持两种不同的持久化操作。Redis的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file,AOF)。这两种方法各有千秋,下面我会详细这两种持久化方法是什么,怎么用,如何选择适合自己的持久化方法

快照(snapshotting)持久化(RDB)

Redis可以通过创建快照来获得内存中在某个时间带你存储的数据的副本。并对副本进行备份复制到其他服务器中(Redis的主从结构),也可以将副本留在本地一边重启服务器的时候使用

快照是Redis默认采用的持久化方式,在redis.conf配置文件中默认有以下配置:

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

AOF(append-only file)持久化

与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:

appendonly yes

开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。

在Redis的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:

appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no        #让操作系统决定何时进行同步

为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec选项 ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

Redis 4.0 对于持久化机制的优化

Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差。

补充内容:AOF 重写

AOF重写可以产生一个新的AOF文件,这个新的AOF文件和原有的AOF文件所保存的数据库状态一样,但体积更小。

AOF重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有AOF文件进行任何读入、分析或者写入操作。

在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作

Redis事务

Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。

在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的可靠性和安全性。在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有持久性(Durability)

缓存雪崩和缓存穿透问题解决方案

缓存雪崩

缓存雪崩是指缓存在同一时间大面积失效,所以后面的请求都会落到数据库,造成数据库短时间承受大量请求而崩溃

解决措施:

  • 事前:尽量保证整个redis集群的高可用性,发现机器宕机尽快补上,选择合适的内存淘汰策略
  • 事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL(数据库)崩掉
  • 事后:利用redis持久化机制保存的数据尽快恢复内存

缓存穿透

缓存穿透指黑客故意请求缓存中不存在的数据,导致所有的请求都落到了数据库上,造成数据库短时间内承受大量请求而崩掉。

解决办法: 有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

如何解决Redis的并发竞争key的问题

所谓 Redis 的并发竞争 Key 的问题也就是多个系统同时对一个 key 进行操作,但是最后执行的顺序和我们期望的顺序不同,这样也就导致了结果的不同!

推荐一种方案:分布式锁(zookeeper 和 redis 都可以实现分布式锁)。(如果不存在 Redis 的并发竞争 Key 问题,不要使用分布式锁,这样会影响性能)

基于zookeeper临时有序节点可以实现的分布式锁。大致思想为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。完成业务流程后,删除对应的子节点释放锁。

在实践中,当然是从以可靠性为主。所以首推Zookeeper

如何保证缓存与数据库双写时的数据一致性?

一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案,读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况

串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。

Redis面试知识扫盲(面试宝典)相关推荐

  1. 【面试资料】 Java中高级核心面试知识解析

    [面试资料] Java中高级核心面试知识解析 一.Java (一). 基础 (二). 容器 (三). 并发 (四). JVM 二.网络 (一). 计算机网络知识 (二). HTTPS中的TLS 三.L ...

  2. Linux纯干货知识总结 | 面试专用

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:阿里技术官方号 https://blog.csdn.net/ ...

  3. java如何实现redis分片存储_面试官:你说一下Redis吧,怎么实现高可用,还有持久化怎么做的?...

    前言 作为Java程序员,在面试过程中,缓存相关的问题是躲不掉的,肯定会问,例如缓存一致性问题,缓存雪崩.击穿.穿透等.说到缓存,那肯定少不了Redis,我在面试的时候也是被问了很多关于Redis相关 ...

  4. 【PHP 面试知识梳理】

    PHP 面试知识梳理 算法与数据结构 BTree和B+tree BTree B树是为了磁盘或者其他存储设备而设计的一种多叉平衡查找树,相对于二叉树,B树的每个内节点有多个分支,即多叉. 参考文章:ht ...

  5. redis怎么修改_面试官问我Redis事务,还问我有哪些实现方式

    ❝ 「第12期」 距离大叔的80期小目标还有68期,今天大叔要跟大家分享的内容是 -- Reids中的事务.同样,这也是redis中重要指数为四颗星的必备基础知识点.下面一起来了解一下吧. ❞ 相信大 ...

  6. 给北上奋进的你一份礼物(java面试知识储备攻略)

    写在前边: 自己带了近俩年的俩个小伙伴要脱离公司,去北上发展,自己其实提供不了太多帮助,想起自己那几年在帝都面试or被面试的场景,在看看他们迷茫的不知道该准备点什么知识去应对面试的情况下,思考了一下午 ...

  7. *Java软件开发面试知识整理*

    Java软件开发面试知识整理 围绕以下几点回答问题:是什么.为什么.什么时候用.项目实现.解决什么问题.遇到的困难 谈谈你对Java和C的理解? Java: 面向对象.Unicode:可以跨平台(JV ...

  8. Redis学习笔记(面试+实战)

    文章目录 概念(面试) 1.什么是Redis 2.Redis的优缺点 3.Redis为什么这么快 4.Redis的持久化 4.1 什么是Redis持久化 4.2 Redis持久化机制 4.2.1RDB ...

  9. Redis你能跟面试官聊哪些?

    简介:以上文章讲述的是[数据库性能调优知识与面试知识(详解四服务器性能剖析)]接下来我总结一下[Redis入门知识点].觉得我还可以的可以加群一起督促学习探讨技术.QQ群:1076570504 个人学 ...

  10. C C++ 面试知识总结,包含STL,数据结构等

    五万字长文 C C++ 面试知识总结(上) https://juejin.im/post/5cbd7603e51d456e2446fcaf 五万字长文 C C++ 面试知识总结(中) https:// ...

最新文章

  1. Google 发布浏览器3D插件 O3D API
  2. 面向过程与面向对象编程的区别和优缺点
  3. python_wifi
  4. 一文让你完全弄懂Stegosaurus
  5. 【Qt】2D绘图之涂鸦板
  6. iOS手势操作简介(六)
  7. Recursive sequence HDU - 5950
  8. 关于OC中的block自己的一些理解(二)
  9. java内存模型—先行发生原则
  10. APP设计~切图那些事儿
  11. 如何找出电脑里的流氓软件_可怕:正版的流氓软件,100个人的电脑里99台都安装了...
  12. 文件指针以及文件的打开与关闭
  13. imap收取163/126邮件报错
  14. ubuntu安装使用redis并设置开机启动
  15. 学习笔记(8):ArcGIS10.X入门实战视频教程(GIS思维)-矢量数据数量分级显示、图表显示,多属性、lyr保存
  16. 转:优秀的人,往往都具备这5种视角
  17. 中国房价必跌的40个理由
  18. i3 1005G1和 i5 1035G1 哪个好
  19. 单元库质量验证方法之compare library
  20. 银行应用USB Key身份认证方案

热门文章

  1. Django (十一) 项目部署 2
  2. HighNewTech:元宇宙(metaverse)的简介(多角度理解与探讨)、发展历史、现状与未来
  3. 终极卸载PC奇安信天擎
  4. String s1 = new String(abc)到底创建了几个对象?底层原理是什么?
  5. 关于Chrome的广告和弹窗拦截插件
  6. java 读取手机sd卡_获取Android手机中SD卡内存信息
  7. 潮流计算程序————支路功率计算与输出程序
  8. 隧道调频广播覆盖系统技术方案
  9. oracle插入表当前时间,ORACLE自动插入当前时间
  10. 【干货】数据结构与算法该如何正确学习?(书籍\视频\网站都推荐了)