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

11个提高 Redis 性能的技巧(redis 性能优化)

wptr33 2025-01-29 18:21 29 浏览

众所周知,Redis 是基于内存型的数据库,因而其有出色的性能。理论上说,单节点Redis可以处理高达10万QPS的流量。如此高性能也意味着如果使用过程中出现延迟,就达不到预期。

所以,在使用Redis时,如何不断发挥其高性能,避免操作延迟的发生是我们需要关注的重点。对此,本文总结了11条的建议。

1. 避免存储键值很大的Key

键值很大的Key,通俗叫法:bigkey。

存储bigkey不仅会像以前文章提到过的那样占用过多的内存,而且对Redis的性能影响也很大。由于 Redis 是在单线程中处理请求的,所以当我们的应用程序写入bigkey时,会消耗更多的时间在“内存分配”上,此时操作延迟就会大大增加。

同样,删除bigkey时,“内存释放”过程也是需要时间的。而且,当我们读取bigkey时,更多的时间会花费在“网络数据传输”上。这时,后续要执行的请求就会排队,Redis的性能也就下降了。

所以,我们的应用程序应尽量不要存储bigkey,以避免操作延迟。

如果确实需要存储bigkey,可以将bigkey拆分成多个小key进行存储。

2. 不适应过于复杂的命令

Redis 以单线程处理请求。除了操作bigkey时后续的请求会出现排队的情况外,执行复杂度过高的命令时也会出现这种情况。

因为执行复杂度过高的命令会消耗更多的CPU资源,而主线程中的其他请求只能等待,此时也会出现排队延迟。

所以,我们应尽量避免执行如 SORT,SINTER, SINTERSTORE,ZUNIONSTORE和ZINTERSTORE等聚合命令。

对于这些聚合操作,建议在客户但执行,不要让 Redis 承担过多的计算工作。

3. 关注DEL命令的时间复杂度

删除某个key时,如果操作不正确,也会影响Redis的性能。

删除key时,我们通常使用DEL命令。回想一下,DEL的时间复杂度是怎样的?

O(1)?其实是不一定的。

当删除值为String类型的key时,时间复杂度确实是O(1)。

但是当我们要删除的key是List/Hash/Set/ZSet类型时,它的复杂度实际上是O(N),N代表元素的数量。也就是说,在删除某个key时,元素越多,DEL的执行速度就越慢。

原因是删除大量元素时,需要依次回收每个元素的内存,元素越多,花费的时间就越长。而且,这个过程默认实在主线程中执行的,必然会阻塞主线程,导致性能问题。

那么,删除元素比较多的key时应该如何处理呢?

建议是批量删除:

  • 对于List类型:多次执行LPOP/RPOP,知道删除所有元素。
  • 对于Hash/Set/ZSet类型:先执行HSCAN/SREM/SCAN查询元素,然后执行HDEL/SREM/ZREM依次删除各个元素。

这部不得不感到惊讶!一个小的删除操作,如果不小心,也会导致性能问题。所以,操作时要格外小心。

4. 启用lazy-free机制

如果无法避免存储bigkey的发生,那么建议启用Redis的lazy-free机制(4.0+版本支持)。

启用这个机制后,当Redis删除一个bigkey时,释放内存的耗时操作将在后台线程中执行,这样可以最大程度地避免对主线程的影响。

5. 执行O(N)命令时,注意N的大小

避免使用过于复杂的命令之后,也不是就可以高枕无忧了!

当执行O(N)的命令时,还需要注意N的大小。

如果一次查询的数据过多,在网络传输过程中也会花费很长时间,增加操作延迟。

所以,对于容器类型(List/Hash/Set/ZSet),当元素数量未知时,千万不要盲目执行LANGE key 0 -1、HGETALL、SMEMBERS、ZRANGE key 0 -1等命令。

查询数据时,可遵循以下原则:

  1. 首选查询数据元素的个数(涉及命令:LLEN、HLEN、SCARD、ZCARD)。
  2. 如果元素数量比较少,可以一次性查询出所有数据。
  3. 如果元素数量非常多,则批量查询数据(涉及命令:LRANGE、HSCAN、SSCAN、ZSCAN)。

6. 使用批处理命令而不是单独的命令

当需要同时操作多个key时,应该使用批量处理命令来处理。

批量操作相对于多个单独操作的优势在于,它可以显著减少客户端和服务器之间网络I/O的往返次数。

以下是给出的建议:

  • 对于String/Hash类型:使用MGET/MSET代替GET/SET,使用 HMGET/HMSET代替HGET/HSET。
  • 对于其他数据类型,使用 Pipeline 将多个命令一次性打包发送到服务器执行。

7. 避免key集中过期

Redis 会以一种定时、惰性的方式清理过期的密钥,这个过程在主线程中执行。 如果业务中存在大量集中过期的键,那么当 Redis 清理过期键时,也会存在阻塞主线程的风险。

为了避免这种情况,在设置过期时间时,可以添加一个随机时间来分散这些key的过去时间,从而减少集中过期对主线程的影响。

8. 长连接操作Redis,合理配置连接池

我们应使用长连接允许Redis,并避免短连接。短连接操作Redis时,每次都需要TCP三次握手和四次挥手,这个过程也会增加操作时间耗时。

