运维面试题-redis(转载)

1.Redis 是一个基于内存的高性能key-value数据库。

2.Redis相比memcached有哪些优点:

  • memcached全部的值均是简单的字符串,redis做为其替代者,支持更为丰富的数据类型
  • redis的速度比memcached快不少
  • redis能够持久化其数据

3.Redis是单线程

redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销php

4.Reids经常使用5种数据类型

  • string,list,set,sorted set,hash

6.Reids6种淘汰策略:

  • noeviction: 不删除策略, 达到最大内存限制时, 若是须要更多内存, 直接返回错误信息。大多数写命令都会致使占用更多的内存(有极少数会例外。
  • allkeys-lru:全部key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
  • volatile-lru:只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
  • allkeys-random:全部key通用; 随机删除一部分 key。
  • volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
  • volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。

7.Redis的并发竞争问题如何解决?

单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis自己没有锁的概念,Redis对于多个客户端链接并不存在竞争,利用setnx实现锁。前端

8.Redis是使用c语言开发的。

9.Redis前端启动命令

./redis-serverjava

10.Reids支持的语言:

java、C、C#、C++、php、Node.js、Go等。git

11.Redis 持久化方案:

Rdb 和 Aofgithub

12.Redis 的主从复制

持久化保证了即便redis服务重启也不会丢失数据,由于redis服务重启后会将硬盘上持久化的数据恢复到内存中,可是当redis服务器的硬盘损坏了可能会致使数据丢失,若是经过redis的主从复制机制就能够避免这种单点故障,redis

13.Redis是单线程的,但Redis为何这么快?

一、彻底基于内存,绝大部分请求是纯粹的内存操做,很是快速。数据存在内存中,相似于HashMap,HashMap的优点就是查找和操做的时间复杂度都是O(1);算法

二、数据结构简单,对数据操做也简单,Redis中的数据结构是专门进行设计的;数据库

三、采用单线程,避免了没必要要的上下文切换和竞争条件,也不存在多进程或者多线程致使的切换而消耗 CPU,不用去考虑各类锁的问题,不存在加锁释放锁操做,没有由于可能出现死锁而致使的性能消耗;数组

四、使用多路I/O复用模型,非阻塞IO;这里“多路”指的是多个网络链接,“复用”指的是复用同一个线程缓存

五、使用底层模型不一样,它们之间底层实现方式以及与客户端之间通讯的应用协议不同,Redis直接本身构建了VM 机制 ,由于通常的系统调用系统函数的话,会浪费必定的时间去移动和请求;

14.为何Redis是单线程的?

Redis是基于内存的操做,CPU不是Redis的瓶颈,Redis的瓶颈最有多是机器内存的大小或者网络带宽。既然单线程容易实现,并且CPU不会成为瓶颈,那就瓜熟蒂落地采用单线程的方案了(毕竟采用多线程会有不少麻烦!)。

15.Redis info查看命令:info memory

16.Redis内存模型

used_memory:Redis分配器分配的内存总量(单位是字节),包括使用的虚拟内存(即swap);Redis分配器后面会介绍。used_memory_human只是显示更友好。

used_memory_rss:Redis进程占据操做系统的内存(单位是字节),与top及ps命令看到的值是一致的;除了分配器分配的内存以外,used_memory_rss还包括进程运行自己须要的内存、内存碎片等,可是不包括虚拟内存。

mem_fragmentation_ratio:内存碎片比率,该值是used_memory_rss used_memory的比值。

mem_allocator:Redis使用的内存分配器,在编译时指定;能够是 libc 、jemalloc或者tcmalloc,默认是jemalloc;截图中使用的即是默认的jemalloc。

17.Redis内存划分

数据

做为数据库,数据是最主要的部分;这部分占用的内存会统计在used_memory中。

进程自己运行须要的内存

Redis主进程自己运行确定须要占用内存,如代码、常量池等等;这部份内存大约几兆,在大多数生产环境中与Redis数据占用的内存相比能够忽略。这部份内存不是由jemalloc分配,所以不会统计在used_memory中。

缓冲内存

缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF缓冲区等;其中,客户端缓冲存储客户端链接的输入输出缓冲;复制积压缓冲用于部分复制功能;AOF缓冲区用于在进行AOF重写时,保存最近的写入命令。在了解相应功能以前,不须要知道这些缓冲的细节;这部份内存由jemalloc分配,所以会统计在used_memory中。

内存碎片

内存碎片是Redis在分配、回收物理内存过程当中产生的。例如,若是对数据的更改频繁,并且数据之间的大小相差很大,可能致使redis释放的空间在物理内存中并无释放,但redis又没法有效利用,这就造成了内存碎片。内存碎片不会统计在used_memory中。

18.Redis对象有5种类型

不管是哪一种类型,Redis都不会直接存储,而是经过redisObject对象进行存储。

19.Redis没有直接使用C字符串

(即以空字符’\0’结尾的字符数组)做为默认的字符串表示,而是使用了SDS。SDS是简单动态字符串(Simple Dynamic String)的缩写。

20.Reidis的SDS在C字符串的基础上加入了free和len字段

21.Reids主从复制

复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操做的负载均衡和简单的故障恢复。缺陷:故障恢复没法自动化;写操做没法负载均衡;存储能力受到单机的限制。

22.Redis哨兵

在复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操做没法负载均衡;存储能力受到单机的限制。

23.Reids持久化触发条件

RDB持久化的触发分为手动触发和自动触发两种。

24.Redis 开启AOF

Redis服务器默认开启RDB,关闭AOF;要开启AOF,须要在配置文件中配置:

appendonly yes

25.AOF经常使用配置总结

下面是AOF经常使用的配置项,以及默认值;前面介绍过的这里再也不详细介绍。

  • appendonly no:是否开启AOF
  • appendfilename "appendonly.aof":AOF文件名
  • dir ./:RDB文件和AOF文件所在目录
  • appendfsync everysec:fsync持久化策略
  • no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;若是开启该选项,能够减轻文件重写时CPU和硬盘的负载(尤为是硬盘),可是可能会丢失AOF重写期间的数据;须要在负载和安全性之间进行平衡
  • auto-aof-rewrite-percentage 100:文件重写触发条件之一
  • auto-aof-rewrite-min-size 64mb:文件重写触发提交之一
  • aof-load-truncated yes:若是AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

26.RDB和AOF的优缺点

RDB持久化

优势:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快不少。固然,与AOF相比,RDB最重要的优势之一是对性能的影响相对较小。

缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然作不到实时持久化,而在数据愈来愈重要的今天,数据的大量丢失不少时候是没法接受的,所以AOF持久化成为主流。此外,RDB文件须要知足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。

AOF持久化

与RDB持久化相对应,AOF的优势在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。

27.持久化策略选择

(1)若是Redis中的数据彻底丢弃也没有关系(如Redis彻底用做DB层数据的cache),那么不管是单机,仍是主从架构,均可以不进行任何持久化。

(2)在单机环境下(对于我的开发者,这种状况可能比较常见),若是能够接受十几分钟或更多的数据丢失,选择RDB对Redis的性能更加有利;若是只能接受秒级别的数据丢失,应该选择AOF。

(3)但在多数状况下,咱们都会配置主从环境,slave的存在既能够实现数据的热备,也能够进行读写分离分担Redis读请求,以及在master宕掉后继续提供服务。

28.redis缓存被击穿处理机制

使用mutex。简单地来讲,就是在缓存失效的时候(判断拿出来的值为空),不是当即去load db,而是先使用缓存工具的某些带成功操做返回值的操做(好比Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操做返回成功时,再进行load db的操做并回设缓存;不然,就重试整个get缓存的方法

29.Redis还提供的高级工具

像慢查询分析、性能测试、Pipeline、事务、Lua自定义命令、Bitmaps、HyperLogLog、发布/订阅、Geo等个性化功能。

30.Redis经常使用管理命令

# dbsize 返回当前数据库 key 的数量。
# info 返回当前 redis 服务器状态和一些统计信息。
# monitor 实时监听并返回redis服务器接收到的全部请求信息。
# shutdown 把数据同步保存到磁盘上,并关闭redis服务。
# config get parameter 获取一个 redis 配置参数信息。(个别参数可能没法获取)
# config set parameter value 设置一个 redis 配置参数信息。(个别参数可能没法获取)
# config resetstat 重置 info 命令的统计信息。(重置包括:keyspace 命中数、
# keyspace 错误数、 处理命令数,接收链接数、过时 key 数)
# debug object key 获取一个 key 的调试信息。
# debug segfault 制造一次服务器当机。
# flushdb 删除当前数据库中全部 key,此方法不会失败。当心慎用
# flushall 删除所有数据库中全部 key,此方法不会失败。当心慎用

31.Reids工具命令

# redis-server:Redis 服务器的 daemon 启动程序
# redis-cli:Redis 命令行操做工具。固然,你也能够用 telnet 根据其纯文本协议来操做
# redis-benchmark:Redis 性能测试工具,测试 Redis 在你的系统及你的配置下的读写性能
$ redis-benchmark -n 100000 –c 50 模拟同时由 50 个客户端发送 100000 个 SETs/GETs 查询
# redis-check-aof:更新日志检查
# redis-check-dump:本地数据库检查

32.为何须要持久化?

因为Redis是一种内存型数据库,即服务器在运行时,系统为其分配了一部份内存存储数据,一旦服务器挂了,或者忽然宕机了,那么数据库里面的数据将会丢失,为了使服务器即便忽然关机也能保存数据,必须经过持久化的方式将数据从内存保存到磁盘中。

33.判断key是否存在

exists key +key名字

34.删除key

del key1 key2 ...

35.缓存和数据库间数据一致性问题

分布式环境下(单机就不用说了)很是容易出现缓存和数据库间的数据一致性问题,针对这一点的话,只能说,若是你的项目对缓存的要求是强一致性的,那么请不要使用缓存。咱们只能采起合适的策略来下降缓存和数据库间数据不一致的几率,而没法保证二者间的强一致性。合适的策略包括 合适的缓存更新策略,更新数据库后要及时更新缓存、缓存失败时增长重试机制,例如MQ模式的消息队列

36.布隆过滤器

bloomfilter就相似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小

37.缓存雪崩问题

存在同一时间内大量键过时(失效),接着来的一大波请求瞬间都落在了数据库中致使链接异常。

解决方案:

一、也是像解决缓存穿透同样加锁排队。

二、创建备份缓存,缓存A和缓存B,A设置超时时间,B不设值超时时间,先从A读缓存,A没有读B,而且更新A缓存和B缓存;

38.缓存并发问题

这里的并发指的是多个redis的client同时set key引发的并发问题。比较有效的解决方案就是把redis.set操做放在队列中使其串行化,必须的一个一个执行,具体的代码就不上了,固然加锁也是能够的,至于为何不用redis中的事务,留给各位看官本身思考探究。

39.Redis分布式

redis支持主从的模式。原则:Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会链接master来同步数据。

这是一个典型的分布式读写分离模型。咱们能够利用master来插入数据,slave提供检索服务。这样能够有效减小单个机器的并发访问数量

40.读写分离模型

经过增长Slave DB的数量,读的性能能够线性增加。为了不Master DB的单点故障,集群通常都会采用两台Master DB作双机热备,因此整个集群的读和写的可用性都很是高。读写分离架构的缺陷在于,无论是Master仍是Slave,每一个节点都必须保存完整的数据,若是在数据量很大的状况下,集群的扩展能力仍是受限于单个节点的存储能力,并且对于Write-intensive类型的应用,读写分离架构并不适合。

41.数据分片模型

为了解决读写分离模型的缺陷,能够将数据分片模型应用进来。

能够将每一个节点当作都是独立的master,而后经过业务实现数据分片。

结合上面两种模型,能够将每一个master设计成由一个master和多个slave组成的模型。

42. redis常见性能问题和解决方案:

Master最好不要作任何持久化工做,如RDB内存快照和AOF日志文件

若是数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

为了主从复制的速度和链接的稳定性,Master和Slave最好在同一个局域网内

尽可能避免在压力很大的主库上增长从库

43.redis通信协议

RESP 是redis客户端和服务端以前使用的一种通信协议;RESP 的特色:实现简单、快速解析、可读性好

44.Redis分布式锁实现

先拿setnx来争抢锁,抢到以后,再用expire给锁加一个过时时间防止锁忘记了释放。**若是在setnx以后执行expire以前进程意外crash或者要重启维护了,那会怎么样?**set指令有很是复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的!

45.Redis作异步队列

通常使用list结构做为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。缺点:在消费者下线的状况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。**能不能生产一次消费屡次呢?**使用pub/sub主题订阅者模式,能够实现1:N的消息队列。

46.Redis中海量数据的正确操做方式

利用SCAN系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成数据迭代。

47.SCAN系列命令注意事项

  • SCAN的参数没有key,由于其迭代对象是DB内数据;
  • 返回值都是数组,第一个值都是下一次迭代游标;
  • 时间复杂度:每次请求都是O(1),完成全部迭代须要O(N),N是元素数量;
  • 可用版本:version >= 2.8.0;

48.Redis 管道 Pipeline

在某些场景下咱们在一次操做中可能须要执行多个命令,而若是咱们只是一个命令一个命令去执行则会浪费不少网络消耗时间,若是将命令一次性传输到 Redis中去再执行,则会减小不少开销时间。可是须要注意的是 pipeline中的命令并非原子性执行的,也就是说管道中的命令到达 Redis服务器的时候可能会被其余的命令穿插

49.事务不支持回滚

50.手写一个 LRU 算法

class LRUCache<K, V\> extends LinkedHashMap<K, V\> {
    private final int CACHE\_SIZE;

    /\*\*
     \* 传递进来最多能缓存多少数据
     \*
     \* @param cacheSize 缓存大小
     \*/
    public LRUCache(int cacheSize) {
        // true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        CACHE\_SIZE \= cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V\> eldest) {
        // 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
        return size() \> CACHE\_SIZE;
    }
}

51.多节点 Redis 分布式锁:Redlock 算法

获取当前时间(start)。

依次向 N 个 Redis节点请求锁。请求锁的方式与从单节点 Redis获取锁的方式一致。为了保证在某个 Redis节点不可用时该算法可以继续运行,获取锁的操做都须要设置超时时间,须要保证该超时时间远小于锁的有效时间。这样才能保证客户端在向某个 Redis节点获取锁失败以后,能够马上尝试下一个节点。

计算获取锁的过程总共消耗多长时间(consumeTime = end - start)。若是客户端从大多数 Redis节点(>= N/2 + 1) 成功获取锁,而且获取锁总时长没有超过锁的有效时间,这种状况下,客户端会认为获取锁成功,不然,获取锁失败。

若是最终获取锁成功,锁的有效时间应该从新设置为锁最初的有效时间减去 consumeTime

若是最终获取锁失败,客户端应该马上向全部 Redis节点发起释放锁的请求。

52.Redis 中设置过时时间主要经过如下四种方式

  • expire key seconds:设置 key 在 n 秒后过时;
  • pexpire key milliseconds:设置 key 在 n 毫秒后过时;
  • expireat key timestamp:设置 key 在某个时间戳(精确到秒)以后过时;
  • pexpireat key millisecondsTimestamp:设置 key 在某个时间戳(精确到毫秒)以后过时;

53.Reids三种不一样删除策略

定时删除:在设置键的过时时间的同时,建立一个定时任务,当键达到过时时间时,当即执行对键的删除操做

惰性删除:听任键过时无论,但在每次从键空间获取键时,都检查取得的键是否过时,若是过时的话,就删除该键,若是没有过时,就返回该键

按期删除:每隔一点时间,程序就对数据库进行一次检查,删除里面的过时键,至于要删除多少过时键,以及要检查多少个数据库,则由算法决定。

54.定时删除

  • 优势:对内存友好,定时删除策略能够保证过时键会尽量快地被删除,并释放国期间所占用的内存
  • 缺点:对cpu时间不友好,在过时键比较多时,删除任务会占用很大一部分cpu时间,在内存不紧张但cpu时间紧张的状况下,将cpu时间用在删除和当前任务无关的过时键上,影响服务器的响应时间和吞吐量

55.按期删除

因为定时删除会占用太多cpu时间,影响服务器的响应时间和吞吐量以及惰性删除浪费太多内存,有内存泄露的危险,因此出现一种整合和折中这两种策略的按期删除策略。

  1. 按期删除策略每隔一段时间执行一次删除过时键操做,并经过限制删除操做执行的时长和频率来减小删除操做对CPU时间的影响。
  2. 定时删除策略有效地减小了由于过时键带来的内存浪费。

56.惰性删除

  • 优势:对cpu时间友好,在每次从键空间获取键时进行过时键检查并是否删除,删除目标也仅限当前处理的键,这个策略不会在其余无关的删除任务上花费任何cpu时间。
  • 缺点:对内存不友好,过时键过时也可能不会被删除,致使所占的内存也不会释放。甚至可能会出现内存泄露的现象,当存在不少过时键,而这些过时键又没有被访问到,这会可能致使它们会一直保存在内存中,形成内存泄露。

57.Reids 管理工具:Redis Manager 2.0

github地址

58.Redis常见的几种缓存策略

  • Cache-Aside
  • Read-Through
  • Write-Through
  • Write-Behind

59.Redis Module 实现布隆过滤器

Redis module 是Redis 4.0 之后支持的新的特性,这里不少国外牛逼的大学和机构提供了不少牛逼的Module 只要编译引入到Redis 中就能轻松的实现咱们某些需求的功能。在Redis 官方Module 中有一些咱们常见的一些模块,咱们在这里就作一个简单的使用。

  • neural-redis 主要是神经网络的机器学,集成到redis 能够作一些机器训练感兴趣的能够尝试
  • RedisSearch 主要支持一些富文本的的搜索
  • RedisBloom 支持分布式环境下的Bloom 过滤器

60.Redis 究竟是怎么实现“附近的人”

使用方式

GEOADD key longitude latitude member \[longitude latitude member ...\]

将给定的位置对象(纬度、经度、名字)添加到指定的key。其中,key为集合名称,member为该经纬度所对应的对象。在实际运用中,当所需存储的对象数量过多时,可经过设置多key(如一个省一个key)的方式对对象集合变相作sharding,避免单集合数量过多。

成功插入后的返回值:

(integer) N

其中N为成功插入的个数。

相关文章
相关标签/搜索