当前位置:首页 > 数码 > Redis-感觉-变慢了-检查这些潜在原因 (redis淘汰策略有哪些)

Redis-感觉-变慢了-检查这些潜在原因 (redis淘汰策略有哪些)

admin8个月前 (04-17)数码85

前言

本期继续分享 Redis 相关知识,帮助大家在 Redis 变慢时从容应对,冷静分析问题。为了方便阅读,文章分为上下两篇。

Redis 作为一款业内使用率最高的内存数据库,其性能非常高,单节点的 QPS 压测能达到 18 万以上。当应用访问 Redis 时,响应延迟变大可能会对业务造成巨大影响。

在日常使用 Redis 时,您可能遇到过以下问题:

  • Redis 响应变慢,查询缓慢
  • Redis 内存占用率过高,导致性能下降
  • Redis 服务出现故障或异常

面对这些访问变慢问题,许多人往往不知所措,不知道从哪里下手。这是因为他们缺乏对 Redis 架构体系、核心功能实现原理以及命令使用限制的理解。

本文将一一分析可能导致 Redis 变慢的原因,帮助您在看完上篇后形成一个比较完整的排查思路方案。

Redis 真的变慢了吗?

当服务响应较慢时,首先需要排查内部原因,确定是否是由 Redis 服务导致的。因为系统可能涉及较长的链路和多个服务,例如同一个接口可能调用 MySQL、MQ、Redis 等其他组件和服务。

因此,需要确定访问 Redis 服务是否变慢,从而拖慢了整个服务的响应。首先需要自查:

  • 检查系统负载是否过高,导致 Redis 服务响应变慢
  • 查看 Redis 日志,查找是否存在异常或错误信息
  • 使用 Redis 命令查看当前 Redis 服务器的状态,例如内存使用率、连接数等

通过自查,可以初步判断 Redis 服务是否变慢。如果是,则需要进一步分析具体原因。

后续部分将详细分析导致 Redis 变慢的常见原因,敬请关注下篇。


redis阻塞了怎么办

单线程你别阻塞,Redis时延问题分析及应对

Redis的事件循环在一个线程中处理,作为一个单线程程序,重要的是要保证事件处理的时延短,这样,事件循环中的后续任务才不会阻塞;当redis的数据量达到一定级别后(比如20G),阻塞操作对性能的影响尤为严重;下面我们总结下在redis中有哪些耗时的场景及应对方法;

耗时长的命令造成阻塞

keys、sort等命令

keys命令用于查找所有符合给定模式 pattern 的 key,时间复杂度为O(N), N 为数据库中 key 的数量。当数据库中的个数达到千万时,这个命令会造成读写线程阻塞数秒;类似的命令有sunion sort等操作;如果业务需求中一定要使用keys、sort等操作怎么办?

解决方案:

在架构设计中,有“分流”一招,说的是将处理快的请求和处理慢的请求分离来开,否则,慢的影响到了快的,让快的也快不起来;这在redis的设计中体现的非常明显,redis的纯内存操作,epoll非阻塞IO事件处理,这些快的放在一个线程中搞定,而持久化,AOF重写、Master-slave同步数据这些耗时的操作就单开一个进程来处理,不要慢的影响到快的;同样,既然需要使用keys这些耗时的操作,那么我们就将它们剥离出去,比如单开一个redis slave结点,专门用于keys、sort等耗时的操作,这些查询一般不会是线上的实时业务,查询慢点就慢点,主要是能完成任务,而对于线上的耗时快的任务没有影响;

smembers命令

smembers命令用于获取集合全集,时间复杂度为O(N),N为集合中的数量;如果一个集合中保存了千万量级的数据,一次取回也会造成事件处理线程的长时间阻塞;

解决方案:和sort,keys等命令不一样,smembers可能是线上实时应用场景中使用频率非常高的一个命令,这里分流一招并不适合,我们更多的需要从设计层面来考虑;在设计时,我们可以控制集合的数量,将集合数一般保持在500个以内;比如原来使用一个键来存储一年的记录,数据量大,我们可以使用12个键来分别保存12个月的记录,或者365个键来保存每一天的记录,将集合的规模控制在可接受的范围;

