redis面试题 Redis简介和优缺点 Redis 与memcached 相比有哪些优势? redis数据类型 Redis 主要消耗什么物理资源? 数据淘汰策略 一个字符串类型的值能存储最大容量是多少? MySQL里有2000w 数据,redis中只存20w的数据,如何保证redis 中的数据都是热点数据? 过期策略 LRU算法 为什么Redis 需要把所有数据放到内存中? Redis 如何做内存优化? Redis 集群会有写操作丢失吗?为什么? Redis 集群的主从复制模型是怎样的? Redis 中的管道有什么用? 缓存

redis本质上是一个Key- Value 类型的内存数据库,是纯内存操作。定期 通过异步操作把数据库数据flush 到硬盘上进行保存。

优点: - 性能出色 - 支持保存多种数据结构,且单个value最大限制是1GB - 可以设置一个时效时间

应用:List做FIFO双向链表就可以实现一个轻量级的高性能消息队列服务。而用Set就可以做一个高性能的tag系统

缺点:数据库容量收到物理内存限制,不好做海量数据的高性能读写。

Redis 与memcached 相比有哪些优势?

1 .memcached 所有的值均是简单的字符串, redis 作为其替代者, 支持更为丰富的数据类型 2.redis 的速度比memcached 快很多 3.redis可以持久化数据

redis数据类型

String 、List 、Set、Zset 、hash

Redis 主要消耗什么物理资源?

内存

数据淘汰策略

作为一个内存数据库,redis在内存空间不足的时候,为了保证命中率,就会选择一定的数据淘汰策略

  • volatile-lru(推荐使用):从设置了过期时间的数据集中,选择最近最久未使用的数据释放;
  • allkeys-lru:从数据集中(包括设置过期时间以及未设置过期时间的数据集中),选择最近最久未使用的数据释放;
  • volatile-random:从设置了过期时间的数据集中,随机选择一个数据进行释放;
  • allkeys-random:从数据集中(包括了设置过期时间以及未设置过期时间)随机选择一个数据进行入释放;
  • volatile-ttl:从设置了过期时间的数据集中,选择马上就要过期的数据进行释放操作;
  • noeviction(默认):不删除任意数据(但redis还会根据引用计数器进行释放),这时如果内存不够时,会直接返回错误。

一个字符串类型的值能存储最大容量是多少?

512M

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

限定redis占用的内存,redis会根据自身数据淘汰策略,留下热数据到内存。所以可以计算100w数据大约占用的内存,

然后设置一下redis内存限制即可,并将淘汰策略设置为allkeys-lru或者volatile-lru.

设置redis最大占用内存:

打开redis配置文件,设置maxmemory参数,maxmemory是bytes字节类型哦!

maxmemory 268435456

设置过期策略:

maxmemory-policy volatile-lru

过期策略

redis会把设置了过期时间的key放入一个独立的字典里,在key过期时并不会立刻删除它。而是通过两种策略:

  • 惰性删除:客户端访问某个key,redis检查key是否过期,过期了就删掉
  • 定期扫描:redis默认每秒执行10次过期扫描,扫描策略如下:
    1. 从过期字典中随机选择20个key
    2. 删除20个key中已过期的key
    3. 如果过期的key比例超过25%就会重复第一步

LRU算法

维护一个链表,用于顺序存放被访问过的key,在访问数据是,最新访问过的key将被移动到表头,这样最近访问的key在表头,最少访问的key在表尾

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

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写 入磁盘。所以redis 具有快速和数据待久化的特征,如果不将数据放在内存中, 磁盘I/O速度为严重影响redis的性能。

Redis 如何做内存优化?

尽可能使用散列表(hashes) , 散列表(是说散列表里面存储的数少) 使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。 比如你的web系统中有一个用户对象,不要为这个用户的名称, 姓氏, 邮箱, 密码设罢单独的key, 而是应该把这个用户的所有信息存储到一张散列表里面。

Redis 集群会有写操作丢失吗?为什么?

Redis 并不能保证数据的强一致性, 这意味这在实际中集群在特定的条件下可能会丢失写操作。

Redis 集群的主从复制模型是怎样的?

为了使在部分节点在失败或者大部分节点无法通信的情况下集群仍然可用, 所以集群使用了主从复制模型, 每个节点都会有N - 1 个复制品.

Redis 中的管道有什么用?

一次清求/响应服务器能实现处理新的清求即使旧的清求还未被响应, 这样就可以将多个命令发送到服务器, 而不用等待回复, 最后在一个步骤中读取该答复。这就是管道( pi pelinin g ) , 比如我在论坛系统项目中邮件发送了解到的POP3 协议已经实现支待这个功能,可以大大加快了从服务器下载新邮件的过程。

缓存

缓存雪崩

对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机。缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据库必然扛不住,它会报一下警,然后就挂了。此时,如果没有采用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。

这就是缓存雪崩。

缓存雪崩的事前事中事后的解决方案如下。

事前:redis 高可用,主从+哨兵,redis cluster,避免全盘崩溃。 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。 事后:redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

用户发送一个请求,系统 A 收到请求后,先查本地 ehcache 缓存,如果没查到再查 redis。如果 ehcache 和 redis 都没有,再查数据库,将数据库中的结果,写入 ehcache 和 redis 中。

限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空白的值。

好处:

  • 数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。
  • 只要数据库不死,就是说,对用户来说,部分的请求都是可以被处理的。
  • 只要有部分的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来一次。

缓存穿透

对于系统A,假设一秒 5000 个请求,结果其中 4000 个请求是找不到的

比如发出的那 4000 个请求,缓存中查不到,每次你去数据库里查,也查不到。

举个栗子。数据库 id 是从 1 开始的,结果黑客发过来的请求 id 全部都是负数。这样的话,缓存中不会有,请求每次都“视缓存于无物”,直接查询数据库。这种恶意攻击场景的缓存穿透就会直接把数据库给打死。

解决方式很简单,每次系统 A 从数据库中只要没查到,就写一个空值到缓存里去,比如 set -999 UNKNOWN。然后设置一个过期时间,这样的话,下次有相同的 key 来访问的时候,在缓存失效之前,都可以直接从缓存中取数据。

缓存击穿

缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

解决方式也很简单,可以将热点数据设置为永远不过期;或者基于 redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据。