不少文章都会说,redis支持5种经常使用的数据类型,这实际上是存在很大的歧义。redis里存的都是二进制数据,其实就是字节数组(byte[]),这些字节数据是没有数据类型的,只有把它们按照合理的格式解码后,能够变成一个字符串,整数或对象,此时才具备数据类型。面试
这一点必需要记住。因此任何东西只要能转化成字节数组(byte[])的,均可以存到redis里。管你是字符串、数字、对象、图片、声音、视频、仍是文件,只要变成byte数组。redis
所以redis里的String指的并非字符串,它其实表示的是一种最简单的数据结构,即一个key只能对应一个value。这里的key和value都是byte数组,只不过key通常是由一个字符串转换成的byte数组,value则根据实际须要而定。算法
在特定状况下,对value也会有一些要求,好比要进行自增或自减操做,那value对应的byte数组必需要能被解码成一个数字才行,不然会报错。数据库
那么List这种数据结构,其实表示一个key能够对应多个value,且value之间是有前后顺序的,value值能够重复。windows
Set这种数据结构,表示一个key能够对应多个value,且value之间是没有前后顺序的,value值也不能够重复。后端
Hash这种数据结构,表示一个key能够对应多个key-value对,此时这些key-value对之间的前后顺序通常意义不大,这是一个按照名称语义来访问的数据结构,而非位置语义。数组
Sorted Set这种数据结构,表示一个key能够对应多个value,value之间是有大小排序的,value值不能够重复。每一个value都和一个浮点数相关联,该浮点数叫score。元素排序规则是:先按score排序,再按value排序。缓存
集群带来的好处是显而易见的,好比容量增长、处理能力加强,还能够按须要进行动态的扩容、缩容。但同时也会引入一些新的问题,至少会有下面这两个。服务器
一是数据分配:存数据时应该放到哪一个节点上,取数据时应该去哪一个节点上找。
二是数据移动:集群扩容,新增长节点时,该节点上的数据从何处来;集群缩容,要剔除节点时,该节点上的数据往何处去。网络
上面这两个问题有一个共同点就是,如何去描述和存储数据与节点的映射关系。又由于数据的位置是由key决定的,因此问题就演变为如何创建起各个key和集群全部节点的关联关系。
集群的节点是相对固定和少数的,虽然有增长节点和剔除节点。但集群里存储的key,则是彻底随机、没有规律、不可预测、数量庞多,还很是琐碎。
这就比如一所大学和它的全部学生之间的关系。若是大学和学生直接挂钩的话,必定会比较混乱。现实是它们之间又加入了好几层,首先有院系,其次有专业,再者有年级,最后还有班级。通过这四层映射以后,关系就清爽不少了。
这实际上是一个很是重要的结论,这个世界上没有什么问题是不能经过加入一层来解决的。若是有,那就再加入一层。计算机里也是这样的。
redis在数据和节点之间又加入了一层,把这层称为槽(slot),因该槽主要和哈希有关,又叫哈希槽。
最后变成了,节点上放的是槽,槽里放的是数据。槽解决的是粒度问题,至关于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。
能够这样来理解,你的学习桌子上堆满了书,乱的很,想找到某本书很是困难。因而你买了几个大的收纳箱,把这些书按照书名的长度放入不一样的收纳箱,而后把这些收纳箱放到桌子上。
这样就变成了,桌子上是收纳箱,收纳箱里是书籍。这样书籍移动很方便,搬起一个箱子就走了。寻找书籍也很方便,只要数一数书名的长度,去对应的箱子里找就好了。
其实咱们也没作什么,只是买了几个箱子,按照某种规则把书装入箱子。就这么简单的举动,就完全改变了原来人心涣散的情况。是否是有点小小的神奇呢。
一个集群只能有16384个槽,编号0-16383。这些槽会分配给集群中的全部主节点,分配策略没有要求。能够指定哪些编号的槽分配给哪一个主节点。集群会记录节点和槽的对应关系。
接下来就须要对key求哈希值,而后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384。
以槽为单位移动数据,由于槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。
使用哈希函数计算出key的哈希值,这样就能够算出它对应的槽,而后利用集群存储的槽和节点的映射关系查询出槽所在的节点,因而数据和节点就映射起来了,这样数据分配问题就解决了。
客户端只要和集群中的一个节点创建连接后,就能够获取到整个集群的全部节点信息。此外还会获取全部哈希槽和节点的对应关系信息,这些信息数据都会在客户端缓存起来,由于这些信息至关有用。
客户端能够向任何节点发送请求,那么拿到一个key后到底该向哪一个节点发请求呢?其实就是把集群里的那套key和节点的映射关系理论搬到客户端来就好了。
因此客户端须要实现一个和集群端同样的哈希函数,先计算出key的哈希值,而后再对16384取余,这样就找到了该key对应的哈希槽,利用客户端缓存的槽和节点的对应关系信息,就能够找到该key对应的节点了。
接下来发送请求就能够了。还能够把key和节点的映射关系缓存起来,下次再请求该key时,直接就拿到了它对应的节点,不用再计算一遍了。
理论和现实老是有差距的,集群已经发生了变化,客户端的缓存还没来得及更新。确定会出现拿到一个key向对应的节点发请求,其实这个key已经不在那个节点上了。此时这个节点应该怎么办?
这个节点能够去key实际所在的节点上拿到数据再返回给客户端,也能够直接告诉客户端key已经不在我这里了,同时附上key如今所在的节点信息,让客户端再去请求一次,相似于HTTP的302重定向。
这实际上是个选择问题,也是个哲学问题。结果就是redis集群选择了后者。所以,节点只处理本身拥有的key,对于不拥有的key将返回重定向错误,即-MOVED key 127.0.0.1:6381,客户端从新向这个新节点发送请求。
因此说选择是一种哲学,也是个智慧。稍后再谈这个问题。先来看看另外一个状况,和这个问题有些相同点。
redis有一种命令能够一次带多个key,如MGET,我把这些称为多key命令。这个多key命令的请求被发送到一个节点上,这里有一个潜在的问题,不知道你们有没有想到,就是这个命令里的多个key必定都位于那同一个节点上吗?
就分为两种状况了,若是多个key不在同一个节点上,此时节点只能返回重定向错误了,可是多个key彻底可能位于多个不一样的节点上,此时返回的重定向错误就会很是乱,因此redis集群选择不支持此种状况。
若是多个key位于同一个节点上呢,理论上是没有问题的,redis集群是否支持就和redis的版本有关系了,具体使用时本身测试一下就好了。
在这个过程当中咱们发现了一件很有意义的事情,就是让一组相关的key映射到同一个节点上是很是有必要的,这样能够提升效率,经过多key命令一次获取多个值。
那么问题来了,如何给这些key起名字才能让他们落到同一个节点上,难不成都要先计算个哈希值,再取个余数,太麻烦了吧。固然不是这样了,redis已经帮咱们想好了。
能够来简单推理下,要想让两个key位于同一个节点上,它们的哈希值必需要同样。要想哈希值同样,传入哈希函数的字符串必须同样。那咱们只能传进去两个如出一辙的字符串了,那不就变成同一个key了,后面的会覆盖前面的数据。
这里的问题是咱们都是拿整个key去计算哈希值,这就致使key和参与计算哈希值的字符串耦合了,须要将它们解耦才行,就是key和参与计算哈希值的字符串有关可是又不同。
redis基于这个原理为咱们提供了方案,叫作key哈希标签。先看例子,{user1000}.following,{user1000}.followers,相信你已经看出了门道,就是仅使用Key中的位于{和}间的字符串参与计算哈希值。
这样能够保证哈希值相同,落到相同的节点上。可是key又是不一样的,不会互相覆盖。使用哈希标签把一组相关的key关联了起来,问题就这样被轻松愉快地解决了。
相信你已经发现了,要解决问题靠的是巧妙的奇思妙想,而不是非要用牛逼的技术牛逼的算法。这就是小强,小而强大。
最后再来谈选择的哲学。redis的核心就是以最快的速度进行经常使用数据结构的key/value存取,以及围绕这些数据结构的运算。对于与核心无关的或会拖累核心的都选择弱化处理或不处理,这样作是为了保证核心的简单、快速和稳定。
除此以外,选择单线程还有如下这些缘由:
一、redis都是对内存的操做,速度极快(10W+QPS)
二、总体的时间主要都是消耗在了网络的传输上
三、若是使用了多线程,则须要多线程同步,这样实现起来会变的复杂
四、线程的加锁时间甚至都超过了对内存操做的时间
五、多线程上下文频繁的切换须要消耗更多的CPU时间
六、还有就是单线程自然支持原子操做,并且单线程的代码写起来更简单
事务你们都知道,就是把多个操做捆绑在一块儿,要么都执行(成功了),要么一个也不执行(回滚了)。redis也是支持事务的,但可能和你想要的不太同样,一块儿来看看吧。
redis的事务能够分为两步,定义事务和执行事务。使用multi命令开启一个事务,而后把要执行的全部命令都依次排上去。这就定义好了一个事务。此时使用exec命令来执行这个事务,或使用discard命令来放弃这个事务。
redis事务具备如下特色:
一、若是开始执行事务前出错,则全部命令都不执行
二、一旦开始,则保证全部命令一次性按顺序执行完而不被打断
三、若是执行过程当中遇到错误,会继续执行下去,不会中止的
四、对于执行过程当中遇到错误,是不会进行回滚的
看完这些,真想问一句话,你这能叫事务吗?很显然,这并非咱们一般认为的事务,由于它连原子性都保证不了。保证不了原子性是由于redis不支持回滚,不过它也给出了不支持的理由。
不支持回滚的理由:
一、redis认为,失败都是由命令使用不当形成
二、redis这样作,是为了保持内部实现简单快速
三、redis还认为,回滚并不能解决全部问题
哈哈,这就是霸王条款,所以,好像使用redis事务的不太多
客户端和集群的交互过程是串行化阻塞式的,即客户端发送了一个命令后必须等到响应回来后才能发第二个命令,这一来一回就是一个往返时间。若是你有不少的命令,都这样一个一个的来进行,会变得很慢。
redis提供了一种管道技术,可让客户端一次发送多个命令,期间不须要等待服务器端的响应,等全部的命令都发完了,再依次接收这些命令的所有响应。这就极大地节省了许多时间,提高了效率。
聪明的你是否是意识到了另一个问题,多个命令就是多个key啊,这不就是上面提到的多key操做嘛,那么问题来了,你如何保证这多个key都是同一个节点上的啊,哈哈,redis集群又放弃了对管道的支持。
简单了解下redis的协议,知道redis的数据传输格式。
发送请求的协议:
参数个数CRLF[图片上传失败...(image-db6153-1582806589792)]
参数N的字节数CRLF参数N的数据CRLF
例如,SET name lixinjie,实际发送的数据是:
*3\r\n$3\r\nSET\r\n$4\r\nname\r\n$8\r\nlixinjie\r\n
接受响应的协议:
单行回复,第一个字节是+
错误消息,第一个字节是-
整型数字,第一个字节是:
批量回复,第一个字节是$
例如,
+OK\r\n -ERR Operation against\r\n :1000\r\n $6\r\nfoobar\r\n *2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
可见redis的协议设计的很是简单。
文章篇幅问题,我这里只解析部分题目,,若有须要所有答案的能够关注个人公众号【风平浪静如码】点资料领取获取,另外我也整理出了全套Java面试题解析PDF版,有须要也能够进公众号获取!
一、什么是 Redis?
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 适合的场景主要局限在较小数据量的高性能操做和运算上。
二、Redis 相比 memcached 有哪些优点?
三、Redis 支持哪几种数据类型?
String、List、Set、Sorted Set、hashes
四、Redis 主要消耗什么物理资源?
内存。
五、Redis 的全称是什么?
Remote Dictionary Server。
六、Redis 有哪几种数据淘汰策略?
noeviction:返回错误当内存限制达到而且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但 DEL 和几个例外)
allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过时集合的键,使得新添加的数据有空间存放。
allkeys-random: 回收随机的键使得新添加的数据有空间存放。
volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过时集合的键。
volatile-ttl: 回收在过时集合的键,而且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
七、Redis 官方为何不提供 Windows 版本?
由于目前 Linux 版本已经至关稳定,并且用户量很大,无需开发 windows 版本,反而会带来兼容性等问题。
八、一个字符串类型的值能存储最大容量是多少?
512M
九、为何 Redis 须要把全部数据放到内存中?
Redis 为了达到最快的读写速度将数据都读到内存中,并经过异步的方式将数据写入磁盘。
因此 Redis 具备快速和数据持久化的特征。若是不将数据放在内存中,磁盘 I/O 速度为严重影响 Redis 的性能。在内存愈来愈便宜的今天,Redis 将会愈来愈受欢迎。
若是设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。
十、Redis 集群方案应该怎么作?都有哪些方案?
十一、Redis 集群方案什么状况下会致使整个集群不可用?
有 A,B,C 三个节点的集群,在没有复制模型的状况下,若是节点 B 失败了,那么整个集群就会觉得缺乏 5501-11000 这个范围的槽而不可用。
十二、MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数据都是热点数据?
Redis 内存数据集大小上升到必定大小的时候,就会施行数据淘汰策略。
1三、Redis 有哪些适合的场景?
1四、Redis 支持的 Java 客户端都有哪些?官方推荐用哪一个?
Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson。
1五、Redis 和 Redisson 有什么关系?
Redisson 是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List,ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock,AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。
1六、Jedis 与 Redisson 对比有什么优缺点?
Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令的支持;Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能较为简单,不支持字符串操做,不支持排序、事务、管道、分区等 Redis 特性。Redisson 的宗旨是促进使用者对 Redis 的关注分离,从而让使用者可以将精力更集中地放在处理业务逻辑上。
1七、Redis 如何设置密码及验证密码?
设置密码:config set requirepass 123456
受权密码:auth 123456
1八、说说 Redis 哈希槽的概念?
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每一个 key 经过 CRC16 校验后对 16384 取模来决定放置哪一个槽,集群的每一个节点负责一部分hash 槽。
1九、Redis 集群的主从复制模型是怎样的?
为了使在部分节点失败或者大部分节点没法通讯的状况下集群仍然可用,因此集群使用了主从复制模型,每一个节点都会有 N-1 个复制品.
20、Redis 集群会有写操做丢失吗?为何?
Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操做。
2一、Redis 集群之间是如何复制的?
2二、Redis 集群最大节点个数是多少?
2三、Redis 集群如何选择数据库?
2四、怎么测试 Redis 的连通性?
2五、Redis 中的管道有什么用?
2六、怎么理解 Redis 事务?
2七、Redis 事务相关的命令有哪几个?
2八、Redis key 的过时时间和永久有效分别怎么设置?
2九、Redis 如何作内存优化?
30、Redis 回收进程如何工做的?
3一、Redis 回收使用的是什么算法?
3二、Redis 如何作大量数据插入?
3三、为何要作 Redis 分区?
3四、你知道有哪些 Redis 分区实现方案?
3五、Redis 分区有什么缺点?
3六、Redis 持久化数据和缓存怎么作扩容?
3七、分布式 Redis 是前期作仍是后期规模上来了再作好?为何?
3八、Twemproxy 是什么?
3九、支持一致性哈希的客户端有哪些?
40、Redis 与其余 key-value 存储有什么不一样?
4一、Redis 的内存占用状况怎么样?
4二、都有哪些办法能够下降 Redis 的内存使用状况呢?
4三、查看 Redis 使用状况及状态信息用什么命令?
4四、Redis 的内存用完了会发生什么?
4五、Redis 是单线程的,如何提升多核 CPU 的利用率?
4六、一个 Redis 实例最多能存放多少的 keys?List、Set、Sorted Set 他们最多能存放多少元素?
4七、Redis 常见性能问题和解决方案?
4八、Redis 提供了哪几种持久化方式?
4九、如何选择合适的持久化方式?
50、修改配置不重启 Redis 会实时生效吗?
文章篇幅问题,我这里只解析部分题目,,若有须要所有答案的能够关注个人公众号【风平浪静如码】点资料领取获取,另外我也整理出了全套Java面试题解析PDF版,有须要也能够进公众号获取!
部分资料图分享
欢迎你们关注我新开通的公众号【风平浪静如码】,海量Java相关文章,学习资料都会在里面更新,整理的资料也会放在里面。
以为写的还不错的就点个赞,加个关注呗!点关注,不迷路,持续更新!!!