纯原创最全Redis面试题整理 - Go语言中文社区

纯原创最全Redis面试题整理


 

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API的非关系型数据库。

传统数据库遵循 ACID 规则。而 Nosql(Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称) 一般为分布式而分布式一般遵循 CAP 定理。

Github 源码:https://github.com/antirez/redis

Redis 官网:https://redis.io/

Redis支持的数据类型?

String字符串:

格式: set key value

string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

string类型是Redis最基本的数据类型,一个键最大能存储512MB。

 

Hash(哈希)

格式: hmset name  key1 value1 key2 value2

Redis hash 是一个键值(key=>value)对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

 

List(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

格式: lpush  name  value

在 key 对应 list 的头部添加字符串元素

格式: rpush  name  value

在 key 对应 list 的尾部添加字符串元素

格式: lrem name  index

key 对应 list 中删除 count 个和 value 相同的元素

格式: llen name  

返回 key 对应 list 的长度

 

Set(集合)

格式: sadd  name  value

Redis的Set是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

 

zset(sorted set:有序集合)

格式: zadd  name score value

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

Redis 提供了两种持久化方式:RDB(默认) 和AOF 

RDB:

rdb是Redis DataBase缩写

功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数

AOF:

Aof是Append-only file缩写

每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作

aof写入保存:

WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件

SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

存储结构:

  内容是redis通讯协议(RESP )格式的命令文本存储。

比较

1、aof文件比rdb更新频率高,优先使用aof还原数据。

2、aof比rdb更安全也更大

3、rdb性能比aof好

4、如果两个都配了优先加载AOF

03

刚刚上面你有提到redis通讯协议(RESP ),能解释下什么是RESP?有什么特点?(可以看到很多面试其实都是连环炮,面试官其实在等着你回答到这个点,如果你答上了对你的评价就又加了一分)

RESP 是redis客户端和服务端之前使用的一种通讯协议;

RESP 的特点:实现简单、快速解析、可读性好

For Simple Strings the first byte of the reply is "+" 回复

For Errors the first byte of the reply is "-" 错误

For Integers the first byte of the reply is ":" 整数

For Bulk Strings the first byte of the reply is "$" 字符串

For Arrays the first byte of the reply is "*" 数组

Redis 有哪些架构模式?讲讲各自的特点

单机版

 

特点:简单

问题:

1、内存容量有限 2、处理能力有限 3、无法高可用。

主从复制

Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而通过复制创建出来的服务器复制品则为从服务器(slave)。 只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步 给从服务器,从而一直保证主从服务器的数据相同。

特点:

1、master/slave 角色

2、master/slave 数据相同

3、降低 master 读压力在转交从库

问题:

无法保证高可用

没有解决 master 写的压力

哨兵

Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:

监控(Monitoring):    Sentinel  会不断地检查你的主服务器和从服务器是否运作正常。

提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。

特点:

1、保证高可用

2、监控各个节点

3、自动故障迁移

缺点:主从模式,切换需要时间丢数据

没有解决 master 写的压力

集群(proxy 型):

Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器; Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。

特点:1、多种 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins 

2、支持失败节点自动删除

3、后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操作单个 Redis 一致

缺点:增加了新的 proxy,需要维护其高可用。

 

failover 逻辑需要自己实现,其本身不能支持故障的自动转移可扩展性差,进行扩缩容都需要手动干预

集群(直连型):

从redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

特点:

1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。

2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。

3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。

4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本

5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色提升。

缺点:

1、资源隔离性较差,容易出现相互影响的情况。

2、数据通过异步复制,不保证数据的强一致性

什么是一致性哈希算法?什么是哈希槽?

这两个问题篇幅过长 网上找了两个解锁的不错的文章

https://www.cnblogs.com/lpfuture/p/5796398.html

https://blog.csdn.net/z15732621582/article/details/79121213

Redis是基于CAP理论的,什么是CAP理论?

可以参考我的上一篇文章。

如果有人问你CAP理论是什么,就把这篇文章发给他。

Redis常用命令?

Keys pattern

*表示区配所有

以bit开头的

查看Exists  key是否存在

Set

设置 key 对应的值为 string 类型的 value。

setnx

设置 key 对应的值为 string 类型的 value。如果 key 已经存在,返回 0,nx 是 not exist 的意思。

删除某个key

第一次返回1 删除了 第二次返回0

Expire 设置过期时间(单位秒)

TTL查看剩下多少时间

返回负数则key失效,key不存在了

Setex

设置 key 对应的值为 string 类型的 value,并指定此键值对应的有效期。

Mset

一次设置多个 key 的值,成功返回 ok 表示所有的值都设置了,失败返回 0 表示没有任何值被设置。

Getset

设置 key 的值,并返回 key 的旧值。

Mget

一次获取多个 key 的值,如果对应 key 不存在,则对应返回 nil。

Incr

对 key 的值做加加操作,并返回新的值。注意 incr 一个不是 int 的 value 会返回错误,incr 一个不存在的 key,则设置 key 为 1

incrby

同 incr 类似,加指定值 ,key 不存在时候会设置 key,并认为原来的 value 是 0

Decr

对 key 的值做的是减减操作,decr 一个不存在 key,则设置 key 为-1

Decrby

同 decr,减指定值。

Append

给指定 key 的字符串值追加 value,返回新字符串值的长度。

Strlen

取指定 key 的 value 值的长度。

persist xxx(取消过期时间)

选择数据库(0-15库)

Select 0 //选择数据库

move age 1//把age 移动到1库

Randomkey随机返回一个key

Rename重命名

Type 返回数据类型

使用过Redis分布式锁么,它是怎么实现的?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!

使用过Redis做异步队列么,你是怎么用的?有什么缺点?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。

缺点:

在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

能不能生产一次消费多次呢?

使用pub/sub主题订阅者模式,可以实现1:N的消息队列。

什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

 

NoSql入门和概述

1、  为什么用nosql?(2-4问题)

NoSQL数据库的发展能很好的处理这些大文本数据的数据。

2、数据存储的瓶颈是什么?

1)     数据量的总大小 一个机器放不下时

