Chinaunix首页 | 论坛 | 博客
  • 博客访问: 25304
  • 博文数量: 13
  • 博客积分: 464
  • 博客等级: 下士
  • 技术积分: 140
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-19 21:58
文章分类

全部博文(13)

分类: NOSQL

2016-12-27 11:19:40

原文


【Redis有多快】

Redis自带 redis-benchmark 工具,模拟N个Clients同时向Redis发送共M个请求的场景,类似Apache的 ab 工具

用法:
redis-benchmark [-h ] [-p ] [-c ] [-n [-k ]

选项:
 -h    待测试Redis的IP,默认为 127.0.0.1
 -p    待测试Redis的Port,默认为 6379
 -s    待测试Redis的Socket文件,如果给出会覆盖IP和Port
 -a    待测试Redis的认证密码
 -c    测试的并发连接数,默认为 50 个
 -n    测试共发出多少次请求,默认为 10万
 -d    SET和GET操作的数据大小,单位bytes,默认为 2字节
 --dbnum    在第几号DB上进行测试,默认为 0
 -k    请求执行后,连接是保持长连(1),还是断开重连(0),默认为 1
 -r    测试中,SET/GET/INCR的Key名为随机值,SADD的值为随机值,该参数用于指定随机值的个数,随机值为12位数字,范围从0到该参数值减1,例如 -r 100000,则随机值范围为000000000000~000000099999
 -P    指定管道(pipelining)每次发送的请求个数,默认为 1,表示不使用管道
 -q    简洁输出,只输出每秒query数
 --csv    CSV输出格式
 -l    循环测试,一直运行测试直到手动停止
 -t    只运行指定的测试项,列表用逗号分隔,例如 set,get,lpush
 -I    空闲模式,只是打开指定个数的连接,不发出任何请求

例如:
redis-benchmark -q -n 100000


【只运行指定的测试】

在执行redis-benchmark时,不必每次都运行所有的默认测试项,可以使用 -t 指定测试项

例如:只进行set和lpush操作的测试
$ redis-benchmark -t set,lpush -n 100000 -q


【指定键空间大小】

默认的测试只对单个Key进行操作,可以使用 -r选项 模拟巨大键空间的场景

例如:做一个用10万个KEY做百万次SET操作的测试
$ redis-benchmark -t set -r 100000 -n 1000000


【使用管道】

默认情况下,每个Client只有在得到前一条命令执行的回复后才会发送下一条命令,这意为Redis在每个Client的每条命令上都有一次读取回复操作,也就是RTT(往返传输用时)

Redis支持管道(pipelining),它可以一次发送多条命令,是一个经常被使用的特性,能够显著提升Redis每秒处理的请求数,明显提升性能

例如:使用长度为16的管道进行测试
$ redis-benchmark -n 1000000 -t set,get -P 16 -q


【陷阱和误区】

黄金规则:该基准测试只能用于Redis之间的比较
例如,不同Redis版本在同一负载下的对比,或相同版本Redis在不同操作类型下的对比

如果打算把Redis与其他对比,在评估时要考虑它们之间功能和技术的差异
- Redis是一个服务端,所有命令的执行过程都包含了网络上的传输往返,在这方面与嵌入式数据库(SQLite、BerkeleyDB等)对比是不适合的,因为执行中的最大耗时主要在网络层
- Redis所有命令都要求返回确认,而其他某些数据库是不需要的,例如MongoDB默认不要求写操作确认,把Redis和单向请求型的数据库对比,作用不大
- 向Redis循环发送命令是无法压测到Redis的,更像是在测量网络延迟,要真正测试Redis,需要打开多个连接,并发执行命令,或用管道(pipelining)汇集多条命令一起执行
- Redis是一个可以持久化数据的内存数据库,如果要将它与传统数据库(MySQL、PostgreSQL等)对比,需要开启AOF功能并制定数据同步策略
- Redis是单线程的,无法从多CPU上获益,所以将它与多线程数据库对比并不适合

一个普遍误解是,redis-benchmark是为了表现出Redis的一流性能而设计的,通过redis-benchmark得到的结果有点虚假,是真实应用达不到的,这是完全错误的,redis-benchmark是一个快速有效的方式,在给定的硬件平台上评估出Redis的性能,然而,这并不代表着该Redis的最大承载能力,实际上,使用管道(pipelining)可以轻易的编写出一个能产生更高吞吐量的程序,因为redis-benchmark的默认行为只是展现多连接下的并发吞吐量,没有使用管道或其他并行请求,要使用管道模式运行redis-benchmark达到更高吞吐量,需要明确给出-P选项

在很多基于Redis的真实应用里,确实使用了管道(pipelining)以有效的提升性能

基准测试应该以同一方式在要对比的数据库上执行相同的操作,所以用redis-benchmark的结果与其他基准测试的结果进行对比是无意义的,例如,Redis和Memcached在单线程模式下对比GET/SET操作,都是内存数据库,在协议层工作方式几乎相同,假设他们以各自的测试程序用近似的连接数执行相同的操作,对比才是有意义的

最后,当对一个非常高效的数据库进行压测时,可能很难使其饱和,有时性能的瓶颈是在客户端,而非数据库端,在这种情况下,客户端(基准测试程序)必须被修正或水平扩展,为了能达到最大吞吐量


【影响Redis性能的因素】

有多个因素直接影响到Redis的性能,在此提及是因为它们会改变基准测试的结果,若想在较低端的硬件上为多数应用提供良好的Redis性能时,请关注它们

- 网络的带宽和延迟通常对性能有直接影响,在执行压测前使用ping命令检查和查看客户端和服务端的网络延迟是个好方法,对于带宽,通常使用压测结果估算出吞吐量与实际的网络理论带宽进行对比,例如对4KB字符串压测结果为10万q/s,实际消耗带宽3.2Gbit/s,则适合跑在10Gbit/s的链路上,而不是1Gbit/s的,在很多现实情况下,Redis的吞吐量是被网络限制的,而不是CPU运算能力,要提升单机吞吐量可以考虑使用一块10Gbit/s的网卡,或多块1Gbit/s的网卡做bonding
- CPU是另一个重要因素,由于是单线程,Redis喜好有大缓存的高速CPU,而不是多核,在这方面,Intel目前是赢家,Redis在AMD CPU上的性能只有同规格的Intel CPU的一半,当客户端和服务端运行在相同规格的硬件上时,CPU是redis-benchmark的限制因素
- RAM的速度和内存带宽对全局性能有较小影响,对于较大对象(>10KB),影响会更大些,但是为了提升Redis性能去买昂贵的高速内存并不划算
- 在相同硬件的情况下,跑在VM里的Redis会慢些,如果条件允许,Redis更适合跑在物理机上,但这并不意为Reids在虚拟环境下就很慢,交付性能依然是很优秀的,并且多数严重的性能问题可能是虚拟环境不良导致的,如配置超分、高延迟的非本地磁盘,或是使用低速的fork系统调用的低版本虚拟软件
- 当Redis和压测程序运行在同一台机器上时,TCP/IP回路和Unix域套接字被使用,以Linux举例,Unix域套接字要比TCP/IP回路高出将近50%的吞吐量,如果使用管道(pipelining),TCP/IP回路的劣势就缩小了,redis-benchmark默认使用非管道的TCP/IP回路
- 当通过网络访问Redis时,若数据大小维持在网络包(ethernet packet)大小之下(大约1.5KB),使用管道(pipelining)聚合命令是非常高效的,实际上,处理结果集在1KB以下的查询的吞吐量几乎是相同的
- 在多CPU插槽的服务器上,Redis性能依赖于NUMA配置和程序执行位置,最明显的表现是redis-benchmark会因客户端和服务端执行在不同的处理器(core)上而得到不同的压测结果,要得到固定的压测结果,必须使用“进程定位工具”,如Linux上的numactl或taskset,最有效的组合是把客户端和服务端运行在同一CPU的二个不同的处理器上,这样有利于从L3缓存上获益
- 客户端连接数也是一项重要因素,基于epoll/kqueue技术,Redis的事件轮询是可扩展的,已有压测表明Redis在超过6万个连接时仍能支撑5万q/s,根据经验,有3万个连接时的处理吞吐量只有1百个连接时的一半
- 通过调优网卡(NIC)配置和相关中断可以提升到更高的吞吐量,将网卡的接收/发送(Rx/Tx)队列分别和指定的CPU核(core)进行绑定(affinity),启用RPS(Receive Packet Steering)特性,此方法用于单队列网卡在多CPU的环境下效果明显,另外,网卡的Jumbo frames特性可以将MTU(Maximum Transmission Unit)从默认的1500提升到9000(就是帧的大小,单位byte),在处理大对象时能带来性能提升
- 以操作系统为基础,可以用不同的内存分配模块去编译Redis,如libc malloc、jemalloc或tcmalloc,根据设备速度和内存碎片情况,它们会有不同的处理行为,如果没有自己编译Redis,可以使用INFO命令查看mem_allocator字段得知使用哪种内存分配方式,请记住,由于压测工具不会长时间运行,所以无法形成线上环境那样明显的外部碎片

科普:
内存碎片分为内部(internal)和外部(external)两种
- 内部碎片,OS以page为最小单位分配内存,page默认大小为4KB,当内存分配给进程后,由于操作的数据大小可能与page大小不一致,例如进程操作的数据为3K,这样每个page都会有1K的空余,这就形成了碎片,由于这块内存空间有所属的进程,所以称为(进程)内部碎片,尤其是分配给进程的最后一个内存page,进程很可能用不满或用不了,例如进程申请21K内存,而为了4K对齐,系统会分配给进程24K内存,多给的3K进程是不会使用的,这种余下用不满或用不了的内存同样也是内部碎片
- 外部碎片,内存以page为单位被顺序分配,但由于每个进程每次请求和释放的内存大小不同,就会形成一些因为太小而无法被OS分配给进程的内存空间,由于它们不属于任何进程,所以称为外部碎片,例如进程A分配到10个page,进程B分配到10个page,A释放内存,C从A还给OS的内存空间中分配到8个,剩余2个page,此时A再申请5个page的话,由于空闲的2个page不够用,所以只能在B的那10个page之后的内存空间里分配,于是空闲的2个page就成了外部碎片


【其它考量事宜】

任何基准测试都有同一个重要目标:可重现的压测结果,才能用于与其他压测结果进行比较

- 压测应该尽量运行在独立的硬件上,如果做不到,则必须监控系统以检查压测不被其它活动干扰
- 有些服务器有可变的CPU主频技术,控制该技术的策略可以在OS层设置,部分型号的CPU在调整主频后的负载表现要比其他的更激进些,为了得到可重现的压测结果,最好在压测时把所有CPU都设置到最高的固定主频
- 一个要点是,为压测准备好系统,必须有足够的内存(RAM)而不是SWAP,在Linux上,不要忘记设置overcommit_memory参数为1,32位和64位的Redis在内存操作上绝对是不同的
- 如果在压测中启用RDB或AOF,要检查系统中没有其他IO活动,避免把RDB或AOF文件放置在NAS或NFS上,或其他影响到网络带宽和网络延迟的设备上,如Amazon EC2上的EBS
- 设置Redis的日志级别为warning或notice,而不是verbose或debug,避免把生成的日志文件存放在远程文件系统上
- 避免使用会影响到压测结果的监控工具,例如以固定间隔周期执行INFO命令查看统计信息是较好的方法,而MONITOR命令会明显的影响到压测性能



阅读(731) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Redis文档翻译

给主人留下些什么吧!~~