redis面试题

redis是C语言编写的,key-value数据库,包含的数据类型:自符串、列表、集合、有序集合、hash。
数据是在内存中操作的,定期flush到硬盘上保存,因此,他是现在以知的最快的key-value DB。单个key的数据最大为1G。memcached最大为1M.

redis与memcached的区别:

  • Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
  • redis支持主从复制,master-salve的模式
  • reids支持数据持久化,memcached只能将数据存在内存中
  • redis的速度比memcached块
  • Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的IO复用模型

使用缓存的优点:

  • 提高性能。查询速度比查询mysql速度块
  • 提高并发能力。缓存缓解了部分请求

redis的优点

  • 速度块
  • 支持丰富的数据类型
  • 支持事务
  • 可用于缓存,可以设置消息过期时间

redis命中率

命中:可以通过缓存取的所需的数据
为名中:无法通过缓存取的所需的数据,需要再次查询数据库或执行其他操作

info 
keyspace_hits:0                #命中
keyspace_misses:0          #未命中

命中率:keyspace_hits/(keyspace_misses+keyspace_hits)
一般情况下,一个缓存失效机制,和过期时间设计良好的系统命中率可以达到95%

最大空间:缓存中可以存放的最大元素的数量,一旦缓存中元素数量超过这个值就会触发缓存启动清空策率

清空策率:

  • FIFO(先进先出)最先进入缓存的数据在缓存空间不够的情况下(超出最大元素限制)会被优先被清除掉,以腾出新的空间接受新的数据。策略算法主要比较缓存元素的创建时间。在数据实效性要求场景下可选择该类策略,优先保障最新数据可用。
  • LFU(最少使用政策):无论是否过期,根据元素的被使用次数判断,清除使用次数较少的元素释放空间
  • LRU(最近最少使用)根据元素最后一次被使用的时间戳,清除最远使用时间戳的元素释放空间

redis缓存失效移除政策
redis-key的三种过期政策:

  • 惰性删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key,这是被动的!
  • 定期删除:由于惰性删除策略无法保证冷数据被及时删掉,所以 redis 会定期主动淘汰一批已过期的key。
  • 主动删除:当前已用内存超过maxmemory限定时,触发主动清理策略,该策略由启动参数的配置决定,可配置数据淘汰策略

影响缓存命中率的几个因素:
1、业务场景和业务需求:缓存适合“读多写少”的业务场景,反之,使用缓存的意义其实并不大,命中率会很低。互联网应用的大多数业务场景下都是很适合使用缓存的。

2、缓存的设计(粒度和策略):通常情况下,缓存的粒度越小,命中率会越高。
例如:当缓存单个对象的时候(例如:单个用户信息),只有当该对象对应的数据发生变化时,我们才需要更新缓存或者让移除缓存。而当缓存一个集合的时候(例如:所有用户数据),其中任何一个对象对应的数据发生变化时,都需要更新或移除缓存。
此外,缓存的更新/过期策略也直接影响到缓存的命中率。当数据发生变化时,直接更新缓存的值会比移除缓存(或者让缓存过期)的命中率更高,当然,系统复杂度也会更高。

3、缓存容量和基础设施
缓存的容量有限,则容易引起缓存失效和被淘汰(目前多数的缓存框架或中间件都采用了LRU算法)。同时,缓存的技术选型也是至关重要的,比如采用应用内置的本地缓存就比较容易出现单机瓶颈,而采用分布式缓存则毕竟容易扩展。所以需要做好系统容量规划,并考虑是否可扩展。通常,两种也可以结合使用,不过实现复杂度也会相应提升,具体看并发量。

4、其他因素
当缓存节点发生故障时,需要避免缓存失效并最大程度降低影响,这种特殊情况也是架构师需要考虑的。业内比较典型的做法就是通过一致性Hash算法,或者通过节点冗余的方式。

提高缓存命中率的方法:
通常来讲,在相同缓存时间和key的情况下,并发越高,缓存的收益会越高,即便缓存时间很短。
需要在业务需求,缓存粒度,缓存策略,技术选型等各个方面去通盘考虑并做权衡。尽可能的聚焦在高频访问且时效性要求不高的热点业务上,通过缓存预加载(预热)、增加存储容量、调整缓存粒度、更新缓存等手段来提高命中率。

