Redis实践

Redis实践

使用复杂度高的命令

如果在使用Redis时,发现访问延迟突然增大,如何进行排查?

首先,第一步,建议你去查看一下Redis的慢日志。Redis提供了慢日志命令的统计功能,我们通过以下设置,就可以查看有哪些命令在执行时延迟比较大。

首先设置Redis的慢日志阈值,只有超过阈值的命令才会被记录,这里的单位是微妙,例如设置慢日志的阈值为5毫秒,同时设置只保留最近1000条慢日志记录:

# 命令执行超过5毫秒记录慢日志
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近1000条慢日志
CONFIG SET slowlog-max-len 1000

设置完成之后,所有执行的命令如果延迟大于5毫秒,都会被Redis记录下来,我们执行SLOWLOG get 5​查询最近5条慢日志:

127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693       # 慢日志ID2) (integer) 1593763337  # 执行时间3) (integer) 5299        # 执行耗时(微妙)4) 1) "LRANGE"           # 具体执行的命令和参数2) "user_list_2000"3) "0"4) "-1"
2) 1) (integer) 326922) (integer) 15937633373) (integer) 50444) 1) "GET"2) "book_price_1000"
...

通过查看慢日志记录,我们就可以知道在什么时间执行哪些命令比较耗时,如果你的业务经常使用O(n)以上复杂度的命令,例如sort​、sunion​、zunionstore​,或者在执行O(n)命令时操作的数据量比较大,这些情况下Redis处理数据时就会很耗时。

如果你的服务请求量并不大,但Redis实例的CPU使用率很高,很有可能是使用了复杂度高的命令导致的。

存储大key

如果查询慢日志发现,并不是复杂度较高的命令导致的,例如都是SET​、DELETE​操作出现在慢日志记录中,那么你就要怀疑是否存在Redis写入了大key的情况。

Redis在写入数据时,需要为新的数据分配内存,当从Redis中删除数据时,它会释放对应的内存空间。

如果一个key写入的数据非常大,Redis在分配内存时也会比较耗时。同样的,当删除这个key的数据时,释放内存也会耗时比较久

你需要检查你的业务代码,是否存在写入大key的情况,需要评估写入数据量的大小,业务层应该避免一个key存入过大的数据量。

那么有没有什么办法可以扫描现在Redis中是否存在大key的数据吗?

Redis也提供了扫描大key的方法:

redis-cli -h <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mi>o</mi><mi>s</mi><mi>t</mi><mo>−</mo><mi>p</mi></mrow><annotation encoding="application/x-tex">host -p </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"><span class="mord mathnormal">h</span><span class="mord mathnormal">os</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222em;"><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"><span class="mord mathnormal">p</span></span></span></span></span>port --bigkeys -i 0.01
</span></span></span></span>

使用上面的命令就可以扫描出整个实例key大小的分布情况,它是以类型维度来展示的。

需要注意的是当我们在线上实例进行大key扫描时,Redis的QPS会突增,为了降低扫描过程中对Redis的影响,我们需要控制扫描的频率,使用i​参数控制即可,它表示扫描过程中每次扫描的时间间隔,单位是秒。

使用这个命令的原理,其实就是Redis​在内部执行scan​命令,遍历所有key​,然后针对不同类型的key​执行strlen​、llen​、hlen​、scard​、zcard​来获取字符串的长度以及容器类型(list/dict/set/zset)​的元素个数。

而对于容器类型的key,只能扫描出元素最多的key​,但元素最多的key​不一定占用内存最多,这一点需要我们注意下。不过使用这个命令一般我们是可以对整个实例中key​分布情况有比较清晰的了解。

针对大key​的问题,Redis​官方在4.0版本推出了lazy-free​的机制,用于异步释放大key​的内存,降低对Redis​性能的影响。

即使这样,我们也不建议使用大key,大key在集群的迁移过程中,也会影响到迁移的性能

集中过期

有时你会发现,平时在使用Redis​时没有延时比较大的情况,但在某个时间点突然出现一波延时,而且报慢的时间点很有规律,例如某个整点,或者间隔多久就会发生一次。

如果出现这种情况,就需要考虑是否存在大量key集中过期的情况。

如果有大量的key在某个固定时间点集中过期,在这个时间点访问Redis时,就有可能导致延迟增加。

解决方案是,在集中过期时增加一个随机时间,把这些需要过期的key的时间打散即可

