Redis

redis的内存淘汰算法和原理是什么?还有

redis确保了再内存紧张的情况下,仍然能够保持高效的性能。选择合适的淘汰策略很重要。它
取决于你的应用场景和你希望如何权衡存储和性能。使用redis的时候,建议经常去监控内存的
使用情况,并根据需要去调整淘汰策略。

redis中的淘汰策略:内存在使用率达到maxmemory上限时的一种内存释放行为。redis里面提
供了很多种内存淘汰算法。主要分为四类:
1.random算法:随机移除某个key
2.ttl算法:在设置过期期间的key中,去把更早过期时间的key有限的移除。
3.lru算法:移除最近很少使用的key,是一种比较常见的内存淘汰算法。在redis里面,会维护
一个大小为16的候选池(数据根据时间进行排序,然后每次随机取出5个key放到候选池里面,当
满了以后,访问时间间隔最大的key就会从候选池中取出来淘汰掉)
缺点:假如说一个key的访问频率很低,但是最近一次偶然被访问到,LRU就会认为这是一个热key,
从而不会被淘汰掉。
4.lfu算法:为了修补lru算法的漏洞,在redis4里面增加了一个LFU算法。相比较LRU来说,LFU
增加了访问频率这个维度,来统计数据的热点情况。LFU的主要设计是使用了两个双向链表组成了一
个二维双向链表一个链表用来保存访问频率。另一个链表用来保存频率相同的所有元素。当添加元素
的时候访问次数默认是1,于是找到相同访问频次的节点,然后添加到相同频率节点对应的双向链表
的头部。当这个key被访问的时候,就会增加对应key的访问频次。并且把当前访问节点移动到下一个
访问频次的节点。
在这个方案中,

Redis_第1张图片Redis_第2张图片

redis持久化AOF和RDB区别,分别解决什么场景? 

为了解决发生宕机后数据持久化的问题,redis提供了两种持久化策略:
RDB:在指定的时间间隔内,把内存的数据集快照写入磁盘(也就是保留某个时间点的数据)

Redis_第3张图片Redis遇到Hash冲突怎么办?

hash结构:Hash结构的底层数据结构是使用一张全局的Hash表,来保存所有的键值对。这张hash表有多个
哈希桶组成,哈希桶的安全元素保存了key和value的指针。(其中key指向的实际的键,value
指向的实际的值)

hash冲突:所谓的hash冲突不同的key计算出结果落到同一个哈希桶里面。Redis为了解决哈希冲突问题,采用
了**链式寻址法**(采用了链表的方式来保存同一个哈希桶中的多个元素。这个部分的实现和java中
的HashMap是一样的)。

如果出现了大量的key的冲突导致链表过长的情况会导致数据检索效率变慢。redis是如何解决的?
解决方案:为了保持高效性,redis会对hash表做rehash的操作,也就是通过增加哈希桶来减少
冲突。为了rehash更高效redis还默认使用了两个全局哈希表,一个是用来当前使用称为主hash表,
一个用来扩容称为备用hash表。

Redis_第4张图片

redis为什么这么快?

决定redis请求效率的因素主要有三个方面的原因。分别是网络、cpu、内存。
在网络层面reids采用了多路复用的设计,提升了整个并发的处理连接数。不过这个阶段Server端的
所有IO操作,都是由同一个主线程来处理,这时候IO的瓶颈就会影响到redis端的整体处理性能。所
以从redis6.0开始,在多路复用层面增加了多线程的处理来优化IO的处理能力。不过,具体的数据操作
仍然是由主线程来处理的。所以我们可以认为redis认为数据IO的处理依然是单线程。从CPU层面来说,
redis只需要采用单线程就可以了,原因有两个:
1.如果采用多线程对于redis中数据操作都需要通过同步的方式来保证数据安全性。这反而会影响redis
的性能。
2.在Linux系统上,redis通过piplining可以处理100万个请求每秒。而应用程序的计算复杂度主要是
O(N)或者O(log(N)),不会消耗太多的CPU和内存。
最后redis本身的数据结构也做了很多优化。比如通过压缩表来合理的利用内存空间,他通过跳跃表的设计
去降低时间复杂度。同时还提供了Hash、String、Set、Zset、List等。不同时间复杂度的数据类型使得
我们在不同的开发场景中去选择不同的类型去降低时间复杂度同时适应更多的场景选择。

