Redis10大性能优化策略(下)

这篇具有很好参考价值的文章主要介绍了Redis10大性能优化策略(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.慢查询优化

1)尽量不使用 O(N) 以上复杂度过高的命令,对于数据的聚合操作,放在客户端做。
2)执行 O(N) 命令,保证 N 尽量的小(推荐 N <= 300),每次获取尽量少的数据,让 Redis 可以及时处理返回。

2.集中过期优化

一般有两种方案来规避这个问题:

1.集中过期 key 增加一个随机过期时间,把集中过期的时间打散,降低 Redis 清理过期 key 的压力
2.如果你使用的 Redis 是 4.0 以上版本,可以开启 lazy-free 机制,当删除过期 key 时,把释放内存的操作放到后台线程中执行,避免阻塞主线程。

第一种方案,在设置 key 的过期时间时,增加一个随机时间,伪代码可以这么写:

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

第二种方案,Redis 4.0 以上版本,开启 lazy-free 机制:

# 释放过期 key 的内存,放到后台线程执行
lazyfree-lazy-expire yes

运维层面,你需要把 Redis 的各项运行状态数据监控起来,在 Redis 上执行 INFO 命令就可以拿到这个实例所有的运行状态数据。
在这里我们需要重点关注 expired_keys 这一项 ,它代表整个实例到目前为止,累计删除过期 key 的数量。

你需要把这个指标监控起来,当这个指标在很短时间内出现了突增,需要及时报警出来,然后与业务应用报慢的时间点进行对比分析,确认时间是否一致,如果一致,则可以确认确实是因为集中过期 key 导致的延迟变大。

3.实例内存达到上限优化

1)避免存储 bigkey,降低释放内存的耗时
2)淘汰策略改为随机淘汰,随机淘汰比 LRU 要快很多(视业务情况调整)
3)拆分实例,把淘汰 key 的压力分摊到多个实例上
4)如果使用的是 Redis 4.0 以上版本,开启 layz-free 机制,把淘汰 key 释放内存的操作放到后台线程中执行(配置 lazyfree-lazy-eviction = yes)

4.fork耗时严重优化

1)控制 Redis 实例的内存:尽量在 10G 以下,执行 fork 的耗时与实例大小有关,实例越大,耗时越久。
2)合理配置数据持久化策略:在 slave 节点执行 RDB 备份,推荐在低峰期执行,而对于丢失数据不敏感的业务(例如把 Redis 当做纯缓存使用),可以关闭 AOF 和 AOF rewrite。
3)Redis 实例不要部署在虚拟机上:fork 的耗时也与系统也有关,虚拟机比物理机耗时更久。
4)降低主从库全量同步的概率:适当调大 repl-backlog-size 参数,避免主从全量同步。

从建立同步时,优先检测是否可以尝试只同步部分数据,这种情况就是针对于之前已经建立好了复制链路,只是因为故障导致临时断开,故障恢复后重新建立同步时,为了避免全量同步的资源消耗,Redis会优先尝试部分数据同步,如果条件不符合,才会触发全量同步。

这个判断依据就是在master上维护的复制缓冲区大小,如果这个缓冲区配置的过小,很有可能在主从断开复制的这段时间内,master产生的写入导致复制缓冲区的数据被覆盖,重新建立同步时的slave需要同步的offset位置在master的缓冲区中找不到,那么此时就会触发全量同步。

如何避免这种情况?解决方案就是适当调大复制缓冲区repl-backlog-size的大小,这个缓冲区的大小默认为1MB,如果实例写入量比较大,可以针对性调大此配置。

5.多核CPU优化

如果你确实想要绑定 CPU,可以优化的方案是,不要让 Redis 进程只绑定在一个 CPU 逻辑核上,而是绑定在多个逻辑核心上,而且,绑定的多个逻辑核心最好是同一个物理核心,这样它们还可以共用 L1/L2 Cache。
当然,即便我们把 Redis 绑定在多个逻辑核心上,也只能在一定程度上缓解主线程、子进程、后台线程在 CPU 资源上的竞争。