如果不容易将集合划分为多个子集合,而坚持用一个大集合来存储,那么在取集合的时候可以考虑使用SRANDMEMBER key [count];随机返回集合中的指定数量,当然,如果要遍历集合中的所有元素,这个命令就不适合了;

save命令

save命令使用事件处理线程进行数据的持久化;当数据量大的时候,会造成线程长时间阻塞(我们的生产上,reids内存中1个G保存需要12s左右),整个redis被block;save阻塞了事件处理的线程,我们甚至无法使用redis-cli查看当前的系统状态,造成“何时保存结束,目前保存了多少”这样的信息都无从得知;

解决方案:我没有想到需要用到save命令的场景,任何时候需要持久化的时候使用bgsave都是合理的选择(当然,这个命令也会带来问题,后面聊到);

fork产生的阻塞

在redis需要执行耗时的操作时,会新建一个进程来做,比如数据持久化bgsave:开启RDB持久化后,当达到持久化的阈值,redis会fork一个新的进程来做持久化,采用了操作系统的copy-on-wirte写时复制策略,子进程与父进程共享Page。如果父进程的Page(每页4K)有修改,父进程自己创建那个Page的副本,不会影响到子进程;fork新进程时,虽然可共享的数据内容不需要复制,但会复制之前进程空间的内存页表,如果内存空间有40G(考虑每个页表条目消耗 8 个字节),那么页表大小就有80M,这个复制是需要时间的,如果使用虚拟机,特别是Xen虚拟服务器,耗时会更长;在我们有的服务器结点上测试,35G的数据bgsave瞬间会阻塞200ms以上;

类似的,以下这些操作都有进程fork;

四个大点,搞懂 Redis 到底快在哪里?

现在我们都用高级语言来编程,比如Java、python等。也许你会觉得C语言很古老,但是它真的很有用,毕竟unix系统就是用C实现的,所以C语言是非常贴近操作系统的语言。Redis就是用C语言开发的,所以执行会比较快。

Redis将所有数据放在内存中,非数据同步正常工作中,是不需要从磁盘读取数据的,0次IO。内存响应时间大约为100纳秒,这是Redis速度快的重要基础。先看看CPU的速度:

拿我的电脑来说,主频是3.1G,也就是说每秒可以执行3.1*10^9个指令。所以说CPU看世界是非常非常慢的,内存比它慢百倍,磁盘比他慢百万倍,你说快不快?

借了一张《深入理解计算机系统》的图,展示了一个典型的存储器层次结构,在L0层,CPU可以在一个时钟周期访问到,基于SRAM的高速缓存春续期,可以在几个CPU时钟周期访问到,然后是基于DRAM的主存,可以在几十到几百个时钟周期访问到他们。

第一,单线程简化算法的实现,并发的数据结构实现不但困难且测试也麻烦。第二,单线程避免了线程切换以及加锁释放锁带来的消耗,对于服务端开发来说,锁和线程切换通常是性能杀手。当然了,单线程也会有它的缺点,也是Redis的噩梦: 阻塞。如果执行一个命令过长,那么会造成其他命令的阻塞,对于Redis是十分致命的 ,所以Redis是面向快速执行场景的数据库。

除了Redis之外,也是单线程,Nginx也是单线程,但他们都是服务器高性能的典范。

Redis

在这之前先要说一下传统的阻塞I/O是如何工作的:当使用read或者write对某一文件描述符(File Descriptor FD)进行读写的时候,如果数据没有收到,那么该线程会被挂起,直到收到数据。阻塞模型虽然易于理解,但是在需要处理多个客户端任务的时候,不会使用阻塞模型。

I/O多路复用实际上是指多个连接的**管理可以在同一进程。**多路是指网络连接,复用只是同一个线程。在网络服务中,I/O多路复用起的作用是一次性把多个连接的事件通知业务代码处理,处理的方式由业务代码来决定。在I/O多路复用模型中,最重要的函数调用就是I/O 多路复用函数,该方法能同时监控多个文件描述符(fd)的读写情况,当其中的某些fd可读/写时,该方法就会返回可读/写的fd个数。

Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll的read、write、close等都转换成事件,不在网络I/O上浪费过多的时间。实现对多个FD读写的监控,提高性能。

