赞
踩
文章目录:
Redis概述
什么是Redis?
Redis的优缺点?
Redis为什么常常用做缓存?相比于guava有什么优势?
Redis和Memcached的区别与共同点?
Redis是单线程还是多线程?Redis为什么这么快?
Redis6.0之后为什么引入了多线程?
Redis的数据类型有哪些?
Redis的数据结构有哪些?
Redis的应用场景有哪些?
Redis是单线程的,如何提高CPU的利用率?
过期键的删除策略
键的过期删除策略
Redis的内存淘汰机制是什么样的?
Redis的持久化
什么是Redis的持久化?
Redis常见的持久化机制有哪些?有什么有优缺点?
Redis的事务
什么是Redis的事务
Redis事务的相关命令
Redis事务执行的三个阶段
Redis事务的特性
Redis事务为什么不支持回滚?
Redis的集群、主从、哨兵
Redis集群的实现方案有哪些?
Redis主从架构中数据丢失吗
如何解决主从架构数据丢失问题?
Redis集群的主从复制过程是什么样的?
Redis是如何保证主从服务器一致处于连接状态以及命令是否丢失?
因为网络原因在主从复制过程中停止复制会怎么样?
了解Redis哈希槽吗?
Redi集群最大的节点个数是多少?为什么?
Redis集群是如何选择数据库的?
Redis高可用方案如何实现?
Redis的分区
Redis的分区作用是什么?
Redis分区有哪些实现方案?
Redis分区的缺点?
Redis的分布式问题
什么是分布式锁?
分布式锁具有哪些特性?
分布式锁的实现方法?
Redis如何实现分布式锁?
Redis并发竞争key问题应该如何解决?
什么是RedLock
Redis的缓存问题
说下什么是缓存雪崩、缓存穿透、缓存击穿,及它们的解决方案
如何保证缓存与数据库双写时的数据一致性?
Redis其他高频面试题
一个字符串类型的值能存储最大容量是多少?
Redis如何实现大量数据插入?
如何通过Redis实现异步队列?
如何通过Redis实现延时队列?
Redis回收使用什么算法?
Redis 里面有1亿个 key,其中有 10 个 key 是包含 java,如何将它们全部找出来?
生产环境中的Redis是如何部署的
Redis是一个高性能的非关系型的键值对数据库,使用C编写实现的。与传统的数据库不同的是Redis是存在内存中的,所以读写速度非常快,每秒可以处理超过10万次的读写操作,这也是Redis常常被用作缓存的原因。
优点:
读写性能好,读的速度可达110000次/s,写的速度可达81000次/s。
支持数据持久化,有AOF和RDB两中持久化方式
数据结构丰富,支持String、List、Set、Hash等结构
支持事务,Redis所有的操作都是原子性的,并且还支持几个操作合并后的原子性执行,原子性指操作要么成功执行,要么失败不执行,不会执行一部分。
支持主从复制,主机可以自动将数据同步到从机,进行读写分离。
缺点:
因为Redis是将数据存到内存中的,所以会受到内存大小的限制,不能用作海量数据的读写
Redis不具备自动容错和恢复功能,主机或从机宕机会导致前端部分读写请求失败,需要重启机器或者手动切换前端的IP才能切换
缓存的定义是访问速度比一般随机存取存储器快的一种高速存储器,而因为Redis是基于内存提供了高性能的数据存取功能,其比较显著的优势就是非常地快。
缓存可以分为本地缓存或者分布式缓存,比较常用的guava缓存就是一种本地缓存,其主要特点是轻量并且快速,生命周期随着JVM的销毁而结束,缺点是在多实例的情况下,每个实例都要自己保存一份缓存,这样会导致缓存的一致性出现问题。
Redis则是分布式缓存,在多实例情况下,每个实例都共享一份缓存数据,缓存具备一致性。缺点是要保持Redis的高可用整体架构会比较复杂。
相同点:
两者的读写性能都比较高
都是基于内存的数据库,通常被当作缓存使用
都有过期策略
都是基于C语言实现
不同点:
不同点 | Redis | Memcached |
---|---|---|
是否支持复制 | 支持主从复制 | 不支持复制 |
key长度 | 长度最大为 2GB | 长度最多为 250 个字节 |
数据类型 | 不仅支持key-value类型的数据,还支持hash、list、set、zset等数据等数据类型的数据 | 仅支持key-value类型的数据 |
数据持久化 | 支持数据持久化,可以将数据保存到磁盘 | 不支持数据持久化 |
网络IO模型 | 单线程的多路 IO 复用模型 | 多线程的非阻塞IO模式 |
集群 | 原生支持cluster 模式集群 | 无原生 |
Redis6.0之前是单线程的,为什么Redis6.0之前采用单线程而不采用多线程呢?
简单来说,就是Redis官方认为没必要,单线程的Redis的瓶颈通常在CPU的IO,而在使用Redis时几乎不存在CPU成为瓶颈的情况。使用Redis主要的瓶颈在内存和网络,并且使用单线程也存在一些优点,比如系统的复杂度较低,可为维护性较高,避免了并发读写所带来的一系列问题。
Redis为什么这么快主要有以下几个原因:
运行在内存中
数据结构简单
使用多路IO复用技术
单线程实现,单线程避免了线程切换、锁等造成的性能开销。
前面说了那么多Redis使用单线程的原因,但从Redis6.0后开始支持多线程了,简直打脸有点快。那么为什么较新的Redis版本又开始支持多线程了呢?
前面也说了Redis的瓶颈在内存和网络,Redis6.0引入多线程主要是为了解决网路IO读写这个瓶颈,执行命令还是单线程执行的,所以也不存在线程安全问题。
Redis6.0默认是否开启了多线程呢?
默认是没有开启的,如需开启,需要修改配置文件redis.conf:io-threads-do-reads no,no改为yes
Redis的常见的数据类型有String、Hash、Set、List、ZSet。还有三种不那么常见的数据类型:Bitmap、HyperLogLog、Geospatial。
数据类型 | 可以存储的值 | 可进行的操作 | 应用场景 |
---|---|---|---|
STRING | 字符串、整数、浮点数 | 对整数或浮点数可以进行自增、自减操作 对字符串操作 |
键值对缓存及常规计数: 微博数, 粉丝数 |
LIST | 列表(内部使用双向列表实现) | 向列表两端添加元素,或者获得列表的某一个片段 | 存储文章ID列表、存储评论列表等 |
SET | 无序集合(内部使用值为空的散列表) | 增加/删除元素、获取集合中元素、取交集并集等等 | 共同好友、共同关注等 |
ZSET | 有序集合(内部使用散列表和跳表) | 添加、获取、删除元素 根据分值范围或者成员来获取元素 计算一个键的排名 |
去重、获取排名前几的用户 |
HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对 获取所有键值对 检查某个键是否存在 |
常用于存储对象 |
Bitmap:位图,是一个以位为单位的数组,数组中只能存储1或0,数组的下标在Bitmap中叫做偏移量。Bitmap实现统计功能,更省空间。面试中常问的布隆过滤器就有用到这种数据结构,布隆过滤器可以判断出哪些数据一定不在数据库中,所以常被用来解决Redis缓存穿透问题。
Hyperloglog:HyperLogLog 是一种用于统计基数的数据集合类型,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。HyperLogLog 的优点是,在输入元素的数量或者体积非常大时,计算基数所需的空间总是固定 的、并且是很小的。缺点是 HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。常见的应用场景:统计网站的UV
Geospatial:主要用于存储地理位置信息,常用于定位附近的人,打车距离的计算等。
很多人都会把数据结构和数据类型混为一谈,包括很多面试官问的时候也没有刻意区分这两个。Redis的数据结构比较多,篇幅有限,这里只重点介绍面试常问的跳跃表。
Redis的数据结构有简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表等。
简单动态字符串:大家都知道,Redis的底层是用C语言编写,但Redis并没有直接使用C语言传统的字符串表示,而是构建了一种名为简单动态字符串的抽象类型。
链表:链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。链表是列表的底层实现之一。
字典:字典,又称为符号表(symbol table)、关联数组(associativearray)或映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构。字典在Redis中的应用相当广泛,比如Redis的数据库就是使用字典来作为底层实现的,对数据库的增、删、查、改操作也是构建在对字典的操作之上的。
整数集合: 整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现。
压缩列表(ziplist):压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构。
对象:可能看到这里,很多人在想Redis的数据结构和数据类型的区别,其实上面介绍的是Redis的底层数据结构,但Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构,是不是这就和前面对上了。
看到这里很多人会好奇,为什么不直接使用这些底层数据结构,而是要创建对象系统。对象系统主要有以下优点:
通过这五种不同类型的对象,Redis可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。
我们可以针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。
实现了基于引用计数技术的内存回收机制,当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放,了解Java虚拟机的垃圾回收机制看到这里是不是很熟悉。
edis还通过引用计数技术实现了对象共享机制,这一机制可以在适当的条件下,通过让多个数据库键共享同一个对象来节约内存。
对象这部分占了比较大的篇幅,其实面试中问的也不多,但为了更方便理解,介绍地多些。顺便看下这些底层数据结构和对象系统的对应关系。
最后介绍下面试中常问的跳跃表。
跳跃表(skiplist):跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。跳跃表作是序集合键的底层实现之一。
和链表、字典等数据结构被广泛地应用在Redis内部不同,Redis只在两个地方用到了跳跃表,一个是实现有序集合键,另一个是在集群节点中用作内部数据结构,除此之外,跳跃表在Redis里面没有其他用途。
跳跃表本质上采用的是一种空间换时间的策略,是一种可以可以进行二分查找的有序链表,跳表在原有的有序链表上增加了多级索引,通过索引来实现快速查询。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。
这是一个原始的有序列表,时间复杂度为O(n)。
为了提高查找效率,可以对链表建立一级索引,如下图,在之前找到11这个元素需要遍历6个节点,现在需要5个。链表越长,效率提升越明显。
为了继续提高查找效率可以继续增加索引
对于理想的跳表&#x
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。