11个提高 Redis 性能的技巧(redis 性能优化)
wptr33 2025-01-29 18:21 16 浏览
众所周知,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等命令。
查询数据时,可遵循以下原则:
- 首选查询数据元素的个数(涉及命令:LLEN、HLEN、SCARD、ZCARD)。
- 如果元素数量比较少,可以一次性查询出所有数据。
- 如果元素数量非常多,则批量查询数据(涉及命令: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。为什么呢?以下是总结的三个原因:
- 在一个连接上操作多个数据库数据时,每次都需要先执行 SELECT,这会给Redis带来额外的压力。
- 使用多个数据库的目的是为了根据不同的业务线来存储数据。那么为什么不将它们拆分并存储在多个实例呢?部署多个实例,拆分存储,多个业务线不会互相影响,也可以提高Redis的访问性能。
- Redis Cluster 只支持 db 0,如果以后想迁移 Redis Cluster,会增加迁移成本。
10. 采用读写分离+分片集群
如果我们的业务的读取请求量很大,那么我们可以部署多个从库来实现读写分离,让 Redis 的从库分担读取压力,从而提高性能。
如果我们的业务的写入请求量也非常大,单个实例已经无法支撑这么大的写入流量,那么这时候就需要使用分片集群来分担写入压力。
11. 不要启用AOF或配置AOF每秒刷盘
对于数据丢失不敏感的业务,建议不要启用AOF,避免AOF写入磁盘导致Redis性能下降。
如需确实需要启用AOF,那么建议将其配置为 appendfsynce everysec,并将数据持久化的磁盘刷新操作放到后台线程执行,以尽量减少Redis写入磁盘对性能的影响。
以上就是Redis高性能方面的实用优化,如果你非常关心Redis的性能问题,你可以结合这几个方面进行针对性的优化。当然,您还有其他好的方案,欢迎您不吝赐教。
相关推荐
- Linux文件系统操作常用命令(linux文件内容操作命令)
-
在Linux系统中,有一些常用的文件系统操作命令,以下是这些命令的介绍和作用:#切换目录,其中./代表当前目录,../代表上一级目录cd#查看当前目录里的文件和文件夹ls#...
- 别小看tail 命令,它难倒了技术总监
-
我把自己以往的文章汇总成为了Github,欢迎各位大佬star...
- lnav:基于 Linux 的高级控制台日志文件查看器
-
lnav是一款开源的控制台日志文件查看器,专为Linux和Unix-like系统设计。它通过自动检测日志文件的格式,提取时间戳、日志级别等关键信息,并将多个日志文件的内容按时间顺序合并显示,...
- 声明式与命令式代码(声明模式和命令模式)
-
编程范式中的术语和差异信不信由你,你可能已经以开发人员的身份使用了多种编程范例。因为没有什么比用编程理论招待朋友更有趣的了,所以这篇文章可以帮助您认识代码中的流行范例。命令式编程命令式编程是我们从As...
- linux中的常用命令(linux常用命令和作用)
-
linux中的常用命令linux中的命令统称shell命令shell是一个命令行解释器,将用户命令解析为操作系统所能理解的指令,实现用户与操作系统的交互shell终端:我们平时输入命令,执行程序的那个...
- 提高工作效率的--Linux常用命令,能够决解95%以上的问题
-
点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf...
- 如何限制他人操作自己的电脑?(如何控制别人的电脑不让发现)
-
这段时间,小猪罗志祥正处于风口浪尖,具体是为啥?还不知道的小伙伴赶紧去补一下最近的娱乐圈八卦~简单来说,就是我们的小罗同事,以自己超强的体力,以及超强的时间管理能力,重新定义了「多人运动」的含义,重新...
- 最通俗易懂的命令模式讲解(命令模式百科)
-
我们先不讲什么是命令模式,先通过一个场景来引出命令模式,看看命令模式能解决什么样的问题。现在有一个渣男张三,他有还几个女朋友,你现在是不是还是单身狗,你就说你气不气?然后他需要每天分别叫几个女朋友起床...
- 互联网大厂后端必看!Spring Boot 中Runtime执行与停止命令?
-
你是否曾在使用SpringBoot开发项目时,遇到需要执行系统命令的场景?比如调用脚本进行文件处理,又或是启动外部程序?很多后端开发人员会使用Processexec=Runtime.get...
- Linux 常用命令(linux常用的20个命令面试)
-
日志排查类操作命令...
- Java字节码指令:if_icmpgt(0xA3)(java字节码使用的汇编语言)
-
if_icmpgt是Java字节码中的一条条件跳转指令,其全称是"IfIntegerCompareGreaterThan"。它用于比较两个整数值的大小。如果栈顶的第一个...
- 外贸干货|如何增加领英的曝光量和询盘
-
#跨境电商#...
- golang执行linux命令(golang调用shell脚本)
-
需求需要通过openssl生成rsa秘钥,然后保存该秘钥。代码实例packagemainimport("io/ioutil""bytes"&...
- LINUX磁盘挂载(linux磁盘挂载到windows)
-
1、使用root用户查看磁盘挂载情况:fdisk-l2、使用df查看当前磁盘挂载情况,根据和fdisk-l的结果进行对比,查看还有那些磁盘未使用3、挂载:mount磁盘挂载路径...
- Linux命令学习——nl命令(linux ln命令的使用)
-
nl命令主要功能为每一个文件添加行号,每一个输入的文件添加行号后发送到标准输出。当没有文件或文件为-时,读取标准输入...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)