尊重所有声音 但只成为自己 先赞再看 养成习惯 第一次以总结的方式写文章 错的地方请大家指正 谢谢
开始
redis的特点
先从redis的特点开始
- Redis 采用单线程模式处理请求。这样做的原因有 2 个:一个是因为采用了非阻塞的异步事件处理机制;另一个是缓存数据都是内存操作 IO 时间不会太长,单线程可以避免线程上下文切换产生的代价。
- Redis 支持持久化,所以 Redis 不仅仅可以用作缓存,也可以用作 NoSQL 数据库。
- Redis 还有一个非常大的优势,就是除了 K-V 之外,还支持多种数据格式,例如 list、set、sorted set、hash 等。
- Redis 提供主从同步机制,以及 Cluster 集群部署能力,能够提供高可用服务。
相信大家对这些定义也是不陌生的 在面视的时候面试官问到为什么你们公司选用redis的时候可以先从特点开始掰扯 ,另外就是大家还可以去了解一下Memcache的特点,到时候可以说 目前市面上比较常用的缓存中间件有 Redis 和 Memcached 不过中和考虑了他们的优缺点,最后选择了Redis。
redis的数据类型
redis的数据类型有哪些啊?
String Hash List Set SortedSet
(大家知道这五种数据结构的场景最好)
如果你想在面试中显的你突出 你可以说一下redis的几种特殊的数据结构 HyperLogLog、Geo、Pub/Sub。如果还想加分 可以说你还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML 下去小伙伴们可以去钻研一下
redis 如何实现消息队列
实现消息队列方式有很多,比如ActiveMQ,RabbitMQ,Kafka等,但是也可以基于redis来实现,可以降低系统的维护成本和实现复杂度
1.基于异步消息队列List lpush-brpop(rpush-blpop)
一般使用list结构作为队列 使用rpush作为生产者 使用lpop作为消费者 当没有消息的时候 lpop会一直空轮询,消耗资源,这个时候list有个blpop 在队列没有数据的时候进入休眠状态直到数据到来,一但数据到来就立刻醒过来,消息延迟几乎为0 可以忽略不计。
注: 还有个问题那就是空闲连接,如果线程一直阻塞在那里,redis客户端的连接就成了闲置连接,闲置过久的话服务器一般会主动断开连接,减少闲置资源占用,这个时候blpop和brpop或者抛出异常,所以在编写客户端消费者的时候要小心,如果捕获到异常,还有重试。
2. PUB/SUB,订阅/发布模式
使用PUB/SUB 实现 1:N的消息队列
3. 基于Sorted-Set的实现
使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
这里说一下 为什么很多人说不要使用redis做消息队列。我经常听到很多人讨论,关于把 Redis 当作队列来用是否合适的问题。 有些人表示赞成,他们认为 Redis 很轻量,用作队列很方便。 也些人则反对,认为 Redis 会丢数据,最好还是用专业的队列中间件更稳妥。其实我想说的是如果你的业务场景足够简单,对于数据丢失不敏感,而且消息积压概率比较小的情况下,把 Redis 当作队列是完全可以的。 而且,Redis 相比于 Kafka、RabbitMQ,部署和运维也更加轻量。 如果你的业务场景对于数据丢失非常敏感,而且写入量非常大,消息积压时会占用很多的机器资源,那么我建议你使用专业的消息队列中间件。
redis持久化(高频)
如果你在面试的时候面试官问到你redis持久化 你可以说 RDB和AOF 当让了它们的优缺点一定要掌握的
RDB
先来说说这个RDB
优点
他会生成多个数据文件,每个数据文件分别都代表了某一时刻Redis里面的数据,RDB对Redis的性能影响非常小,是因为在同步数据的时候他只是fork了一个子进程去做持久化的,而且他在数据恢复的时候速度比AOF来的快。
缺点
DB都是快照文件,都是默认五分钟甚至更久的时间才会生成一次,这意味着你这次同步到下次同步这中间五分钟的数据都很可能全部丢失掉。AOF则最多丢一秒的数据,数据完整性上高下立判。还有就是RDB在生成数据快照的时候,如果文件很大,客户端可能会暂停几毫秒甚至几秒,你公司在做秒杀的时候他刚好在这个时候fork了一个子进程去生成一个大快照,这样超卖是必然会发生的,要是说普通商品还好说,要是热门商品比如华为mate40、iphone12那对公司造成的后果相信是很严重的
我们再来说说AOF
优点
刚才提到了,RDB五分钟一次生成快照,但是AOF是一秒一次去通过一个后台的线程fsync操作,那最多丢这一秒的数据。AOF在对日志文件进行操作的时候是以append-only的方式去写的,他只是追加的方式写数据,自然就少了很多磁盘寻址的开销了,写入性能是很快的,文件也不容易破损。(这里补充一下aof其实最多丢失2秒数据和aof的重写有关) AOF的日志是通过一个叫非常可读的方式记录的,这样的特性就适合做灾难性数据误删除的紧急恢复了,比如公司的实习生通过flushall清空了所有的数据,只要这个时候后台重写还没发生,你马上拷贝一份AOF日志文件,把最后一条flushall命令删了,然后开除实习生就可以了。
缺点
一样的数据,AOF文件比RDB还要大。AOF开启后,他不是每秒都要去异步刷新一次日志嘛 所以说redis支持写的QPS会比RDB支持写的要低
如果这个时候你给面试官讲完RDB和AOF 面试官问你那你两者怎么选择
小孩子才做选择,我全都要,你单独用RDB你会丢失很多数据,你单独用AOF,你数据恢复没RDB来的快,真出什么时候第一时间用RDB恢复,然后AOF做数据补全,真香!RDB/AOF一起上,才是互联网时代一个高健壮性系统的王道。
RDB做镜像全量持久化,AOF做增量持久化。因为RDB会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要AOF来配合使用。在redis实例重启时,会使用RDB持久化文件重新构建内存,再使用AOF重放近期的操作指令来实现完整恢复重启之前的状态。
这里很好理解,把RDB理解为一整个表全量的数据,AOF理解为每次操作的日志就好了,服务器重启的时候先把表的数据全部搞进去,但是他可能不完整,你再回放一下日志,数据不就完整了嘛。不过Redis本身的机制是 AOF持久化开启且存在AOF文件时,优先加载AOF文件;AOF关闭或者AOF文件不存在时,加载RDB文件;加载AOF/RDB文件城后,Redis启动成功; AOF/RDB文件存在错误时,Redis启动失败并打印错误信息
redis主从同步(高频)
主从之间的数据怎么同步
提到这个,就跟我前面提到的数据持久化的RDB和AOF有着比密切的关系了。 我先说下为啥要用主从这样的架构模式,前面提到了单机QPS是有上限的,而且Redis的特性就是必须支撑读高并发的,那你一台机器又读又写,这谁顶得住啊,不当人啊!但是你让这个master机器去写,数据同步给别的slave机器,他们都拿去读,分发掉大量的请求那是不是好很多,而且扩容的时候还可以轻松实现水平扩容。
回归正题,他们数据怎么同步的呢?
你启动一台slave 的时候,他会发送一个psync命令给master ,如果是这个slave第一次连接到master,他会触发一个全量复制。master就会启动一个线程,生成RDB快照,还会把新的写请求都缓存在内存中,RDB文件生成后,master会将这个RDB发送给slave的,slave拿到之后做的第一件事情就是写进本地的磁盘,然后加载进内存,然后master会把内存里面缓存的那些新命名都发给slave。
redis淘汰策略
定期删除
定期好理解,默认100ms就随机抽一些设置了过期时间的key,去检查是否过期,过期了就删了。
为啥不扫描全部设置了过期时间的key呢?
假如Redis里面所有的key都有过期时间,都扫描一遍?那太恐怖了,而且我们线上基本上也都是会设置一定的过期时间的。全扫描跟你去查数据库不带where条件不走索引全表扫描一样,100ms一次,Redis累都累死了。
惰性删除
惰性删除,见名知意,惰性嘛,我不主动删,我懒,我等你来查询了我看看你过期没,过期就删了还不给你返回,没过期该怎么样就怎么样。
最后就是如果的如果,定期没删,我也没查询,那可咋整?
内存淘汰机制
官网上给到的内存淘汰机制是以下几个:
- noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
- allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
- volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
- allkeys-random: 回收随机的键使得新添加的数据有空间存放。
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
- 如果没有键满足回收的前提条件的话,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了。
至于LRU的话 真实面试中会让你写LUR算法,你可别搞原始的那个,那真TM多,写不完的 我们熟悉的LinkedHashMap 也实现了LRU算法 找一个数据结构实现下Java版本的LRU还是比较容易的,知道啥原理就好了个。下面这个是LinkedHashMap的可以借鉴一下
最后
本帅第一次写文章记录一下今天 说一下上面写的都是本帅看了无数文档翻阅了无数文章最后总结的问题 让我受益匪浅的一名作者[敖丙]如果感兴趣的童鞋可以关注走一波 juejin.cn/user/440649… 大家共同进步 另外码字真的难
最后的最后大家有哪里不懂得可以在下面评论 看到会回复的 我说的不正确或者不全面的 希望大家指正出来 大家共同进步