Redis 响应延迟问题排查 已翻译 100%

QLeelulu 投递于 2013/01/10 15:12 (共 32 段, 翻译完成于 03-09)
阅读 40426
收藏 113
15
加载中

本文将有助于你找出Redis 响应延迟的问题所在。

文中出现的延迟(latency)均指从客户端发出一条命令到客户端接受到该命令的反馈所用的最长响应时间。Reids通常处理(命令的)时间非常的慢,大概在次微妙范围内,但也有更长的情况出现。

王薇
王薇
翻译于 2013/01/10 19:28
3

计算延迟时间

如果你正在经历响应延迟问题,你或许能够根据应用程序的具体情况算出它的延迟响应时间,或者你的延迟问题非常明显,宏观看来,一目了然。不管怎样吧,用redis-cli可以算出一台Redis 服务器的到底延迟了多少毫秒。踹这句:

redis-cli --latency -h `host` -p `port`

 

王薇
王薇
翻译于 2013/01/10 19:42
2

网络和通信引起的延迟

当用户连接到Redis通过TCP/IP连接或Unix域连接,千兆网络的典型延迟大概200us,而Unix域socket可能低到30us。这完全基于你的网络和系统硬件。在通信本身之上,系统增加了更多的延迟(线程调度,CPU缓存,NUMA替换等等)。系统引起的延迟在虚拟机环境远远高于在物理机器环境。

mr.questionmark
mr.questionmark
翻译于 2013/01/11 06:17
1

实际情况是即使Redis处理大多数命令在微秒之下,客户机和服务器之间的交互也必然消耗系统相关的延迟。

一个高效的客户机因而试图通过捆绑多个命令在一起的方式减少交互的次数。服务器和大多数客户机支持这种方式。聚合命令象MSET/MGET也可以用作这个目的。从Redis 2.4版本起,很多命令对于所有的数据类型也支持可变参数。

mr.questionmark
mr.questionmark
翻译于 2013/01/11 06:31
2

这里有一些指导:

  • 如果你负担的起,尽可能的使用物理机而不是虚拟机来做服务器
  • 不要经常的connect/disconnect与服务器的连接(尤其是对基于web的应用),尽可能的延长与服务器连接的时间。
  • 如果你的客户端和服务器在同一台主机上,则使用Unix域套接字
  • 尽量使用聚合命令(MSET/MGET)或可变参数命令而不是pipelining
  • 如果可以尽量使用pipelining而不是序列的往返命令。
  • 针对不适合使用原始pipelining的情况,如某个命令的结果是后续命令的输入,在以后的版本中redis提供了对服务器端的lua脚本的支持,实验分支版本现在已经可以使用了。

在Linux上,你可以通过process placement(taskset)、cgroups、real-time priorities(chrt)、NUMA配置(numactl)或使用低延迟内核的方式来获取较低的延迟。请注意Redis 并不适合被绑到单个CPU核上。redis会在后台创建一些非常消耗CPU的进程,如bgsave和AOF重写,这些任务是绝对不能和主事件循环进程放在一个CPU核上的。

大多数情况下上述的优化方法是不需要的,除非你确实需要并且你对优化方法很熟悉的情况下再使用上述方法。


LoveFancy
LoveFancy
翻译于 2013/02/01 14:15
1

Redis的单线程属性

Redis 使用了单线程的设计, 意味着单线程服务于所有的客户端请求,使用一种复用的技术。这种情况下redis可以在任何时候处理单个请求, 所以所有的请求是顺序处理的。这和Node.js的工作方式很像, 所有的产出通常不会有慢的感觉,因为处理单个请求的时间非常短,但是最重要的是这些产品被设计为非阻塞系统调用,比如从套接字中读取或写入数据。

我提到过Redis从2.4版本后几乎是单线程的,我们使用线程在后台运行一些效率低下的I/O操作, 主要关系到硬盘I/O,但是这不改变Redis使用单线程处理所有请求的事实。

