1、Redis缓存刷新策略有哪些?
- Redis提供了以下几种缓存刷新策略
- 基于过期时间:可以设置key的过期时间,当过期时间到达后,Redis会自动删除该key。
- 基于LRU算法:Redis使用LRU算法来淘汰最近最少使用的key,以保留热点数据。
- 基于LFU算法:Redis使用LFU算法来淘汰最不经常使用的key,以保留热点数据。
- 基于手动刷新:可以手动删除缓存中的key,或者通过发送通知来通知客户端删除key。
- 基于定时刷新:可以定时清空缓存,或者定时刷新缓存中的数据,以保持数据的及时性。
2、Redis持久化方式有哪些?有什么区别?
- Redis提供两种持久化机制:RDB和AOF。
- RDB(Redis DataBase)持久化:会将Redis在内存中的数据快照保存到磁盘上,形成一个RDB文件,该文件包含了Redis在某个时间点上的数据快照
- 优点:
- 只有一个dump.rdb文件,方便持久化
- 容灾性好,一个文件可以保存到安全的磁盘。
- 性能最大化,fork子进程来完成写操作,让主进程继续处理命令,I/O最大化
- 数据集较大时,比AOF的启动效率更高。
- 缺点:
- 数据安全性较低,RDB是间隔一段时间进行持久化,如果持久化之间Redis发生故障,会发生数据丢失,因此这种方式更适合数据要求不严谨的时候。
- 优点:
- AOF(Append Only File)持久化:是将Redis写操作记录到一个文件中,每次Redis执行一条写命令,就将该命令写入AOF文件中,这样可以保证每条命令都能被保存下来。AOF文件可以进行追加和重写操作,当文件太大时,Redis会自动进行重写,将多次修改合并成一条,以减少磁盘占用空间。
- 优点:
- 数据安全:AOF持久化可以配置
appendfsync
属性,它可以指定AOF文件的刷盘策略。默认情况下appendfsync
的值为everysec
。即每秒中将AOF缓存中的数据写入磁盘一次。但是,用户也可以将appendfsync
的值设置为always
,这样每次执行写操作都会立即将AOF缓存中的数据写入磁盘。这样即使Redis发生异常情况。只要AOF文件中已经记录了相应的写操作,就可以通过AOF文件来恢复数据。 - 数据一致性:AOF持久化是通过append模式写入文件的,即每次写操作都是追加到AOF文件末尾。因此,即使Redis在写入AOF文件的过程中宕机,AOF文件也不会损坏,而是只会丢失一部分的数据。当Redis重新启动是,会通过redis-check-aof工具将AOF文件中不一致的数据进行修复,保证数据的一致性。需要注意的是,使用AOF持久化时,如果Redis频繁执行写操作,那么AOF文件可能会非常大,可能影响性能。因此,用户可以通过配置AOF重写规则,定期对AOF文件进行压缩,以减小文件大小。
- 数据安全:AOF持久化可以配置
- 缺点:
- AOF文件比RDB文件大,且恢复速度慢。
- 数据集较大时,比RDB启动效率低。
- 优点:
- Redis支持同时使用RDB和AOF持久化机制。在使用时,Redis会先尝试使用AOF文件来恢复数据,如果AOF文件不存在或者恢复失败,Redis会尝试使用RDB文件来恢复数据。同时使用两种持久化机制可以在保证数据完整性的同时提高恢复速度。
3、 持久化有两种,那么该怎么选择呢?
- 不要仅仅使用RDB,因为那样会导致丢失很多数据。虽然RDB持久化机制的忒但是可以生成数据的快照,这样在恢复数据的时候非常快速。但是RDB持久化只在发生故障时执行,如果Redis崩溃或意外关闭,可能会丢失最近执行的一些命令。因此,建议使用AOF持久化来记录Redis执行的所有写操作,并将RDB持久化用于冷备。
- 也不要仅仅使用AOF,虽然AOF持久化机制可以记录Redis执行的所有写操作,因此在数据恢复方面会比RDB更加健壮,但是它也存在一些问题。如果仅使用AOF进行冷备,那么在恢复数据时,它可能会比RDB持久化慢。如果只使用AOF持久化,那么可能会因为AOF文件过大导致性能下降。
- Redis支持同时使用AOF和RDB持久化机制。使用AOF持久化可以保证数据不丢失,并作为数据恢复的首选,使用RDB持久化作为冷备,以提供快速数据恢复选项。这种方式可以利用AOF和RDB持久化机制的优点来提高数据安全性和恢复速度。
- 如果同时使用RDB和AOF持久化机制,在Redis重启时,会使用AOF来重构数据,因为AOF中的数据更加完整。
4、怎么使用Redis实现消息队列?
- Redis可以使用list结构作为队列来实现消息队列,使用rpush生产消息,使用lpop消费消息。当lpop没有消息的时候,需要适当的sleep一会儿再重试。但是也可以使用blpop命令来阻塞住,直到消息到来,避免了sleep操作。
- 如果需要实现生产一次消费多次的场景,可以使用pub/sub主题订阅者模式,实现
1:N
的消息队列。 - 但是pub/sub的缺点是在消费者下线的情况下,生产的消息会丢失。因此,如果需要更可靠的消息队列,需要使用专业的消息队列,例如RabbitMQ。
- 此外,Redis还可以使用sortedset结构来实现延时队列。使用时间戳作为score,消息内容作为key,调用zadd来生产消息。消费者可以使用zrangebyscore指令获取N秒之前的数据,然后轮询进行处理。
5、说说你对Redis事务的理解
- 什么是Redis事务?
- Redis中的事务是一组命令的集合,是Redis的最小执行单位。它可以保证一次执行多个命令,每个事务是一个单独的隔离操作,事务中的所有命令都会被序列化、按顺序地执行,服务端在执行事务的过程中,不会被其他客户端发送来的命令请求打断。Redis事务通过MULTI、EXEC、DISCARD、WATCH等命令来实现的。
命令 | 作用 |
---|---|
MULTI | 开启一个事务 |
EXEC | 提交事务,从命令队列中取出提交的操作命令,进行实际执行 |
DISCARD | 放弃一个事务,清空命令队列 |
WATCH | 检测一个或多个键的值在事务执行期间是否发生变化,如果发生变化,那么当前事务放弃执行 |
- Redis事务的注意点有哪些?
- Redis事务是不支持回滚的。
- Redis服务端在执行事务的过程中,不会被其他客户端发送来的命令请求打断,直到事务命令全部执行完毕才会执行其他客户端的命令。
- Redis事务为什么不支持回滚?
- Redis的事务不支持回滚,但是执行的命令如果有语法错误,Redis会执行失败,这些问题可以从程序层面捕获并解决。但是如果出现其他问题,则依然会继续执行剩下的命令。这样做的原因是因为回滚需要增加很多工作,而不支持回滚可以保持简单、快速的特性。
6、Redis为什么设计成单线程的?
- Redis的单线程设计是其高性能的重要原因之一。Redis单线程的设计思想主要是为了避免多线程带来的上下文切换、锁竞争等开销。从而提高Redis的效率和性能。
- 具体来说,Redis单线程的设计主要有以下几个方面的考虑:
- 避免上下文切换:在多线程环境下,线程的切换会涉及到上下文的切换,这个切换本身就就会消耗CPU资源和时间。而Redis单线程的设计可以避免这种上下文切换的开销,从而提高Redis的性能。
- 避免锁竞争:在多线程环境下,线程之间共享数据时需要使用锁来保证数据的一致性和可靠性。而所本身也会带来开销和竞争,降低Redis的效率和性能。而Redis单线程的设计可以避免这种锁竞争的开销,从而提高Redis的性能。
- 减少内存分配:在多线程环境下,线程之间需要共享内存,而内存共享会涉及到内存分配和管理的开销。而Redis单线程的设计可以避免这种内存分配的开销,从而提高Redis的效率和性能。
7、什么是Bigkey?会存在什么影响
- Bigkey指的是Redis中的大键,即占用内存较多的键值对。造成的影响如下:
- 内存占用:Bigkey会占用大量的内存资源,导致Redis内存不足,从而影响Redis的性能和可用性。
- 网络传输:Bigkey会增加网络传输的负担,因为在进行数据备份和复制的时候,需要将Bigkey的数据全部传输,从而增加了网络带宽的使用。
- 超时阻塞:由于Bigkey占用的空间较大,所以Redis在对其操作时,可能会消耗过长的时间,导致客户端超时阻塞。因为Redis采用单线程模型,当处理一个大key时,其他请求必须等待该操作完成后才能执行,而这个操作可能会需要较长的时间,从而导致阻塞。为了避免这种情况的发生,可以对bigkey进行拆分或优化。
- 内存碎片:Bigkey会导致Redis中出现内存碎片,从而影响Redis的内存使用效率,导致Redis内存占用率上升。
8、 说说Redis哈希槽的概念
- Redis哈希槽是Redis集群中用来实现数据分片的一种机制,可以将所有的键均匀地分布到多个节点上,以实现高可用和高性能分布式数据存储。
- 具体来说,Redis集群将整个数据集分为16384个哈希槽,每个节点负责其中的一部分哈希槽,节点之间通过Gossip协议进行通信,维护整个集群的状态。当一个客户端想要访问一个键时,Redis会根据键名计算出该键对应的哈希值,然后找到哈希槽的编号,再根据哈希槽的映射关系,将请求路由到对应节点上。
9、 Redis常见性能问题和解决方案有哪些?
- 网络延迟:Redis的性能很大程度上受限于网络延迟,因此需要尽可能减少网络传输次数和数据量,避免过多的网络IO操作
- 解决方案:可以使用Redis的Pipline特性,将多个请求打包发送,减少网络传输的次数;也可以使用Redis的批量操作命令,将多个数据一次性提交,减少网络传输的数据量。
- 大量的数据读写:Redis的单线程模型会在高并发读写的情况下出现性能瓶颈,导致响应时间变长。
- 解决方案:可以使用Redis的主从复制和集群特性,将数据分布在多个节点上,增加系统的读写并发能力。
- 慢查询:当Redis中存在大量慢查询操作时,会影响Redis的整体性能。
- 解决方案:可以使用Redis的slowlog功能,记录Redis的慢查询操作,并使用Redis的监控工具进行监控,及时发现慢查询问题。
- 内存使用过多:Redis需要将所有的数据存储在内存中,当数据量过大时,会占用大量的内存资源,导致Redis的性能下降。
- 解决方案:可以使用Redis的持久化功能,将数据写入磁盘中,以释放内存空间;也可以使用Redis的内存优化技巧,如删除不必要的数据、合理使用Redis的数据结构等。
- 阻塞操作:当Redis执行某些操作时,会阻塞其他操作的执行,从而影响Redis的整体性能。
- 解决方案:可以使用Redis的异步操作特性,将阻塞操作转化为异步操作,以提高Redis的性能和吞吐量。
10、 如果Redis中有1亿个key,其中有10W个key是以某个固定的已知前缀开头的,如何将它们全部找出来?
- 我们可以使用keys命令或scan命令,然而在数据量庞大的环境下,不推荐使用keys命令。
- keys命令是遍历查询的,时间复杂度为O(n),数据量越大查询时间越长,且Redis是单线程的,使用keys命令会导致线程阻塞一段时间,从而导致Redis会出现假死问题,直到keys命令执行完毕才能恢复,这在生产环境下是不可接受的。此外,keys命令没有分页功能,会一次性查询出所有符合条件的key值,输出的信息非常多。
- 相对来说,scan命令比keys命令更适合生产环境。sacn命令可以实现和keys命令相同的匹配功能,但是在执行过程中不会阻塞线程,并且查询的数据可能存在重复,需要客户端去重。因为scan命令是通过游标方式查询的,所以不会导致Redis出现假死问题。Redis在查询过程中会把游标返回给客户端,单词返回控制且游标不为0,则说明遍历还没有结束,客户端继续遍历查询。但是,scan命令在检索的过程中,被删除的元素是不会被查询出来的,如果在迭代过程中有元素被修改,scan命令也不能保证查询出对应的元素。相对来说,scan命令查找花费的时间会比keys命令长。
- 补充:假死问题
- Redis假死问题是指当Redis实例在进行某些耗时操作时(例如遍历所有key),由于Redis是单线程的,所以这个操作会导致Redis线程被阻塞,从而导致Redis无法处理其他请求,造成Redis服务不可用的状态。在这种情况下,Redis似乎已经死了,但其实Redis线程仍在执行操作,只是无法处理其他请求而已。因此,这种状态被称为Redis假死问题。避免Redis假死问题的常见方法是使用Redis提供的异步命令和管道技术,以避免在生产环境中会使用遍历所有key的操作。
11、如果有大量的key需要设置同一时间过期,一般需要注意什么?
- 如果大量缓存同时失效,会导致大量的请求直接访问数据库,容易造成数据库崩溃或者降低数据库的性能,进而影响整个系统的稳定性。
- 为了预防这种情况的发生,我们最好在设计数据过期时间的时候,都加上一个随机值,让过期时间更加分散,从而尽量避免大量的key在同一时刻失效。