- Redis是什么
Redis 是一个基于内存的高性能key-value数据库
2.Redis相比memcached有哪些优势
- redis支持更为丰富的数据类型
- redis的速度比memcached快很多
- redis可以持久化其数据
3.Redis为什么是单线程的
因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了
4.为什么Redis是单线程还这么快
- 完全基于内存操作,数据都是存在内存中,键值对的形式储存
- 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的
- 避免了不必要的上下文切换,也不存在多线程的切换而消耗CPU
- 使用多路I/O复用模型,非阻塞IO
- 自己构建了VM机制,避免调用系统函数浪费时间
5.说一下Redis的持久化机制
- RDB持久化:该机制可以在指定的时间间隔内生成数据集的时间点快照
- AOF持久化:记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集
6.Redis的优缺点
优点 :
- 性能极高
- 丰富的数据类型
- 原子性,Redis所有的操作都是原子性的
- 丰富的特性,支持发布订阅,通知,key过期等
缺点 :
- 内存数据库,内存大小是Redis的瓶颈,内存增长过快,需要定期删除数据
- 进行重启将硬盘中的数据加载进内存,时间比较久。在这个过程中,redis不能提供服务
7.Redis适合的场景有哪些
- 会话缓存
- 全页缓存
- 队列
- 排行榜/计数器
- 发布/订阅
8.如何保证Redis储存的数据都是热点数据
实行数据淘汰策略
9.Redis的数据淘汰策略
- volatile-lru :从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
- volatile-ttl :从已设置过期时间的数据集中挑选将要过期的数据淘汰
- volatile-random :从已设置过期时间的数据集中任意选择数据淘汰
- allkeys-lru :从数据集中挑选最近最少使用的数据淘汰
- allkeys-random :从数据集中任意选择数据淘汰
- no-enviction (驱逐):禁止驱逐数据,新写入操作会报错
10.缓存雪崩是怎么产生的,怎么解决
原因 :
缓存在同一时刻失效,导致大量请求直接访问数据库,而对数据库造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
解决 :
大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开。
11.缓存穿透是怎么产生的,怎么解决
原因 :
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
解决 :
- 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。(推荐)
- 如果查询返回的数据为空,仍然把这个空的结果进行缓存,把过期时间设置得很短,最长不超过五分钟。
12.Redis多机部署如何保证数据一致性
主从复制,读写分离
一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
13.Redis对于大量请求怎么处理
redis是一个单线程程序,也就说同一时刻它只能处理一个客户端请求;
redis是通过IO多路复用(select,epoll, kqueue,依据不同的平台,采取不同的实现)来处理多个客户端请求的
14.Redis常见性能问题和解决方案
- Master最好不要做任何持久化工作(Master本身压力就很大,持久化操作会更加加大Master的压力),如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
- 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
- 尽量避免在压力很大的主库上增加从库
- 主从复制不要用图状结构,用单向链表结构更为稳定
15.为什么Redis的操作是原子性的,怎么保证原子性的
Redis的操作之所以是原子性的,是因为Redis是单线程的。Redis本身提供的所有API都是原子操作,Redis中的事务其实是要保证批量操作的原子性。
16.说一下Redis的事务
- Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的
- Redis会将一个事务中的所有命令序列化,然后按顺序执行
- Redis 不支持回滚,Redis在事务失败时不进行回滚,而是继续执行余下的命令, 所以 Redis 的内部可以保持简单且快速
- 如果在一个事务中的命令出现错误,那么所有的命令都不会执行
- 如果在一个事务中出现运行错误,那么正确的命令会被执行
17.为什么Redis不支持回滚
只有当发生语法错误(这个问题在命令队列时无法检测到),Redis命令才会执行失败, 或对keys赋予了一个类型错误的数据:这意味着这些都是程序性错误,这类错误在开发的过程中就能够发现并解决掉,几乎不会出现在生产环境。不需要回滚也使得Redis内部更加简单,而且运行速度更快。
- Redis怎么开启AOF
Redis服务器默认开启RDB,关闭AOF。要开启AOF,需要在配置文件中配置:appendonly yes
19.如何选择持久化策略
- 如果Redis中的数据完全丢弃也没有关系(如Redis完全用作DB层数据的cache),那么无论是单机,还是主从架构,都可以不进行任何持久化
- 在单机环境下(对于个人开发者,这种情况可能比较常见),如果可以接受十几分钟或更多的数据丢失,选择RDB对Redis的性能更加有利;如果只能接受秒级别的数据丢失,应该选择AOF
- 在多数情况下,我们都会配置主从环境,slave的存在既可以实现数据的热备,也可以进行读写分离分担Redis读请求,以及在master宕掉后继续提供服务
20.为什么需要持久化
由于Redis是一种内存型数据库,即服务器在运行时,系统为其分配了一部分内存存储数据,一旦服务器挂了,或者突然宕机了,那么数据库里面的数据将会丢失,为了使服务器即使突然关机也能保存数据,必须通过持久化的方式将数据从内存保存到磁盘中
21.Redis和数据库如何保证数据一致性
原因:
读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存和数据库间的数据一致性问题。不管是先写数据库,再删除缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。举个例子:
- 如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。
- 如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。
解决:
- 延时双删:在写库前后都进行redis的缓存删除,并且第二次以延迟的方式进行。第二次缓存要延迟删除主要是删除在写请求过程中造成的读请求脏数据。
- 主动加载:在db更新的时候同步或者异步进行缓存更新。写流程:第一步先删除缓存,删除之后再更新DB,之后再异步将数据刷回缓存。读流程:第一步先读缓存,如果缓存没读到,则去读DB,之后再异步将数据刷回缓存。
22.Redis的缓存并发问题怎么解决
这里的并发指的是多个redis的client同时set key引起的并发问题。比较有效的解决方案就是把redis.set操作放在队列中使其串行化,必须的一个一个执行。当然加锁也是可以的。
23.说说Redis的三种不同缓存删除策略
定时删除 :在设置键的过期时间的同时,创建一个定时任务,当键达到过期时间时,立即执行对键的删除操作
惰性删除 :放任键过期不管,但在每次从键空间获取键时,都检查取得的键是否过期,如果过期的话,就删除该键,如果没有过期,就返回该键
定期删除 :每隔一点时间,程序就对数据库进行一次检查,删除里面的过期键,至于要删除多少过期键,以及要检查多少个数据库,则由算法决定
24.如何使用Redis做异步队列
一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。