Redis概念理清 | 青训营

214 阅读13分钟

1、Redis是什么?

1.1 Redis概念

Redis(Remote Dictionary Server)是一种开源的高性能键值存储数据库,常用于缓存和数据存储。它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等,并提供快速读写操作。Redis的内存存储和持久化机制,以及发布/订阅功能,使其在实时数据处理、会话管理和高速缓存方面广泛应用。其简单的API、复制和高可用性特性,使其成为构建快速、可靠应用的强大工具。

1.2为什么我们需要Redis

同样是数据库,为什么我们需要Redis,用MySQL不行吗?

现在需要处理的数据量相比较于以前大大上升了,MySQL从单机演进出了集群,由于数据量的增长,MySQL读写数据压力的不断增加,我们出于对性能的考虑,Redis就应运而生了~ Redis是基于内存的数据库,因此读写速度非常快,适用于需要快速响应和高并发的场景,如缓存、实时计数等。而MySQL是基于磁盘的,虽然也有缓存机制,但在大量读写请求下可能会受到磁盘I/O的限制,性能不如Redis。

当然我们也会用到MySQL,比如我们经常访问的数据可以分为“冷热”数据。经常被访问到的数据被称为“热数据”,它就会被存到Redis里面,以便下次更快的读取。很少访问到的数据被称为“冷数据”,他就会被存放到MySQL里面。

2、Redis的应用案例

2.1 连续签到

利用Redis实现连续签到通常基于以下原理:

  1. 键值存储: 每个用户的签到记录可以使用Redis的键值对来存储。每个用户对应一个键,其值可以是一个有序集合(Sorted Set)或者列表(List)。
  2. 时间戳: 在签到时,会记录当前的时间戳作为签到时间。
  3. 连续性判断: 通过对有序集合或列表的成员进行查找和比较,可以判断用户是否连续签到。有序集合的分值可以表示时间戳,使得记录按照时间顺序排列。
  4. 过期时间: Redis可以设置键的过期时间,用于限定用户签到记录的保留时间,避免数据长时间无用。
  5. 定时任务: 可以使用Redis的定时任务(例如:Redis的过期键通知)来检查连续性,例如每天零点,检查前一天的签到记录,判断是否连续。

2.2 消息通知

利用Redis实现消息通知通常基于以下原理:

  1. 发布/订阅模型: Redis提供了发布/订阅(Pub/Sub)模型,允许一个消息发布者(Publisher)将消息发送给多个订阅者(Subscribers)。
  2. 频道(Channel): 消息通过Redis的频道进行发布和订阅。发布者将消息发布到一个频道,而订阅者可以订阅感兴趣的频道以接收相关消息。
  3. 消息队列: Redis的发布/订阅模型也可以用作简单的消息队列,发布者将消息发布到频道,订阅者从频道接收消息,实现消息传递和通知功能。
  4. 实时性: Redis的发布/订阅模型具有实时性,订阅者可以立即收到发布者发送的消息,适用于实时通知需求。

2.3 计数

利用Redis实现计数(如点赞数、浏览数)通常基于以下原理:

  1. 键值存储: Redis是一个键值存储数据库,可以用来存储计数器的值。每个计数器可以对应一个键。
  2. 数据类型选择: Redis提供多种数据结构,用于不同的计数需求。常用的有字符串(String)和哈希(Hash)。
  3. 自增操作: 利用Redis提供的自增(INCR)操作,可以将计数器的值在每次操作时增加。这是一种原子操作,能够在多线程或分布式环境中确保计数的准确性。
  4. 设置过期时间: 如果需要限制计数的有效时间,可以设置键的过期时间。这在一些临时计数需求(如短期活动的浏览数统计)中很有用。
  5. 持久化和内存管理: Redis提供了持久化选项,可以将计数数据保存到磁盘上。同时,由于计数数据可能增长,需要注意内存管理,避免过多的内存占用。

2.4 排行榜