2)     数据的索引(B+ Tree)一个机器的内存放不下时

3)     访问量(读写混合)一个实例不能承受

 如果满足了上述1 or 3个,进化......

3、进化过程?

1)     Memcached(缓存)+MySQL+垂直拆分

2)     Memcached只能缓解数据库的读取压力。Mysql的master-slave模式读写分离。

3)     分表分库+水平拆分+mysql集群:在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。

4、MySQL的扩展性瓶颈

MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

(存大文本时候,数据大,数据回复慢,扩展性差,IO压力大,表结构维护困难)

5、NoSql是什么?

NoSQL(NoSQL = NotOnly SQL ),意即“不仅仅是SQL”,

泛指非关系型的数据库。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

6、NoSql能干嘛?

容易扩展

大数据量高性能:具有非常高的读写性能,无关系性,数据库的结构简单。

一般MySQL使用Query Cache,每次表的更新Cache就失效,大粒度的Cache,在针对交互频繁的应用,Cache性能不高。而NoSQL的Cache是记录级的,是细粒度的Cache,性能高很多了。

多样灵活的数据模型:NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。

7、RDBMS vs NoSQL(关系型数据库与非关系型数据库比较)

RDBMS

- 高度组织化结构化数据

- 结构化查询语言(SQL

- 数据和关系都存储在单独的表中。

- 数据操纵语言,数据定义语言

- 严格的一致性

- 基础事务

NoSQL

- 代表着不仅仅是SQL

- 没有声明性查询语言

- 没有预定义的模式

-键 - 值对存储,列存储,文档存储,图形数据库

- 最终一致性,而非ACID属性

- 非结构化和不可预知的数据

- CAP定理

- 高性能,高可用性和可伸缩性

8、大数据时代,互联网的3V3高:

 海量,多样,实时,高并发,高可扩,高性能。

9、NoSQL数据模型?

聚合模型:KV键值,bson,列族,图形

10、传统ACID是什么?

原子性,一致性,隔离性,持久性

11、CAP?

强一致性,可用性,分区容错性

分区容忍性是我们必须需要实现的。

所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。

==============================================================

C:强一致性 A:高可用性 P:分布式容忍性

 CA 传统Oracle数据库

 AP 大多数网站架构的选择

 CPRedis、Mongodb

 注意:分布式架构的时候必须做出取舍。

一致性和可用性之间取一个平衡。多余大多数web应用,其实并不需要强一致性。

因此牺牲C换取P,这是目前分布式数据库产品的方向

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,

最多只能同时较好的满足两个。

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。

CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。

AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

12、分布式+集群

分布式系统(distributedsystem

 由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。分布式系统是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。分布式系统可以应用在在不同的平台上如:Pc、工作站、局域网和广域网上等。

Redis入门介绍

1、 Redis是什么?

C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行,并支持持久化的NoSQL数据库。

2、 Redis与其他key-value缓存产品比较的特点?

Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用;

Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储;

Redis支持数据的备份,即master-slave模式的数据备份

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。

因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。

Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能。

比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。

Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

3、 Redis能干嘛?

1)     内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务

2)     取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面

