Redis-大厂程序员是怎么用的

Redis是什么

为什么需要Redis,Redis的基本工作原理

Redis:开源的、高性能的、支持多种数据结构的Key-Value数据库。不仅是一个缓存系统,还是一个持久化的数据库,能够在内存中高效地进行读写操作。

背景:数据量增加、读写数据压力的不断增加(如秒杀、抢购、社交平台的点赞、评论等),传统关系型数据库(如 MySQL)往往无法满足高并发的需求,可能导致响应时间过长、系统崩溃等问题。Redis 的出现提供了一个高效的解决方案。

高性能读写操作: Redis 是一个内存数据库,通过内存存储数据,读取速度极快,尤其在处理大量并发请求时表现优异。

数据持久化:虽然 Redis 是一个内存数据库,但它支持两种持久化机制:RDB 快照AOF(追加日志)。这使得 Redis 即使在系统重启或故障时,也能恢复数据。

单线程执行:Redis的命令由单一线程处理,避免了多线程带来的复杂性和性能瓶颈。在单线程下实现高并发处理,避免了多线程并发时可能出现的锁竞争、死锁等问题。虽然单线程看似是性能瓶颈,但 Redis 使用了非常高效的事件驱动机制,能够在一个线程内处理成千上万的请求。

数据从内存读取:Redis 的数据是存储在内存中的,所有的读写操作都直接在内存中完成。因此,Redis 的访问速度非常快,能够在毫秒级的时间内完成请求的处理。相对于传统的磁盘数据库(如 MySQL),Redis 的速度更具优势。

RESP协议:RESP 协议设计上非常简洁,支持文本和二进制格式,能够在客户端和 Redis 服务器之间高效地传递数据。

冷热数据分离:为了提高系统性能,Redis 通常用于缓存热点数据(热数据),例如用户登录信息、商品库存、点赞数等。对于冷数据,则存储在 MySQL 等传统数据库中。这样,Redis 可以加速对热点数据的访问,而数据库则负责存储较少被访问的数据。

过期时间和内存回收:Redis 提供了缓存数据的过期策略。你可以为每个键设置过期时间,超过这个时间后,Redis 会自动删除该键值。此外,Redis 还支持多种内存淘汰策略,例如:LRU(最久未使用)、LFU(最不常使用)等,用于在内存满时选择删除哪些数据。

Redis应用案例

通过案例,了解Redis的实际应用场景,并介绍Redis常用数据结构

连续签到,消息通知,计数,排行榜,限流,分布式锁

这里用到了很多掘金本身的例子来说,这点很不错

连续签到

连续签到天数,如果签到中断就会重置

使用 String 数据类型来存储用户的连续签到天数。

为了避免用户签到次数被重复计算,设置一个过期时间(expireAt),在用户签到到期后重置。

Key:用户id
value:252(连续签到天数)
expireAt:后天的0点(过期时间)

Redis 会通过 INCR 命令对连续签到天数进行递增,同时设置 expireAt 来确保每天签到重置。

消息通知

当文章更新时,用户需要接收到推送通知,将更新后的文章推送到 Redis 的 List 中。客户端从 List 中获取消息进行处理。Redis 可以通过消息队列高效地处理这些需求。

使用 List 数据结构来实现消息队列。

利用 Redis 的 List 操作(如 LPUSHBRPOP)来将消息存入队列并通知客户端。

消息队列(必考项)

List数据结构Quicklist,由一个双向链表和listpack实现,支持高效的插入和弹出操作。

计数

很多应用需要对用户的某些操作进行计数。例如,点赞数、访问量、用户行为记录等。这些计数值可能需要存储在一起,以便进行统一管理和查询。

将多个Key-value存到hash数据结构中

使用 Pipeline 批量操作:如果需要对多个计数项进行批量操作,Redis 支持 Pipeline 技术,可以将多个命令打包发送到 Redis 服务器,从而减少网络往返的延迟,提升操作效率。

排行榜

积分变化时,排名要实时变更

使用 ZSet(有序集合) 数据结构来存储排名信息。

