redis面试题

0. redis 是单线程,是怎么解决高并发问题的?

这个我当时是这样回答的:单线程想高并发,就是用到了类似 nginx 的事件循环之类的技术。

参考回答:

(1)redis 是基于内存的,内存的读写速度非常快(纯内存); 数据存在内存中,数据结构用HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O(1)。

(2)redis是单线程的,省去了很多上下文切换线程的时间(避免线程切换的资源消耗)。

(3)redis 使用 I/O 多路复用技术,可以处理高并发的连接(非阻塞I/O)。(如果你懂 I/O 多路复用,可以展开讲一讲,展示你钻研的深度)

写到这里,猫哥自己也产生了疑问,什么是事件循环,什么是 I/O 多路复用,两者有什么关系?于是找了找学习资料,整理如下,如有反对意见,请文末留言讨论。

事件循环是一种编程范式,通常,我们写服务器处理模型的程序时,有以下几种模型:

(1)每收到一个请求,创建一个新的进程,来处理该请求;(2)每收到一个请求,创建一个新的线程,来处理该请求;(3)每收到一个请求,放入一个事件列表,让主进程通过非阻塞 I/O 方式来处理请求;

第三种,就是事件驱动的方式,比如 Python 中的 协程就是事件循环,也大多数网络服务器采用的方式比如 Nginx。

比如说 javascript 吧,一大特点就是单线程,那为什你没有觉得浏览器中的 javascript 慢呢?肯定没有,对吧,因为 javascript 在处理 DOM 时也用到了事件循环。

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。但是如果任务是计算型任务,CPU 忙不过来,等就等了,如果是 I/O 型任务,主线程完全可以不管 I/O 设备,而是挂起处于等待中的任务,先运行排在后面的任务。等到 I/O 设备返回了结果,把挂起的任务继续执行下去。

也就是说主线程之外,有一个任务队列,只要异步任务(异步 I/O)有了结果,就在任务队列中放置一个事件,主线程中任务执行完就会去任务队列取出有结果的异步任务执行,具体过程如下图所示:


因为整个过程是不断循环的,这种运行机制又称事件循环。到这里,相信你已经对事件循环有一个比较清晰的印象了。

什么是 I/O 多路复用?这里借用下知乎的高赞回答:

I/O多路复用技术(multiplexing)是什么? - 知乎

也就是说 select、poll、epoll 都是 I/O 多路复用的机制,区别如下:

说到这里,你应该明白了,事件循环是一种编程范式,很多场景都可以这样来设计代码,而 I/O 多路复用是一种 I/O 模型,是操作系统提供的一种机制,与进程、线程的概念是等价的,也就是说现代操作系统提供三种并发机制:

(1)多进程

(2)多线程

(3 )I/O 多路复用

1.

2. 删除:过期策略

3. 回收:内存空间不足,自主放弃

 

4.

5.

6. redis复制原理

 

7. redis缓存问题和解决方案

通用问题:大量key直接访问数据库

通用解决方案:去另外redis抢锁,抢到锁后访问数据库。即对于某个key只有一个访问O(1)

8. Redis key的过期时间和永久有效分别怎么设置?

EXPIRE 和 PERSIST 命令。

9. 我们知道通过expire来设置key 的过期时间,那么对过期的数据怎么处理呢?

除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:
1)定时去清理过期的缓存;
2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。

两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。

10. redis内存

(1)Redis的内存用完了会发生什么?
如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回。)或者你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

(2)Redis如何做内存优化?
可以好好利用 Hash, list, sorted set, set 等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面线程模型。

(3)Redis 报内存不足怎么处理?

1)修改配置文件 redis.conf 的 maxmemory 参数,增加 Redis 可用内存;
2)设置缓存淘汰策略,提高内存的使用效率;
3)使用 Redis 集群模式,提高存储量。

11. 为什么 Redis 单线程模型效率也能那么高?
 

1)C语言实现,效率高
2)纯内存操作
3)基于非阻塞的IO复用模型机制
4)单线程的话就能避免多线程的频繁上下文切换问题
5)丰富的数据结构(全称采用hash结构,读取速度非常快,对数据存储进行了一些优化,比如亚
索表,跳表等)

12. Redis线程模型