3)     模拟类似于HttpSession这种需要设定过期时间的功能

4)     发布、订阅消息系统

5)     定时器、计数器

4、 Redis在Linux中关闭

单实例关闭:redis-cli shutdown;多实例关闭,指定端口关闭:redis-cli -p 6379 shutdown

5、Redis启动后杂项基础知识讲解

1)     单进程模型来处理客户端的请求。对读写等事件的响应是通过对epoll函数的包装来做到的。Redis的实际处理速度完全依靠主进程的执行效率;

2)     epoll是Linux内核为处理大批量文件描述符而作了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本,能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。

3)     默认16个数据库,类似数组下表从零开始,初始默认使用零号库

4)     select命令切换数据库

5)     dbsize查看当前数据库的key的数量

6)     flushdb:清空当前库

7)     Flushall;通杀全部库

8)     统一密码管理,16个库都是同样密码,要么都OK要么一个也连接不上

9)     Redis索引都是从零开始

10)   默认端口是6379

6.使用redis有哪些好处?   

  1. 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) 

  2. 支持丰富数据类型,支持string,list,set,sorted set,hash 

  3. 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 

  4. 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

7.redis相比memcached有哪些优势?   

  1. memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 

  2. redis的速度比memcached快很多

  3. redis可以持久化其数据

8.Memcache与Redis的区别都有哪些?  

  1. 存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。 

  2. 数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。 

  3. 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。 

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

  1. Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

  2. Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

  3. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

  4. Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

Redis数据类型

1、Redis的五大数据类型?

String(字符串),hash(哈希,类似java里的Map),list(列表),set(集合),zset(sorted set:有序集合)。

如果你是Redis中高级用户,还需要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。

如果你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。

2、String 字符串类型

string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M

字符串对象的编码可以是int、raw或者embstr。

(1)  int 编码:保存的是可以用 long 类型表示的整数值。

(2)  raw 编码:保存长度大于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

(3)  embstr 编码:保存长度小于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

int 编码是用来保存整数值,raw编码是用来保存长字符串,而embstr是用来保存短字符串。

普通的字符串有两种,embstr和raw。embstr是Redis 3.0新增的数据结构,在2.8中是没有的。如果字符串对象的长度小于39字节,就用embstr对象。否则用传统的raw对象。

embstr和raw使用的存储结构如图:

embstr的好处有如下几点:

embstr的创建只需分配一次内存,而raw为两次(一次为sds分配对象,另一次为objet分配对象,embstr省去了第一次)。

相对地,释放内存的次数也由两次变为一次。

