Redis面试精选
1、redis 简介
简单来说 redis 就是一个数据库,不过与传统https://download.csdn.net/download/liyangxueit/12307486库不同的是 redis 的数据是存在内存中的,所以存写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
基本概念
redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库(非关系性数据库)。
redis的优势
- 速度快,(1)因为数据存在内存中,(2)类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
- 支持丰富数据类型,支持string,list,set,sorted set,hash
- 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
- 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
2、为什么要用 redis /为什么要用缓存
主要从“高性能”和“高并发”这两点来看待这个问题。
高性能:
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在数缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
redis的应用场景
- 缓存
(1) 对于一些要返回给前端数据的缓存,当有大量数据库sql操作时候,为了避免每次接口请求都要去查询数据库,可以把一些数据缓存到redis中,这样是直接从内存中获取数据,速度回增快很多。
(2) web端用户,用于登陆缓存session数据,登陆的一些信息存到session中,缓存到redis中
- 队列
redis中提供了list接口,这个list提供了lpush和rpop,这两个方法具有原子性,可以插入队列元素和弹出队列元素。
- 数据存储
redis是非关系型数据库,可以把redis直接用于数据存储,提供了增删改查等操作,因为redis有良好的硬盘持久化机制,redis数据就可以定期持久化到硬盘中,保证了redis数据的完整性和安全性。
- redis锁实现防刷机制
redis锁可以处理并发问题,redis数据类型中有一个set类型,set类型在存储数据的时候是无序的,而且每个值是不一样的,不能重复,这样就可以快速的查找元素中某个值是否存在,精确的进行增加删除操作
3、为什么要用 redis 而不用 map/guava 做缓存?
缓存分为本地缓存和分布式缓存。以 Java 为例,使用自带的 map 或者 guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 jvm 的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。
使用 redis 或 memcached 之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。缺点是需要保持 redis 或 memcached服务的高可用,整个程序架构上较为复杂。
4、redis 和 memcached 的区别
对于 redis 和 memcached 的区别有下面四点。
- redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
- Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中。
- 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的.
- Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型。
5、redis 常见数据结构以及使用场景分析
Redis支持五中数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及zset(sortedset:有序集合)。
5.1、字符串(STRING)
String是Redis最基本的数据类型,结构为一个key对应一个value。
String类型是二进制安全的,意味着可以包含任何数据,比如jpg图片或者序列化的对象。
String类型的最大能存储512M。
不像Linux有那么多充满想象力的命令,还喜欢带一对莫名其妙的参数。Redis的原语命令很简单,而且有规律可循,一句话概括,就是干净利索脆。
比如我们想设置往Redis中存放一个用户名,用String类型存储:
127.0.0.1:6379> SET name chenlongfei
OK
“OK”是Redis返回的响应,代表设置成功。
取出这个name的值:
127.0.0.1:6379> GET name
"chenlongfei"
想修改name的值为“clf”,重新SET一遍,覆盖掉原来的值:
127.0.0.1:6379> SET name clf
OK
127.0.0.1:6379> GET name
"clf"
想删除该条数据:
127.0.0.1:6379> DEL name
(integer) 1 --该数字代表影响的记录总数
127.0.0.1:6379> GET name
(nil) --nil代表为空,不存在该对象
增删改查命令一分钟学会,想忘记都难,妈妈再也不用担心我的学习!
5.2、哈希(HASH)
Redis的哈希是field和value之间的映射,即键值对的集合,所以特别适合用于存储对象。
Redis 中每个 hash 最多可以存储 232 - 1 键值对(40多亿)。
例如,我们想在Redis中存储一个用户信息,包括用户ID,用户名,邮箱地址三个字段:
127.0.0.1:6379>HMSET user_1 userId 123 userName clf email chenlongfei@163.com
OK
127.0.0.1:6379> HGETALL user_1
1) "userId"
2) "123"
3) "userName"
4) "clf"
5) "email"
6) chenlongfei@163.com
5.3、列表(LIST)
Redis列表是简单的字符串列表,按照插入顺序排序。支持添加一个元素到列表头部(左边)或者尾部(右边)的操作。
一个列表最多可以包含 232- 1 ,即超过40亿个元素。
例如,我们想用一个名为“Continents”的列表盛放五大洲的名字:
127.0.0.1:6379> LPUSH Continents Asia Africa America Oceania Antarctica
(integer) 5
127.0.0.1:6379> LRANGE Continents 0 4 --获取下标为0~4的元素
1) "Antarctica"
2) "Oceania"
3) "America"
4) "Africa"
5) "Asia"
Redis列表虽然名为列表,其实从特性上来讲更像是栈,以最近放进去的元素为头,以最早放进去的元素为尾,所以,Redis列表的下标呈倒序排列。上例中依次放进去的五个元素:Asia、Africa、America、Oceania、Antarctica,下标分别为4、3、2、1、0。这与Java中List的概念完全不一样,需要特别注意。
与栈类似,当执行POP操作时,Redis列表弹出的是最新放进去的元素,类似于栈顶元素。
Redis列表还支持一种阻塞式操作,比如BLPOP(Blockd List Pop之缩写),移出并获取列表的第一个元素,如果列表没有元素(或列表不存在)会阻塞列表直到等待超时或发现可弹出元素为止。
例如,我们对一个不存在的列表“myList”执行BLPOP命令:
BLPOPmyList 20 -- 弹出myList列表的第一个元素,如果没有,阻塞20秒
该客户端会进入阻塞状态,如果20秒之内该列表存入了元素,则弹出:
27.0.0.1:6379> BLPOP myList 20 --若无元素则进入阻塞状态,限时20秒
1) "myList"
2) "hello"
(6.20s)
如果超时后仍然没有等到元素,则结束阻塞,返回nil:
127.0.0.1:6379> BLPOP myList 20
(nil)
(20.07s)
5.4、集合(SET)
Redis集合是String类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232- 1 ,即每个集合最多可存储40多亿个成员。
集合的一大特点就是不能有重复元素,如果插入重复元素,Redis会忽略该操作:
127.0.0.1:6379> SADD direction east west south north
(integer) 4
127.0.0.1:6379> SMEMBERS direction
1) "west"
2) "east"
3) "north"
4) "south"
127.0.0.1:6379> SADD direction east
(integer) 0 --east元素已经存在,该操作无效
127.0.0.1:6379> SMEMBERS direction
1) "west"
2) "east"
3) "north"
4) "south"
5.5、有序集合(ZSET)
Redis 有序集合和集合一样也是String类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。Redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232- 1 ,即每个集合最多可存储40多亿个成员。
例如,、使用有序列表来存储学生的成绩单:
127.0.0.1:6379> ZADD scoreList 82 Tom
(integer) 1
127.0.0.1:6379> ZADD scoreList 65.5 Jack
(integer) 1
127.0.0.1:6379> ZADD scoreList 43.5 Rubby
(integer) 1
127