伪代码可以这么写:

# 在过期时间点之后的5分钟内随机过期掉
redis.expireat(key, expire_time + random(300))

实例内存达到上限

有时我们把Redis当做纯缓存使用,就会给实例设置一个内存上限maxmemory​,然后开启LRU淘汰策略。

当实例的内存达到了maxmemory​后,你会发现之后的每次写入新的数据,有可能变慢了。

导致变慢的原因是,当Redis内存达到maxmemory​后,每次写入新的数据之前,必须先踢出一部分数据,让内存维持在maxmemory​之下。

这个踢出旧数据的逻辑也是需要消耗时间的,而具体耗时的长短,要取决于配置的淘汰策略:

  • allkeys-lru:不管key是否设置了过期,淘汰最近最少访问的key
  • volatile-lru:只淘汰最近最少访问并设置过期的key
  • allkeys-random:不管key是否设置了过期,随机淘汰
  • volatile-random:只随机淘汰有设置过期的key
  • allkeys-ttl:不管key是否设置了过期,淘汰即将过期的key
  • noeviction:不淘汰任何key,满容后再写入直接报错
  • allkeys-lfu:不管key是否设置了过期,淘汰访问频率最低的key(4.0+支持)
  • volatile-lfu:只淘汰访问频率最低的过期key(4.0+支持)

我们最常使用的一般是allkeys-lru​或volatile-lru​策略,它们的处理逻辑是,每次从实例中随机取出一批key​(可配置),然后淘汰一个最少访问的key​,之后把剩下的key​暂存到一个池子中,继续随机取出一批key​,并与之前池子中的key​比较,再淘汰一个最少访问的key​。以此循环,直到内存降到maxmemory​之下。

如果使用的是allkeys-random​或volatile-random​策略,那么就会快很多,因为是随机淘汰,那么就少了比较key​访问频率时间的消耗了,随机拿出一批key​后直接淘汰即可,因此这个策略要比上面的LRU​策略执行快一些。

fork耗时严重

如果你的Redis开启了自动生成RDB和AOF重写功能,那么有可能在后台生成RDB和AOF重写时导致Redis的访问延迟增大,而等这些任务执行完毕后,延迟情况消失。

遇到这种情况,一般就是执行生成RDB和AOF重写任务导致的。

生成RDB​和AOF​都需要父进程fork​出一个子进程进行数据的持久化,在fork​执行过程中,父进程需要拷贝内存页表给子进程,如果整个实例内存占用很大,那么需要拷贝的内存页表会比较耗时,此过程会消耗大量的CPU​资源,在完成fork​之前,整个实例会被阻塞住,无法处理任何请求,如果此时CPU​资源紧张,那么fork​的时间会更长,甚至达到秒级。这会严重影响Redis​的性能。

我们可以执行info​命令,查看最后一次fork​执行的耗时latest_fork_usec​,单位微妙。这个时间就是整个实例阻塞无法处理请求的时间。

要想避免这种情况,我们需要规划好数据备份的周期,建议在从节点上执行备份,而且最好放在低峰期执行。如果对于丢失数据不敏感的业务,那么不建议开启RDB​和AOF​重写功能。

另外,fork的耗时也与系统有关,如果把Redis部署在虚拟机上,那么这个时间也会增大。所以使用Redis时建议部署在物理机上,降低fork的影响。

使用Swap

如果你发现Redis突然变得非常慢,每次访问的耗时都达到了几百毫秒甚至秒级,那此时就检查Redis​是否使用到了Swap​,这种情况下Redis​基本上已经无法提供高性能的服务。

我们知道,操作系统提供了Swap机制,目的是为了当内存不足时,可以把一部分内存中的数据换到磁盘上,以达到对内存使用的缓冲。

但当内存中的数据被换到磁盘上后,访问这些数据就需要从磁盘中读取,这个速度要比内存慢太多!

尤其是针对Redis这种高性能的内存数据库来说,如果Redis中的内存被换到磁盘上,对于Redis这种性能极其敏感的数据库,这个操作时间是无法接受的。

我们需要检查机器的内存使用情况,确认是否确实是因为内存不足导致使用到了Swap​。

如果确实使用到了Swap​,要及时整理内存空间,释放出足够的内存供Redis​使用,然后释放Redis​的Swap​,让Redis​重新使用内存。