举个形象的例子吧。比如一个tcp服务器处理20个客户端socket。A方案:顺序处理,如果第一个socket因为网卡读数据处理慢了,一阻塞后面都玩蛋去。B方案:每个socket请求都创建一个分身子进程来处理,不说每个进程消耗大量系统资源,光是进程切换就够操作系统累的了。C方案**(I/O复用模型,epoll) :将用户socket对应的fd注册进epoll(实际上服务器和操作系统之间传递的不是socket的fd而是fd_set的数据结构),然后epoll只告诉哪些需要读/写的socket,只需要处理那些活跃的、有变化的socket fd的就好了。这样,整个过程只在调用epoll的时候才会阻塞,收发客户消息是不会阻塞的。

:-D 搜索微信号(ID: 芋道源码 ),可以获得各种 Java 源码解析、原理讲解、面试题、学习指南。

:-D 并且,回复【 书籍 】后,可以领取笔者推荐的各种 Java 从入门到架构的 100 本书籍。

:-D 并且,回复【 技术群 】后,可以加入专门讨论 Java、后端、架构的技术群。

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: Redis

“Redis-感觉-变慢了-检查这些潜在原因 (redis淘汰策略有哪些)” 的相关文章

Redis数据删除后-内存占用为何居高不下 (redis数据类型)

Redis数据删除后-内存占用为何居高不下 (redis数据类型)

作为面试经验丰富的开发人员,肯定会遇到过这样的问题:做了数据删除操作,为什么使用 top 命令时,仍然显示 Redis 占用了大量内存? 答案 这是因为当数据删除后,Re...

Redis中分布式锁的防死锁机制 (redis中文网)

Redis中分布式锁的防死锁机制 (redis中文网)

分布式锁在分布式系统中是一种常见的需求。它用于防止对共享资源的并发访问,确保数据一致性和可靠性。在 Redis 中实现分布式锁可以通过使用 SETNX(SET if Not eXists)命令来尝...

排查与处置指南-Redis大Key危害 (排查与处置指的是什么)

排查与处置指南-Redis大Key危害 (排查与处置指的是什么)

这是一位同窗往年秋招参与得物一面遇到的疑问,完整面经如下: 这个疑问在面试中还是比拟容易遇到的,尤其是在调查性能优化相关常识点的时刻。 通常状况下,问了bigkey(大Key)还会继续...

探索强大的工具优化集群性能和可靠性-Redis运维神器 (探索强大的工作有哪些)

探索强大的工具优化集群性能和可靠性-Redis运维神器 (探索强大的工作有哪些)

监控工具 INFO 命令 INFO 命令是 Redis 提供的监控命令,可以返回丰富的实例运行监控信息。INFO 命令的参数为 section,取值如下:...

Redis-使用哈希槽而非一致性哈希的原因 (redis淘汰策略有哪些)

Redis-使用哈希槽而非一致性哈希的原因 (redis淘汰策略有哪些)

引言 在分布式系统中,数据分片和负载均衡是至关重要的。哈希槽和一致性哈希两种方法都可以实现这些目标,但它们各有优缺点。本文将讨论为什么在某些情况下使用哈希槽而不是一致性哈希。 哈希槽 哈希...

上古程序猿推戴经常使用Redis的执著理由 (上古教程)

上古程序猿推戴经常使用Redis的执著理由 (上古教程)

最近,在知乎上看到这样一个疑问: 有些上古程序猿不时保持推戴经常使用怎样办? 终究用不用Redis?为什么用?怎样用?让咱们看看网友怎样说…… @灵剑...

成功多规则限流的思索与通常-Redis (成功的规则)

成功多规则限流的思索与通常-Redis (成功的规则)

市面上很多引见如何成功限流的,然而大局部都有一个缺陷,就是只能成功繁多的限流,比如1分钟访问1次或许60分钟访问10次这种,然而假构想一个接口两种规则都须要满足呢,咱们的名目又是散布式名目,应该如何处...

解锁你的海量数据摸索之旅-Redis-全文搜查-的弱小新配置 (解锁海量任务)

解锁你的海量数据摸索之旅-Redis-全文搜查-的弱小新配置 (解锁海量任务)

在2021年我就了解到earch这个名目,并曾经把它用于我的开源名目newbee-mall-pro中。 就我的经常使用体验来说,便捷场景下,用来平替Elasticsearch的经常使用场景曾...