13. Redis事务

(1)def:区分事务和redis事务

事务:是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。ACID

redis事务:一次性、顺序性、排他性的执行一个队列中的一系列命令。

(2)Redis事务的三个阶段

  • 开启:以MULTI开始一个事务

  • 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面

  • 执行:由EXEC命令触发事务

  • 如果客户端发送的命令为 EXEC 、 DISCARD 、 WATCH 、 MULTI 四个命令的其中一个, 那么服务器立即执行这个命令。
  • 与此相反, 如果客户端发送的命令是 EXEC 、 DISCARD 、 WATCH 、 MULTI 四个命令以外的其他命令, 那么服务器并不立即执行这个命令, 而是将这个命令放入一个事务队列里面, 然后向客户端返回 QUEUED 回复。

(3)Redis事务相关命令

Redis事务功能是通过MULTI、EXEC、DISCARD、WATCH 四个原语实现的。Redis会将一个事务中的所有命令序列化,然后按顺序执行。
1)redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速;
2)如果在一个事务中的命令出现错误,那么所有的命令都不会执行。
3)如果在一个事务中出现运行错误,那么正确的命令会被执行
4)WATCH 命令是一个乐观锁,可以为 Redis 事务提供 check-and-set (CAS)行为。 可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令

Redis使用WATCH命令来决定事务是继续执行还是回滚,那就需要在MULTI之前使用WATCH来监控某些键值对,然后使用MULTI命令来开启事务,执行对数据结构操作的各种命令,此时这些命令入队列。当使用EXEC执行事务时,首先会比对WATCH所监控的键值对,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的任何命令,同时事务回滚。当然无论是否回滚,Redis都会取消执行事务前的WATCH命令。

5)MULTI命令用于开启一个事务,它总是返回OK。 MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
6)EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。
7)通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
8)UNWATCH命令可以取消watch对所有key的监控。

(4)Redis事务的ACID

  • 原子性atomicity

首先通过上文知道 运行期的错误是不会回滚的,很多文章由此说Redis事务违背原子性的;而官方文档认为是遵从原子性的。

Redis官方文档给的理解是,Redis的事务是原子性的:所有的命令,要么全部执行,要么全部不执行。而不是完全成功。

  • 一致性consistency

redis事务可以保证命令失败的情况下得以回滚,数据能恢复到没有执行之前的样子,是保证一致性的,除非redis进程意外终结。

  • 隔离性Isolation

redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式(v6.0之前),可以保证命令执行过程中不会被其他客户端命令打断。

但是,Redis不像其它结构化数据库有隔离级别这种设计。

  • 持久性Durability

redis事务是不保证持久性的,这是因为redis持久化策略中不管是RDB还是AOF都是异步执行的,不保证持久性是出于对性能的考虑。

(5)Redis集群会有写操作丢失吗?为什么?

Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。

(6)Redis事务其他实现

1)基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行,其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续运行完
2)基于中间标记变量,通过另外的标记变量来标识事务是否执行完成,读取数据时先读取该标记变量判断是否事务执行完成。但这样会需要额外写代码实现,比较繁琐集群方案哨兵模式

(7)为什么 Redis 不支持回滚?

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

14. Redis 集群模式

Redis 集群架构模式有哪几种?
Redis 集群架构是支持单节点单机模式的,也支持一主多从的主从结构,还支持带有哨兵的集群部
署模式

14.1 哨兵(sentinel)

(1)介绍:哨兵的核心功能是主节点的自动故障转移。

哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:

集群监控:负责监控 redis master 和 slave 进程是否正常工作。
消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。

(2)核心知识
哨兵至少需要 3 个实例,来保证自己的健壮性。
哨兵 + redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集群的高可用性。

14.2 官方Redis Cluster 方案(服务端路由查询)

015.数据分布算法:hash+ 一致性 hash + redis cluster 的 hash slot - CodeNow99 - 博客园

Redis Cluster是一种服务端Sharding技术,3.0版本开始正式提供。Redis Cluster并没有使用一致性hash,而是采用 hash slot 算法。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。

 15. Redis 主从架构

redis replication -> 主从架构 -> 读写分离 -(redismasterslave)> 水平扩容支撑读高并发 redis replication 的核心机制