对于时效性很高(或缓存空间有限),内容跨度很大(或访问很随机),并且访问量不高的应用来说缓存命中率可能长期很低,可能预热后的缓存还没来得被访问就已经过期了。

redis缓存雪崩

  • 由于redis的宕机,导致全部请求都请求数据库

解决方法:
1.使用redis集群或使用redis的哨兵模式(宕机前)
2.使用本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库被干掉(宕机时)
3.使用数据持久化(RDB<快照>或AOF<保存命令>)

  • redis设置的缓存清除策略导致,设置了相同的清空时间,导致缓存失效

解决方法:在缓存的时候给过期时间加上一个随机值,尽量避免在同一时间缓存失效

redis缓存穿透

由于每次请求一个一定不存在的key,导致redis不命中,因此每次请求都去数据库查询,增加数据库的压力,严重会导致数据库的崩溃

解决方法:
1.使用布隆过滤器,将不合法的请求过滤掉,使之无法到达数据库层
2.将这个空值设置到缓存中,当遇到这个值时就返回设定值,当然,应该给该值设定一个短的过期时间

MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?
当缓存达到大小达到一定值时,就会使用淘汰策略

Redis支持的Java客户端都有哪些?官方推荐用哪个?
redisson、jedis 官方推荐redisson

redis与redisson的关系
Redisson是一个高级的分布式协调Redis客服端

jedis与redisson的区别
jedis是java实现的redis客户端,功能齐全。而redisson的宗旨是使用者对redis的分离,使其更专著于业务代码

redis的主从复制是异步复制

redis事务
redis事务是连续的指令集,当执行事务时,redis不会停止,直到事务执行完成
事务的原子性:要么事务全部执行、要么事务全不执行
若要进行复杂的操作,可以使用lua脚本

查看redis的信息命令:info

redis是单线程的,如何高效的使用CPU
在一台机器上启动多个redis实例或者使用数据分片

redis常见的性能问题及解决方法
1.master最好不要作数据持久化
2.在一个slave节点进行数据持久化,使用AOF,每秒一次

  1. 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...
    这样遇到单点问题只是slave1变为master,其他不变

redis集群:

  • cluster
  • codis


    image.png

    Codis 是一个代理中间件,用的是 GO 语言开发的,因为Codis是一个无状态的,所以可以增加多个Codis来提升QPS,同时也可以起着容灾的作用

RDB的缺点:

  • 不能保持高的数据可用性,若在持久化之前数据丢失,就无法备份
  • 使用fork子进程完成的,在集群规模较大时,容易影响服务器性能

AOF的缺点:

  • 恢复速度比RDB慢
  • AOF运行效率低于RDB

Redis性能调优

简单的redis优化

  • 尽量使用短的key,因为在redis中,key也是会占先当大的存储空间的
  • 不要使用keys * ,这条命令是阻塞的。当执行这条命令时,该实例不会再处理其他请求。使用SCAN代替(SCAN,用于迭代元素,每次返回少量的元素)
  • 设置key的有效时间
  • 选择合适的回收策略

尽管Redis是一个非常快速的内存数据存储媒介,也并不代表Redis不会产生性能问题。
前文中提到过,Redis采用单线程模型,所有的命令都是由一个线程串行执行的,所以当某个命令执行耗时较长时,会拖慢其后的所有命令,这使得Redis对每个任务的执行效率更加敏感。

针对Redis的性能优化,主要从下面几个层面入手:

  • 最初的也是最重要的,确保没有让Redis执行耗时长的命令
  • 使用pipelining将连续执行的命令组合执行
  • 操作系统的Transparent huge pages功能必须关闭:
echo never > /sys/kernel/mm/transparent_hugepage/enabled

  • 如果在虚拟机中运行Redis,可能天然就有虚拟机环境带来的固有延迟。可以通过./redis-cli --intrinsic-latency 100命令查看固有延迟。同时如果对Redis的性能有较高要求的话,应尽可能在物理机上直接部署Redis。
  • 检查数据持久化策略
  • 考虑引入读写分离机制

长耗时命令

Redis绝大多数读写命令的时间复杂度都在O(1)到O(N)之间,在文本和官方文档中均对每个命令的时间复杂度有说明。