embstr的objet和sds放在一起,更好地利用缓存带来的优势。

而embstr的坏处也很明显,如果字符串的长度增加需要重新分配内存时,整个redisObject和sds都需要重新分配空间,因此redis中的embstr实现为只读。

3、hash

Redis hash 是一个键值对集合。

哈希对象的编码可以是 ziplist 或者 hashtable。

hashtable 编码的哈希表对象底层使用字典数据结构,哈希对象中的每个键值对都使用一个字典键值对。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

类似Java里面的Map<String,Object>

4、list(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。它的底层实际是个链表

列表对象的编码可以是ziplist(压缩链表) 和 linkedlist(双端链表)。

ziplist是一种压缩链表,它的好处是更能节省内存空间,因为它所存储的内容都是在连续的内存区域当中的。当列表对象元素不大,每个元素也不大的时候,就采用ziplist存储。但当数据量过大时就ziplist就不是那么好用了。因为为了保证他存储内容在内存中的连续性,插入的复杂度是O(N),即每次插入都会重新进行realloc。如下图所示,对象结构中ptr所指向的就是一个ziplist。整个ziplist只需要malloc一次,它们在内存中是一块连续的区域。

linkedlist是一种双向链表。它的结构比较简单,节点中存放pre和next两个指针,还有节点相关的信息。当每增加一个node的时候,就需要重新malloc一块内存。

5、Set(集合)

Redis的Set是string类型的无序集合。它是通过HashTable实现实现的,

集合对象的编码可以是 intset 或者 hashtable。

intset 编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合中。

6、zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。

redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。

有序集合的编码可以是 ziplist 或者 skiplist。

skiplist 编码的有序集合对象使用 zet 结构作为底层实现,一个 zset 结构同时包含一个字典和一个跳跃表:

7、常用命令案例

a)     keys *

b)     existskey的名字,判断某个key是否存在

c)     movekey db   --->当前库就没有了,被移除了

d)     expirekey 秒钟:为给定的key设置过期时间

e)     ttl key查看还有多少秒过期,-1表示永不过期,-2表示已过期

f)      typekey 查看你的key是什么类型

8、Redis字符串(String)

  单值单value

set/get/del/append/strlen

Incr/decr/incrby/decrby,一定要是数字才能进行加减

 getrange/setrange:获取指定区间范围内的值,类似between......and的关系,从零到负一表示全部

 setex(set with expire)键秒值/setnx(set if not exist)

 mset/mget/msetnx:mset:同时设置一个或多个 key-value 对。

 getset(先get再set):将给定 key 的值设为 value ,并返回 key 的旧值(oldvalue)。

简单一句话,先get然后立即set

9、Redis列表(List)

单值多value

lpush/rpush/lrange

       lpop/rpop

 lindex,按照索引下标获得元素(从上到下):通过索引获取列表中的元素 lindex key index

 llen

 lrem key 删N个value: * 从left往right删除2个值等于v1的元素,返回的值为实际删除的数量

 *  LREM list3 0 值,表示删除全部给定的值。零个就是全部值

 ltrim key 开始index 结束index,截取指定范围的值后再赋值给key

       rpoplpush 源列表 目的列表:移除列表的最后一个元素,并将该元素添加到另一个列表并返回

 lset key index value

       linsert key  before/after 值1 值2

性能:

它是一个字符串链表,left、right都可以插入添加;如果键不存在,创建新的链表;

如果键已存在,新增内容;如果值全移除,对应的键也就消失了。链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。

10、Redis集合(Set)

单值多value

sadd/smembers/sismember

 scard,获取集合里面的元素个数

 srem key value 删除集合中元素

 srandmember key 某个整数(随机出几个数): *  从set集合里面随机取出2个 *  如果超过最大数量就全部取出, *  如果写的值是负数,比如-3 ,表示需要取出3个,但是可能会有重复值。

 spop key 随机出栈

 smove key1 key2 在key1里某个值      作用是将key1里的某个值赋给key2