1)redis 采用异步方式复制数据到 slave 节点,不过 redis2.8 开始,slave node 会周期性地确认自己每次复制的数据量;
2)一个 master node 是可以配置多个 slave node 的; slave node 也可以连接其他的 slave node;
3)slave node 做复制的时候,不会 block master node 的正常工作;
4)slave node 在做复制的时候,也不会 block 对自己的查询操作,它会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了;
5)slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量。
注意,如果采用了主从架构,那么建议必须开启 master node 的持久化,不建议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制, slave node 的数据也丢了;
6)另外,master 的各种备份方案,也需要做。万一本地的所有文件丢失了,从备份中挑选一份 rdb 去恢复 master,这样才能确保启动的时候,是有数据的,即使采用了后续讲解的高可用机制,slave node 可以自动接管 master node,但也可能 sentinel 还没检测到 master failure,master node 就自动重启了,还是可能导致上面所有的 slave node 数据被清空。
 

16. Redis 主从复制

redis 主从复制的核心原理当启动一个 slave node 的时候,它会发送一个 PSYNC 命令给 master node。如果这是 slave node 初次连接到 master node,那么会触发一次 full resynchronization 全量复制。此时 master 会启动一个后台线程,开始生成一份RDB 快照文件,同时还会将从客户端 client 新收到的所有写命令缓存在内存中。RDB 文件生成完毕后, master 会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中,接着 master 会将内存中缓存的写命令发送到 slave,slave 也会同步这些数据。slave node 如果跟 master node 有网络故障,断开了连接,会自动重连,连接之后 master node 仅会复制给 slave 部分缺少的数据。

缺点:所有的slave节点数据的复制和同步都由master节点来处理,会照成master节点压力太大,使用主从从结构来解决
 

1)当从库和主库建立MS关系后,会向主数据库发送SYNC命令
2)主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程),并将期间接收到的写命令存起来
3)当快照完成后,主Redis会将快照文件和所有缓存的写命令发送给从Redis
4)从Redis接收到后,会载入快照文件并且执行收到的缓存的命令
5)之后,主Redis每当接收到写命令时就会将命令发送从Redis,从而保证数据的一致

17. 分区
 

(1)Redis是单线程的,如何提高多核CPU的利用率?

可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU,你可以考虑一下分片(shard)。

(2)为什么要做Redis分区?

分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你 多只能使用一台机器的内存。分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。

(3)你知道有哪些Redis分区实现方案?

客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个 redis节点读取。大多数客户端已经实现了客户端分区。
代理分区:意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy。
查询路由(Query routing) :意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。

(4)Redis分区有什么缺点?

涉及多个key的操作通常不会被支持。例如你不能对两个集合求交集,因为他们可能被存储到不同的Redis实例(实际上这种情况也有办法,但是不能直接使用交集指令)。
同时操作多个key,则不能使用Redis事务.
分区使用的粒度是key,不能使用一个非常长的排序key存储一个数据集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set)
当使用分区的时候,数据处理会非常复杂,例如为了备份你必须从不同的Redis 实例和主机同时收集RDB / AOF文件。
分区时动态扩容或缩容可能非常复杂。Redis集群在运行时增加或者删除Redis 节点,能做到 大程度对用户透明地数据再平衡,但其他一些客户端分区或者代理分区方法则不支
持这种特性。然而,有一种预分片的技术也可以较好的解决这个问题。
 

18. 什么是 RedLock

Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式名叫
Redlock,此种方式比原先的单节点的方法更安全。它可以保证以下特性:
1)安全特性:互斥访问,即永远只有一个 client 能拿到锁
2)避免死锁: 终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区
3)容错性:只要大部分 Redis 节点存活就可以正常提供服务缓存异常缓存雪崩

19. 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)

20. Jedis与Redisson对比有什么优缺点?

Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;
Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

21. 如何保证缓存与数据库双写时的数据一致性?

你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况, 好不要做这个方案,读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。还有一种方式就是可能会暂时产生不一致的情况,但是发生的几率特别小,就是先更新数据库,然后再删除缓存。

22. Redis常见性能问题和解决方案?

23. 假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?

1)使用 keys 命令

