Redis 基准测试
在 Redis 服务器上使用 redis-benchmark 工具
Redis 开源版 |
---|
Redis 有多快?
Redis 包含 redis-benchmark
工具,用于模拟 N 个客户端同时发送 M 个总查询(类似于 Apache 的 ab
工具)。下面是针对 Linux 盒子执行的基准测试的完整输出。
支持以下选项
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
--user <username> Used to send ACL style 'AUTH username pass'. Needs -a.
-c <clients> Number of parallel connections (default 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)
--threads <num> Enable multi-thread mode.
--cluster Enable cluster mode.
--enable-tracking Send CLIENT TRACKING on before starting benchmark.
-k <boolean> 1=keep alive 0=reconnect (default 1)
-r <keyspacelen> Use random keys for SET/GET/INCR, random values for
SADD, random members and scores for ZADD.
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.
-P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).
-e If server replies with errors, show them on stdout.
(No more than 1 error per second is displayed.)
-q Quiet. Just show query/sec values
--precision Number of decimal places to display in latency output (default 0)
--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.
--help Output this help and exit.
--version Output version and exit.
在启动基准测试之前,您需要有一个正在运行的 Redis 实例。一个典型的示例如下:
redis-benchmark -q -n 100000
使用这个工具非常简单,您也可以编写自己的基准测试,但与任何基准测试活动一样,有一些陷阱需要避免。
仅运行部分测试
每次执行 redis-benchmark 时,您无需运行所有默认测试。选择部分测试最简单的方法是使用 -t
选项,例如以下示例:
$ redis-benchmark -t set,lpush -n 100000 -q
SET: 180180.17 requests per second, p50=0.143 msec
LPUSH: 188323.91 requests per second, p50=0.135 msec
在上面的示例中,我们要求仅测试 SET 和 LPUSH 命令,以静默模式运行(请参阅 -q
开关)。
也可以直接指定要进行基准测试的命令,例如以下示例:
$ redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"
script load redis.call('set','foo','bar'): 69881.20 requests per second
选择键空间的尺寸
默认情况下,基准测试针对单个键运行。在 Redis 中,这种合成基准测试与实际基准测试之间的差异不大,因为它是一个内存系统;但是,通过使用大键空间,可以强调缓存未命中,并且通常可以模拟更真实的实际工作负载。
这可以通过使用 -r
开关来实现。例如,如果我想运行一百万次 SET 操作,每次操作使用 10 万个可能键中的随机一个键,我将使用以下命令行:
$ redis-cli flushall
OK
$ redis-benchmark -t set -r 100000 -n 1000000
====== SET ======
1000000 requests completed in 13.86 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.76% `<=` 1 milliseconds
99.98% `<=` 2 milliseconds
100.00% `<=` 3 milliseconds
100.00% `<=` 3 milliseconds
72144.87 requests per second
$ redis-cli dbsize
(integer) 99993
使用 Pipelining
默认情况下,每个客户端(如果未通过 -c
指定,基准测试会模拟 50 个客户端)只有在收到前一个命令的回复后才会发送下一个命令,这意味着服务器可能需要一次读取调用来读取每个客户端发送的每个命令。此外,还需要支付 RTT(往返时间)成本。
Redis 支持 pipelining,因此可以一次发送多个命令,这是实际应用程序经常利用的一个特性。Redis pipelining 能够显著提高服务器每秒可以处理的操作数量。
这是在 11 英寸 MacBook Air 上使用 16 条命令的 pipelining 运行基准测试的示例
$ redis-benchmark -n 1000000 -t set,get -P 16 -q
SET: 1536098.25 requests per second, p50=0.479 msec
GET: 1811594.25 requests per second, p50=0.391 msec
使用 pipelining 可显著提升性能。
陷阱和误解
第一点是显而易见的:一个有用的基准测试的黄金法则是只比较同类事物。例如,可以在相同的工作负载下比较不同版本的 Redis,或者比较相同版本但使用不同选项的 Redis。如果您计划将 Redis 与其他产品进行比较,那么评估功能和技术差异并将其考虑在内非常重要。
- Redis 是一个服务器,因此所有命令都涉及网络往返。嵌入式数据存储不涉及网络和协议管理。在将此类产品与 Redis 进行比较时,应使用命令执行时间而不是端到端时间。
- Redis 命令对所有常用命令返回确认。有些其他数据存储不这样做。将 Redis 与涉及单向查询的存储进行比较,其用处不大。
- 天真地迭代同步 Redis 命令并不能对 Redis 本身进行基准测试,而只是测量您的网络(或 IPC)延迟以及客户端库的固有延迟。要真正测试 Redis,您需要使用多个连接(如 redis-benchmark)和/或使用 pipelining 聚合多个命令和/或使用多个线程或进程。
- Redis 是一个内存数据存储,带有一些可选的持久化选项。如果您计划将其与事务服务器(MySQL、PostgreSQL 等)进行比较,则应考虑启用 AOF 并确定合适的 fsync 策略。
- 从命令执行的角度来看,Redis 大多数情况下是单线程服务器(实际上现代版本的 Redis 将线程用于不同的任务)。它并非设计用于从多个 CPU 核心中获益。如果需要,用户应启动多个 Redis 实例以在多个核心上进行横向扩展。将一个单一的 Redis 实例与多线程数据存储进行比较是不太公平的。
一个常见的误解是,redis-benchmark 的设计是为了让 Redis 的性能看起来非常出色,认为 redis-benchmark 达到的吞吐量有些人工化,实际应用程序无法达到。这实际上是不正确的。
redis-benchmark
程序是在给定硬件上获取一些数据并评估 Redis 实例性能的快速且实用的方法。然而,默认情况下,它并不代表 Redis 实例能够承受的最大吞吐量。实际上,通过使用 pipelining 和快速客户端 (hiredis),编写一个生成比 redis-benchmark 更高吞吐量的程序相当容易。redis-benchmark 的默认行为是仅通过并发来达到吞吐量(即创建多个连接到服务器)。除非通过 -P
参数明确启用,否则它不使用 pipelining 或任何并行性(每个连接最多一个待处理查询,并且不使用多线程)。因此,在某种程度上,使用 redis-benchmark
并同时在后台触发例如 BGSAVE
操作,将为用户提供更接近最差情况而不是最佳情况的数据。
要使用 pipelining 模式运行基准测试(并获得更高的吞吐量),您需要明确使用 -P 选项。请注意,这仍然是现实的行为,因为许多基于 Redis 的应用程序积极使用 pipelining 来提高性能。但是,您应该使用一个大致与您在应用程序中能够使用的平均 pipeline 长度相等的 pipeline 大小,以便获得实际的数据。
最后,基准测试应应用于相同的操作,并且对于您想要比较的多个数据存储以相同的方式工作。将 redis-benchmark 的结果与另一个基准测试程序的结果进行比较并进行推断是完全没有意义的。
例如,可以在 GET/SET 操作上比较单线程模式下的 Redis 和 memcached。两者都是内存数据存储,在协议层面大多以相同方式工作。只要它们各自的基准测试应用程序以相同的方式聚合查询(pipelining)并使用相似数量的连接,这种比较实际上是有意义的。
Redis (antirez) 和 memcached (dormando) 开发者之间的对话完美地说明了这一点。
antirez 1 - 关于 Redis、Memcached、速度、基准测试和厕所
dormando - Redis VS Memcached(稍好一点的基准测试)
antirez 2 - Memcached/Redis 基准测试更新
您可以看到,最终,一旦考虑了所有技术方面,这两种解决方案之间的差异并非如此惊人。请注意,在这些基准测试之后,Redis 和 memcached 都得到了进一步优化。
最后,在对非常高效的服务器进行基准测试时(像 Redis 或 memcached 这样的存储绝对属于此类),可能很难使服务器达到饱和。有时,性能瓶颈在于客户端,而不是服务器端。在这种情况下,必须修复客户端(即基准测试程序本身),或者进行横向扩展,以达到最大吞吐量。
影响 Redis 性能的因素
有多个因素直接影响 Redis 的性能。我们在此提及它们,因为它们可能会改变任何基准测试的结果。但请注意,在低端、未经优化的机器上运行的典型 Redis 实例通常能为大多数应用程序提供足够好的性能。
- 网络带宽和延迟通常直接影响性能。在启动基准测试之前,使用 ping 程序快速检查客户端和服务器主机之间的延迟是否正常是一个好习惯。关于带宽,通常估计以 Gbit/s 为单位的吞吐量并将其与网络的理论带宽进行比较很有用。例如,一个在 Redis 中以 100000 q/s 速率设置 4 KB 字符串的基准测试,实际上将消耗 3.2 Gbit/s 的带宽,可能适用于 10 Gbit/s 链路,但不适用于 1 Gbit/s 链路。在许多实际场景中,Redis 的吞吐量受网络限制远早于受 CPU 限制。为了在单个服务器上整合多个高吞吐量的 Redis 实例,值得考虑配置 10 Gbit/s 网卡或多个带 TCP/IP bonding 的 1 Gbit/s 网卡。
- CPU 是另一个非常重要的因素。作为单线程应用,Redis 倾向于使用具有大缓存但核心不多的快速 CPU。在这方面,Intel CPU 目前是赢家。与类似的 Nehalem EP/Westmere EP/Sandy Bridge Intel CPU 相比,在 AMD Opteron CPU 上运行 Redis 只能获得一半的性能,这并不罕见。当客户端和服务器在同一台机器上运行时,CPU 是 redis-benchmark 的限制因素。
- 内存速度和内存带宽对于整体性能似乎不太关键,特别是对于小对象。但对于大对象(大于 10 KB)而言,可能会变得更明显。通常,购买昂贵的快速内存模块来优化 Redis 并不划算。
- 与在相同硬件上非虚拟化运行相比,Redis 在虚拟机上运行速度较慢。如果条件允许,最好在物理机上运行 Redis。但这并不意味着 Redis 在虚拟化环境中运行缓慢,其性能仍然非常好,虚拟化环境中大多数严重的性能问题是由于过度配置、高延迟的非本地磁盘,或者旧的 hypervisor 软件导致
fork
syscall 实现较慢。 - 当服务器和客户端基准测试程序在同一台机器上运行时,可以使用 TCP/IP loopback 和 unix domain sockets。根据平台的不同,unix domain sockets 可以比 TCP/IP loopback 获得大约 50% 的更高吞吐量(例如在 Linux 上)。redis-benchmark 的默认行为是使用 TCP/IP loopback。
- 当大量使用 pipelining(即长 pipeline)时,unix domain sockets 相对于 TCP/IP loopback 的性能优势往往会减小。
- 当使用以太网访问 Redis 时,使用 pipelining 聚合命令在数据大小保持在以太网数据包大小(约 1500 字节)以下时特别高效。实际上,处理 10 字节、100 字节或 1000 字节的查询几乎会产生相同的吞吐量。请参阅下图。
- 在多 CPU socket 服务器上,Redis 性能取决于 NUMA 配置和进程位置。最明显的效果是 redis-benchmark 结果看起来不确定,因为客户端和服务器进程随机分布在核心上。为了获得确定性结果,需要使用进程放置工具(在 Linux 上:taskset 或 numactl)。最有效的组合始终是将客户端和服务器放在同一 CPU 的两个不同核心上,以利用 L3 缓存。这里展示了对 3 种服务器 CPU(AMD Istanbul、Intel Nehalem EX 和 Intel Westmere)进行 4 KB SET 基准测试的一些结果,这些 CPU 的相对位置不同。请注意,此基准测试并非旨在比较 CPU 模型本身(因此未公开 CPU 的确切型号和频率)。
- 对于高端配置,客户端连接数也是一个重要因素。基于 epoll/kqueue,Redis 事件循环具有相当好的可扩展性。Redis 在超过 60000 个连接的情况下已进行过基准测试,并且在此条件下仍然能够维持 50000 q/s 的吞吐量。根据经验,一个拥有 30000 个连接的实例只能处理拥有 100 个连接时可达到吞吐量的一半。这里有一个示例,展示了 Redis 实例的吞吐量与连接数的关系
- 对于高端配置,可以通过调整网卡配置和相关的中断来实现更高的吞吐量。通过设置 Rx/Tx 网卡队列与 CPU 核心之间的亲和性,并激活 RPS (Receive Packet Steering) 支持,可以达到最佳吞吐量。有关更多信息,请参阅此帖子。使用大对象时,巨型帧(Jumbo frames)也可能提供性能提升。
- 根据平台的不同,Redis 可以针对不同的内存分配器(libc malloc、jemalloc、tcmalloc)进行编译,这些分配器在原始速度、内部和外部碎片方面可能具有不同的行为。如果您没有自己编译 Redis,可以使用 INFO 命令检查
mem_allocator
字段。请注意,大多数基准测试运行时间不够长,不足以产生明显的外部碎片(与生产环境中的 Redis 实例不同)。
其他需要考虑的事项
任何基准测试的一个重要目标是获得可重现的结果,以便可以将其与���他测试的结果进行比较。
- 一个好的做法是尽量在隔离的硬件上运行测试。如果不可能,则必须监控系统以检查基准测试是否受到某些外部活动的影响。
- 某些配置(台式机和笔记本电脑肯定是,某些服务器也是)具有可变的 CPU 核心频率机制。控制此机制的策略可以在操作系统级别设置。一些 CPU 模型在根据工作负载调整 CPU 核心频率方面比其他模型更积极。为了获得可重现的结果,最好为参与基准测试的所有 CPU 核心设置尽可能高的固定频率。
- 一个重要点是根据基准测试调整系统大小。系统必须有足够的 RAM 且不能发生交换。在 Linux 上,不要忘记正确设置
overcommit_memory
参数。请注意,32 位和 64 位 Redis 实例的内存占用量不同。 - 如果您计划在基准测试中使用 RDB 或 AOF,请检查系统中没有其他 I/O 活动。避免将 RDB 或 AOF 文件放在 NAS 或 NFS 共享上,或任何其他影响您网络带宽和/或延迟的设备上(例如,Amazon EC2 上的 EBS)。
- 将 Redis 日志级别(loglevel 参数)设置为 warning 或 notice。避免将生成的日志文件放在远程文件系统上。
- 避免使用可能改变基准测试结果的监控工具。例如,定期使用 INFO 收集统计信息可能没问题,但 MONITOR 将显著影响测量的性能。
不同 Redis 版本在裸金属服务器上的基准测试结果
至关重要的是,Redis 的性能在每个发布版本中都能无缝保持或提升。
为了评估这一点,我们使用 redis-benchmark
对一系列命令类型对独立 redis-server 上的已发布 Redis 版本(从 v2.6.0 开始)进行了基准测试,重复运行相同的基准测试多次,以确保其统计意义,并测量运行间方差。
使用的硬件平台是一台稳定的裸金属 HPE ProLiant DL380 Gen10 服务器,配备一个 Intel(R) Xeon(R) Gold 6230 CPU @ 2.10GHz,禁用 Intel HT 技术,禁用 CPU 频率缩放,所有可配置的 BIOS 和 CPU 系统设置都设置为性能模式。
该机器运行的是 Ubuntu 18.04 Linux release 4.15.0-123,Redis 使用 gcc 7.5.0 编译。所使用的基准测试客户端(redis-benchmark
)在所有测试中保持稳定,版本为 redis-benchmark 6.2.0 (git:445aa844)
。redis-server 和 redis-benchmark 进程都绑定到特定的物理核心。
所有测试均使用以下基准测试选项
- 测试是在 50 个并发客户端执行 500 万个请求的情况下进行的。
- 测试使用 loopback 接口执行。
- 测试在不使用 pipelining 的情况下执行。
- 使用的 payload 大小为 256 字节。
- 每个 redis-benchmark 进程使用 2 个线程,以确保基准测试客户端不是瓶颈。
- 对 Strings、Hashes、Sets 和 Sorted Sets 数据类型进行了基准测试。
下面按数据类型列出了获得的结果。
其他 Redis 基准测试工具
有几个第三方工具可用于对 Redis 进行基准测试。有关每个工具的目标和功能的更多信息,请参阅其文档。
- 来自 Redis Labs 的 memtier_benchmark 是一个用于生成 Redis 和 Memcache 流量并进行基准测试的 NoSQL 工具。
- 来自 Twitter 的 rpc-perf 是一个支持 Redis 和 Memcache 的 RPC 服务基准测试工具。
- 来自 Yahoo @Yahoo 的 YCSB 是一个基准测试框架,包含许多数据库的客户端,包括 Redis。