诊断延迟问题
查找响应缓慢的原因
本文档将帮助您理解如果您在使用Redis时遇到延迟问题,可能是什么原因。
在这种情况下,延迟是指客户端发出命令到客户端接收到命令回复之间的最大延迟。通常Redis的处理时间极低,在亚微秒范围内,但在某些条件下会导致更高的延迟数值。
我时间不多,给我清单
以下文档对于以低延迟方式运行Redis非常重要。然而,我理解我们都很忙,所以让我们从一个快速检查清单开始。如果您未能遵循这些步骤,请返回此处阅读完整的文档。
- 确保你没有运行阻塞服务器的慢命令。使用Redis的慢日志功能来检查这一点。
- 对于EC2用户,请确保使用基于HVM的现代EC2实例,如m3.medium。否则fork()会非常慢。
- 必须从内核中禁用透明大页。使用
echo never > /sys/kernel/mm/transparent_hugepage/enabled
来禁用它们,并重新启动您的Redis进程。 - 如果您使用的是虚拟机,可能存在与Redis无关的固有延迟。使用
./redis-cli --intrinsic-latency 100
检查您可以从运行时环境中预期的最小延迟。注意:您需要在服务器上运行此命令,而不是在客户端。 - 启用并使用Redis的延迟监控功能,以便获取Redis实例中延迟事件和原因的可读描述。
一般来说,使用下表来权衡持久性与延迟/性能,从更强的安全性到更好的延迟排序。
- AOF + fsync always: 这是非常慢的,只有在你知道自己在做什么的情况下才应该使用它。
- AOF + 每秒 fsync:这是一个很好的折衷方案。
- AOF + 每秒 fsync + no-appendfsync-on-rewrite 选项设置为 yes:这与上述情况相同,但在重写期间避免 fsync 以降低磁盘压力。
- AOF + fsync never. 在这种设置中,fsync由内核决定,磁盘压力和延迟峰值风险更小。
- RDB。在这里,根据您配置的保存触发器,您有广泛的权衡选择。
现在,对于有15分钟时间的人来说,详情如下...
测量延迟
如果您正在经历延迟问题,您可能知道如何在应用程序的上下文中测量它,或者您的延迟问题甚至在宏观上也非常明显。然而,redis-cli 可以用来以毫秒为单位测量 Redis 服务器的延迟,只需尝试:
redis-cli --latency -h `host` -p `port`
使用内部Redis延迟监控子系统
自 Redis 2.8.13 起,Redis 提供了延迟监控功能,能够采样不同的执行路径以了解服务器在何处阻塞。这使得调试本文档中描述的问题变得更加简单,因此我们建议尽快启用延迟监控。请参阅延迟监控文档。
虽然延迟监控的采样和报告功能将使您更容易理解Redis系统中延迟的来源,但仍建议您广泛阅读此文档,以更好地理解Redis和延迟峰值的问题。
延迟基准
有一种延迟是运行Redis的环境固有的,即由操作系统内核提供的延迟,如果你使用虚拟化,还包括你使用的虚拟机管理程序提供的延迟。
虽然这种延迟无法消除,但研究它很重要,因为它是基线,换句话说,由于内核或虚拟机管理程序的实现或设置,您无法实现比环境中每个进程所经历的延迟更好的Redis延迟。
我们称这种延迟为固有延迟,并且从Redis版本2.8.7开始,redis-cli
能够测量它。这是在入门级服务器上运行的Linux 3.11.0下的一个示例运行。
注意:参数 100
是测试将执行的秒数。
我们运行测试的时间越长,就越有可能发现延迟峰值。100 秒通常是合适的,但你可能希望在不同的时间进行几次运行。请注意,该测试对 CPU 要求很高,可能会使系统中的单个核心饱和。
$ ./redis-cli --intrinsic-latency 100
Max latency so far: 1 microseconds.
Max latency so far: 16 microseconds.
Max latency so far: 50 microseconds.
Max latency so far: 53 microseconds.
Max latency so far: 83 microseconds.
Max latency so far: 115 microseconds.
注意:在这种特殊情况下,redis-cli 需要在你运行或计划运行 Redis 的服务器上运行,而不是在客户端上。在这种特殊模式下,redis-cli 根本不连接到 Redis 服务器:它只会尝试测量内核不提供 CPU 时间来运行 redis-cli 进程本身的最大时间。
在上述示例中,系统的固有延迟仅为0.115毫秒(或115微秒),这是一个好消息,但请记住,固有延迟可能会随着时间的推移而变化,具体取决于系统的负载。
虚拟化环境不会显示很好的数字,特别是在高负载或有嘈杂邻居的情况下。以下是在运行Redis和Apache的Linode 4096实例上的运行结果:
$ ./redis-cli --intrinsic-latency 100
Max latency so far: 573 microseconds.
Max latency so far: 695 microseconds.
Max latency so far: 919 microseconds.
Max latency so far: 1606 microseconds.
Max latency so far: 3191 microseconds.
Max latency so far: 9243 microseconds.
Max latency so far: 9671 microseconds.
这里我们有一个9.7毫秒的内在延迟:这意味着我们不能向Redis要求更好的性能。然而,在不同的虚拟化环境中,在高负载或有干扰的情况下,其他运行可能会显示出更差的值。我们能够在其他方面运行正常的系统中测量到高达40毫秒的延迟。
由网络和通信引起的延迟
客户端通过TCP/IP连接或Unix域连接连接到Redis。1 Gbit/s网络的典型延迟约为200微秒,而使用Unix域套接字的延迟可以低至30微秒。这实际上取决于您的网络和系统硬件。除了通信本身之外,系统还会增加一些额外的延迟(由于线程调度、CPU缓存、NUMA布局等)。在虚拟化环境中,系统引起的延迟明显高于物理机器。
结果是,即使Redis在亚微秒范围内处理大多数命令,执行多次往返服务器的客户端也必须支付这些网络和系统相关的延迟。
因此,一个高效的客户端会尝试通过将多个命令管道化在一起来限制往返次数。这完全由服务器和大多数客户端支持。像MSET/MGET这样的聚合命令也可以用于此目的。从Redis 2.4开始,许多命令还支持所有数据类型的可变参数。
以下是一些指导原则:
- 如果可以负担得起,建议使用物理机而不是虚拟机来托管服务器。
- 不要系统性地连接/断开与服务器的连接(特别是对于基于Web的应用程序)。尽可能保持连接的长久性。
- 如果您的客户端与服务器位于同一主机上,请使用Unix域套接字。
- 优先使用聚合命令(MSET/MGET),或者使用带有可变参数的命令(如果可能),而不是管道。
- 如果可能,优先使用管道化而不是一系列的往返操作。
- Redis 支持 Lua 服务器端脚本,以处理不适合原始流水线的情况(例如,当一个命令的结果是后续命令的输入时)。
在Linux上,有些人可以通过调整进程位置(taskset)、cgroups、实时优先级(chrt)、NUMA配置(numactl)或使用低延迟内核来实现更好的延迟。请注意,原版的Redis并不适合绑定在单个CPU核心上。Redis可以派生后台任务,这些任务可能会非常消耗CPU,比如BGSAVE
或BGREWRITEAOF
。这些任务绝不能与主事件循环运行在同一个核心上。
在大多数情况下,不需要进行这种系统级别的优化。只有在需要并且熟悉它们的情况下才进行。
Redis的单线程特性
Redis 使用了一种主要是单线程的设计。这意味着一个单一的进程通过一种称为多路复用的技术来服务所有客户端请求。这意味着 Redis 在任何一个给定的时刻只能服务一个请求,因此所有的请求都是按顺序服务的。这与 Node.js 的工作方式非常相似。然而,这两种产品通常不被认为是慢的。这部分是由于完成单个请求所需的时间很短,但主要是因为这些产品设计为在系统调用(如从套接字读取数据或向套接字写入数据)上不会阻塞。
我说Redis是主要单线程的,因为实际上从Redis 2.4开始,我们在Redis中使用线程来在后台执行一些慢速I/O操作,主要与磁盘I/O相关,但这并不改变Redis使用单线程处理所有请求的事实。
由慢命令产生的延迟
单线程的一个后果是,当一个请求处理缓慢时,所有其他客户端都将等待该请求被处理。在执行普通命令时,比如GET
或SET
或LPUSH
,这根本不是问题,因为这些命令在恒定(且非常短)的时间内执行。然而,有些命令操作许多元素,比如SORT
、LREM
、SUNION
等。例如,取两个大集合的交集可能需要相当长的时间。
所有命令的算法复杂度都有文档记录。在使用你不熟悉的命令时,系统性地检查它是一个良好的实践。
如果您有延迟问题,您应该避免对由许多元素组成的值使用慢命令,或者您应该使用Redis复制运行一个副本,在那里运行所有慢查询。
可以使用Redis的慢日志功能来监控慢命令。
此外,您可以使用您喜欢的进程监控程序(如top、htop、prstat等)快速检查主Redis进程的CPU消耗。如果CPU消耗高而流量不高,通常表明使用了慢命令。
重要提示:执行慢命令产生延迟的一个非常常见的来源是在生产环境中使用KEYS
命令。如Redis文档中所记录的,KEYS
应仅用于调试目的。自Redis 2.8以来,引入了新命令以逐步迭代键空间和其他大型集合,请查看SCAN
、SSCAN
、HSCAN
和ZSCAN
命令以获取更多信息。
由fork产生的延迟
为了在后台生成RDB文件,或者在启用AOF持久化时重写仅追加文件,Redis必须派生后台进程。 fork操作(在主线程中运行)本身可能会引起延迟。
在大多数类Unix系统上,分叉是一项昂贵的操作,因为它涉及复制大量与进程相关的对象。这对于与虚拟内存机制相关的页表尤其如此。
例如,在Linux/AMD64系统上,内存被划分为4 kB的页面。 为了将虚拟地址转换为物理地址,每个进程都存储一个页表(实际上表示为树),其中至少包含进程地址空间每个页面的指针。因此,一个24 GB的大型Redis实例需要一个24 GB / 4 kB * 8 = 48 MB的页表。
当执行后台保存时,此实例将需要被分叉,这将涉及分配和复制48 MB的内存。这需要时间和CPU,特别是在虚拟机上,分配和初始化大块内存可能会非常昂贵。
不同系统中的Fork时间
现代硬件在复制页表方面非常快,但Xen不是。
Xen的问题不是虚拟化特有的,而是Xen特有的。例如,使用VMware或Virtual Box不会导致fork时间变慢。
下表比较了不同Redis实例大小的fork时间。数据是通过执行BGSAVE并查看INFO
命令输出中的latest_fork_usec
字段获得的。
然而,好消息是基于EC2 HVM的新型实例在fork时间上表现更好,几乎与物理服务器相当,因此例如使用m3.medium(或更好)的实例将提供良好的结果。
- VMware上的Linux beefy虚拟机 6.0GB RSS在77毫秒内完成fork(每GB 12.8毫秒)。
- 在物理机上运行的Linux(未知硬件) 6.1GB RSS在80毫秒内分叉(每GB 13.1毫秒)
- 在物理机上运行的Linux(Xeon @ 2.27Ghz) 6.9GB RSS在62毫秒内分叉(每GB 9毫秒)。
- 6sync上的Linux虚拟机(KVM) 360 MB RSS在8.2毫秒内分叉(每GB 23.3毫秒)。
- EC2上的Linux虚拟机,旧实例类型(Xen) 6.1GB RSS在1460毫秒内分叉(每GB 239.3毫秒)。
- EC2上的Linux虚拟机,新实例类型(Xen) 1GB RSS在10毫秒内分叉(每GB 10毫秒)。
- Linode上的Linux虚拟机(Xen) 0.9GB RSS在382毫秒内分叉(每GB 424毫秒)。
正如你所看到的,某些在Xen上运行的虚拟机性能下降幅度在一个数量级到两个数量级之间。对于EC2用户,建议很简单:使用基于现代HVM的实例。
由透明大页引起的延迟
不幸的是,当Linux内核启用了透明大页时,Redis在使用fork
调用以便持久化到磁盘后,会遭受很大的延迟惩罚。大页是以下问题的原因:
- 调用Fork时,会创建两个共享大页面的进程。
- 在一个繁忙的实例中,几个事件循环的运行会导致命令针对数千个页面,导致几乎整个进程内存的写时复制。
- 这将导致高延迟和高内存使用。
确保使用以下命令禁用透明大页:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
由交换(操作系统分页)引起的延迟
Linux(以及许多其他现代操作系统)能够将内存页面从内存重新定位到磁盘,反之亦然,以便高效地使用系统内存。
如果Redis页面被内核从内存移动到交换文件,当Redis使用存储在该内存页面中的数据时(例如访问存储在该内存页面中的键),内核将停止Redis进程以便将该页面移回主内存。这是一个涉及随机I/O的慢操作(与访问已经在内存中的页面相比),并将导致Redis客户端经历异常的延迟。
内核将Redis内存页面重新定位到磁盘上,主要有三个原因:
- 系统处于内存压力之下,因为正在运行的进程需要比可用物理内存更多的内存。这个问题的最简单实例就是Redis使用的内存超过了可用内存。
- Redis实例的数据集,或数据集的一部分,大部分是完全空闲的(从未被客户端访问过),因此内核可能会将空闲的内存页面交换到磁盘上。这个问题非常罕见,因为即使是一个稍微慢一点的实例也会经常访问所有的内存页面,迫使内核将所有页面保留在内存中。
- 某些进程在系统上生成了大量的读或写I/O。由于文件通常会被缓存,这往往会增加内核的文件系统缓存压力,从而导致交换活动。请注意,这包括Redis RDB和/或AOF后台线程,它们可能会生成大文件。
幸运的是,Linux 提供了很好的工具来调查这个问题,所以当怀疑由于交换导致的延迟时,最简单的事情就是检查是否是这种情况。
首先要做的是检查Redis在磁盘上交换的内存量。为此,您需要获取Redis实例的pid:
$ redis-cli info | grep process_id
process_id:5454
现在进入此进程的 /proc 文件系统目录:
$ cd /proc/5454
在这里,您会找到一个名为smaps的文件,它描述了Redis进程的内存布局(假设您使用的是Linux 2.6.16或更新版本)。 该文件包含了关于我们进程内存映射的非常详细的信息,其中一个名为Swap的字段正是我们所需要的。然而, 由于smaps文件包含了我们Redis进程的不同内存映射(进程的内存布局比简单的线性页数组更复杂),所以并不只有一个交换字段。
由于我们对进程交换的所有内存感兴趣,首先要做的是在所有文件中搜索Swap字段:
$ cat smaps | grep 'Swap:'
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 12 kB
Swap: 156 kB
Swap: 8 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 4 kB
Swap: 0 kB
Swap: 0 kB
Swap: 4 kB
Swap: 0 kB
Swap: 0 kB
Swap: 4 kB
Swap: 4 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
Swap: 0 kB
如果所有内容都是0 kB,或者有零星的4k条目,那么一切完全正常。实际上,在我们的示例实例中(一个真实网站运行Redis并每秒服务数百用户),有一些条目显示了更多的交换页面。为了调查这是否是一个严重的问题,我们更改了命令以打印内存映射的大小:
$ cat smaps | egrep '^(Swap|Size)'
Size: 316 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 8 kB
Swap: 0 kB
Size: 40 kB
Swap: 0 kB
Size: 132 kB
Swap: 0 kB
Size: 720896 kB
Swap: 12 kB
Size: 4096 kB
Swap: 156 kB
Size: 4096 kB
Swap: 8 kB
Size: 4096 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 1272 kB
Swap: 0 kB
Size: 8 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 16 kB
Swap: 0 kB
Size: 84 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 8 kB
Swap: 4 kB
Size: 8 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 4 kB
Swap: 4 kB
Size: 144 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 4 kB
Swap: 4 kB
Size: 12 kB
Swap: 4 kB
Size: 108 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 272 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
从输出中可以看出,有一个720896 kB的映射(只有12 kB被交换),另一个映射中有156 kB被交换:基本上我们的内存中只有非常小的一部分被交换,因此这不会造成任何问题。
如果进程内存中有大量数据被交换到磁盘上,那么你的延迟问题很可能与交换有关。如果你的Redis实例遇到这种情况,你可以使用vmstat命令进一步验证:
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 3980 697932 147180 1406456 0 0 2 2 2 0 4 4 91 0
0 0 3980 697428 147180 1406580 0 0 0 0 19088 16104 9 6 84 0
0 0 3980 697296 147180 1406616 0 0 0 28 18936 16193 7 6 87 0
0 0 3980 697048 147180 1406640 0 0 0 0 18613 15987 6 6 88 0
2 0 3980 696924 147180 1406656 0 0 0 0 18744 16299 6 5 88 0
0 0 3980 697048 147180 1406688 0 0 0 4 18520 15974 6 6 88 0
^C
对于我们需求来说,输出中感兴趣的部分是两列si和so,它们计算了从/到交换文件交换的内存量。如果你在这两列中看到非零计数,那么你的系统中存在交换活动。
最后,iostat 命令可用于检查系统的全局 I/O 活动。
$ iostat -xk 1
avg-cpu: %user %nice %system %iowait %steal %idle
13.55 0.04 2.92 0.53 0.00 82.95
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util
sda 0.77 0.00 0.01 0.00 0.40 0.00 73.65 0.00 3.62 2.58 0.00
sdb 1.27 4.75 0.82 3.54 38.00 32.32 32.19 0.11 24.80 4.24 1.85
如果你的延迟问题是由于Redis内存被交换到磁盘上,你需要降低系统中的内存压力,要么在Redis使用的内存超过可用内存时增加更多的RAM,要么避免在同一系统中运行其他消耗大量内存的进程。
由于AOF和磁盘I/O导致的延迟
另一个延迟的来源是由于Redis的仅追加文件支持。 AOF基本上使用两个系统调用来完成其工作。一个是 write(2),用于将数据写入仅追加文件,另一个是 fdatasync(2),用于将内核文件缓冲区刷新到磁盘,以确保用户指定的持久性级别。
write(2) 和 fdatasync(2) 调用都可能是延迟的来源。 例如,write(2) 在系统范围内同步进行时,或者当输出缓冲区已满且内核需要刷新到磁盘以接受新写入时,可能会阻塞。
fdatasync(2) 调用是延迟的一个较差来源,因为在许多内核和文件系统的组合中,它可能需要几毫秒到几秒钟才能完成,特别是在有其他进程进行I/O的情况下。因此,从 Redis 2.4 开始,Redis 尽可能在不同的线程中执行 fdatasync(2) 调用。
我们将看到在使用AOF文件时,配置如何影响延迟的数量和来源。
AOF可以通过appendfsync配置选项以三种不同的方式在磁盘上执行fsync(此设置可以在运行时使用CONFIG SET命令进行修改)。
-
当appendfsync设置为no时,Redis不执行fsync。 在这种配置下,唯一的延迟来源可能是write(2)。 当这种情况发生时,通常没有解决方案,因为磁盘无法应对Redis接收数据的速度,但如果磁盘没有被其他进行I/O的进程严重拖慢,这种情况并不常见。
-
当appendfsync设置为everysec时,Redis每秒执行一次fsync。它使用一个不同的线程,如果fsync仍在进行中,Redis会使用一个缓冲区来延迟write(2)调用最多两秒钟(因为在Linux上,如果对同一文件进行fsync,write会阻塞)。然而,如果fsync耗时过长,Redis最终会执行write(2)调用,即使fsync仍在进行中,这可能会导致延迟。
-
当appendfsync设置为always时,每次写操作都会在执行fsync后向客户端回复OK代码(实际上Redis会尝试将同时执行的多个命令合并为一个fsync)。在这种模式下,性能通常非常低,强烈建议使用快速的磁盘和能够在短时间内执行fsync的文件系统实现。
大多数Redis用户会为appendfsync配置指令选择no或everysec设置。为了最小化延迟,建议避免在同一系统中运行其他进行I/O操作的进程。使用SSD硬盘也会有所帮助,但通常即使是非SSD硬盘,在磁盘空闲时,Redis写入仅追加文件而不执行任何寻道操作,也能表现良好。
如果你想调查与仅追加文件相关的延迟问题,你可以在Linux下使用strace命令:
sudo strace -p $(pidof redis-server) -T -e trace=fdatasync
上述命令将显示Redis在主线程中执行的所有fdatasync(2)系统调用。使用上述命令,当appendfsync配置选项设置为everysec时,您将看不到后台线程执行的fdatasync系统调用。为了查看这些调用,只需在strace命令中添加-f开关。
如果您愿意,您还可以使用以下命令查看 fdatasync 和 write 系统调用:
sudo strace -p $(pidof redis-server) -T -e trace=fdatasync,write
然而,由于write(2)也用于向客户端套接字写入数据,这可能会显示太多与磁盘I/O无关的内容。显然,没有办法告诉strace只显示慢速系统调用,所以我使用以下命令:
sudo strace -f -p $(pidof redis-server) -T -e trace=fdatasync,write 2>&1 | grep -v '0.0' | grep -v unfinished
由过期产生的延迟
Redis 以两种方式驱逐过期的键:
- 一种懒惰的方式是在命令请求一个键时使其过期,但发现它已经过期。
- 一种主动方式每100毫秒使一些键过期。
主动过期设计为自适应的。每100毫秒(每秒10次)启动一个过期周期,并将执行以下操作:
- 采样
ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP
键,淘汰所有已过期的键。 - 如果发现超过25%的键已过期,则重复。
鉴于ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP
默认设置为20,并且该过程每秒执行十次,通常每秒只有200个键会被主动过期。这足以在即使长时间未访问已过期键的情况下快速清理数据库,因此惰性算法没有帮助。同时,每秒仅过期200个键对Redis实例的延迟没有影响。
然而,该算法是自适应的,如果在采样的键集中发现超过25%的键已经过期,它将循环。但考虑到我们每秒运行该算法十次,这意味着在我们的随机样本中超过25%的键在同一秒内过期的不幸事件至少会发生。
基本上这意味着如果数据库在同一秒内有许多、许多键过期,并且这些键至少占当前设置了过期时间的键的25%,Redis可能会阻塞,以便将已过期的键的百分比降至25%以下。
这种方法是为了避免为已经过期的键使用过多的内存,通常这是完全无害的,因为大量键在同一秒内过期的情况很奇怪,但用户广泛使用EXPIREAT
并设置相同的Unix时间并非不可能。
简而言之:请注意,许多键同时过期可能是延迟的一个来源。
Redis 软件看门狗
Redis 2.6 引入了 Redis 软件看门狗,这是一个调试工具,旨在跟踪那些由于某种原因而无法使用常规工具分析的延迟问题。
软件看门狗是一个实验性功能。虽然它设计用于生产环境,但在继续之前应小心备份数据库,因为它可能会与Redis服务器的正常执行产生意外的交互。
重要的是,只有在无法通过其他方式跟踪问题时,才将其作为最后手段使用。
这是这个功能的工作原理:
- 用户使用
CONFIG SET
命令启用软件看门狗。 - Redis 开始持续监控自身。
- 如果Redis检测到服务器被阻塞在某些操作中,这些操作返回速度不够快,可能是延迟问题的根源,那么会在日志文件中记录一个关于服务器被阻塞位置的低级别报告。
- 用户通过Redis Google Group联系开发者,在消息中包含监视报告。
请注意,此功能无法通过redis.conf文件启用,因为它设计为仅在已经运行的实例中启用,并且仅用于调试目的。
要启用该功能,只需使用以下内容:
CONFIG SET watchdog-period 500
周期以毫秒为单位指定。在上面的示例中,我指定仅在服务器检测到500毫秒或更长的延迟时记录延迟问题。最小可配置周期为200毫秒。
当你完成软件看门狗的使用后,你可以通过将watchdog-period
参数设置为0来关闭它。重要提示:请记住这样做,因为让实例在看门狗开启的状态下运行超过所需时间通常不是一个好主意。
以下是软件看门狗检测到延迟超过配置的延迟时,您将在日志文件中看到的打印示例:
[8547 | signal handler] (1333114359)
--- WATCHDOG TIMER EXPIRED ---
/lib/libc.so.6(nanosleep+0x2d) [0x7f16b5c2d39d]
/lib/libpthread.so.0(+0xf8f0) [0x7f16b5f158f0]
/lib/libc.so.6(nanosleep+0x2d) [0x7f16b5c2d39d]
/lib/libc.so.6(usleep+0x34) [0x7f16b5c62844]
./redis-server(debugCommand+0x3e1) [0x43ab41]
./redis-server(call+0x5d) [0x415a9d]
./redis-server(processCommand+0x375) [0x415fc5]
./redis-server(processInputBuffer+0x4f) [0x4203cf]
./redis-server(readQueryFromClient+0xa0) [0x4204e0]
./redis-server(aeProcessEvents+0x128) [0x411b48]
./redis-server(aeMain+0x2b) [0x411dbb]
./redis-server(main+0x2b6) [0x418556]
/lib/libc.so.6(__libc_start_main+0xfd) [0x7f16b5ba1c4d]
./redis-server() [0x411099]
------
注意:在示例中使用了DEBUG SLEEP命令以阻塞服务器。如果服务器在不同的上下文中阻塞,堆栈跟踪会有所不同。
如果您碰巧收集了多个看门狗堆栈跟踪,建议您将所有内容发送到Redis Google Group:我们获得的跟踪越多,就越容易理解您的实例存在的问题。