直接使用 keys 命令查询,但是如果是在生产环境下使用会出现一个问题,keys 命令是遍历查询
的,查询的时间复杂度为 O(n),数据量越大查询时间越长。而且 Redis 是单线程,keys 指令会导
致线程阻塞一段时间,会导致线上 Redis 停顿一段时间,直到 keys 执行完毕才能恢复。这在生产
环境是不允许的。除此之外,需要注意的是,这个命令没有分页功能,会一次性查询出所有符合条
件的 key 值,会发现查询结果非常大,输出的信息非常多。所以不推荐使用这个命令。

2)使用 scan 命令

scan 命令可以实现和 keys 一样的匹配功能,但是 scan 命令在执行的过程不会阻塞线程,并且查
找的数据可能存在重复,需要客户端操作去重。因为 scan 是通过游标方式查询的,所以不会导致
Redis 出现假死的问题。Redis 查询过程中会把游标返回给客户端,单次返回空值且游标不为 0,则说明遍历还没结束,客户端继续遍历查询。scan 在检索的过程中,被删除的元素是不会被查询出来的,但是如果在迭代过程中有元素被修改,scan 不能保证查询出对应元素。相对来说,scan 指令查找花费的时间会比 keys 指令长。
 

24. Redis回收进程如何工作的?

1)一个客户端运行了新的命令,添加了新的数据。
2)Redis检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
3) 一个新的命令被执行,等等。
4) 所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。

如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。Redis回收使用的是LRU算法。

25. Redis 的同步机制了解是什么?

Redis 支持主从同步、从从同步。如果是第一次进行主从同步,主节点需要使用 bgsave 命令,再将后续修改操作记录到内存的缓冲区,等 RDB 文件全部同步到复制节点,复制节点接受完成后将
RDB 镜像记载到内存中。等加载完成后,复制节点通知主节点将复制期间修改的操作记录同步到复制节点,即可完成同步过程。

26. 什么是 bigkey?会存在什么影响?

bigkey 是指键值占用内存空间非常大的 key。例如一个字符串 a 存储了 200M 的数据。
bigkey 的主要影响有:
网络阻塞;获取 bigkey 时,传输的数据量比较大,会增加带宽的压力。
超时阻塞;因为 bigkey 占用的空间比较大,所以操作起来效率会比较低,导致出现阻塞的可能
性增加。

导致内存空间不平衡;一个 bigkey 存储数据量比较大,同一个 key 在同一个节点或服务器中存
储,会造成一定影响。

27. 什么情况下可能会导致 Redis 阻塞?

28. Redis 有哪些适合的场景?

1)会话缓存( Session Cache)

2)全页缓存( FPC)

3)队列

4)排行榜/计数器

5)发布/订阅

29. Redis 如何解决 key 冲突?

Redis 如果 key 相同,后一个 key 会覆盖前一个 key。如果要解决 key 冲突,最好给 key 取好名区
分开,可以按业务名和参数区分开取名,避免重复 key 导致的冲突。

30. 说说Redis持久化机制
 

Redis是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的。 实现:单独创建fork()一个子进程,将当前父进程的数据库数据复制到子进程的内存中,然后由子进程写入到临时文件中,持久化的过程结束了,再用这个临时文件替换上次的快照文件,然后子进程退出,内存释放。

RDB:Redis默认的持久化方式。按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二进制文件。即Snapshot快照存储,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期。( 快照可以是其所表示的数据的一个副本,也可以是数据的一个复制品。)
AOF:Redis会将每一个收到的写命令都通过Write函数追加到文件最后,类似于MySQL的binlog。当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。 当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。

31. redis的数据类型,以及每种数据类型的使用场景
 

(一)String

这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。

(二)hash

这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。

(三)list

使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适—取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。

(四)set

因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

(五)sorted set

sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。

32. redis的过期策略以及内存淘汰机制
 

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

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

2)定期删除+惰性删除是如何工作的呢? 定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

3)采用定期删除+惰性删除就没其他问题了么?不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制

在redis.conf中有一行配置,该配置就是配内存淘汰策略的。

maxmemory-policy volatile-lru

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

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

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

no-enviction(驱逐):禁止驱逐数据,新写入操作会报错 ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatilerandom 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致


33. Redis 缓存刷新策略有哪些?

