Redis 的性能常见问题

目录

Redis 性能分析定位

复杂度过高的命令

BigKey 性能问题

Key 集中过期问题

淘汰策略性能问题

RDB 和 AOF 重写

大内存页性能影响

AOF 模式刷盘机制

Redis 绑定 CPU

Redis 内存碎片


Redis 性能分析定位

首先我们要通过一些手段,分析定位是否是 Redis 问题

1. 应用程序作时间跟踪,比如服务链路、针对性时间日志等等,首先明确是 Redis 环节问题

2. 排除应用程序到 Redis 主机之间的网络延迟和丢包的现象

比如从应用程序到 Redis 主机作 ping 测试

3. 排出主机上的其它程序,操作系统配置对 Redis 的影响

比如在 Numa 架构下,Redis 进程和网卡被分配到不同的物理 CPU 上

4. 通过基准测试,进行一步分析 Redis 性能问题

5. 如果是集群的情况下,一般需要单个排除

我们可以使用以下命令,查看一段时间内 Redis 的最小、最大、平均访问延迟

redis-cli -h 127.0.0.1 -p 6379 --latency-history -i 1min --采用实时查看

LATENCY HISTOGRAM --查看历史统计数据

复杂度过高的命令

通过 Redis 的慢日志(slowlog)进行分析定位

1. 查看 Redis 慢日志之前,我们需要设置慢日志的阈值。例如,设置慢日志的阈值为 10000 微秒,并且保留最近 128 条慢日志记录

slowlog-log-slower-than 10000

slowlog-max-len 128

2. 这里我们可以通过执行命令:SLOWLOG get 50 进行查看以慢日志,进而分析原因

1) 唯一标志

2) 时间戳

3) 耗时(微秒)

4) 具体的命令

3. Redis 复杂度过高,一般是操作的内存数据过于复杂,或者是返回客户端的数据量比较大

比如像 SORT、SUNION、KEYS *、MGET、MSET 等命令,极有可能导致 Redis 变慢

BigKey 性能问题

如果一个 key 写入的 value 非常大,那么 Redis 在分配内存时就会比较耗时。同样的,当删除这个 key 时,释放内存也会比较耗时,这种类

型的 key 我们一般称之为 bigkey

Redis 中的 Key,原则上越小越好,一般超过 10K 时,Redis 性能会急剧下降,我们要特别小心

1. Redis 提供了扫描 bigkey 的命令,执行以下命令就可以扫描出,一个实例中 bigkey 的 top1 分布情况

redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.1

2. 针对 top N 的统计,我们可以采用 memory usage a 来进行统计

127.0.0.1:6379> memory usage a

(integer) 496

性能建议:

1. 强烈建议不写 bigkey

2. 开启惰性释放机制

lazyfree-lazy-user-del yes

lazyfree-lazy-server-del yes

replica-lazy-flush yes

Key 集中过期问题

Redis 的过期数据采用被动过期 + 主动过期两种策略:

1. 被动过期:只有当访问某个 key 时,才判断这个 key 是否已过期,如果已过期,则从实例中删除

2. 主动过期:Redis 内部维护了一个定时任务,默认每隔 100 毫秒(1 秒 10 次)就会从全局的过期哈希表中随机取出 20 个 key,然后删除其中过期的 key,如果过期 key 的比例超过了 25%,则继续重复此过程,直到过期 key 的比例下降到 25% 以下,或者这次任务的执行耗时超过

了 25 毫秒,才会退出循环

3. 如果对于 Key 过期出现过度集中问题,那么 Redis 的 CPU 会出现较大的波大

性能建议:

1. 集中过期 key 增加一个随机过期时间,把集中过期的时间打散,降低 Redis 清理过期 key 的压力

2. 如果是 Redis 是 4.0 以上版本,可以开启 lazy-free 机制,当删除过期 key 时,把释放内存的操作放到后台线程中执行,避免阻塞主线程

lazyfree-lazy-expire yes

淘汰策略性能问题

当我们把 Redis 当做纯缓存使用时,通常会给这个实例设置一个内存上限 maxmemory,然后设置一个数据淘汰策略;如果 Redis 实例设置了

内存上限 maxmemory,那么也有可能导致 Redis 变慢

原因在于,当 Redis 内存达到 maxmemory 后,每次写入新的数据之前,Redis 必须先从实例中踢出一部分数据,让整个实例的内存维持在

maxmemory 之下,然后才能把新数据写进来。

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

性能建议:

1. 避免存储 bigkey

2. 降低释放内存的耗时淘汰策略改为随机淘汰,随机淘汰比 LRU 要快很多

3. 开启憜性淘汰,lazyfree-lazy-eviction = yes

RDB 和 AOF 重写

当 Redis 开启了后台 RDB 和 AOF rewrite 后,在执行时,它们都需要主进程创建出一个子进程进行数据的持久化

主进程创建子进程,会调用操作系统提供的 fork 函数;而 fork 在执行过程中,主进程需要拷贝自己的内存页表给子进程,如果这个实例很大,

那么这个拷贝的过程也会比较耗时