数学集合类

       差集:sdiff:在第一个set里面而不在后面任何一个set里面的项

       交集:sinter:

       并集:sunion

11、Redis哈希(Hash)

       KV模式不变,但V是一个键值对

               hset/hget/hmset/hmget/hgetall/hdel

               hlen

               hexists key 在key里面的某个值的key

               hkeys/hvals

               hincrby/hincrbyfloat

               hsetnx:不存在赋值,存在了无效。

12、Redis有序集合Zset(sortedset)

在set基础上,加一个score值。之前set是k1 v1v2 v3,现在zset是k1 score1 v1score2 v2

zadd/zrange

       withscores

       zrangebyscorekey 开始score 结束score

 zrem key 某score下对应的value值,作用是删除元素

 zcard/zcount key score区间/zrank key values值,作用是获得下标值/zscore key 对应值,获得分数

 zrevrank key values值,作用是逆序获得下标值

 zrevrange

 zrevrangebyscore  key 结束score 开始score

12.Redis的过期策略

Redis采用的是定期删除+惰性删除策略。

13.为什么不用定时删除策略?

定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.

14.定期删除+惰性删除是如何工作的?

定期删除,Redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,Redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。于是,在你获取某个key的时候,Redis会检查一下,这个key是否过期了?如果过期了此时就会删除。

15.采用定期删除+惰性删除就没其他问题了?

不是,如果定期删除没删除key,也就是说惰性删除没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。

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

相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。

redis 提供 6种数据淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  4. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  6. no-enviction(驱逐):禁止驱逐数据

17.请用Redis和任意语言实现一段恶意登录保护的代码,限制1小时内每用户Id最多只能登录5次。具体登录函数或功能用空函数即可,不用详细写出。

用列表实现:列表中每个元素代表登陆时间,只要最后的第5次登陆时间和现在时间差不超过1小时就禁止登陆.用Python写的代码如下:

#!/usr/bin/env python3
import redis  
import sys  
import time  

r = redis.StrictRedis(host=’127.0.0.1′, port=6379, db=0)  
try:       
   id = sys.argv[1]
except:      
   print(‘input argument error’)    
   sys.exit(0)  
if r.llen(id) >= 5 and time.time() – float(r.lindex(id, 4)) <= 3600:      
   print(“you are forbidden logining”)
else:       
   print(‘you are allowed to login’)    
   r.lpush(id, time.time())    
   # login_func()

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

512M

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

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

如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

20.Redis是单进程单线程的

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

21.redis的并发竞争问题如何解决?

Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。

对此有2种解决方法:

1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。

2.服务器角度,利用setnx实现锁。

注:对于第一种,需要应用程序自己处理资源的同步,可以使用的方法比较通俗,可以使用synchronized也可以使用lock;第二种需要用到Redis的setnx命令,但是需要注意一些问题。

22.redis事物的了解CAS(check-and-set 操作实现乐观锁 )?

和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石。

相信对有关系型数据库开发经验的开发者而言这一概念并不陌生,即便如此,我们还是会简要的列出Redis中事务的实现特征

  1. 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。

  2. 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。

  3. 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。

  4. 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。

  5. 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。

Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。

此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。

23.WATCH命令和基于CAS的乐观锁: 

在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能。假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以通知调用者事务

执行失败。例如,我们再次假设Redis中并未提供incr命令来完成键值的原子性递增,如果要实现该功能,我们只能自行编写相应的代码。其伪码如下:

val = GET mykey
val = val + 1
SET mykey $val

以上代码只有在单连接的情况下才可以保证执行结果是正确的,因为如果在同一时刻有多个客户端在同时执行该段代码,那么就会出现多线程程序中经常出现的一种错误场景--竞态争用(race condition)。

比如,客户端A和B都在同一时刻读取了mykey的原有值,假设该值为10,此后两个客户端又均将该值加一后set回Redis服务器,这样就会导致mykey的结果为11,而不是我们认为的12。为了解决类似的问题,我们需要借助WATCH命令的帮助,见如下代码:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