释放Redis​的Swap​过程通常要重启实例,为了避免重启实例对业务的影响,一般先进行主从切换,然后释放旧主节点的Swap​,重新启动服务,待数据同步完成后,再切换回主节点即可。

可见,当Redis​使用到Swap​后,此时的Redis​的高性能基本被废掉,所以我们需要提前预防这种情况。

我们需要对Redis机器的内存和Swap使用情况进行监控,在内存不足和使用到Swap时及时报警出来,及时进行相应的处理

网卡负载过高

特点就是从某个时间点之后就开始变慢,并且一直持续。这时你需要检查一下机器的网卡流量,是否存在网卡流量被跑满的情况。

网卡负载过高,在网络层和TCP层就会出现数据发送延迟、数据丢包等情况。Redis的高性能除了内存之外,就在于网络IO,请求量突增会导致网卡负载变高。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/46469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

王牌站士Ⅶ--理解大型语言模型LLM的参数

模型的大小并不一定决定其成功 在学习任何大型语言模型 (LLM) 时&#xff0c;您首先会听到的事情之一就是给定模型有多少个参数。如果您查看下面的图表&#xff0c;您会注意到参数大小范围很广 - 一个模型可能有 10 亿或 20 亿个参数&#xff0c;也可能有超过 1.75 万亿个参数。…

c++学习30自平衡树

#pragma once // 定义AVL树节点结构 template<class K, class V> struct AVLTreeNode {// 节点默认构造函数AVLTreeNode(): _left(nullptr), _right(nullptr), _parent(nullptr), _by(0){}AVLTreeNode<K, V>* _left; // 左子节点指针AVLTreeNode<K, V>…

Java —— abstract关键字

abstract关键字 1.抽象类与抽象方法 随着继承层次中一个个新子类的定义&#xff0c;类变得越来越具体&#xff0c;而父类则更一般&#xff0c;更通用。有时将一个父类设计得非常抽象&#xff0c;以至于它没有具体的实例&#xff0c;只提供该顶层类的功能&#xff08;只有顶层…

了解redis

1.什么是redis&#xff1f; redis是一款高性能的NOSQL系列的非关系型数据库 想了解非关系型数据库概念前往上期(NoSQL Not Only SQL)&#xff0c;意即“不仅仅是SQL”-CSDN博客 Redis是用C语言开发的一个开源的高性能键值对&#xff08;key-value&#xff09;数据库&#x…

老年生活照护实训室:让养老护理更个性化

本文探讨了老年生活照护实训室在实现养老护理个性化方面的重要作用。通过分析其提供的实践环境、专业培训、模拟案例和评估机制&#xff0c;阐述了如何培养护理人员的个性化服务能力&#xff0c;以满足老年人多样化的需求&#xff0c;提高养老护理的质量和满意度。 在老龄化社会…

CentOS7.X系统部署Zabbix6.0版本(可跟做)

文章目录 一、部署环境说明二、基本环境部署步骤1、环境初始化操作2、部署并配置Nginx3、部署并配置PHP4、测试NginxPHP环境5、部署并配置MariaDB 三、Zabbix-Server部署步骤1、编译安装Zabbix-Server2、导入Zabbix初始化库3、配置Zabbix前端UI4、启动Zabbix-Server5、WEB页面配…

java代码:单链表的实现

