redis的内存参数详解及线上问题解决思路

redis性能会受到什么影响

  • 内存容量
  • cpu使用率
  • 网络
  • 使用/优化不当

redis性能出现问题的表象有哪些

  • 连接超时
  • 延时过高

查看redis的某些参数和其含义

info

连接redis以后,输入info,info命令输出的数据可分为10个类别,分别是:

  • server
  • clients
  • memory
  • persistence
  • stats
  • replication
  • cpu
  • commandstats
  • cluster
  • keyspace

可以使用info 加上上面的随意一个类别,来分类别查询,例如 info memory。

我们重点讲解其中的memory分类和stats分类还有clents分类

memory

内存使用量:used_memory

由Redis分配器分配的内存总量,以字节(byte)为单位。 其中used_memory_human上的数据和used_memory是一样的值,它以M为单位显示,仅为了方便阅读。

它包含了实际缓存占用的内存和Redis自身运行所占用的内存(如元数据、lua)。它是由Redis使用内存分配器分配的内存,所以这个数据并没有把内存碎片浪费掉的内存给统计进去。如果used_memory>可用最大内存,那就说明Redis实例正在进行内存交换或者已经内存交换完毕。

其他字段代表的含义,都以字节为单位:

  • used_memory_rss:从操作系统上显示已经分配的内存总量,表示该进程所占物理内存的大小
  • mem_fragmentation_ratio: 内存碎片率。

mem_fragmentation_ratio = used_memory_rss / used_memory

mem_fragmentation_ratio < 1:

表示Redis内存分配超出了物理内存,操作系统正在进行内存交换,内存交换会引起非常明显的响应延迟;

mem_fragmentation_ratio > 1 :是合理的,一般在1.2-1.5之间都算是比较正常的;

mem_fragmentation_ratio > 1.5 :

说明Redis消耗了实际需要物理内存的150%以上,其中50%中大部分是内存碎片率,可能是操作系统或Redis实例中内存管理变差的表现。内存碎片化过高的解决办法,一种是重启服务器,另一种是开启碎片自动清理或者手动清理

  • used_memory_lua: Lua脚本引擎所使用的内存大小。
  • mem_allocator: 在编译时指定的Redis使用的内存分配器,可以是libc、jemalloc、tcmalloc。其中libc适合存储大key,其他两个存储大key的时候内存碎片率容易过高,存储小key的时候性能更好。默认的为jemalloc。

使用内存峰值

