Redis 压力测试 & 服务监控
Redis 压力测试
Redis 安装成功后,会在 /usr/local/bin/目录下生成redis-benchmark压测工具。该工具模拟N个客户端同时执行Redis指令,默认提供一组默认测试参数,用户可以自定义其属性,更改测试行为。
参数说明
# 执行以下指令 查看其参数信息
redis-benchmark -h
Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
-h <hostname> Server hostname (default 127.0.0.1)
-p <port> Server port (default 6379)
-s <socket> Server socket (overrides host and port)
-a <password> Password for Redis Auth
-c <clients> Number of parallel connections (default 50) # 默认模拟50个客户端连接 即50并发
-n <requests> Total number of requests (default 100000) # 默认总共请求次数
-d <size> Data size of SET/GET value in bytes (default 3) # 数据默认大小
--dbnum <db> SELECT the specified db number (default 0) # 指定数据库 默认0号数据库
-k <boolean> 1=keep alive 0=reconnect (default 1)
-r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
Using this option the benchmark will expand the string __rand_int__
inside an argument with a 12 digits number in the specified range
from 0 to keyspacelen-1. The substitution changes every time a command
is executed. Default tests use this to hit random keys in the
specified range. # 该选项针对SET/GET/INCR指令生成12位的随机键值,对SADD指令生成12位随机Value值,随机数在0-keyspacelen-1范围内生成
-P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).
-q Quiet. Just show query/sec values
--csv Output in CSV format
-l Loop. Run the tests forever
-t <tests> Only run the comma separated list of tests. The test
names are the same as the ones produced as output.
-I Idle mode. Just open N idle connections and wait.
默认压测
# 执行压测 默认请求数量 10w
# -q 仅显示 qps 信息
redis-benchmark -q -n 100000
如下图,默认情况下 redis-benchmark工具会执行多个脚本进行测试
结果说明
# get指令 每秒qps为70372, 50%的请求延迟在 0.327 毫秒
GET: 70372.98 requests per second, p50=0.327 msec
指定测试
也许只需要测试指定的指令,而非执行所有默认的压测命令,可以通过 -t 选项指定待运行的指令
# 压测仅执行 set 指令
$ redis-benchmark -t set -n 100000 -q
SET: 73475.39 requests per second, p50=0.327 msec
此外,你也可以使用script load 命令对指定的Redis命令进行压测命令
redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"
script load redis.call('set','foo','bar'): 74128.98 requests per second, p50=0.327 msec
指定Key大小
默认情况下,benchmark对单个键值进行测试,通常情况下可以通过使用更大的键值模拟真实的工作场景。理由是:键值越大,并发情况下,网络带宽占用相对来说比较高,因此更接近业务场景。
使用 -r 选项指定key的大小。例如,如果我想运行一百万个SET操作,在100k个可能的键中,对每个操作使用一个随机键:
$ redis-benchmark -t set -r 100000 -n 1000000
====== SET ======
1000000 requests completed in 14.23 seconds
50 parallel clients
3 bytes payload
keep alive: 1
host configuration "save": 3600 1 300 100 60 10000
host configuration "appendonly": no
multi-thread: no
...
Summary:
throughput summary: 70283.95 requests per second
latency summary (msec):
avg min p50 p95 p99 max
0.368 0.168 0.335 0.551 0.695 5.743
$ redis-cli dbsize
(integer) 99993
管道测试
默认情况下,benchmark工具模拟50个客户端,每个客户端只能等待Redis服务器返回,才能继续发送下一个指令。这意味着服务器需要按顺序读取每一个请求指令,此外每次发送请求之前还会由于TCP连接握手消耗时间。
Redis 支持批量发送请求指令,一次请求发送多个指令,从而加快应用系统整体的响应速度,这是优化Redis常用的方式。
benchmark工具支持管道批量发送指令,
# 使用pipeline 每次发送16个指令;系统吞吐量差不多 提高10倍
redis-benchmark -n 1000000 -t set,get -P 16 -q
SET: 662690.56 requests per second, p50=0.999 msec
GET: 795544.94 requests per second, p50=0.799 msec
注意事项
压测工具的重要目标是获取重复的测试结果,以便与其他测试结果进行比较,最终选择最优方案。相同的压测工具在不同硬件、不同系统、不同环境设置下压测的结果不尽一致,通常而言,需要考虑以下场景:
- 在隔离的硬件上进行测试 避免其他因素干扰
- 系统CPU工作频率会影响测试结果, 最好为基准测试中涉及的所有CPU内核设置可能的最高固定频率
- 系统必须保证足够的RAM,Linux环境中 请正确设置overcommit_memory参数
- Redis开启RDB、AOF时,请关闭系统中的其他IO活动,避免造成交叉影响
- 将Redis日志记录级别(loglevel参数)设置为警告或通知。避免将生成的日志文件( IO活动)
- 避免使用可能改变基准测试结果的监控工具。例如,定期使用INFO收集统计数据可能很好,但MONITOR将显著影响测量的性能
Redis 服务监控
Redis性能监控非常重要,运维人员可以监控通过监控关键指标,以跟踪Redis实例的性能。本篇介绍下Redis监控关键指标以及如何进行监控。由于Redis是内存数据库,因此监控系统资源利用率非常重要,Redis检测指标主要包含:
- 性能
- 内存
- Redis基本情况
性能指标
延迟
延迟是衡量Redis性能的重要指标,它是只Redis客户端发送请求到接收响应的时间差。快速检查Redis延迟的方法:
# 该命令显示Redis ping 命令的网络延迟
redis-cli --latency -h 127.0.0.1 -p 6379
- 274 samples - Redis CLI发出PING的次数 上述命令记录了274个请求和响应
- min - redis cli发出PING的时间与收到回复的时间之间的最小延迟 单位毫秒
- max - redis cli发出PING的时间与收到回复的时间之间的最大延迟 单位毫秒 如上图 1ms
- avg - 采样数据的平均响应时间,0.27毫秒
CPU使用率
如果发现Redis导致的CPU使用率高,则应进一步调查。CPU使用率高也可能与命令执行时间长有关。此时需要使用Redis慢日志功能是否存在长时间执行的命令
127.0.0.1:6379> info cpu
# CPU
used_cpu_sys:6.472493
used_cpu_user:3.873488
used_cpu_sys_children:0.000000
used_cpu_user_children:0.000000
缓存命中率
Redis缓存命中率是要监视的重要性能指标之一。表示Redis实例的使用效率。该比率表示所有读取操作中成功命中(读取)的百分比。计算如下:
缓存命中率 = (keyspace_hits)/(keyspace_hits + keyspace_misses)
# info stats 可查看命中率相关参数说明
127.0.0.1:6379> info stats
# Stats
...
total_eviction_exceeded_time:0
current_eviction_exceeded_time:0
keyspace_hits:0
keyspace_misses:0
...
内存指标
如果Redis实例的内存使用量超过总可用内存,则会导致内存交换。内存交换涉及通过将未使用的内存内容移动到磁盘来回收内存空间。从磁盘写入或读取速度要慢得多,而且无法达到使用Redis的目的。跟踪内存使用情况可以确保Redis实例使用的内存少于总可用内存。
开发者可以使用maxmemory指令为Redis配置最大内存;或者通过redis.config 配置最大内存值;当Redis使用的内存达到阈值时,可以使用内存淘汰策略删除未使用的key值。
内存碎片
内存碎片问题会导致性能降低和延迟增加。理想情况下,Redis需要连续的内存段来存储数据。但如果操作系统找不到连续的部分,它会分配碎片内存部分来存储Redis数据,这会导致内存寻址开销。
127.0.0.1:6379> info memory
# Memory
# redis 占用内存
used_memory:1193712
used_memory_human:1.14M
# 操作系统占用内存
used_memory_rss:1953792
used_memory_rss_human:1.86M
...
Redis中的内存碎片 是计算used_Memory_rss与used_Memory的比率。通常情况下,大于或接近1的内存碎片比率被认为是健康的。如果它低于1,则意味着您需要立即为Redis分配更多内存,否则它将开始交换内存。
内存淘汰策略
当Redis达到max_memory_limit时,需要指定策略将过期数据删除,以腾出内存空间容纳新的KEY-VALUE值。指定Redis内存淘汰策略,对于维持系统的稳定性非常重要。Redis默认支持以下淘汰机制:
- noeviction - 当达到内存限制并且客户端尝试执行可能导致使用更多内存的命令时,将
返回错误
- allkeys-lru - 通过尝试
先删除最近使用较少的(LRU)键
来移出键,以便为添加的新数据腾出空间 - volatile-lru - 通过尝试
先删除最近使用较少的且设置了过期时间的(LRU)键
来移出键,以便为添加的新数据腾出空间 - allkeys-random -
随机删除键
,以便为添加的新数据腾出空间 - volatile-random -
随机删除设置了过期时间的键
,以便为添加的新数据腾出空间 - volatile-ttl - 删除设置了到期时间的键,并尝试首先删除具有较短生存时间(TTL)的键
可以修改redis.conf 中的属性 maxmemory-policy 指定相关策略,该功能默认关闭。
Redis 基本情况
除了性能和内存指标外,了解Redis实例的一些基本活动指标也是很有用的:
-
connected_clients - 客户端连接数
-
blocked_clients - 阻塞客户端数
-
connected_slaves - 连接副本数
-
total_commands_processed - redis实例处理的命令总数
-
keyspace - 了解Redis数据库中的KEY数量很重要 keyspace参数提供有关键数和过期键数的统计信息
127.0.0.1:6379> info keyspace # Keyspace 数据库0中有1个key db0:keys=1,expires=0,avg_ttl=0
收集指标
Redis INFO 指令提供以下相关维度信息的收集
- Server
- Clients
- Memory
- Persistence
- stats
- replication
- CPU
- commandstats
- cluster
- keyspace
慢日志查询
Redis 默认将执行时间超过1秒请求定义为慢日志,可以通过客户端进行显示。可以在redis.conf文件中自定义执行时长
# The following time is expressed in microseconds, so 1000000 is equivalent
# to one second. Note that a negative number disables the slow log, while
# a value of zero forces the logging of every command.
# 单位: 微秒, 1000000 == 1秒 ; 值若为 -1 表示不记录slow log;0 表示强制记录所有命令。
slowlog-log-slower-than 10000
将其设置为0 ,然后客户端展示慢日志
127.0.0.1:6379> slowlog get 10
1) 1) (integer) 2
2) (integer) 1670946587
3) (integer) 48
4) 1) "slowlog"
2) "help"
5) "127.0.0.1:61208"
6) ""
查看slowlog帮助文档
127.0.0.1:6379> slowlog help
1) SLOWLOG <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
2) GET [<count>]
3) Return top <count> entries from the slowlog (default: 10, -1 mean all).
4) Entries are made of:
5) id, timestamp, time in microseconds, arguments array, client IP and port,
6) client name
7) LEN
8) Return the length of the slowlog.
9) RESET
10) Reset the slowlog.