利用Redis实现排行榜通常基于以下原理:

  1. 有序集合(Sorted Set): Redis的有序集合是一种数据结构,其中每个成员都关联有一个分值(score)。有序集合内的成员按照分值进行排序,这使得它非常适合用于实现排行榜。
  2. 分值和成员: 在排行榜中,每个项目或实体都对应一个成员,其在有序集合中的分值表示其在排行中的位置或分数。
  3. 添加和更新: 将每个实体添加到有序集合中,分值表示其排行的权重或得分。如果需要更新排行,可以通过修改分值来实现。
  4. 获取排名: 可以通过成员在有序集合中的排名(排名从小到大或从大到小)来获取其在排行榜中的位置。
  5. 获取范围: Redis提供根据分值范围或排名范围来获取一定范围内的排行榜数据。
  6. 删除和剔除: 可以根据需要从排行榜中删除或剔除实体。对于过期的排行,可以设置键的过期时间来自动剔除。
  7. 数据展示: 根据排行榜的需求,将有序集合中的成员和分值展示为具体的排行榜列表。
  8. 更新频率: 排行榜的更新频率可以根据业务需求决定,可以是实时更新,也可以是定期更新。

2.5 限流

利用Redis实现限流通常基于以下原理:

  1. 计数器和时间窗口: 限流的目标是控制在一段时间内的请求频率。这可以通过在Redis中创建一个计数器,记录在特定时间窗口内的请求次数。
  2. String和过期时间: Redis的字符串(String)类型适用于存储计数器的值,同时可以利用Redis的过期时间特性,设置键的过期时间以实现时间窗口的自动清除。
  3. 单线程处理命令: Redis是单线程处理命令的,这使得操作具有原子性,避免了多线程环境下的竞争条件。在执行计数操作时,不会受到其他并发命令的干扰。
  4. 自增操作: 使用Redis的自增操作(如INCR)来递增计数器的值。每次请求到达时,会对计数器执行自增操作。
  5. 时间窗口限制: 设置一个时间窗口,限制在该时间段内的请求次数。超过时间窗口后,可以通过重置计数器来重新开始计数。
  6. 计数判断: 在每次请求前,检查计数器的值是否超过设定的阈值。如果在限制范围内,允许请求继续;否则拒绝请求。
  7. 分布式场景: Redis的单线程特性在分布式场景下也有优势。通过Redis的分布式锁和同步机制,可以确保多个节点之间的计数器同步和一致性。

2.6 分布式锁

以下是Redis实现分布式锁的原理:

  1. 获取锁: 当一个进程(或线程)需要获得分布式锁时,它会尝试在Redis中创建一个特定的键,并设置一个过期时间。这个操作需要使用Redis的SET命令,但需要设置一个NX(如果键不存在则设置)选项,以确保只有一个进程能成功地创建这个键,即获得了锁。
  2. 过期时间: 为了避免某个进程获取锁后因异常退出而无法释放锁,锁的键通常会设置一个过期时间。一旦过期时间到达,Redis会自动释放这个键,其他进程就可以再次尝试获取锁。
  3. 释放锁: 当进程完成了需要锁保护的操作,它会使用DEL命令来删除锁的键,从而释放锁。这个操作需要确保只有锁的拥有者才能释放锁,以防止误释放。
  4. 保持原子性: Redis的命令是原子性的,所以获取锁、设置过期时间和释放锁这些操作是原子的,不会受到其他进程的干扰。
  5. 避免死锁: 设置合理的锁的过期时间是避免死锁的关键。如果获取锁的进程崩溃或异常退出,锁会在一段时间后自动释放,避免永久占用资源。
  6. 保持一致性: 通过使用Redis的单线程处理命令的特性,分布式锁能够在不同的节点上保持一致性,确保只有一个进程获得了锁。

3、Redis使用注意事项

3.1 避免使用大Key、热Key

在使用Redis时,有两个重要的概念需要注意:大Key和热Key。这些问题可能会影响Redis的性能和可用性,因此需要特别关注和处理。

  1. 大Key: 大Key是指存储在Redis中的某个键对应的值非常大,通常是大于Redis的最大对象大小(通常为512MB)。大Key会影响Redis的性能和内存使用,因为读写操作需要处理大量数据。同时,大Key可能导致阻塞其他操作,因为读取或写入大Key会占用较长时间的CPU和带宽资源。

    注意事项:

    • 避免存储大量数据在单个Key中,考虑分割成多个较小的Key来存储。
    • 使用Hash或List等数据结构来分割大数据,以避免单个Key的大小过大。
    • 压缩大Key
  2. 热Key: 热Key是指被大量访问的键,导致某个特定的Key成为热点,造成了不均衡的访问分布。热Key会导致单个Key的读写操作非常频繁,影响了Redis的性能和并发能力。当热Key达到一定阈值时,可能会导致Redis服务器的性能问题或甚至宕机。

    注意事项:

    • 使用合理的缓存策略,如Least Recently Used (LRU) 或 Least Frequently Used (LFU),以避免某个Key长时间占用缓存。
    • 如果可能,将热Key进行分片或分散,以减轻对单个Key的访问压力。