ZSet 数据结构:zskiplist + dict

ZSet 结合了跳跃表和哈希表的特性,通过跳跃表找到元素,再通过dict找到元素的值

限流

为了防止系统被大量并发请求压垮,通常需要对某些操作进行限流。

利用 Redis 的 String 类型和 计时器(例如时间戳)来实现限流。1s只放行N个,超过限制N则拦截禁止访问

Key通过当前时间戳进行拼装,Key: API 请求标识 + 时间戳

Key: API 请求标识 + 时间戳
Value: 请求计数

分布式锁

在高并发的秒杀、抢购等场景,一次只能有一个协程执行Redis 可以通过分布式锁来保证这一点。

使用 Redis 提供的 SETNX 命令(即 Set if Not Exists)来实现分布式锁。

抢夺锁,完成业务逻辑,释放锁

redis执行线程是单线程

存在的问题

​ 业务超时问题:当业务执行的时间超过锁的超时时间,可能会导致并发问题。为避免死锁,锁超时后需要重新设置锁的有效期。

​ Redis 主备切换问题:在 Redis 主从复制架构中,当主节点故障时,切换到备节点可能导致临界点问题,尤其是主节点的缓存未及时同步到从节点时。

​ Redis 集群脑裂问题:当 Redis 集群发生网络分区时,可能会出现多个主节点同时处理请求,导致数据不一致的情况。

Redis使用注意事项

在字节跳动使用Redis有哪些注意事项

大Key、热Key

大 Key:在 Redis 中,如果某个键的数据量过大,会导致内存占用过多,并且在进行操作时可能会产生性能瓶颈。

​ 避免使用大 Key 的方法:拆分、压缩

拆分:将大数据拆分为多个小 Key,分散存储。

压缩:对于存储大量数据的 Key,可以进行压缩,以减小内存占用。

热 Key:热点数据是频繁被访问的数据,如果某些 Key 被频繁访问,会导致 Redis 在这些 Key 上产生过高的负载,从而影响整体性能。

冷热分离:将访问频率较高的数据(热数据)缓存到 Redis,而将较少访问的数据(冷数据)存储到数据库(如 MySQL)。如榜单只缓存前10页,后续数据走db

使用 LocalCache:引入本地缓存(如 Java 的 Guava 或 Golang 的 Bigcache),减少对 Redis 的频繁访问,减轻 Redis 的压力。

Redis 代理:使用 Redis 代理来发现和处理热 Key,确保 Redis 能承载高频访问的负载。

慢查询场景

容易导致redis慢查询的操作

单批次操作过多的 Key-Value 对

​ 使用命令如 MSETMGETHMSETHGETALL 等一次性处理大量数据时,如果操作的数据量非常大,就会对 Redis 服务器造成较大的负担。

复杂查询操作

​ 查询包含大量成员的有序集合(ZSET)或哈希(HASH)时,如果数据量非常大,Redis 需要消耗较长时间来计算排名、排序等。

长时间阻塞操作

​ 一些 Redis 命令可能会在执行期间阻塞当前线程,特别是涉及到大数据量的操作时。这会导致其他客户端的请求排队,增加延迟。

缓存穿透、缓存雪崩(必考)

缓存穿透:热点数据查询绕过缓存,直接查询数据库

​ 查询不存在的数据的查询请求会直接打到db

​ 热Key过期会有大量请求击穿至db

​ 如何减少缓存穿透:缓存空值,布隆过滤器

缓存雪崩:大量缓存同时过期

​ 如何避免缓存雪崩:

​ 缓存空值,将缓存失效时间反散开

​ 使用缓存集群

小结

  • 大 Key 和热 Key:通过拆分、压缩和冷热分离来优化内存使用,并引入本地缓存减少对 Redis 的访问压力。
  • 慢查询:避免在单次操作中使用过多的键值对,合理拆分批量操作,避免对 Redis 产生过大负担。
  • 缓存穿透和缓存雪崩:通过缓存空值、使用布隆过滤器以及反散列过期时间等手段来降低这些问题的发生概率,保证系统的稳定性。