因为这些子进程、子线程还是会在这多个逻辑核心上进行切换,存在性能损耗。
如何再进一步优化?

可能你已经想到了,我们是否可以让主线程、子进程、后台线程,分别绑定在固定的 CPU 核心上,不让它们来回切换,这样一来,他们各自使用的 CPU 资源互不影响。
其实,这个方案 Redis 官方已经想到了。

Redis 在 6.0 版本已经推出了这个功能,我们可以通过以下配置,对主线程、后台线程、后台 RDB 进程、AOF rewrite 进程,绑定固定的 CPU 逻辑核心:

Redis6.0 前 绑定CPU核

taskset -c 0 ./redis-server

Redis6.0 后 绑定CPU核

# Redis Server 和 IO 线程绑定到 CPU核心 0,2,4,6
server_cpulist 0-7:2
# 后台子线程绑定到 CPU核心 1,3
bio_cpulist 1,3
# 后台 AOF rewrite 进程绑定到 CPU 核心 8,9,10,11
aof_rewrite_cpulist 8-11
# 后台 RDB 进程绑定到 CPU 核心 1,10,11
# bgsave_cpulist 1,10-1

如果你使用的正好是 Redis 6.0 版本,就可以通过以上配置,来进一步提高 Redis 性能。

这里我需要提醒你的是,一般来说,Redis 的性能已经足够优秀,除非你对 Redis 的性能有更加严苛的要求,否则不建议你绑定 CPU。

6.查看Redis内存是否发生Swap

$ redis-cli info | grep process_id
process_id: 5332

最后,运行下面的命令,查看该 Redis 进程的使用情况。在这儿,我只截取了部分结果:

$ cat /proc/5332/smaps | egrep '^(Swap|Size)'
Size: 584 kB
Swap: 0 kB
Size: 4 kB
Swap: 4 kB
Size: 4 kB
Swap: 0 kB
Size: 462044 kB
Swap: 462008 kB
Size: 21392 kB
Swap: 0 kB

一旦发生内存 swap,最直接的解决方法就是增加机器内存。如果该实例在一个 Redis 切片集群中,可以增加 Redis 集群的实例个数,来分摊每个实例服务的数据量,进而减少每个实例所需的内存量。

7.内存大页

如果采用了内存大页,那么,即使客户端请求只修改 100B 的数据,Redis 也需要拷贝 2MB 的大页。相反,如果是常规内存页机制,只用拷贝 4KB。两者相比,你可以看到,当客户端请求修改或新写入数据较多时,内存大页机制将导致大量的拷贝,这就会影响 Redis 正常的访存操作,最终导致性能变慢。

首先,我们要先排查下内存大页。方法是:在 Redis 实例运行的机器上执行如下命令:

$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never

如果执行结果是 always,就表明内存大页机制被启动了;如果是 never,就表示,内存大页机制被禁止。

在实际生产环境中部署时,我建议你不要使用内存大页机制 ,操作也很简单,只需要执行下面的命令就可以了:

echo never /sys/kernel/mm/transparent_hugepage/enabled

其实,操作系统提供的内存大页机制,其优势是,可以在一定程序上降低应用程序申请内存的次数。
但是对于 Redis 这种对性能和延迟极其敏感的数据库来说,我们希望 Redis 在每次申请内存时,耗时尽量短,所以我不建议你在 Redis 机器上开启这个机制。

8.删除使用Lazy Free

支持版本:Redis 4.0+

1)主动删除键使用lazy free

UNLINK命令

127.0.0.1:7000> LLEN mylist
(integer) 2000000
127.0.0.1:7000> UNLINK mylist
(integer) 1
127.0.0.1:7000> SLOWLOG get
1) 1) (integer) 1
   2) (integer) 1505465188
   3) (integer) 30
   4) 1) "UNLINK"
      2) "mylist"
   5) "127.0.0.1:17015"
   6) ""