通过命令,我们可以查看上一次 fork 消耗的时间

redis-cli info|grep latest_fork_usec

性能建议:

1. 控制 Redis 实例的内存:尽量在 20G 以下,理论上越小越好,执行 fork 的耗时与实例大小有关,实例越大,耗时越久

2. 合理配置数据持久化策略:在 slave 节点执行 RDB 备份,推荐在低峰期执行,而对于丢失数据不敏感的业务(例如把 Redis 当做纯缓存使用),

可以关闭 AOF 和 AOF rewrite

3. Redis 实例不要部署在虚拟机上:fork 的耗时也与系统也有关,虚拟机比物理机耗时更久

4. 降低主从库全量同步的概率:适当调大 repl-backlog-size 参数,避免主从全量同步

大内存页性能影响

我们都知道,应用程序向操作系统申请内存时,是按内存页进行申请的,而常规的内存页大小是 4KB。

Linux 内核从 2.6.38 开始,支持了内存大页机制,该机制允许应用程序以 2MB 大小为单位,向操作系统申请内存

应用程序每次向操作系统申请的内存单位变大了,但这也意味着申请内存的耗时变长

但是对于 Redis 这种对性能和延迟极其敏感的数据库来说,我们希望 Redis 在每次申请内存时,耗时尽量短,所以我不建议你在 Redis 机器上

开启这个机制。

性能建议:

1、查看 Redis 机器是否开启了内存大页: #如果输出选项是 always,就表示目前开启了内存大页机制

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

2、关闭大内存页

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

AOF 模式刷盘机制

AOF 刷盘不同模式对性能影响是不一样

性能建议:

1. 如果是热点场景,建议大家关闭 rdb 和 aof

2. 在 SATA 和 SAS 普通盘上,appendfsync=always 和 appendfsync=everysec 性能差异基本在 50 倍以上

3. 在 aof 开启而且刷盘方式 appendfsync=always 时,磁盘对 Redis 的写入性能影响非常大,通常我们只在 SSD 时才尝试开启

4. 如果主机 IO 非常繁忙,appendfsync=everysec 在极限情况下可能导致 Redis 主线程堵塞

Redis 绑定 CPU

很多时候,我们在部署服务时,为了提高服务性能,降低应用程序在多个 CPU 核心之间的上下文切换带来的性能损耗,通常采用的方案是进

程绑定 CPU 的方式提高性能

Redis6.0 以前,绑定 CPU 也会带来风险,如果我们把 Redis 进程只绑定了一个 CPU 逻辑核心上,那么当 Redis 在进行数据持久化时,fork 出 的子进程会继承父进程的 CPU 使用偏好。

而此时的子进程会消耗大量的 CPU 资源进行数据持久化(把实例数据全部扫描出来需要耗费 CPU),这就会导致子进程会与主进程发生 CPU 争抢,进而影响到主进程服务客户端请求,访问延迟变大

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

性能建议

1. Redis Server 和 IO 线程绑定到 CPU 核心 0,2,4,6:

server_cpulist 0-7:2

2. 后台子线程绑定到 CPU 核心 1,3:

bio_cpulist 1,3

3. 后台 AOF rewrite 进程绑定到 CPU 核心 8,9,10,11:

aof_rewrite_cpulist 8-11

4. 后台 RDB 进程绑定到 CPU 核心 1,10,11:

bgsave_cpulist 1,10-1

在 Numa 架构下,Redis 绑定的 CPU 要在同一个物理 CPU 下,而且必须和网卡绑定在同一个物理 CPU 下

Redis 内存碎片

Redis 的数据都存储在内存中,当我们的应用程序频繁修改 Redis 中的数据时,就有可能会导致 Redis 产生内存碎片

内存碎片会降低 Redis 的内存使用率,我们可以通过执行 INFO 命令,得到这个实例的内存碎片率

mem_fragmentation_ratio = used_memory_rss / used_memory

其中 used_memory 表示 Redis 存储数据的内存大小,而 used_memory_rss 表示操作系统实际分配给 Redis 进程的大小

如果 mem_fragmentation_ratio > 2,说明内存碎片率已经超过了 100%,这时我们就需要采取一些措施来降低内存碎片了

性能建议:

如果是 Redis 4.0 以下版本,只能通过重启实例来解决

如果是 Redis 4.0 +版本,正好提供了自动碎片整理的功能,可以通过配置开启碎片自动整理

activedefrag yes #开启自动内存碎片整理

active-defrag-ignore-bytes 100mb #内存使用 100MB 以下,不进行碎片整理

active-defrag-threshold-lower 50 #内存碎片率超过 50%,开始碎片整理

active-defrag-threshold-upper 100 #内存碎片率超过 100%,尽最大努力碎片整理

active-defrag-cycle-min 1 #内存碎片整理占用 CPU 资源最小百分比

active-defrag-cycle-max 25 #内存碎片整理占用 CPU 资源最大百分比

active-defrag-max-scan-fields 1000 #碎片整理期间,对于 List/Set/Hash/ZSet 类型元素一次 Scan 的数量

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ym影子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值