Redis_第5张图片Redis_第6张图片

redis如何实现延时队列?

延时队列的场景:它通常用于在未来的某个时间执行某个任务的场景。比如:订单超时的处理
、定时任务等

在redis里面可以使用Zset这个有序集合来实现延时队列,具体的实现方式:

Redis_第7张图片

Redis_第8张图片

Redis_第9张图片

问题:但是消费端需要不断的向redis去发起轮询所以它会存在两个问题

Redis_第10张图片

Redis_第11张图片Redis_第12张图片

redis中的大key如何处理?

问题解析:在企业级的开发中错误使用redis有可能会出现大key的问题,主要考查对于redis性能
优化和存储策略的了解

Redis_第13张图片最明显的几个问题:

1.内存占用
大key占用大量的内存资源导致redis实例的内存压力增加
2.网络传输延迟
大key的读写操作可能会增加网络传输的延迟影响性能
3.持久化备份
大key的持久化备份需要更多的磁盘空间和时间
提出应对处理Redis大key的策略,能够解释每种策略的优劣和适用场景
框架思想:了解redis中数据结构和特性从而能够在实际的开发中去选择合适的存储方案并进行性能优化
和资源管理

解决方案:
1.把大key分割成多个小key来存储
比如:把一个大的Hash结构分割为小的Hash的结构。每个小的Hash结构代表一部分数据,这样可以减少单个
key的大小去降低内存的压力。
2.搭建redis cluster集群,把key分配到不同的hash slot槽所在的分片上
这样可以降低单个redis节点的存储压力
3.如果已经存在了大key,可以做数据的拆分和迁移
按照业务需求和规则将大key拆分成多个小的key并分布到不同的redis的实例上,然后在迁移完成之后清理
到不需要使用的大Key。
4.考虑是使用压缩算法进行压缩,去减少存储的空间的占用
在存储数据之前对数据进行压缩在读取的时候进行解压缩,以节省存储空间和减少网络传输的数据量
5.从业务层面进行分析,了解大key产生的原因,并根据需求和访问模式进行相应优化
比如使用更加合适的数据结构优化业务逻辑和设计方案等等。

redis里面的key过期了,为什么内存 没有被释放?

问题解析:在redis中key的过期清理是通过使用定期删除和惰性删除两种机制来实现的。
定期删除:redis会隔一段时间执行一次定期删除操作。
在每次执行删除的时候,redis会随机抽取一部分的key,并检查它们是否已经过期。如果
发现有过期的key就直接删除,并且释放对应的内存空间。这种机制保证了redis能够定期
清理掉过期的key,但并不保证所有过期的key都会被立即清理掉。
惰性删除:当一个key被访问的时候redis会检测key是否过期则删除并释放相应的内存空间。

问题解答:当redis中key过期的时候,虽然这个key在逻辑上已经过期了,redis并不会立即
释放对应的内存空间。由于redis采用了定期删除和惰性删除来清理key,这两种机制意味着redis
中的key的过期清理并不是实时的。所以即使key过期了redis也不会立即清理它们。只有在执行
定期删除或者访问的时候才会进行清理操作。因此一些过期的key可能会在一段时间内仍然存在redis
中,直到触发了相应的清理机制,会删除或者释放内存。

redis中有哪些过期策略?

在redis里面有3种过期策略:
定时过期:是指每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即对key进行清理
这个策略可以立即清除过期的数据,对内存很友好,但是会占用大量的cpu资源从而影响到缓存的响应
时间和吞吐量。

惰性过期:是指被动访问某个key的时候,才会判断可以是否已过期,过期则清除。这策略可以最大化
的节约CPU的资源,但是对内存非常不友好。在极端情况下,可能会出现大量过期的key没有被再次访
问,从而不会被清除导致占用大量内存。