注意:DEL命令,还是并发阻塞的删除操作

FLUSHALL/FLUSHDB ASYNC

127.0.0.1:7000> DBSIZE
(integer) 1812295
127.0.0.1:7000> flushall  //同步清理实例数据,180万个key耗时1020毫秒
OK
(1.02s)
127.0.0.1:7000> DBSIZE
(integer) 1812637
127.0.0.1:7000> flushall async  //异步清理实例数据,180万个key耗时约9毫秒
OK
127.0.0.1:7000> SLOWLOG get
 1) 1) (integer) 2996109
    2) (integer) 1505465989
    3) (integer) 9274       //指令运行耗时9.2毫秒
    4) 1) "flushall"
       2) "async"
    5) "127.0.0.1:20110"
    6) ""

2)被动删除键使用lazy free

lazy free应用于被动删除中,目前有4种场景,每种场景对应一个配置参数;默认都是关闭。

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no

lazyfree-lazy-eviction
针对redis内存使用达到maxmeory,并设置有淘汰策略时;在被动淘汰键时,是否采用lazy free机制;因为此场景开启lazy free, 可能使用淘汰键的内存释放不及时,导致redis内存超用,超过maxmemory的限制。此场景使用时,请结合业务测试。(生产环境不建议设置yes)

lazyfree-lazy-expire
针对设置有TTL的键,达到过期后,被redis清理删除时是否采用lazy free机制;此场景建议开启,因TTL本身是自适应调整的速度。

lazyfree-lazy-server-del
针对有些指令在处理已存在的键时,会带有一个隐式的DEL键的操作。如rename命令,当目标键已存在,redis会先删除目标键,如果这些目标键是一个big key,那就会引入阻塞删除的性能问题。此参数设置就是解决这类问题,建议可开启。

slave-lazy-flush
针对slave进行全量数据同步,slave在加载master的RDB文件前,会运行flushall来清理自己的数据场景, 参数设置决定是否采用异常flush机制。如果内存变动不大,建议可开启。可减少全量同步耗时,从而减少主库因输出缓冲区爆涨引起的内存使用增长。

3)lazy free的监控

lazy free能监控的数据指标,只有一个值:lazyfree_pending_objects,表示redis执行lazy free操作,在等待被实际回收内容的键个数。并不能体现单个大键的元素个数或等待lazy free回收的内存大小。所以此值有一定参考值,可监测redis lazy free的效率或堆积键数量;比如在flushall async场景下会有少量的堆积。

# info memory
# Memory
lazyfree_pending_objects:0

注意事项 :unlink命令入口函数unlinkCommand()和del调用相同函数delGenericCommand()进行删除KEY操作,使用lazy标识是否为lazyfree调用。如果是lazyfree,则调用dbAsyncDelete()函数。
但并非每次unlink命令就一定启用lazy free,redis会先判断释放KEY的代价(cost),当cost大于LAZYFREE_THRESHOLD(64)才进行lazy free.
释放key代价计算函数lazyfreeGetFreeEffort(),集合类型键,且满足对应编码,cost就是集合键的元数个数,否则cost就是1。

举例:
一个包含100元素的list key, 它的free cost就是100
一个512MB的string key, 它的free cost是1, 所以可以看出,redis的lazy free的cost计算主要时间复杂度相关。

9.AOF优化

Redis 提供了一个配置项,当子进程在 AOF rewrite 期间,可以让后台子线程不执行刷盘(不触发 fsync 系统调用)操作。

这相当于在 AOF rewrite 期间,临时把 appendfsync 设置为了 none,配置如下:

# AOF rewrite 期间,AOF 后台子线程不进行刷盘操作
# 相当于在这期间,临时把 appendfsync 设置为了 none
no-appendfsync-on-rewrite yes