通常来说,O(1)的命令是安全的,O(N)命令在使用时需要注意,如果N的数量级不可预知,则应避免使用。例如对一个field数未知的Hash数据执行HGETALL/HKEYS/HVALS命令,通常来说这些命令执行的很快,但如果这个Hash中的field数量极多,耗时就会成倍增长。
又如使用SUNION对两个Set执行Union操作,或使用SORT对List/Set执行排序操作等时,都应该严加注意。

避免在使用这些O(N)命令时发生问题主要有几个办法:

  • 不要把List当做列表使用,仅当做队列来使用
  • 通过机制严格控制Hash、Set、Sorted Set的大小
  • 可能的话,将排序、并集、交集等操作放在客户端执行
  • 绝对禁止使用KEYS命令
  • 避免一次性遍历集合类型的所有成员,而应使用SCAN类的命令进行分批的,游标式的遍历

Redis提供了SCAN命令,可以对Redis中存储的所有key进行游标式的遍历,避免使用KEYS命令带来的性能问题。同时还有SSCAN/HSCAN/ZSCAN等命令,分别用于对Set/Hash/Sorted Set中的元素进行游标式遍历。SCAN类命令的使用请参考官方文档:https://redis.io/commands/scan

Redis提供了Slow Log功能,可以自动记录耗时较长的命令。相关的配置参数有两个:

slowlog-log-slower-than xxxms  #执行时间慢于xxx毫秒的命令计入Slow Log
slowlog-max-len xxx  #Slow Log的长度,即最大纪录多少条Slow Log

使用SLOWLOG GET [number]命令,可以输出最近进入Slow Log的number条命令。
使用SLOWLOG RESET命令,可以重置Slow Log

网络引发的延迟

  • 尽可能使用长连接或连接池,避免频繁创建销毁连接
  • 客户端进行的批量数据操作,应使用Pipeline特性在一次交互中完成。具体请参照本文的Pipelining章节

数据持久化引发的延迟

Redis的数据持久化工作本身就会带来延迟,需要根据数据的安全级别和性能要求制定合理的持久化策略:

  • AOF + fsync always的设置虽然能够绝对确保数据安全,但每个操作都会触发一次fsync,会对Redis的性能有比较明显的影响
  • AOF + fsync every second是比较好的折中方案,每秒fsync一次
  • AOF + fsync never会提供AOF持久化方案下的最优性能
  • 使用RDB持久化通常会提供比使用AOF更高的性能,但需要注意RDB的策略配置
  • 每一次RDB快照和AOF Rewrite都需要Redis主进程进行fork操作。fork操作本身可能会产生较高的耗时,与CPU和Redis占用的内存大小有关。根据具体的情况合理配置RDB快照和AOF Rewrite时机,避免过于频繁的fork带来的延迟

Redis在fork子进程时需要将内存分页表拷贝至子进程,以占用了24GB内存的Redis实例为例,共需要拷贝24GB / 4kB * 8 = 48MB的数据。在使用单Xeon 2.27Ghz的物理机上,这一fork操作耗时216ms。

可以通过INFO命令返回的latest_fork_usec字段查看上一次fork操作的耗时(微秒)

Swap引发的延迟

当Linux将Redis所用的内存分页移至swap空间时,将会阻塞Redis进程,导致Redis出现不正常的延迟。Swap通常在物理内存不足或一些进程在进行大量I/O操作时发生,应尽可能避免上述两种情况的出现。

/proc/<pid>/smaps文件中会保存进程的swap记录,通过查看这个文件,能够判断Redis的延迟是否由Swap产生。如果这个文件中记录了较大的Swap size,则说明延迟很有可能是Swap造成的。

数据淘汰引发的延迟

当同一秒内有大量key过期时,也会引发Redis的延迟。在使用时应尽量将key的失效时间错开。

引入读写分离机制

Redis的主从复制能力可以实现一主多从的多节点架构,在这一架构下,主节点接收所有写请求,并将数据同步给多个从节点。
在这一基础上,我们可以让从节点提供对实时性要求不高的读请求服务,以减小主节点的压力。
尤其是针对一些使用了长耗时命令的统计类任务,完全可以指定在一个或多个从节点上执行,避免这些长耗时命令影响其他请求的响应。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352