Redis延迟监控框架详解

Redis经常在一些要求非常苛刻的情况中使用,它的每个实例每秒钟都会处理大量的查询请求。与此同时,平均响应时间和最坏情况延时对于延迟时间的要求非常严格。

虽然Redis是一种内存系统,但是它会以不同的方式处理操作系统,例如,在将数据持久化至磁盘中时。除此之外,Redis还实现了一组丰富的命令。某些命令运行速度很快,时间复杂度为O(1)或O(logN);其他命令运行速度较慢,时间复杂度为O(N),它们可能会导致延迟飙升。

最后,Redis是单线程工作的:从每个CPU核心能够处理的工作负载来看,以及Redis提供的延迟数据来看,单线程模式通常是有优势的;但是,Redis同时也对延迟时间提出了挑战,因为单线程必须能够增量地处理某些任务,比如键过期,Redis需要以一种不影响为其他客户端提供服务的方式处理这些任务。

由于上述种种原因,Redis 2.8.13引入了一个新特性,叫做延迟监控(Latency Monitoring),它可以帮助用户检查和定位可能的延迟问题。延迟监控由下面的几个组件构成:

  • 延迟挂钩:这个组件会对延迟敏感的各种代码路径进行采样。
  • 时间序列:这个组件会记录由各种事件造成的延迟飙升。
  • 报告引擎:这个组件会从时间序列中取出原始数据。
  • 分析引擎:这个组件会根据测量方法向用户提供易读的报告和提示信息。

本文只会详细描述延迟监控子系统的各项功能。如果想要了解如何检查和定位Redis的延迟问题,请参考《Redis延迟问题的排查方法》。

一、事件和时间序列

不同的受监控代码路径具有不同的名称,这些名称也被称为事件。例如,command是一个事件,可用于测量执行速度较慢的命令,这些命令可能会导致延迟飙升;而fast-command也是一个事件,可用于监控执行速度较快的命令,这些命令的时间复杂度为O(1)或O(LogN)。其他事件都没有通用性,这些事件可以分别用于监控Redis执行的某个非常具体的操作。例如,fork事件只能监控Redis执行fork(2)系统调用所消耗的时间。

当事件的运行时间超过已配置的延迟阈值时,便会发生延迟飙升。每个受监控的事件都有一个独立的时间序列。时间序列的工作原理如下所示:

  • 每次发生延迟飙升时,Redis便会将其记录在合适的时间序列中。
  • 每个时间序列都是由160个元素组成的。
  • 每个元素都是一对值:一个值是发生延迟飙升时的UNIX时间戳;另一个值是事件运行耗费的时间,以毫秒为单位。
  • 如果相同事件的多次延迟飙升连续发生,那么它们便会被合并为一次延迟飙升(取最大的延迟时间)。因此,即使某个给定事件连续发生了多次延迟飙升,如果用户将延迟阈值设置得太低,那么至少会有180秒的历史数据是有效的。
  • 每个元素都会记录历史最大延迟时间。

二、如何启用延迟监控功能

相同的延迟时间,对于一些用例来说就是高延迟,但是对于另一些用例来说却是低延迟,这是为什么呢?对于一些应用程序来说,所有的查询操作都必须在1毫秒之内完成;但是对于另一些应用程序来说,少数客户端有时候却能接受2秒的延迟时间。

如果想要启用延迟监控功能,那么首先需要设置一个延迟阈值(Latency Threshold),单位为毫秒。只有执行时间超过指定阈值的事件才会被记录为延迟飙升的事件。用户应当根据自身需求,合理地设置延迟阈值。例如,对于某个基于Redis的应用程序来说,如果它能够接受的最大延迟时间是100毫秒,那么这个阈值就应当设置为100毫秒,这样便能将导致服务器阻塞时间等于或超过100毫秒的所有事件全部记录下来。

你可以在运行时启用延迟监控功能,这是非常简单的。你可以在生产环境的服务器中运行以下命令:

  1. CONFIG SET latency-monitor-threshold 100

在默认情况下,即使延迟监控功能几乎不会造成任何实际的性能开销,Redis也会禁用这项监控功能(将延迟阈值设置为0)。然而,虽然延迟监控功能需要使用的内存非常少,但是也不能毫无理由地提高工作正常的Redis实例的内存使用率基线。

三、如何使用LATENCY命令

LATENCY命令是用户和延迟监控子系统之间的操作界面。正如很多其他的Redis命令一样,LATENCY命令也可以接受多个不同的子命令,每个子命令都具有不同的功能。下文将会详述每个子命令的使用方法和功能。

1. LATENCY LATEST

LATENCY LATEST命令会报告日志中最近的延迟事件。每个事件都具有以下字段:

  • 事件名称
  • 事件最近一次发生延迟飙升的UNIX时间戳
  • 事件最近一次的延迟时间(以毫秒为单位)
  • 事件的历史最大延迟时间

上述的历史最大延迟时间并不真的是从Redis实例启动至今的最大延迟时间,因为你可以使用LATENCY RESET命令重置事件的历史数据,这个命令在下文会有描述。

LATENCY LATEST命令的使用示例如下图所示:

LATENCY LATEST命令示例

2. LATENCY HISTORY event-name

当你需要从事件的时间序列中获取原始数据时,可以使用LATENCY HISTORY命令,获取的数据格式是成对的时间戳-延迟时间。这个命令最多可以获取给定事件的最近160个元素。如果某个应用程序想要监控延迟时间、显示图表等等,那么它可能会从事件的时间序列中获取原始数据。

LATENCY HISTORY命令的使用示例如下图所示:

LATENCY HISTORY命令示例

3. LATENCY RESET [event-name … event-name]

LATENCY RESET命令,如果调用时没有使用任何参数,那么便会重置所有的事件,丢弃当前已经记录的延迟飙升事件,并且重置最大延迟时间寄存器。

如果调用时使用事件名称作为参数,那么便会只重置指定的事件。这个命令会返回在命令执行期间被重置的事件时间序列的数量。

4. LATENCY GRAPH event-name

这个命令会为指定的事件产生一个ASCII风格的图表:

LATENCY GRAPH命令示例

在每个图列下方的纵向标签表示相应事件是在多久之前发生的,以秒、分钟、小时或天为单位。例如,“39s”表示图表的第一个事件是在15秒之前发生的。

这个命令会在延迟的最大-最小的范围之内,规格化显示图表。因此,较低行中的_符号表示最小延迟,较高行中的#符号表示最大延迟。

当你需要快速分析给定延迟事件的趋势时,graph子命令就显得非常有用,你不需要使用其他的工具,也不需要解释LATENCY HISTORY命令返回的原始数据。

5. LATENCY DOCTOR

LATENCY DOCTOR命令是延迟监控功能的最强大的分析工具,它能够提供更多的统计数据(例如,两次延迟飙升之间的平均时间和中位差),以及一份易于阅读的事件分析报告。对于某些事件来说(例如,fork事件),这个命令能够提供更多的信息(例如,调用fork系统调用的速率)。

如果你想通过Redis的邮件列表咨询延迟时间相关的问题,那么你应当在邮件中贴出LATENCY DOCTOR命令的输出信息。

LATENCY DOCTOR命令的使用示例如下图所示:

LATENCY DOCTOR命令示例

LATENCY DOCTOR命令能够列出一些指导建议,例如开启慢日志(Slow Log)进一步排查问题原因,查看是否有大对象被回收或过期,以及操作系统的配置建议等等。