当然,开启这个配置项,在 AOF rewrite 期间,如果实例发生宕机,那么此时会丢失更多的数据,性能和数据安全性,你需要权衡后进行选择。

如果占用磁盘资源的是其他应用程序,那就比较简单了,你需要定位到是哪个应用程序在大量写磁盘,然后把这个应用程序迁移到其他机器上执行就好了,避免对 Redis 产生影响。
当然,如果你对 Redis 的性能和数据安全都有很高的要求,那么建议从硬件层面来优化 ,更换为 SSD 磁盘,提高磁盘的 IO 能力,保证 AOF 期间有充足的磁盘资源可以使用。同时尽可能让Redis运行在独立的机器上。

10.Swap优化

1)增加机器的内存,让 Redis 有足够的内存可以使用
2)整理内存空间,释放出足够的内存供 Redis 使用,然后释放 Redis 的 Swap,让 Redis 重新使用内存

释放 Redis 的 Swap 过程通常要重启实例,为了避免重启实例对业务的影响,一般会先进行主从切换,然后释放旧主节点的 Swap,重启旧主节点实例,待从库数据同步完成后,再进行主从切换即可。
预防的办法就是,你需要对 Redis 机器的内存和 Swap 使用情况进行监控,在内存不足或使用到 Swap 时报警出来,及时处理。

11、Redis变慢了排查步骤

1.获取 Redis 实例在当前环境下的基线性能。
2.是否用了慢查询命令?如果是的话,就使用其他命令替代慢查询命令,或者把聚合计算命令放在客户端做。
3.是否对过期 key 设置了相同的过期时间?对于批量删除的 key,可以在每个 key 的过期时间上加一个随机数,避免同时删除。
4.是否存在 bigkey?对于 bigkey 的删除操作,如果你的 Redis 是 4.0 及以上的版本,可以直接利用异步线程机制减少主线程阻塞;如果是 Redis 4.0 以前的版本,可以使用 SCAN 命令迭代删除;对于 bigkey 的集合查询和聚合操作,可以使用 SCAN 命令在客户端完成。
5.Redis AOF 配置级别是什么?业务层面是否的确需要这一可靠性级别?如果我们需要高性能,同时也允许数据丢失,可以将配置项 no-appendfsync-on-rewrite 设置为 yes,避免 AOF 重写和 fsync 竞争磁盘 IO 资源,导致 Redis 延迟增加。当然, 如果既需要高性能又需要高可靠性,最好使用高速固态盘作为 AOF 日志的写入盘。
6.Redis 实例的内存使用是否过大?发生 swap 了吗?如果是的话,就增加机器内存,或者是使用 Redis 集群,分摊单机 Redis 的键值对数量和内存压力。同时,要避免出现 Redis 和其他内存需求大的应用共享机器的情况。
7.在 Redis 实例的运行环境中,是否启用了透明大页机制?如果是的话,直接关闭内存大页机制就行了。
8.是否运行了 Redis 主从集群?如果是的话,把主库实例的数据量大小控制在 2~4GB,以免主从复制时,从库因加载大的 RDB 文件而阻塞。
9.是否使用了多核 CPU 或 NUMA 架构的机器运行 Redis 实例?使用多核 CPU 时,可以给 Redis 实例绑定物理核;使用 NUMA 架构时,注意把 Redis 实例和网络中断处理程序运行在同一个 CPU Socket 上。文章来源地址https://www.toymoban.com/news/detail-541503.html

