Java面试题-Redis(更新于202004)

目录

@、什么是redis?

@、使用redis做缓存的原因?

@、Redis官方为什么不提供Windows版本?

@、Memcache与Redis的区别都有哪些?

@、Redis相比memcached有哪些优势?

@、Redis有哪些数据结构?

@、为什么redis需要把所有数据放到内存中?

@、redis丢失问题常见原因?

@、redis的事务?

@、什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

@、Redis如何做持久化的?

@、对多级缓存的理解?

@、redis常见性能问题和解决方案

@、Redis有哪些适合的场景?


@、什么是redis?

Redis的全称Remote Dictionary Server。

Redis 是一个基于内存的高性能key-value非关系型数据库,由于数据存在内存里面,读写速度特别快。

很像memcached,整个数据库都加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。

因为是纯内存操作,所以Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DataBase。

Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,

比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。

另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。

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

@、使用redis做缓存的原因?

redis是用C语言编写的,稳定性和性能更好。支持集群模式和持久化等特性,不会应为缓存量太多而导致虚拟机崩溃。Redis是独立部署的,即使网站更新,redis缓存的数据也不会消失。

集群搭建(redis需要3台主机,3台从机,则配置6台,需要6个端口):

1:安装ruby环境,上传接口工程,安装接口程序,拷贝脚本到指定位置

2:创建6个redis实例,修改配置文件 ,然后启动所有redis实例(为简化启动步骤,可编写启动脚本)。

3:执行创建集群的命令,连接测试

@、Redis官方为什么不提供Windows版本?

因为目前Linux版本已经相当稳定,而且用户量很大,无需开发windows版本,反而会带来兼容性等问题。

@、Memcache与Redis的区别都有哪些?

1)存储方式

Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。

Redis可以把数据保存在硬盘上,用来保证数据的持久性。

2)数据类型

Memcache的数据类型比较简单。

Redis有复杂的数据类型。

3)使用底层模型不同

它们之间底层的实现方式 以及与客户端之间通信的应用协议不一样。

4)value大小

redis最大可以达到1GB,而memcache只有1MB

@、Redis相比memcached有哪些优势?

(1) 数据类型:memcached所有的值均是简单的字符串,redis作为其替代者, 支持更为丰富的数据类型

(2) redis的速度比memcached快很多

(3) redis可以持久化其数据

@、Redis有哪些数据结构?

字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。

String字符串:

格式: set key value

string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

string类型是Redis最基本的数据类型,一个键最大能存储512MB。

Hash(哈希)

格式: hmset name  key1 value1 key2 value2

Redis hash 是一个键值(key=>value)对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

List(列表)

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

格式: lpush  name  value

在 key 对应 list 的头部添加字符串元素

格式: rpush  name  value

在 key 对应 list 的尾部添加字符串元素

格式: lrem name  index

key 对应 list 中删除 count 个和 value 相同的元素

格式: llen name  

返回 key 对应 list 的长度

Set(集合)

格式: sadd  name  value

Redis的Set是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

zset(sorted set:有序集合)

格式: zadd  name score value

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

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

更进一步,redis还有数据结构HyperLogLog、Geo、Pub/Sub、BloomFilter,RedisSearch,Redis-ML等

@、为什么redis需要把所有数据放到内存中?

Redis为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。

如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。

如果设置了最大使用的内存,则数据量达到内存限值后,将不能继续插入新值。

@、redis丢失问题常见原因?

程序bug或人为误操作

因客户端缓冲区内存使用过大,导致大量键被LRU淘汰

主库故障后自动重启,可能导致数据丢失

网络分区的问题,可能导致短时间的写入数据丢失

主从复制数据不一致,发生故障切换后,出现数据丢失

大量过期键,同时被淘汰清理

@、redis的事务?

Redis的事务是一组命令的集合,Redis事务的实现需要用到 MULTI 和 EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。

@、什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

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

3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?

redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

@、Redis如何做持久化的?

bgsave做镜像全量持久化,aof做增量持久化。

因为bgsave会耗费较长时间,达不到实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。

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

Redis会定期做aof重写,压缩aof文件日志大小。

在redis实例重启时,优先使用aof来恢复内存的状态,如果没有aof日志,就会使用rdb文件来恢复。

讲一下对Redis的同步机制的理解

Redis可以使用主从同步,从从同步。

第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。

加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

@、对多级缓存的理解?

多级缓存就是有多个缓存,将ehcache配合redis缓存,比如ehcache作为1级缓存,使用redis作为2级缓存。

@、redis常见性能问题和解决方案

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

@、Redis有哪些适合的场景?

(1)、会话缓存(Session Cache)最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。

(2)、全页缓存(FPC)除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

(3)、队列Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。

(4),排行榜/计数器Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:ZRANGE user_scores 0 10 WITHSCORESAgora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。

(5)、发布/订阅最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章