Richard_sun
Richard_sun
翻译于 2013/01/16 16:26
1

低效操作产生的延迟

单线程的一个结果是,当一个请求执行得很慢,其他的客户端调用就必须等待这个请求执行完毕。当执行GETSET或者 LPUSH 命令的时候这不是个问题,因为这些操作可在很短的常数时间内完成。然而,对于多个元素的操作,像SORT, LREM, SUNION 这些,做两个大数据集的交叉要花掉很长的时间。

文档中提到了所有操作的算法复杂性。 在使用一个你不熟悉的命令之前系统的检查它会是一个好办法。

可观
可观
翻译于 2013/01/18 16:28
2

如果你对延迟有要求,那么就不要执行涉及多个元素的慢操作,你可以使用Redis的replication功能,把这类慢操作全都放到replica上执行。

可以用Redis 的Slow Log 来监控慢操作。

此外,你可以用你喜欢的进程监控程序(top, htop, prstat, 等...)来快速查看Redis进程的CPU使用率。如果traffic不高而CPU占用很高,八成说明有慢操作。

可观
可观
翻译于 2013/01/25 18:46
1

延迟由fork产生

Redis不论是为了在后台生成一个RDB文件,还是为了当AOF持久化方案被开启时重写Append Only文件,都会在后台fork出一个进程。fork操作(在主线程中被执行)本身会引发延迟。在大多数的类unix操作系统中,fork是一个很消耗的操作,因为它牵涉到复制很多与进程相关的对象。而这对于分页表与虚拟内存机制关联的系统尤为明显

inphyy
inphyy
翻译于 2013/02/04 14:35
1

对于运行在一个linux/AMD64系统上的实例来说,内存会按照每页4KB的大小分页。为了实现虚拟地址到物理地址的转换,每一个进程将会存储一个分页表(树状形式表现),分页表将至少包含一个指向该进程地址空间的指针。所以一个空间大小为24GB的redis实例,需要的分页表大小为  24GB/4KB*8 = 48MB。

当一个后台的save命令执行时,实例会启动新的线程去申请和拷贝48MB的内存空间。这将消耗一些时间和CPU资源,尤其是在虚拟机上申请和初始化大块内存空间时,消耗更加明显。

inphyy
inphyy
翻译于 2013/02/04 12:40
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(18)

一叶舟troy
一叶舟troy

引用来自“黑桃”的评论

汗,对性能的追求无止境,但大多数应用的瓶颈并不在这里,花费大量时间来研究这些边角,是否真的值得?
在哪里呀
一叶舟troy
一叶舟troy
实例会启动新的线程去申请和拷贝48MB的内存空间 并没有占用很多空间呀
BuN_Ny
BuN_Ny

引用来自“xst”的评论

最近在研究或使用redis的可以加q群 (一九一六29202)
群主刚读完redis代码,可以帮童孩们解答问题。
直接拒绝。。
zhh5919
zhh5919
通过huge page,使用两倍的内存,而存储将不再是理论的突发事件。它真的会发生。这段翻译的比较挫啊!我第一次看的时候比较非常迷糊,索性看了原文。按照我的理解,With huge pages, using twice the memory while saving is not anymore a theoretical incident. It really happens.应该是说当我们使用了huge pages,执行bgsave时会使用双倍的内存折不再是一个理论上的突发事件,它真的会发生。bgsave时,fork虽然使用了COW,但同时伴随大量写操作,会产生大量的脏页,这些脏页需要执行真正的内存copy到子进程中,所以说理论上有两倍内存的可能。如使用huge page,内存页少了加重了这个可能
张丛武
好文
fzxu_05
fzxu_05
不错
fzxu_05
fzxu_05
不错
a
aochulai
这研究精神,佩服
-Snowolf-
-Snowolf-
mark
loongwong
loongwong
Mark先
返回顶部
顶部