监控 Redis 内存使用峰值,可以通过命令[config set maxmemory设置允许使用的最大内存。为了防止发生 swap 导致 Redis 性能骤减,甚至由于使用内存超标导致系统kill,建议used_memory_peak(占用内存的峰值)的值与maxmemory 的值有个安全区间,例如1G。

stats

缓存命中和缓存未命中

keyspace_misses,keyspace_hits 这两个指标用来统计缓存的命中率。keyspace_misses值未命中次数,keyspace_hits 表示命令次数。keyspace_hits/(keyspace_misses+keyspace_hits) 就是缓存命中率。②、如果缓存命中率过低,那么要排查对缓存的用法是否有问题。

命令处理数:total_commands_processed

在info信息里的total_commands_processed字段显示了Redis服务处理命令的总数,其命令都是从一个或多个Redis客户端请求过来的。Redis每时每刻都在处理从客户端请求过来的命令,它可以是Redis提供的140种命令的任意一个。 total_commands_processed字段的值是递增的。

每秒操作次数

OPS:instantaneous_pos_per_sec 表示缓存的OPS(operation per second 每秒操作次数)

持久化

rdb_last_bgsave_status,aof_last_bgrewrite_status,即最近一次或者最后一次 RDB/AOF 持久化是否有问题,这两个值都应该时 “OK”。②、由于 Redis 持久化时会 fork 子进程,且 fork 是一个完全阻塞的过程,所以可以监控 fork 耗时即:latest_fork_usec,单位是微妙,如果这个值比较大会影响业务,甚至出现 timeout 。

失效KEY

如果把 Redis 当缓存使用,那么建议所有的 key 都设置 expire 属性,通过命令 redis-cli info Keyspace 得到每个 db 中 key 的数量和设置了 expire属性的 key 的属性,且 expires(表示设置了超时时间的key个数) 需要等于 keys。

clients

阻塞客户端数量

blocked_clients 通常是执行了 list 数据类型的 BLPOP 或者 BRPOP 命令引起的,可以通过[redis-cli info Clients|grep blocked_clients]得到,这个值最好为0。

连接数

连接的客户端数量,connected_clients,这个值与使用 Redis 服务的连接池配置关系比较大,这个值如果很大,需要排查问题原因。另外还有一个拒绝连接数(rejected_connections)也需要关注,这个值理想状态是 0 。如果大于 0,说明创建的连接数大于 maxclients,需要排查原因。是 Redis 连接池配合不合理还是连接这个Redis 的服务过多。

slowlog

使用格式:SLOWLOG subcommand [argument]

什么是 SLOWLOG

Slow log 是 Redis 用来记录查询执行时间的日志系统。

查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间。

另外,slow log 保存在内存里面,读写速度非常快,因此你可以放心地使用它,不必担心因为开启 slow log 而损害 Redis 的速度。

设置 SLOWLOG

Slow log 的行为由两个配置参数:

CONFIG SET slowlog-log-slower-than 100   #单位微秒  1秒 = 1,000,000 微秒

CONFIG SET slowlog-max-len 1000   #设置慢日志队列长度

可以用 config get + 参数的命令查询

查询slow log

要查看 slow log ,可以使用 SLOWLOG GET 或者 SLOWLOG GET number 命令,前者打印所有 slow log ,最大长度取决于 slowlog-max-len 选项的值,而 SLOWLOG GET number 则只打印指定数量的日志,优先打印最新的日志。

查看慢日志数量和重置慢日志队列

  • SLOWLOG LEN :查看数量
  • SLOWLOG RESET :重置慢日志队列

寻找问题的常用方法

跟踪内存使用率

上面我们提到,内存使用率过高的时候,可能会触发内存交换,通过某种算法(通常是LRU算法)把内存中的某些数据写入硬盘上swap区,以便腾出新的物理内存给新页或活动页(page)使用。

在硬盘上进行读写操作要比在内存上进行读写操作慢得多,如果Redis进程上发生内存交换,那么Redis和依赖Redis上数据的应用会受到严重的性能影响。 通过查看used_memory指标可知道Redis正在使用的内存情况,如果used_memory>可用最大内存,那就说明Redis实例正在进行内存交换或者已经内存交换完毕。运维人员根据这个情况,执行相对应的措施,比如增加内存。

查询慢日志

通过查询慢日志,可以定位到一些大key的问题。

查看cpu使用率

通过查看cpu使用率对比监控数据,也可以发现一些问题的起因,比如大key问题(大key发送到客户端的序列化成本),访问量过高,乱用模糊搜索等。

查看当前连接数

info clients 命令来查询

查看redis的日志

比如有可能出现Cant save in background:fork:Cannot allocate memory。

一些实例

redis中cpu飙升

可能的原因:

  1. redis请求的qps过高

对比监控,查看qps和cpu的使用率是否有时间相关性,如果有相关性可能是redis性能不足以应付这种负载。

  1. redis存在大量慢查询

如果慢查询特别多,要具体分析各个慢查询产生的原因,比如大key的序列化,模糊查询(应该使用scan替代keys,这里之后再讲吧。)

redis大量超时

首先检查读写超时时间是否设置的过短,如果确定设置的很短,调大一点观察一下效果。

其次检查出现超时的命令是否本身执行较大的存储或者拉数据任务。如果数据量过大,那么就要考虑做业务拆分。

网络稳定性排查:可以查询tcp的重传率等来定位

是否发生了命令阻塞

如果使用连接池,检查连接池设置是否合理

使用连接池链接完成后是否释放了。

如果以上问题都未解决,那么建议进行扩容或者使用集群。

当使用redis集群后报错:Too Many Cluster Redirections

  • 集群环境中 client 先通过key 计算槽( slot),然后查询 slot 对应到哪个服务器,假设这个 slot 对应到 server1,那么就去请求 server1。

  • 此时如果 server1 整由于执行慢命令而被阻塞且 TCP 队列也已满,那么新来的请求就会直接被拒绝。

  • client 以为是 server1不可用,随即请求另一个服务器 server2。server2 检查到该 slot 由 server1 负责且 server1 心跳检查正常,所以告诉 client 你还是去找 server1 吧。

  • client 又来请求 server1,但是 server1 此时还是阻塞中,又回到 3。当请求的次数超过拒绝服务次数之后,就会抛出异常。

对于这种错误,最首要的就是要优化存储结构或者获取数据方式。其次,增加 TCP 队列长度。再次,扩容也是可以解决的。

Redis 突然间不能访问

返回如下错误:

redis.client.jedis.exception.JedisDataException:MISCONF Redis is configured to save RDB snapshots,
but is currently not able to persist on disk.Commands that may modify the data set are disabled.
Please check Redis logs for details about the error

查看 redis 日志,发现如下错误:Cant save in background:fork:Cannot allocate memory Redis在保存内存的数据到磁盘时,为了防止主线程假死,会Fork 一个子进程来完成这个保存操作,这个Fork 的子进程需要分配与主进程相同的内存,这时候就相当于需要的内存翻倍了。如果这时候可用内存不足以分配需要的内存,将会导致Fork 子进程失败而无法将数据持久化到磁盘。修改Linux内核参数 vm.overcommit_memeory=1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何) 问题便可解决。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页