3.2 慢查询场景

在使用Redis时,慢查询场景是指Redis执行某些命令或操作时的响应时间超过了预期,导致性能下降或影响系统的可用性。以下是在慢查询场景下需要注意的一些方面:

  1. 慢查询检测: Redis提供了SLOWLOG命令,用于记录执行时间超过一定阈值的命令。通过定期检查慢查询日志,可以识别可能引起性能问题的操作。
  2. 分析查询: 当发现慢查询时,需要仔细分析执行该命令的情况。可以使用Redis的EXPLAIN命令或其他监控工具来了解命令的执行计划和资源消耗情况。
  3. 命令优化: 针对慢查询,可以尝试优化命令的参数、数据结构、使用索引等方式,以减少查询时间。
  4. 合理使用索引: 在使用有序集合、哈希表等数据结构时,合理使用索引来加速数据的检索。避免在大数据集上进行全表扫描。
  5. 适当的数据分片: 在分布式环境中,适当地将数据分散到多个节点上,避免单个节点负载过重,从而减少慢查询的可能性。
  6. 避免阻塞操作: 部分Redis命令是阻塞的,例如BLPOP、BRPOP等。在高并发场景中,这些命令可能会导致阻塞操作,影响性能。要谨慎使用,可以考虑异步操作。
  7. 合理设置超时: 在使用阻塞命令时,设置合理的超时时间,以防止长时间的等待造成性能问题。
  8. 使用合适的数据结构: 选择适合场景的数据结构可以极大地提高查询效率。比如,使用哈希表来存储字段,或使用位图来表示状态等。
  9. 监控和预警: 使用监控工具定期检查Redis的性能指标,如响应时间、命令执行时间等。设置预警机制,及时发现慢查询问题。
  10. 缓存优化: 如果某些慢查询是由于缓存失效引起的,可以考虑优化缓存策略,减少缓存失效带来的性能影响。

3.3 注意缓存穿透、缓存雪崩

在使用Redis时,缓存穿透和缓存雪崩是两个重要的缓存相关问题,需要特别注意和处理。以下是对这两个问题的解释:

  1. 缓存穿透(Cache Penetration): 缓存穿透是指在缓存中查找某个数据时,由于该数据在数据源中不存在,导致每次查询都无法从缓存中获取,最终会对数据源造成过多的查询压力。这可能是恶意请求、错误的缓存键或者没有被缓存的数据。

    注意事项和解决方案:

    • 布隆过滤器: 使用布隆过滤器等技术预先过滤不存在的键,避免查找不存在的数据进入缓存层。
    • 空值缓存: 即使数据源中不存在某个键对应的数据,也将这个键存储在缓存中,但设置一个较短的过期时间,防止过多的无效查询。
  2. 缓存雪崩(Cache Avalanche): 缓存雪崩是指在某个时间段内,缓存层中的大量数据同时失效,导致大量的查询请求直接访问数据源,引发数据库短时间内的巨大压力,甚至导致数据库崩溃。

    注意事项和解决方案:

    • 过期时间分散: 设置缓存数据的过期时间时,可以在同一类型的数据上加上随机的小偏移量,使得过期时间分散开来,避免集中失效。
    • 热点数据持久化: 对于热点数据,可以考虑将其持久化,避免在缓存失效时完全依赖数据源。
    • 高可用架构: 使用高可用架构,如主从复制、集群等,分散请求,降低单一节点失效的风险。
    • 限流和熔断: 当缓存失效时,可以通过限制对数据源的请求频率或者熔断来保护数据库。

以上是我观看了《Redis-大厂程序员是怎么用的》这门课后,通过个人理解与上网查找各种资料的出来的总结~