Questions

原理

Redis 为什么快

  • 基于内存

  • 数据结构简单、高效

  • 利用 IO多路复用监听事件、事件驱动

为什么采用单线程?

  • 首先必须明确,redis 单线程指的是网络请求模块使用了一个线程,其他模块有的用的是多线程,并不是一个线程完成了所有功能。

  • 原理上,其采用了利用 epoll 的多路复用特性,因此可以采用单线程处理其网络请求。

  • 6.0 以后,使用了多线程并行处理IO读写事件(网络连接仍然用一个线程处理)。

    • 这种做法和 Gohttp 库异曲同工,netpoll 里只用一个协程处理网络连接,但对连接里请求的读写,仍然是每个连接起两个协程分别负责其读写。

什么情况下使用 redis

  1. 针对热点数据进行缓存

  2. 对于特定限时数据的存放

  3. 针对带热点权值数据的排序

  4. 分布式锁

与memcache的区别

  1. redis 处理网络请求采用单线程模型,而 memcache 采用多线程的方式

  2. redis 支持数据持久化,memcache 不支持

  3. redis 支持的数据格式比 memcache 更多(一般选型都是这个原因)

穿透、击穿、雪崩

缓存穿透

缓存穿透指缓存和数据库均没有需要查询的数据,查询穿透到DB,使数据库压力过大。

解决方法

  1. 前置过滤

    1. 在数据库操作访问前进行校验,对不合法请求直接返回

    2. 每天定时使用布隆过滤器重置所有 key 的集合,先判断 key 在不在,再查 redis / DB

  2. 对于经常被访问的,并且数据库没有的 key,缓存该 key 的值为 null。不过这个得设较短的过期时间,防止数据长时间不一致。

缓存击穿

高频访问的key过期失效,导致缓存瞬间被击穿,打到数据库

解决方法

  1. 设置热点数据永远不过期。

  2. singleflight:从数据库加载到缓存时加锁。

缓存雪崩

缓存雪崩指缓存中一大批数据同时到过期时间。导致大量请求打到数据库

解决方法

  1. 缓存数据设置随机过期时间,防止同一时间大量数据过期。

  2. 设置热点数据永远不过期。

脑裂

是指因为网络问题,导致 master 节点未宕机的情况下,sentinel / 其余master 因为连接不上 master,所以将 slave 提升为 master 。此时存在两个不同的 master 节点。

如果客户端还在基于原来的 master 继续写入数据,那么新的 master 节点将无法同步这些数据,当网络问题解决之后,原先的 master 被降为 slave ,此时再从新的 master 中同步数据,将会造成大量的数据丢失。

解决方法

设置 min-slaves 参数,这样向旧的主节点写数据时会因无法同步给从节点而失败。客户端收到错误时应重新查找主节点

对比 memcache

  1. 数据类型更多:Redis支持多种数据类型,如字符串、列表、哈希、集合、有序集合等,而Memcached只支持简单的键值对。

  2. 持久化:Redis支持将数据持久化到磁盘,即使在服务器重启后也可以恢复数据,而Memcached不支持数据持久化。

  3. 高可用:Redis支持主从复制和集群模式,可以提供更高的可用性和可扩展性。

  4. 更丰富的功能:Redis支持事务、发布/订阅、Lua脚本等更多的功能,可以满足更多的应用场景。

  5. 性能差不多(因为都是读写内存,一般瓶颈在网络)

redis里时间复杂度最高的是哪个命令?

在 Redis 中,时间复杂度最高的命令是 KEYS 命令。 KEYS 命令是用来查找与指定模式匹配的键名。它的时间复杂度为 O(N),其中 N 是键空间的大小。因为它需要遍历整个键空间来查找符合条件的键名,所以在非常大的键空间中使用 KEYS 命令可能会导致 Redis 阻塞一段时间,从而降低 Redis 的性能。

如果想要查找符合某种模式的键名,建议使用更高效的命令,如 SCAN 命令。SCAN 命令可以在时间和空间上更高效地获取符合指定模式的键名。使用 SCAN 命令时,可以通过游标(cursor)来逐步遍历整个键空间,避免一次性遍历导致的性能问题。

其他命令一般都是O(1)、O(lgN) 的时间复杂度

参考

后端技术小牛说

Last updated