【技术补给站】第10期:分析内部运行机制,教你解决Redis性能问题

举报
华为云社区精选 发表于 2021/05/26 14:55:34 2021/05/26
1.8w+ 4 3
【摘要】 聚焦Redis的性能分析,思考Redis 可以通过哪些机制来提高性能,当性能瓶颈发生的时候,我们又能做出哪些优化策略,最终确保业务系统的稳定运行。

Redis是一种键值数据库,有着时延低、性能好、数据结构丰富的特点,常用作缓存、排行榜、计数器、 消息队列等,是电商秒杀、聊天系统等业务场景中的“熟客”。


作为一个“缓存中间商”,Redis的性能问题至关重要,一旦发生操作延迟问题,很容易引起连锁反应。所以本文聚焦Redis的性能分析,从Redis的基本概念出发,了解Redis是什么,它的运行机制,思考Redis可以通过哪些机制来提高性能,当性能瓶颈发生的时候,我们又能做出哪些优化策略,最终确保业务系统的稳定运行。

读懂Redis:缓存神器原来是这样工作的

一个网站总有大量的数据是用户共享的,如果每个用户都去数据库查询,效率就太低了。所以有了新的解决方案:将用户共享数据缓存到服务器的内存中。

举个例子,应用程序们从MySQL查询到的数据,会到Redis这里登记,后面再需要用的时候,就先查找Redis的缓存,无需返回到MySQL查找。一套流程下来,为MySQL减轻了不小的负担,网络服务的性能显著提升。

Redis堪称数据库届的万金油,哪里需要往哪里搬,这也得益于它有着丰富的数据结构,以及强大的读写性能。

以数据结构为例,Redis和其他结构化存储的重要区别便是,它不仅支持字符串,还支持不同类型的抽象数据结构,如列表、映射、集、排序集、HyperLogLogs、位图、流和空间索引等。那么Redis是如何做到如此“万能”的,它支持的这些数据结构又是如何从底层实现呢?《三次给你聊清楚Redis》之Redis是个啥 就从非关系型数据库谈起,详细聊了聊这个问题,就像最简单的字符串,Redis并未沿袭传统c语言的惯例,而是单独构建了一种简单的动态字符串抽象类型,并充分利用SDS实现。

当然,如果你想进一步了解Redis系统的设计理念,比如它通过什么机制将数据缓存到内存中,开发大系统必备技术之Redis技术学习与研究或许会给你一些启发,作者谈到了Redis的历史、流行度、设计思想,并通过支持Redis的Java客户端Jedis ,用详尽的代码案例一步步演示了它支持的数据类型使用方法,它的事务特性、集群等等,更为具象地了解Redis的特点。

当我们对Redis的基本原理了然于胸后,再针对业务场景进行优化时,也能更合理地使用各种Redis命令。

Redis性能:祸福相依的内部运行机制

Redis的最大特点是使用内存来存储数据,当内存超过物理内存的限制后,内存数据会和磁盘产生频繁的交换,最终导致Redis性能急剧下降。所以在生产环境中我们通过配置参数maxmemoey来限制使用的内存大小。 在有趣的Redis:缓存被我写满了,该怎么办? 中,作者详细解释了2个常见的缓存淘汰算法LRU算法和LFU算法,如何删除那些没用的数据。

另一方面,Redis为了把内存中的数据持久到磁盘上,也提供了完善的持久化机制,主要包括2种:

  • RDB:产生一个数据快照文件
  • AOF:实时追加命令的日志文件

但是如果配置不合理,持久化会占用过多内存从而影响性能。举个例子,如果AOF的刷盘时机设置为每次写入都刷盘,由于每次写命令都需要写入文件并刷到磁盘中才会返回,当写入量很大时,会增加磁盘IO的负担,大大降低Redis的写入性能。Redis 持久化是如何做的?一文聊聊 RDB和AOF对比分析 谈到了这两种持久化机制对Redis性能的影响,建议大家针对不同的业务场景选择合适的持久化方式。

在讨论Redis性能问题的时候,不得不提的一点是它的单线程结构,这里的单线程指的是执行命令 ,比如一条命令从客户端到达服务端不会立刻被执行,而是会进入一个队列中等待,每次只会有一条指令被选中执行。【Redis破障之路】:Redis单线程架构 详细分析了单线程模型的Redis为什么性能如此之高,能达到每秒万级别的处理能力,简单透露两点:纯内存访问、I/O多路复用技术,具体可以阅读文章。而Redis的单线程架构,也意味着网络问题会对它的性能产生一定的影响。

