redis优化思路整理

前言

在实际使用过程中, 经常会碰到Redis响应延迟高的问题, 故将可能出现的问题及优化思路整理一下, 以防不时之需. 这里罗列的问题是目前能够想到的, 后续如果遇到新的问题会再回来更新的.

业务修改

主要从Redis的业务使用方面处理, 不需要动到Redis实例.

慢查询

是否存在处理时间过久的操作.

分析慢查询可通过如下方式:

  1. 查看线上延迟是否较高
    • redis-cli --intrinsic-latency 30, 通过命令可分析30s 内的延迟, 作为比较的基线
  2. 查看slowlog
    • redis-cli slowlog get 10, 获取最新的10条慢日志
    • 相关配置:
      • slowlog-log-slower-than 10000: 执行时间大于10000微妙, 会进行慢查询记录
      • slowlog-max-len: 在内存中记录多少条慢查询
  3. 峰值监控
    • redis-cli LATENCY LATEST, 获取超过阈值的命令最新和最大的延迟
    • 相关配置:
      • latency-monitor-threshold 1000: 当命令执行超过1000微妙, 就会被监控

对于慢查询, 解决办法就是使用时间复杂度低的命令. 具体分析下业务

并发高

当并发量过高的时候, 也会导致请求的延迟下降.

可以先想办法降低并发量, 或者水平扩容.

可能用到的分析工具:

  1. redis-faina: facebook开源的分析脚本, 可查看哪些key的访问频率高等
    • redis-cli -p 6379 MONITOR | head -n 100 | ./redis-faina.py

大量 key 同时过期

因为redis的过期策略是, 随机取样, 回收其中已过期的元素, 循环此步骤, 知道取样数据中已过期元素比例小于25%. 而在回收的过程中, 是会阻塞主线程的.

解决办法就是将过期时间添加随机数, 防止同时过期.

同步删除

在执行同步删除操作(如del)时, 需要释放内存空间, 同时若删除的数据很大, 就会导致主线程阻塞.

分析大 key 可能用到的工具:

  • redis-cli --bigkeys -i 0.1: 查找大 key. 每扫描100次, 停0.1s. 避免影响业务
  • redis-clie memory usage key: 查询某个key的内存占用

解决方案, 可将同步删除改为异步删除:

  • del -> unlink
  • flushdb -> flushdb async
  • flushall -> flushall async

系统层面

同时, 在系统层面也存在影响其运行的因素, 包括: 运行配置、内存溢出、IO 阻塞等等. 这里整理一些可能会有影响的因素, 一些是我遇到的, 一些是我想到的, 还有是我在网上找到的.

数据量过大

当数据量较大, 占用内存较高时, 会导致进程的页表变大. 无论是生成rdb还是AOF重写, 都会fork子进程, 而子进程fork时是需要复制页表的, 会导致fork操作变慢. 而fork操作会阻塞主线程.

AOF日志重写

在将数据写入磁盘的过程中, 会存在如下两个步骤:

  1. write: 将数据先存放的缓冲区, 此时还在内存中
  2. fsync: 将数据落盘, 此操作会进行阻塞

Redis的 AOF 日志有两种, 一个是增量日志, 记录每条操作, 一个是全量日志, 用于减少日志体积. AOF增量日志的配置项为appendfsync, 有如下3中策略:

  1. no: 关闭 AOF 日志
  2. always: 同步写. 既每条操作日志在主线程写入后立即调用fsync落盘, 落盘后返回客户端
  3. everysec: 每秒调用fsync进行落盘

在如下场景会造成阻塞:

  • AOF重写会发生大量磁盘 IO
  • 此时fsync会发生阻塞. 即使使用子线程执行fsync, 若主线程发现上一次fsync还未完成, 仍会阻塞等待.

解决方案:

  1. 更换固态硬盘, 提高IO 速度
  2. 修改配置no-appendfsync-on-rewrite yes
    • 表示在 AOF 重写的时候, 不执行fsync操作, 等到重写完毕, 主线程再执行fsync
    • 但这样可能会导致, 若重写过程中宕机, 这期间的操作丢失

内存交换

若物理内存不够用了, 操作系统会将部分内存交换到磁盘上来, 此时磁盘的读取就变慢了.

判断是否发生了交换:

# 获取进程 ID
ps -ef | grep redis
# 查看内存占用及有多少被 swap
# 其结果为进程的所有内存页, 及每页中有多少在磁盘上
cat /proc/22111/smaps | egrep '^(Swap|Size)'