和此前代码不同的是,新代码在获取mykey的值之前先通过WATCH命令监控了该键,此后又将set命令包围在事务中,这样就可以有效的保证每个连接在执行EXEC之前,如果当前连接获取的mykey的值被其它连接的客户端修改,那么当前连接的EXEC命令将执行失败。这样调用者在判断返回值后就可以获悉val是否被重新设置成功。

解析配置文件redis.conf

1、units:配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit;对大小写不敏感

2、includes:redis.conf可以作为总闸,包含其他

3、GENERAL通用

       daemonize

       pidfile

       port

       tcp-backlog:设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列。

在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意Linux内核会将这个值减小到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog两个值

来达到想要的效果。

       timeout

       bind

       tcp-keepalive:单位为秒,如果设置为0,则不会进行Keepalive检测,建议设置成60 

       loglevel

       logfile

       syslog-enabled:是否把日志输出到syslog

       syslog-ident:指定syslog里的日志标志

       syslog-facility:指定syslog设备,值可以是USER或LOCAL0-LOCAL7

       databases

4、SNAPSHOTTING快照

       Save

         save秒钟 写操作次数:

           RDB是整个内存的压缩过的Snapshot,RDB的数据结构,可以配置复合的快照触发条件,

默认:是1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次。

         禁用:如果想禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数也可以。

       stop-writes-on-bgsave-error:如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制

        rdbcompression:对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用,LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能

        rdbchecksum:在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约,10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能

        dbfilename

        dir

5、REPLICATION复制

6、SECURITY安全

       访问密码的查看、设置和取消

7、LIMITS限制

       Maxclients:设置redis同时可以与多少个客户端进行连接。默认情况下为10000个客户端。当你

无法设置进程文件句柄限制时,redis会设置为当前的文件句柄限制值减去32,因为redis会为自

身内部处理逻辑留一些句柄出来。如果达到了此限制,redis则会拒绝新的连接请求,并且向这

些连接请求方发出“max number ofclients reached”以作回应。

       Maxmemory:设置redis可以使用的内存量。一旦到达内存使用上限,redis将会试图移除内部数据,移除规则可以通过maxmemory-policy来指定。如果redis无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,那么redis则会针对那些需要申请内存的指令返回错误信息,比如SET、LPUSH等。

但是对于无内存申请的指令,仍然会正常响应,比如GET等。如果你的redis是主redis(说明你的redis有从redis),那么在设置内存使用上限时,需要在系统中留出一些内存空间给同步队列缓存,只有在你设置的是“不移除”的情况下,才不用考虑这个因素

       maxmemory-policy:

               (1)volatile-lru:使用LRU算法移除key,只对设置了过期时间的键

(2)allkeys-lru:使用LRU算法移除key

(3)volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键

(4)allkeys-random:移除随机的key

(5)volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key

(6)noeviction:不进行移除。针对写操作,只是返回错误信息    

maxmemory-samples: 设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小,redis默认会检查这么多个key并选择其中LRU的那个

8、APPEND ONLY MODE追加

 appendonly

appendfilename

appendfsync

              always:同步持久化 每次发生数据变更会被立即记录到磁盘  性能较差但数据完整性比较好

              everysec:出厂默认推荐,异步操作,每秒记录   如果一秒内宕机,有数据丢失

              no

no-appendfsync-on-rewrite:重写时是否可以运用Appendfsync,用默认no即可,保证数据安全性。

auto-aof-rewrite-min-size:设置重写的基准值

auto-aof-rewrite-percentage:设置重写的基准值

9、常见配置redis.conf介绍

       参数说明

redis.conf 配置项说明如下:

1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程

 daemonize no

2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定

 pidfile /var/run/redis.pid

3.

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/w372426096/article/details/77929579
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-26 18:10:42
  • 阅读 ( 808 )
  • 分类:面试题

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