34. 怎么提高缓存命中率?

1)提前加载数据到缓存中;
2)增加缓存的存储空间,提高缓存的数据;
3)调整缓存的存储数据类型;
4)提升缓存的更新频率。

35. Redis 的对象机制(redisObject)?

比如说, 集合类型就可以由字典和整数集合两种不同的数据结构实现, 但是, 当用户执行 ZADD 命令时, 他/她应该不必关心集合使用的是什么编码, 只要 Redis 能按照 ZADD 命令的指示, 将新元素添加到集合就可以了。

这说明, 操作数据类型的命令除了要对键的类型进行检查之外, 还需要根据数据类型的不同编码进行多态处理.

为了解决以上问题, Redis 构建了自己的类型系统, 这个系统的主要功能包括:

  • redisObject 对象.
  • 基于 redisObject 对象的类型检查.
  • 基于 redisObject 对象的显式多态函数.
  • 对 redisObject 进行分配、共享和销毁的机制.
/*
 * Redis 对象
 */
typedef struct redisObject {

    // 类型
    unsigned type:4;

    // 编码方式
    unsigned encoding:4;

    // LRU - 24位, 记录最末一次访问时间(相对于lru_clock); 或者 LFU(最少使用的数据:8位频率,16位访问时间)
    unsigned lru:LRU_BITS; // LRU_BITS: 24

    // 引用计数
    int refcount;

    // 指向底层数据结构实例
    void *ptr;

} robj;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、什么是 Redis? 2、Redis 相比 memcached 有哪些优势? 3、Redis 支持哪几种数据类型? 4、Redis 主要消耗什么物理资源? 5、Redis 的全称是什么? 6、Redis 有哪几种数据淘汰策略? 7、Redis 官方为什么不提供 Windows 版本? 8、一个字符串类型的值能存储最大容量是多少? 9、为什么 Redis 需要把所有数据放到内存中? 10、Redis 集群方案应该怎么做?都有哪些方案? 11、Redis 集群方案什么情况下会导致整个集群不可用? 12、MySQL 里有 2000w 数据,Redis 中只存 20w 的数据, 如何保证 Redis 中的数据都是热点数据? 13、Redis 有哪些适合的场景? 14、Redis 支持的 Java 客户端都有哪些?官方推荐用哪个? 15、RedisRedisson 有什么关系? 16、Jedis 与 Redisson 对比有什么优缺点? 17、Redis 如何设置密码及验证密码? 18、说说 Redis 哈希槽的概念? 19、Redis 集群的主从复制模型是怎样的? 20、Redis 集群会有写操作丢失吗?为什么? 21、Redis 集群之间是如何复制的? 22、Redis 集群最大节点个数是多少? 23、Redis 集群如何选择数据库? 24、怎么测试 Redis 的连通性? 25、Redis 中的管道有什么用? 26、怎么理解 Redis 事务? 27、Redis 事务相关的命令有哪几个? 28、Redis key 的过期时间和永久有效分别怎么设置? 29、Redis 如何做内存优化? 30、Redis 回收进程如何工作的? 31、Redis 回收使用的是什么算法? 32、Redis 如何做大量数据插入? 33、为什么要做 Redis 分区? 34、你知道有哪些 Redis 分区实现方案? 35、Redis 分区有什么缺点? 36、Redis 持久化数据和缓存怎么做扩容? 37、分布式 Redis 是前期做还是后期规模上来了再做好?为 什么? 38、Twemproxy 是什么? 39、支持一致性哈希的客户端有哪些? 40、Redis 与其他 key-value 存储有什么不同? 41、Redis 的内存占用情况怎么样? 42、都有哪些办法可以降低 Redis 的内存使用情况呢? 43、查看 Redis 使用情况及状态信息用什么命令? 44、Redis 的内存用完了会发生什么? 45、Redis 是单线程的,如何提高多核 CPU 的利用率? 46、一个 Redis 实例最多能存放多少的 keys?List、Set、 Sorted Set 他们最多能存放多少元素? 47、Redis 常见性能问题和解决方案? 48、Redis 提供了哪几种持久化方式? 49、如何选择合适的持久化方式? 50、修改配置不重启 Redis 会实时生效吗?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值