1、代码 package LinkList;public class Linklist {//定义节点&#xff0c;内部类只为其外部类使用//要创建嵌套类的对象&#xff0c;并不需要其外围类的对象&#xff0c;直接使用.nextstatic class ListNode{int val;//数据域ListNode next;//指针&#xff0c;指向下一个结点…

前端面试题日常练-day90 【Less】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末 在Less中&#xff0c;以下哪种语法适用于定义变量&#xff1f; a) $var b) variable c) #variable d) &variable Less中的Mixin是用来做什么的&#xff1f; a) 定义变量 b) 创建循环 c) 处理函数…

数据建设实践之大数据平台(二)安装zookeeper

安装zookeeper 上传安装包到/opt/software目录并解压 [bigdatanode101 software]$ tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/services/ 重命名文件 [bigdatanode101 services]$ mv apache-zookeeper-3.5.7-bin zookeeper-3.5.7 配置环境变量 export JAVA_H…

GPT-4从0到1搭建一个Agent简介

GPT-4从0到1搭建一个Agent简介 1. 引言 在人工智能领域&#xff0c;Agent是一种能够感知环境并采取行动以实现特定目标的系统。本文将简单介绍如何基于GPT-4搭建一个Agent。 2. Agent的基本原理 Agent的核心是感知-行动循环&#xff08;Perception-Action Loop&#xff09;…

C#与倍福Plc通信——使用仿真软件模拟倍福PLC运行

前言 我们在编写上位机与倍福PLC通信的过程中,有时候我们没有真实的Plc,但是我们又想提前测试与倍福PLC的通信,那么这个时候我们就可以使用倍福的仿真软件模拟PLC,然后我们上位机就可以与仿真PLC进行通信了,下面进行详细介绍: 1、下载并安装倍福PLC编程软件TwinCAT 安…

Elasticsearch集群健康检查与监控

在大数据时代&#xff0c;Elasticsearch作为一款高性能、可扩展的搜索与分析引擎&#xff0c;广泛应用于各种需要快速数据检索和分析的场景中。然而&#xff0c;随着数据量的不断增加和集群规模的扩大&#xff0c;保持Elasticsearch集群的健康状态和高效运行变得尤为重要。本文…

python 如何处理图片 举例说明

Python有很多库可以用于处理图片&#xff0c;常用的有Pillow和OpenCV。 举例说明如下&#xff1a; 使用Pillow库读取图片并显示&#xff1a; from PIL import Image# 打开图片 image Image.open(image.jpg)# 显示图片 image.show()使用Pillow库调整图片大小&#xff1a; f…

关于 LayoutInflater.inflate 的取值结论

根节点是否是 mergeViewGroup rootboolean attachToRoot返回值否notNullfalse返回的是 xml 布局的根节点 View 对象&#xff0c;并且对象上拥有根节点上的布局参数。否notNulltrue返回的是添加了根节点View对象以及布局参数的root对象。否nullfalse返回的是没有布局参数信息的根…

Java中的输入输出

输出到控制台 【基本语法】&#xff1a; System.out.println(msg); // 输出一个字符串, 带换行 System.out.print(msg); // 输出一个字符串, 不带换行 System.out.printf(format, msg); // 格式化输出 println 输出的内容自带 \n, print不带 \n printf 的格式化输出方式和…

面试题: C++11用过哪些特性

面试题&#xff1a; C11用过哪些特性 考察重点&#xff1a; 回答问题的层次学习总结的思路 语法糖 关键字&#xff1a; auto, decltypenullptrfinal, overrideconstexpr 语法&#xff1a; 基于范围的for循环 function函数对象&#xff0c;bind, lambda STL容器 array…

Android TabLayout+ViewPager2如何优雅的实现联动详解

一、介绍 Android开发过程中&#xff0c;我们经常会遇到滑动导航栏的做法&#xff0c;之前的做法就是我们通过ViewGroup来转动&#xff0c;然后通过大量的自定义来完成&#xff0c;将导航栏item与viewpage 滑动&#xff0c;达到业务需求 二、现实方案 通过介绍&#xff0c;我…

机器人前沿--PalmE:An Embodied Multimodal Language Model 具身多模态大(语言)模型

首先解释这篇工作名称Palm-E&#xff0c;发表时间为2023.03&#xff0c;其中的Palm是谷歌内部在2022.04开发的大语言模型&#xff0c;功能类似ChatGPT&#xff0c;只是由于各种原因没有那样火起来&#xff0c;E是Embodied的首字母&#xff0c;翻译过来就是具身多模态大语言模型…

36、快手视频解析API接口,免费好用

1、前言 快手视频解析API接口&#xff0c;这个是RollToolsApi通用系列接口的其中一个&#xff0c;内部包含了1个小接口&#xff0c;解析快手链接&#xff0c;获取视频Mp4下载链接&#xff0c;即可下载视频到本地。 查看接口完整信息&#xff1a;https://www.mxnzp.com/doc/de…

Typora中插入LaTex数学公式的使用

文章目录 Typora中插入LaTex数学公式的使用公式的插入上下标括号和分隔符分数开方省略号矢量和均值积分极限累加、累乘及交集、并集希腊字母特殊字符字体大括号和行标字体 大括号和行标其他命令矩阵方程式序列条件表达式配置行高数组与表格嵌套表格或数组方程组连分式交换图表其…