百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

用了缓存后,性能反而更慢了?(缓存会导致什么问题)

wptr33 2025-07-19 23:04 13 浏览

很多小伙伴都知道缓存的好处,从数据库加载数据过慢时,直接上 Redis 缓存!

的确,Redis 高性能 KV 存储是后端开发提升性能的一大利器,但是有没有想过,如果使用姿势不对,使用 Redis 后,性能反而会更慢呢?

今天就来盘下使用 Redis 性能变慢的几个原因以及一些应对手段。

1、网络和通信导致的延迟

比如我们现在要往 Redis 里面写入多个 key 和值:

keyvaluenameyupigendermalebaseshanghai......

很多同学会采取一条一条塞入的方式来完成这些键值对的写入,如图:

可以看到,下一条数据的写入需要等待上一条的返回,这个等待时间除了命令的处理时间,其实网络通信的时间也占据了很大一部分

就好比我们网购了 5 件衣服,都送到了快递驿站,此时我们是去驿站一件一件拿回家快呢?还是 5 件衣服一起拿快呢?

答案显而易见,肯定是一起拿快,如果一件一件的拿,很多时间都消耗在路上了!

同理,对于上面 Redis 这种场景,我们需要使用 MSET 这样的聚合命令,通过 批量操作 来提升性能。如图,一趟搞定!

我本地写了段脚本来实际测试了一下,对比使用 for 循环插入 2W 条记录,和利用 mset 命令一次性插入 2W 条数据的耗时。

结果,for 循环花了 5472 毫秒,mset 花了126 毫秒,它们之间差了 40 多倍

由此可见,这种聚合命令在某些时候下,提升性能的效果还是十分可观的!

类似的聚合命令还有很多,比如 MGET、MHSET、HMGET 等等。

除此之外,也可以使用 Pipeline 一次性打包多条命令执行,更进阶的还有 lua 脚本,这里就不多展开了。

2、忽略复杂度高的命令

很多同学都默认 Redis 很快,于是用起 Redis 没啥负担,就是几行代码的事情嘛~

其实像一些普通命令,比如 SET 或 LPUSH 这种问题确实不大。

用我的一台小破机器测试,一条 set 命令消耗的时间在 10 毫秒以内。

但是有一些命令却不是,比如 SORT、LREM、SUNION。举个例子,比如有两个大集合,存了很多很多数据,此时你要取它们的交集,想想是不是很耗时?

我在 200W 条数据量的情况下使用 SUNION 命令测试,耗时近 5000 毫秒,跟正常的一条 set 的10 毫秒可是差了 500 倍!

而且需要注意,Redis 执行命令是单线程的!如果你前面执行了一个比较耗时的命令,假设此时并发度很高,那么就会有一堆命令排队等着前面耗时的那条命令,这个时候就会产生阻塞。

想想看,本来 redis 能处理 500 条命令,现在只能处理一条了,这种情况频繁一点,在高峰期对业务的影响就会很大。因此在生产环境中,需要慎重的使用这些命令,仔细评估集合的数据量,如果数据量不大,那么才能使用。

对了,这里需要特别强调一个命令:keys,很多生产环境的问题都是因为这条命令导致的。我对这个命令记忆尤其深刻,因为之前有个同事因为执行了这个命令导致线上服务雪崩了!

这个命令它会扫描 db 所有 key ,如果比较耗时,特别是当前 reids 有很多 key 的情况下,很容易造成服务的崩溃,从而引发雪崩!

做个狠点的测试,插入 1 亿条数据,然后执行下 keys 来看看到底得耗时多久!开始!

10分钟过去了....

20分钟过去了...

???中间没忍住想利用可视化工具打开看看已经插入了多少条,然后它崩了!!

行吧,1 亿数据确实有点多,我放弃,不插入了。

重启了 redis desktop manager 一看,已经插入了2900w条了

于是在 2900w 条数据时,执行 keys 命令,消耗了大概 50 多秒。

