redis 面试题

redis的基本数据类型 以及应用场景

String(字符串)

简介:String是Redis最基础的数据结构类型,它是二进制安全的,可以存储图片或者序列化的对象,值最大存储为512M。
简单使用举例: set key value、get key等。
应用场景:k-v式缓存、分布式锁,计数器等。

Hash(哈希)

简介:在Redis中,哈希类型是指v(值)本身又是一个键值对(k-v)结构。
简单使用举例:hset key field value 、hget key field。
应用场景:缓存用户信息等。

List(列表)

简介:列表(list)类型是用来存储多个有序的字符串,一个列表最多可以存储2^32-1个元素。
简单实用举例:lpush key value [value …] 、lrange key start end。
应用场景:消息队列,文章列表。

Set(集合)

简介:集合(set)类型也是用来保存多个的字符串元素,但是不允许重复元素。
简单使用举例:sadd key element [element …]、smembers key。
应用场景:用户标签,生成随机数抽奖、社交需求。

有序集合(zset)

简介:已排序的字符串集合,同时元素不能重复。

简单格式举例:zadd key score member [score member …],zrank key member。
应用场景:排行榜,社交需求(如用户点赞)。

redis优缺点

优点:
1.高性能 高并发
2.支持数据持久化
3.支持事务(redis所有操作都是原子性的)
4.支持主从复制(一份数据 多个节点备份)
缺点:
1.数据库容量小
2.可能导致系统安全问题

redis为什么这么快

1.完全基于内存
2.数据结构简单
3.采用单线程
基于内存存储实现

我们都知道内存读写是比在磁盘快很多的,Redis基于内存存储实现的数据库,相对于数据存在磁盘的MySQL数据库,省去磁盘I/O的消耗。

高效的数据结构

在这里插入图片描述

合理的数据编码

Redis 支持多种数据数据类型,每种基本类型,可能对多种数据结构。什么时候,使用什么样数据结构,使用什么样编码,是redis设计者总结优化的结果。

String:如果存储数字的话,是用int类型的编码;如果存储非数字,小于等于39字节的字符串,是embstr;大于39个字节,则是raw编码。
List:如果列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),使用ziplist编码,否则使用linkedlist编码
Hash:哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable编码。
Set:如果集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码。
Zset:当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码

合理的线程模型

I/O 多路复用

多路I/O复用技术可以让单个线程高效的处理多个连接请求,而Redis使用用epoll作为I/O多路复用技术的实现。并且,Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。

单线程模型

Redis是单线程模型的。

Redis 过期策略

定时过期

每个设置过期时间的key 过期立即清除,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。

惰性过期

访问key时,判断key是否过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

定期过期

定时扫描部分key,检查其中过期的key并清除。

每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。

Redis中同时使用了惰性过期和定期过期两种过期策略。

假设Redis当前存放30万个key,并且都设置了过期时间,如果你每隔100ms就去检查这全部的key,CPU负载会特别高,最后可能会挂掉。
因此,redis采取的是定期过期,每隔100ms就随机抽取一定数量的key来检查和删除的。
但是呢,最后可能会有很多已经过期的key没被删除。这时候,redis采用惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且已经过期了,此时就会删除。

Redis 内存淘汰策略

  1. noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键

  2. allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键

  3. volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键

  4. allkeys-random:加入键的时候如果过限,从所有key随机删除

  5. volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐

  6. volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键

  7. volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键。4.0版本新增

  8. allkeys-lfu:从所有键中驱逐使用频率最少的键。4.0版本新增

redis内存淘汰策略详解

redis内存淘汰策略简述+算法简介

redis实现分布式锁

因为redis是单线程单进程模式,故可以使用 setnx命令来实现分布式锁
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
可使用del命令来释放锁。
SETEX key seconds(过期时间) value  
ttl key 可以查看过期时间 为负数则表示过期

参考 redis分布式锁详解
redission详解

redis缓存异常

1.缓存雪崩: 在同一时间缓存大面积失效 并发量大 对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。
解决方案:
	1.缓存数据的过期时间设置随机,让缓存失效的时间点尽量均匀。
	2.并发量不大的时候可以 可以加锁排队。
	3. 双层缓存策略: C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2C1缓存失效时间设置为短期,C2设置为长期

2.缓存穿透 缓存和数据库都没有的数据 绕过缓存直接查数据库 并发量大 对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。
解决方案:
	1.采用布隆过滤器: 引入了多个互相独立的hash函数 将所有可能存在的数据哈希到一个足够大的map中,一个一定不存在的数据会被这个map拦截掉,从而避免了对底层存储系统的查询压力。
	2.缓存空对象 简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。优势:占用内存空间很小,位存储;性能特别高,使用key的hash判断key存不存在。
3.缓存击穿 缓存中没有但数据库有的数据 并发查同一条数据 引起数据库压力瞬间增大,造成过大压力
解决方案:
	1.加互斥锁 缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。
	如果是单机,可以用synchronized或者lock来处理;
	如果是分布式环境可以用分布式锁就可以了(分布式锁,可以用memcache的add, redis的setnx, zookeeper的添加节点操作)。
	2. “永不过期”,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间。

参考 redis详解

事务四大特性

原子性: 所有的指令要么都执行 要么都不执行
一致性: 如果数据库执行前是一致的,那么在事务执行后,无论事务是否执行成功,数据库也应该是一致的。
隔离性: 即使数据库中有多个事务并发地执行,各个事务之间也不会互相 影响,并且在并发状态下执行的事务和串行执行的事务产生的结果完全相同。
持久性: 执行这个事务所得的结果巳经被保存到 永久性存储介质(比如硬盘)里面了。

redis支持事务吗?

支持事务 但Redis不支持事务回滚机制
即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。
参考 redis事务详解
mysql undo log 日志可实现事务的回滚,通过插入一条执行结果相反的sql语句到日志中。可用于实现 MVCC 多版本并发控制这一机制
undo log 详解

redis 持久化机制

RDB快照

RDB快照是某个时间点的一次全量数据备份,是二进制文件,在存储上非常紧凑。

使用 bgsave命令 可手动触发RDB存储,执行bgsave命令时Redis主进程会fork一个子进程来完成RDB的过程,完成后自动结束。

优点

1.RDB文件小,非常适合定时备份,用于灾难恢复
2.Redis加载RDB文件的速度比AOF快很多,因为RDB文件中直接存储的时内存数据,而AOF文件中存储的是一条条命令,需要重演命令。

缺点

1.RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景。
2.RDB的cow机制中,fork子进程属于重量级操作,并且会阻塞redis主进程。
3.存在老版本的Redis不兼容新版本RDB格式文件的问题.

AOF

AOF日志是持续增量的备份,是基于写命令存储的可读的文本文件。直接调用bgrewriteaof命令来手动触发。

优点

AOF只是追加写日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少

缺点

1.AOF方式生成的日志文件太大,需要不断AOF重写,进行瘦身。
2.即使经过AOF重写瘦身,由于文件是文本文件,文件体积较大(相比于RDB的二进制文件)。
3. AOF重演命令式的恢复数据,速度显然比RDB要慢。

混合模式(4.0版本之后)
将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。即:

大量数据使用粗粒度(时间上)的rdb快照方式,性能高,恢复时间快。
增量数据使用细粒度(时间上)的AOF日志方式,尽量保证数据的不丢失。

参考 redis持久化机制详解

MySQL与Redis 如何保证双写一致性

缓存延时双删
删除缓存重试机制
读取biglog异步删除缓存

Redis 与 MySQL 保证数据一致性

延时双删

先删除缓存,再更新数据库,休眠一会(比如1秒),再次删除缓存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值