另外,当业务规模扩大,单个Redis服务无法承载的时候,我们常常会用分布式架构来提高Redis的性能,Redis主从复制以及哨兵的原理解读Redis Sentinel 源码:Redis的高可用模型分析 都讨论了主从模式下的关键功能:哨兵,通过对其源码的理解,详细说明了哨兵的代码实现方式,并学会使用哨兵功能解决主节点的写能力、存储能力限制等等。

除此之外,诸如数据结构的复杂度、网络带宽、操作系统以及硬件本身都会对Redis的性能产生影响,它的性能问题几乎涵盖了 CPU、内存、网络、磁盘的方方面面,再此不一一赘述。

综上,我们分析了影响Redis性能的一些关键内部机制,比如它的缓存淘汰算法;它的持久化会占用过多内存从而影响性能;它的单线程架构等。通过了解Redis的这些内部实现原理,也能进一步帮助大家排查它的性能问题。

Redis调优:宕机怎么办?收下这几颗灵丹妙药

下面,我们将给出一些应对Redis性能问题的解决方案。

以常见的缓存问题为例,通常情况下,Redis缓存层由于某种原因宕机后,所有的请求会涌向存储层,短时间内的高并发请求可能会导致存储层挂机,称之为“Redis雪崩”。Redis缓存异常应对方案分析 有针对性的总结了Redis发生缓存穿透、雪崩、击穿情况时,能够有效应对的解决方案,比如不要给访问频繁的热点数据设置过期时间,从而解决Redis实例没有起到缓存层作用的问题。

大key也是影响Redis性能的关键因素,如果一个 key 写入的 value 非常大,那么 Redis 在分配内存时就会比较耗时。同样的,当删除这个 key 时,释放内存也会比较耗时,这种类型的 key 我们一般称之为 大key。 在 分布式缓存数据库Redis大KEY问题定位及优化建议 中,作者就针对数据库报错OOM来一步步分析大key的问题,先是查看Redis集群内存监控指标,确认内存异常分片,然后通过在线&离线工具分析,结果显示大key导致数据大小分布不均。对此作者给出了两个方案:短期是删除查询到的key,长期是对大key进行拆分。

另一个经常被诟病性能问题的是fork, fork是开源Redis的一个重要依赖,当 Redis 开启了后台 RDB 和 AOF rewrite 后,在执行时,它们都需要主进程创建出一个子进程进行数据的持久化,fork就是创建子进程的系统调用函数。

在华为云GaussDB(for Redis)服务团队支撑某客户业务上云的过程中 ,就发现了由fork引发的时延抖动问题,文章一场由fork引发的超时,让我们重新探讨了Redis的抖动问题 还原了当时的场景,探究了fork对性能的影响,包括业务抖动、内存率利用率降低和实例容量受限。比如,在电商大促、热点事件等业务高峰时发生上述fork,会导致Redis阻塞,进而对业务造成雪崩的影响。

团队通过修改日志、系统性排查整改代码中的 fork调用,最后在新版本GaussDB(for Redis)中解决了该问题,并清零了内部的fork使用,与原生Redis相比,彻底解决了fork的性能隐患。

其实,考虑到业务场景越来越复杂,原生Redis出现性能瓶颈难以避免。这时候,最简单粗暴的解决方法就是使用商业版本的Redis,一劳永逸解决可能存在的性能问题。

GaussDB(for Redis)与原生Redis集群的性能对比 中,就比较了华为云自研Redis和原生Redis集群在X86架构下的性能测试报告,结果表明GaussDB(for Redis)在性能、抗写和存储成本上的优势明显。

从相识到相惜:Redis与计算存储分离四部曲 进一步从技术角度拆解分析了GaussDB(for Redis)如何在存算分离的架构下,实现强一致、秒扩容、超可用、低成本。以强一致为例,Redis遇到流量压力进行主从切换时很容易发生数据不同步问题,GaussDB ( for Redis)就在存储层(DFV层)去进行强一致的数据同步,而非计算层,这样就避免了任何中间态下的数据的不一致,再也不用担心宕机导致数据丢失。更多的技术细节揭秘,也可以阅读这组专题高斯Redis揭秘系列文章,更全面的认识GaussDB ( for Redis)。

Redis的性能问题,涉及到的技术细节很多,本专题只是列出了一些较为典型的问题,希望读者能够通过上述提及的技术文章,对它有更深入的认识,学会从底层运行机制去思考Redis的性能调优。