同时,我们的客户端应用以连接池的方式访问Redis,并配置合理的参数。当长连接不操作Redis时,应及时释放连接资源。

9. 只是要 db0

虽然Redis提供了16个数据库,但推荐只使用db 0。为什么呢?以下是总结的三个原因:

  1. 在一个连接上操作多个数据库数据时,每次都需要先执行 SELECT,这会给Redis带来额外的压力。
  2. 使用多个数据库的目的是为了根据不同的业务线来存储数据。那么为什么不将它们拆分并存储在多个实例呢?部署多个实例,拆分存储,多个业务线不会互相影响,也可以提高Redis的访问性能。
  3. Redis Cluster 只支持 db 0,如果以后想迁移 Redis Cluster,会增加迁移成本。

10. 采用读写分离+分片集群

如果我们的业务的读取请求量很大,那么我们可以部署多个从库来实现读写分离,让 Redis 的从库分担读取压力,从而提高性能。

如果我们的业务的写入请求量也非常大,单个实例已经无法支撑这么大的写入流量,那么这时候就需要使用分片集群来分担写入压力。

11. 不要启用AOF或配置AOF每秒刷盘

对于数据丢失不敏感的业务,建议不要启用AOF,避免AOF写入磁盘导致Redis性能下降。

如需确实需要启用AOF,那么建议将其配置为 appendfsynce everysec,并将数据持久化的磁盘刷新操作放到后台线程执行,以尽量减少Redis写入磁盘对性能的影响。

以上就是Redis高性能方面的实用优化,如果你非常关心Redis的性能问题,你可以结合这几个方面进行针对性的优化。当然,您还有其他好的方案,欢迎您不吝赐教。

相关推荐

oracle数据导入导出_oracle数据导入导出工具

关于oracle的数据导入导出,这个功能的使用场景,一般是换服务环境,把原先的oracle数据导入到另外一台oracle数据库,或者导出备份使用。只不过oracle的导入导出命令不好记忆,稍稍有点复杂...

继续学习Python中的while true/break语句

上次讲到if语句的用法,大家在微信公众号问了小编很多问题,那么小编在这几种解决一下,1.else和elif是子模块,不能单独使用2.一个if语句中可以包括很多个elif语句,但结尾只能有一个...

python continue和break的区别_python中break语句和continue语句的区别

python中循环语句经常会使用continue和break,那么这2者的区别是?continue是跳出本次循环,进行下一次循环;break是跳出整个循环;例如:...

简单学Python——关键字6——break和continue

Python退出循环,有break语句和continue语句两种实现方式。break语句和continue语句的区别:break语句作用是终止循环。continue语句作用是跳出本轮循环,继续下一次循...

2-1,0基础学Python之 break退出循环、 continue继续循环 多重循

用for循环或者while循环时,如果要在循环体内直接退出循环,可以使用break语句。比如计算1至100的整数和,我们用while来实现:sum=0x=1whileTrue...

Python 中 break 和 continue 傻傻分不清

大家好啊,我是大田。...

python中的流程控制语句:continue、break 和 return使用方法

Python中,continue、break和return是控制流程的关键语句,用于在循环或函数中提前退出或跳过某些操作。它们的用途和区别如下:1.continue(跳过当前循环的剩余部分,进...

L017:continue和break - 教程文案

continue和break在Python中,continue和break是用于控制循环(如for和while)执行流程的关键字,它们的作用如下:1.continue:跳过当前迭代,...

作为前端开发者,你都经历过怎样的面试?

已经裸辞1个月了,最近开始投简历找工作,遇到各种各样的面试,今天分享一下。其实在职的时候也做过面试官,面试官时,感觉自己问的问题很难区分候选人的能力,最好的办法就是看看候选人的github上的代码仓库...

面试被问 const 是否不可变?这样回答才显功底

作为前端开发者,我在学习ES6特性时,总被const的"善变"搞得一头雾水——为什么用const声明的数组还能push元素?为什么基本类型赋值就会报错?直到翻遍MDN文档、对着内存图反...

2023金九银十必看前端面试题!2w字精品!

导文2023金九银十必看前端面试题!金九银十黄金期来了想要跳槽的小伙伴快来看啊CSS1.请解释CSS的盒模型是什么,并描述其组成部分。...

前端面试总结_前端面试题整理

记得当时大二的时候,看到实验室的学长学姐忙于各种春招,有些收获了大厂offer,有些还在苦苦面试,其实那时候的心里还蛮忐忑的,不知道自己大三的时候会是什么样的一个水平,所以从19年的寒假放完,大二下学...

由浅入深,66条JavaScript面试知识点(七)

作者:JakeZhang转发链接:https://juejin.im/post/5ef8377f6fb9a07e693a6061目录...

2024前端面试真题之—VUE篇_前端面试题vue2020及答案

添加图片注释,不超过140字(可选)...

今年最常见的前端面试题,你会做几道?

在面试或招聘前端开发人员时,期望、现实和需求之间总是存在着巨大差距。面试其实是一个交流想法的地方,挑战人们的思考方式,并客观地分析给定的问题。可以通过面试了解人们如何做出决策,了解一个人对技术和解决问...