这两种方案都有点极端所以在redis里面采用了另外一种折中的方案:
定期过期:折中方案会周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比
的方式控制删除频率。这种方式可以调整定时扫描的时间间隔和每次扫描的耗时来实现在不同情况下使
得CPU和内存资源达到一个最优平衡的效果。而在redis里面同时使用了惰性过期和定期过期这两种策
略。

请描述一下redis中的淘汰策略?

1.当redis使用内存达到一个maxmemory的参数配置阀值的时候,redis就会根据配置的内存的
淘汰策略把访问不高的key从内存里面移除掉。maxmemory的默认值是服务器的最大内存。
2.redis默认提供了八种缓存淘汰策略。这八种缓存淘汰策略总的来说归类成五种:
  第一种,采用LRU策略,就是把不经常使用的key直接淘汰掉
  第二种,采用的是LFU的策略,它在LRU的算法上做了一些优化,增加了数据的访问频次。从而去
  确保淘汰的数据是非热点的。
  第三种,是随机策略,也就是说它随机删除一些key。
  第四种,ttl策略,它是从设置到过期时间的key里面,挑选出过期时间最近的一些key,进行优先 
  淘汰。
  第五种,直接报错,当内存不够的时候,直接抛出一个异常。这是默认的一个处理策略。
  这些策略我们可以直接在redis.conf这个文件里面去手动配置和修改,我们可以根据缓存类型和
  缓存使用的场景去选择合适的淘汰策略。
3.在使用缓存的时候建议增加这些缓存的过期时间,我们知道缓存大概得一个生命周期,从而去更好
  的利用缓存。

如何理解redis的线程安全问题?

问题解析:
redisServer本身是一个线程安全的K-V数据库。也就是在redis Server上执行的指令不需要任何
同步机制,不会存在线程安全问题。虽然在redis6.0里面增加多线程的模型,但是这部分增加的线程
只是用来处理网络IO事件,对指令的执行是由主线程来执行(所以不会存在多个线程同时执行指令操作
的情况)。

至于为什么redis没有采用多线程来执行命令,我认为有几个方面的原因:
1.redis Server本身可能出现的性能瓶颈点,无非就是网络IO,CPU,内存。但是CPU并不是redis的
瓶颈点,所以没有必要去使用多线程来执行指令。

2.如果采用多线程意味着对于redis的所有指令操作都
必须要考虑线程安全问题,也就是说需要加锁来解决。这种方式带来的性能影响反而更大。

3.在redis的客户端虽然redis server中的指令执行是原子的,但是有如果有多个redis客户端同时
执行多个指令的时候,就无法保证多个操作原子性。假设两个redis client同时获取redis server
里面的key1同时进行修改和写入。因为多线程环境下的原子性无法被保障,以及多进程情况下共享资源
的访问竞争问题。使得对于redis server的数据操作是不安全的。

但是对于客户端层面的线程安全问题,解决方法有很多:
比如尽可能的使用redis里面的原子指令或者对多个客户端的资源访问加锁,或者通过lua脚本来实现多
个指令的操作等等。

Redis_第14张图片

Redis_第15张图片

 redis中的keys命令有什么问题?

redis中的keys命令用于返回匹配指定规则的所有键。类似于数据库里面like模糊查询匹配功能。
主要考查对redis性能和可靠性的了解以及对redis的使用最佳实践的熟悉程度。

问题解答:
使用keys命令可能会存在几个潜在的问题:
1.性能问题:keys命令需要遍历整个redis的键空间,如果redis中的key数据非常大,遍历过程非常
耗时从而影响性能。
2.阻塞问题:keys命令是一个阻塞命令,它会阻塞所有其他客户端对数据库的访问,直到keys命令结束。
因此执行keys命令失败会导致redis服务器可能会暂时停止响应其他请求,导致服务不可用或响应变慢。

在生产环境下禁止使用keys命令特别是在数据量较大的集群环境中,一旦因为keys命令阻塞了redis的操作
就有可能使得集群判断redis出现故障从而出现故障恢复,引发数据混乱和雪崩等问题。

Redis_第16张图片

你可能感兴趣的:(Java,redis,java)