最后

福利时间到,小编准备了3个小问题,参与互动的小伙伴有机会获得由华为云社区提供的开发者大礼包,任选其一回答即可。

  • 问题1:例举1个会让Redis变慢的现象和原因。
  • 问题2:简单说说你用过的Redis性能调优方案。
  • 问题3:如何避免Redis集群异步复制可能带来的数据丢失,强一致性实现方法有哪些?

欢迎大家踊跃参加。

技术补给站

聚焦热门的细分技术领域,带来系统且专业的干货解读,从而为开发者提供新技术知识的补给,助力技术能力更上一层楼。

往期回顾

【第1期】 中台规划:重磅发布!《IT 2.0时代,华为全场景驱动下中台规划实战全集》


【第2期】数仓调优:数仓性能调优必读:从系统级到SQL级,带你进阶为性能调优高手


【第3期】依赖图绘制:学习大数据治理,手把手教你从零开始画DAG作业依赖图


【第4期】音视频:音视频爆火的背后,藏着哪些技术奥秘?华为云视频云专家为你深度解读


【第5期】云原生:从架构和实践,剖析KubeEdge+Volcano技术硬实力


【第6期】LiteOS实操:带你步步深入LiteOS,掌握物联网开发秘笈


【第7期】 API应用:20个超实用API应用案例,开启API进阶之路(内附资料下载)


【第8期】 HiLens开发:用好ModelArts+HiLens,轻松上手端云协同AI开发


【第9期】 从Angular、React到Vue,探秘三大主流前端框架

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(4

抱歉,系统识别当前为高风险访问,暂不支持该操作
  • 作者头像

    是安可啊2021/05/26 10:30:001楼举报回复

    - 问题1:例举1个会让Redis变慢的现象和原因。

      现象:bigkey造成数据大小分布不均

      原因:如果一个 key 写入的 value 非常大,那么 Redis 在分配内存时就会比较耗时。同样的,当删除这个 key 时,释放内存也会比较耗时。这样可能会导致内存异常分片,最终数据大小会不一致。

    - 问题2:简单说说你用过的Redis性能调优方案。

      1.尽量使用短的key

      2.设置key的有效期,比如一些临时数据(短信校验码),过了有效期Redis就会自动为你清除!

      3.选择回收策略(maxmemory-policy)

    - 问题3:如何避免Redis集群异步复制可能带来的数据丢失,强一致性实现方法有哪些?

      避免异步复制的数据丢失:  配置min-slaves-to-write 1

      有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内。

      强一致性的实现方法:不能存放缓存。

     另外采取的措施是,首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如
    可以利用消息队列。
  • 作者头像

    今夕何夕,见此良人2021/05/27 09:32:392楼举报回复

    哈希表冲突,当key过多时,不同的key可鞥存放在同一个位置,redis在同一个位置形成一个链表进行保存,每个元素(entry)通过指针指向下一个元素
  • 作者头像

    菜鸟级攻城狮2021/05/27 15:12:053楼举报回复

    问题2:简单说说你用过的Redis性能调优方案。
    1.Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。
    2.如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
    3.为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。
    4.尽量避免在压力较大的主库上增加从库
    5.Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
    6.为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:Master<-Slave1<-Slave2<-Slave3..,。这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

    问题3:如何避免Redis集群异步复制可能带来的数据丢失,强一致性实现方法有哪些?
    在redis的配置文件中有两个参数我们可以设置:

    min-slaves-to-write 1
    min-slaves-max-lag 10
    min-slaves-to-write默认情况下是0,min-slaves-max-lag默认情况下是10。
    以上面配置为例,这两个参数表示至少有1个salve的与master的同步复制延迟不能超过10s,一旦所有的slave复制和同步的延迟达到了10s,那么此时master就不会接受任何请求。

    我们可以减小min-slaves-max-lag参数的值,这样就可以避免在发生故障时大量的数据丢失,一旦发现延迟超过了该值就不会往master中写入数据。

    那么对于client,我们可以采取降级措施,将数据暂时写入本地缓存和磁盘中,在一段时间后重新写入master来保证数据不丢失;也可以将数据写入kafka消息队列,隔一段时间去消费kafka中的数据。
  • 作者头像

    iolink10022021/05/28 03:47:214楼举报回复

    当Redis实例使用的内存超过系统可使用的最大内存时,操作系统开始进行内存与硬盘swap空间的交换,硬盘IO性能严重低于内存,造成Redis变慢。解决方案:加大系统内存

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。