在执行 keys 命令的时候,哪怕执行一个普通的 get 命令,也要一直被阻塞。有的时候,单次查询慢,不一定是查询代码的问题。

所以,建议在生产上禁用这类命令,防止一些同学误用产生重大事故!

3、key的集中过期

除了 keys 的问题,之前在生产环境还遇到一个莫名其妙的 Redis 问题。

当时排查的时候,把我头都快搞秃了!

当时遇到的问题就是 key 的集中过期

Redis 淘汰键值对有两种方式:

  1. 惰性淘汰。当命令请求到这个 key 时,看下它过期没,如果过期则清理
  2. 主动淘汰。Redis 每 100 毫秒会随机扫描 20 个 key,删除其中过期的 key,如果过期率超过 25 % ,则会继续这个过程,过期率超过 25 % ,则会继续这个过程,过期率超过 25 % ,则会继续这个过程。没错,会一直重复这个步骤,直到过期率低于 25 % 或者累计耗时超过 25 毫秒才会终止这个步骤。

就是这个主动淘汰机制,使得如果有大批的数据在同一时间到期,那么主要淘汰每次时长都要拉满,这其实就等于主动给 Redis 加压!

好家伙,这种时间的拉长在慢日志里面是查不到的,因为它不是因为命令本身的耗时长,所以当时排查了非常久,让我摸不住头脑的同时,也让我摸不到头发了。

所以在生产上要避免一大堆 key 同时到期,我们在设置过期时间的时候,可以增加一些随机数来打散它们。比如下列代码:

expire(key, time + random(600))

4、bigkey

最后还有一个非常重要的问题点,也是大伙在使用上需要着重关注的点,就是 bigkey 问题。

可以理解为目前的 key 所占的内存比较大,可能是它的值比较多,或者每个值占用的内存比较多。

就好比一个删除(DEL)操作,在我们眼里它不像两个集合交集这么复杂,但是在 bigkey 场景下,它可能就会出现问题!

我们都知道 Redis 占用内存资源,而内存是有限的,因此如果有不需要的内存需要及时释放,所以就会 DEL 某个 key 来释放内存,然后这个 key 又是个 bigkey ,因此释放的内存比较大,这样一来耗时就会比较久,所以一个简单的 DEL 命令都可能会在高峰期造成阻塞。

就好比咱们平日每天扔垃圾,早上出门把昨晚的垃圾一提一扔,轻松!

假设你假期在家蜗居了 7 天,点了 7 天的外卖,然后你这个懒鬼一点都不想出门,垃圾堆着就多了,此时长假结束,你要出门扔垃圾了,请问你能一趟扔完吗?

针对删除的命令,在 Redis 4.0 之后,可以通过 unlink 代替 del,unlink 释放内存是放在后台线程执行的,不会阻塞主线程,6.0 版本开启 lazy-free 后,释放内存都是放在后台线程执行。

不过以上仅仅只是删除的优化,在业务上我们还是需要避免 bigkey 的产生,对于一些已有的 bigkey,要及时做拆分。


以上就是本期分享,希望大家使用 Redis 的时候,多一个心眼,避免事故的发生~

相关推荐

MySQL进阶五之自动读写分离mysql-proxy

自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...

Postgres vs MySQL_vs2022连接mysql数据库

...

3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?

引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...

一文由浅入深带你完全掌握MySQL的锁机制原理与应用

本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...

验证Mysql中联合索引的最左匹配原则

后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...

MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)

目录1.索引基础...

你会看 MySQL 的执行计划(EXPLAIN)吗?

SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...

MySQL 从入门到精通(四)之索引结构

索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...

mysql总结——面试中最常问到的知识点

mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...

mysql总结——面试中最常问到的知识点(2)

首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...

MySQL基础全知全解!超详细无废话!轻松上手~

本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...

深入剖析 MySQL 中的锁机制原理_mysql 锁详解

在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...

Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析

引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...

MySQL基础篇:DQL数据查询操作_mysql 查

一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...

MySql:索引的基本使用_mysql索引的使用和原理

一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...