解决方法就是垂直扩容或水平扩容咯.

主从同步阻塞

在主从同步的开始, 从库获取rdb文件进行全量同步. 此时会先执行flushdb操作, 也会造成阻塞. 原因请参考同步删除

多核CPU

若物理机存在多核 CPU, 那么进程从物理核A 切换到物理核B 时, 不光需要进行上下位切换. 包括L1/L2缓存也要重新加载, 存在一定耗时.

可将进程绑定在单个物理核上运行, 避免切换:

# 查看当前cpu 核心架构
lscpu
# 绑定到同一物理核上的多个逻辑核
# 最好多绑定几个逻辑核, 因为redis 本身是多线程的
taskset -c 0,1 ./redis-server

内存大页

操作系统默认分页为4kb, 若启用大页, 则每页为4mb

在执行备份的时候, 会复制子进程, 此时发生内存更新, 会触发写时复制, 将整个页的数据全部复制.

通过命令cat /sys/kernel/mm/transparent_hugepage/enabled查看是否启用大页. 改为never关闭即可

内存碎片

Redis在运行的过程中, 是否内存并不会将内存还给操作系统, 而是会留下来等待下次使用. 此时就会导致Redis使用的内存较少, 但占用的物理内存较大.

查看内存碎片:

# used_memory: 使用内存
# used_memory_rss: 系统分配的内存
# mem_fragmentation_ratio: 内存碎片率. 等于: used_memory_rss/used_memory
redis-cli info memory

解决方案:

# 修改配置文件启动自动碎片清理
activedefrag yes
# 当碎片字节数超过100mb, 进行清理
active-defrag-ignore-bytes 100mb
# 当内存空间占分配空间的10%, 进行清理
active-defrag-threshold-lower 10
# 清理过程中, CPU使用比例不低于1%, 保证清理正常进行
active-defrag-cycle-min 1
# 清理过程中, CPU使用比例不高于25%, 保证服务正常
active-defrag-cycle-max 25

缓冲区溢出

Redis会将客户端的请求和响应分别放入缓冲区中, 若缓冲区不够用了, 可能会导致溢出.

redis 默认提供最多1G 的输入缓冲区大小, 不可配置.

查看缓冲区占用:

# 查询所有客户端的情况, 其中部分
# cmd: 最新执行的命令
# qbuf: 缓冲区已经使用的大小
# qbuf-free: 缓冲区尚未使用的大小
redis-cli CLIENT LIST

解决:

  1. 判断请求和响应中是否存在大 key 导致缓冲区溢出
  2. 修改配置client-output-buffer-limit, 可更改输出缓冲区的大小
    • client-output-buffer-limit normal 0 0 0: 普通客户端不做限制. 后面的三个0分别表示: 缓冲区大小限制, 持续写入量限制, 持续写入时间限制
    • client-output-buffer-limit pubsub 8mb 2mb 60: 修改订阅客户端的限制. 若60s 内写入超过2mb 或者 总实际占用 量超过8mb, 则会关闭连接
    • client-output-buffer-limit slave 8mb 2mb 60: 针对主从中主节点的复制缓冲区设置. 在全量复制期间暂存的增量数据
  3. 修改配置repl-backlog-size. 此配置为主从节点进行同步的数据存放, 主节点将新增命令记录, 从节点拉取, 是一个环形列表
    • 注意, 此值若设置的太小, 从节点要拉取的数据已经被覆盖了, 就会触发全量复制

运维工具

整理一些在Redis运行过程中可能用到的运维工具.

  • INFO 命令: Redis的info命令本身就能够显示查询一些信息
    • server: 实例本身的信息
    • client: 客户端统计信息
    • stat: 常规的统计信息
    • keyspace: 数据库相关
    • commandstats: 命令统计
    • memory: 内存信息
    • cpu:
    • persistence: RDB和AOF信息
    • replication: 主从复制
    • cluster: 集群信息
  • redis-faina: facebook开源的分析脚本, 可查看哪些key的访问频率高等
  • prometheus: 一款可视化的监控报警系统. 配合插件Redis-exporter
  • cachecloud: 搜狐开源的Redis管理平台. 支持集群、主从、哨兵等的自动化部署和管理
  • redis-shake: 阿里开源的数据迁移工具.

先写这么多, 后面遇到问题再回来加吧.

订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请发表评论。x