到了这里,关于Redis10大性能优化策略(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 架构师成长之路Redis第三篇|Redis key过期清除策略

    maxmemory 100mb 当我们设置的内存达到指定的内存量时, 清除策略的 配置方式决定了默认行为。Redis可以为可能导致使用更多内存的命令返回错误,也可以在每次添加新数据时清除一些旧数据以返回到指定的限制。 当达到最大内存限制时,Redis所遵循的确切行为是使用MaxMemory-

    2024年02月10日
    浏览(36)
  • Redis内存碎片:深度解析与优化策略

    本文已收录至GitHub,推荐阅读 👉 Java随想录 微信公众号:Java随想录 原创不易,注重版权。转载请注明原作者和原文链接 目录 内存碎片如何产生的 内存分配器 怎么看是否有内存碎片 碎片率的意义 清理内存碎片 低于4.0-RC3版本的Redis 高于4.0-RC3版本的Redis 在我们探究和优化

    2024年02月08日
    浏览(40)
  • 【Redis】Redis性能优化:理解与使用Redis Pipeline

    原创不易,注重版权。转载请注明原作者和原文链接 当我们谈论Redis数据处理和存储的优化方法时,「 Redis Pipeline 」无疑是一个不能忽视的重要技术。 在使用Redis的过程中,频繁的网络往返操作可能会引发严重的性能问题,尤其是当大量并发操作需要快速响应的时候。这就是

    2024年02月07日
    浏览(40)
  • Redis性能优化:理解与使用Redis Pipeline

    本文已收录至GitHub,推荐阅读 👉 Java随想录 微信公众号:Java随想录 原创不易,注重版权。转载请注明原作者和原文链接 目录 Pipeline介绍 原生批命令(MSET, MGET) VS Pipeline Pipeline的优缺点 一些疑问 Pipeline代码实现 当我们谈论Redis数据处理和存储的优化方法时,「 Redis Pipeline 」

    2024年02月08日
    浏览(53)
  • redis 性能优化二

    前言 性能优化的第二篇文章,将重点讲一下Redis 的响应延迟,响应延迟如何对redis 进行优化。这个延迟不是说一个命令或者几个命令变慢了,延迟了几秒,就说Redis 变慢了。在不同的软硬件环境下,Redis 本身的绝对性能并不相同。要根据Redis 的基线性能做判断。所谓的基线性

    2024年03月09日
    浏览(57)
  • redis 性能优化一

    目录 前言 尾延迟 前言 说到redis 性能优化,优化的目的是什么?提高响应,减少延迟。就要关注两点,一是尾延迟,二是Redis 的基线性能。只有指标,我们的优化,才有意义,才能做监控以及报警。这些指标需要借助一定工具进行压力测试,高于这个值就说明需要优化了,这

    2024年03月14日
    浏览(48)
  • Redis性能配置优化

      Redis的性能取决于可用内存的大小。如果内存不足,Redis将开始交换(swap),这会极大影响性能。因此,首先我们需要确保Redis所用内存的数量合理。   对于合理的内存使用,我们需要对Redis的maxmemory和maxmemory-policy进行配置,以确保Redis在内存不足时仍能优雅地工作。如

    2024年02月11日
    浏览(32)
  • Redis 性能优化

    当我们操作 Redis 发现耗时较长时,原因可能有两个: 服务间存在网络延迟 Redis 服务本身存在问题 如果是第一种情况,那么所有服务都会发生网络延迟,只需要联系运维处理即可,这里主要讨论第二种情况 基准性能指 Redis 在一台负载正常的机器上的最大响应延迟和平均响应

    2024年02月03日
    浏览(42)
  • Redis缓存设计与性能优化

    缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中 , 通常出于容错的考虑, 如果从存储层查不到数据则不写入缓存层。 缓存穿透将导致不存在的数据每次请求都要到存储层去查询, 失去了缓存保护后端存储的意义。 造成缓存穿透的基本原因有两个:

    2024年02月07日
    浏览(44)
  • 【DB】Redis缓存优化策略之,缓存预热与缓存清除

    1、什么是缓存优化? 缓存是一种数据存储技术 ,用于存储经常访问的数据,以便在需要时快速获取。通过缓存数据,可以减少数据的访问时间和系统的负载,从而提高应用程序的性能。缓存可以应用在多个层次,例如CPU缓存、数据库缓存和Web缓存。 缓存优化 是指通过合理

    2024年01月17日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包