用了缓存后,性能反而更慢了?
liebian365 2025-01-02 17:40 26 浏览 0 评论
很多小伙伴都知道缓存的好处,从数据库加载数据过慢时,直接上 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 淘汰键值对有两种方式:
- 惰性淘汰。当命令请求到这个 key 时,看下它过期没,如果过期则清理
- 主动淘汰。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 的时候,多一个心眼,避免事故的发生~
相关推荐
- C语言自学课程大纲(c语言入门自学资料)
-
一、自学C语言,很多人不知道应该如何学习,从哪儿学习,学习又分为几个阶段,总是学着学着就很迷茫???分享C语言的学习路线图,跟着路线图学吧,天天看。...
- 「linux」定时器方案:红黑树、最小堆和时间轮的原理
-
一、网络事件和时间事件对于服务端来说,驱动服务端逻辑的事件主要有两个,一个是网络事件,另一个是时间事件;...
- 程序员怎么会不知道 C10K 问题呢?
-
昨天的文章中提到了C10K问题,结果好些程序员跑过来问,啥是C10K,我写了这么多年程序,我怎么不知道呢?我说,那你听说过前腿儿猪肉吗?今天简单说说C10K的问题。关于这个问题,Ruby...
- 朝荐开源 - glib(朝廷百科)
-
glib是一套通用的实用程序库,它为C语言提供了许多有用的数据结构、工具函数和抽象层,旨在简化C语言的跨平台开发,并提高代码的可重用性和效率。glib是GTK+和GNOME桌面环...
- libevent总结(事件处理框架)(libevent libev)
-
libevent的事件处理框架是一个反应堆模型,而反应堆模型的核心就是io复用,拿epoll来说反应堆模型有两个核心数据结构,一个是epoll维护的内核事件表,一个是保存激活事件的事件队列当然,值得注...
- 日荐开源 - LibEvent(aldente官网网址)
-
libevent...
- 快递单号一键查询,高效追踪包裹物流,省时省力!
-
在繁忙的现代生活中,快递已成为我们日常生活中不可或缺的一部分。然而,面对众多的快递单号,如何快速、准确地查询包裹的物流信息成为了一个难题。现在,我们为您带来了一款快递单号一键查询工具,让您的物流追踪变...
- 导入不同快递公司下的单号批量查快递动态,一键解决物流查询难题
-
看着满屏快递单号陷入沉思?同事小王已经用《快递批量查询高手》一键导入多家快递,批量查询快递信息并统计了…而你还在中通、圆通、申通官网来回切换到鼠标冒烟?是时候亮出这个让快递公司接口“集体颤抖”的...
- 一键解锁快递查询高效能:批量查询快递,智能排序延误单号
-
当你的客服团队还在用5个浏览器轮番刷新物流页面时,隔壁仓库的王叔已经用快递批量查询高手把多个个滞留件变成会说话的预警红点!这篇教程将揭秘物流圈的「神器」,让「未更新快递」自动排队到你面前认罪。1.在软...
- 一站式快递单号查询平台,修改单号刷新快递信息的快递查询教程
-
一站式快递单号查询平台,支持导入单号查询时修改快递单号,高效刷新快递信息的快递查询教程随着电子商务的繁荣发展,快递业务量不断增长,无论是电商卖家还是普通消费者,对快递信息的查询和管理需求都日益增强。为...
- 高效快递单号查询,批量查询快递信息,多种查看方式满足你的需求
-
最近有很多朋友在问,如何查快递,怎么根据条件查看单号呢?不知道如何操作的宝贝们,下面请随小编一起来试试,希望能给大家带来帮助。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?步骤1:运...
- 物流查询达人必备!一键批量查询快递单号,根据发出时间筛选单号
-
嘿,各位快递查询达人们,是不是经常为海量的快递单号查询而头疼不已?想要一款能够在线批量查询快递动态,还能根据发出物流时间一键筛选所需快递单号信息的神器吗?来来来,让我给你们揭秘一款快递批量查询高手软件...
- 快递查询神器,多单号导入,筛选保存一键完成
-
当面对如山的快递单号,你是否曾感到手足无措?每一个单号都需要你逐一输入、查询,再逐个根据时间差进行筛选,这样的工作无疑是对耐心与精力的双重考验。但别担心,今天,我们将为你揭示一款物流行业的秘密武器——...
- 快递单号查询神器:一键复制粘贴,轻松批量追踪同公司快递
-
嘿,小伙伴们!还在为手动输入快递单号查询物流信息而烦恼吗?是不是觉得每次都要一个个输入单号,既费时又费力?别急,今天我要给大家介绍一款神奇的软件——快递批量查询高手!这款软件就像你的私人快递助手一样,...
- 快递单号查询入口自动批量查询快递动态并根据派件员字段排序单号
-
想象一下,面对堆积如山的快递单号,你不再需要一个个手动输入查询,而是轻轻一点,就能瞬间掌握所有快递的物流动态,甚至还能根据派件员智能排序,让管理变得井井有条。这不再是遥不可及的梦想,快递批量查询高手软...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)