读取统计信息

Cloud Spanner 提供内置表,用于存储有关读取的统计信息。您可以使用 SQL 语句从这些 SPANNER_SYS.READ_STATS* 表中检索统计信息。

何时使用读取统计信息

读取统计信息可让您深入了解应用如何使用数据库,这对于调查性能问题非常有用。例如,您可以查看针对数据库运行的读取形状、它们运行的频率,以及解释这些读取形状的性能特征。您可以使用数据库的读取统计信息来识别导致高 CPU 使用率的读取形状。简而言之,读取统计信息可帮助您从资源使用率角度了解流量进入数据库的行为。

限制

  • 此工具最适合用于分析占大多数 CPU 使用率的类似读取流。它不适合搜索仅运行一次的读取。

  • 这些统计信息中跟踪的 CPU 使用率表示 Spanner 服务器端的 CPU 使用率,不包括预提取的 CPU 使用率和一些其他开销。

  • 系统会尽最大努力收集统计信息。因此,当底层系统出现问题时,可能会错过统计信息。例如,如果存在内部网络问题,则可能会遗漏一些统计信息。

可用情况

SPANNER_SYS 数据只能通过 SQL 接口获得;例如:

  • Google Cloud 控制台中数据库的 Spanner Studio 页面

  • gcloud spanner databases execute-sql 命令

  • executeQuery API

Spanner 提供的其他单次读取方法不支持 SPANNER_SYS

按读取形状分组的 CPU 使用率

下面的表跟踪特定时间段内 CPU 使用率最高的读取形状:

  • SPANNER_SYS.READ_STATS_TOP_MINUTE:以1 分钟为间隔汇总的读取形状统计信息。
  • SPANNER_SYS.READ_STATS_TOP_10MINUTE:以 10 分钟为间隔汇总的读取形状统计信息。
  • SPANNER_SYS.READ_STATS_TOP_HOUR:以 1 小时为间隔汇总的读取形状统计信息。

这些表具有以下属性:

  • 每个表包含表名指定的非重叠时间段长度的数据。

  • 间隔基于时钟时间。1 分钟间隔结束于分钟,10 分钟间隔从小时开始每 10 分钟结束一次,而 1 小时间隔结束于小时。在每个时间间隔后,Spanner 都会从所有服务器收集数据,稍后这些数据在 SPANNER_SYS 表中可用。

    例如,在上午 11:59:30,SQL 查询可用的最近时间段为:

    • 1 分钟:上午 11:58:00–11:58:59
    • 10 分钟:上午 11:40:00–11:49:59
    • 1 小时:上午 10:00:00–10:59:59
  • Spanner 按读取形状对统计信息进行分组。如果存在标记,则 FPRINT 是标记的哈希。否则为 READ_COLUMNS 值的哈希值。

  • 每一行都包含特定读取形状的所有执行统计信息,Spanner 会在指定的时间间隔内捕获其中的统计信息。

  • 如果 Spanner 无法存储该时间间隔内每个不同读取形状运行的相关信息,则系统会优先选择在指定时间间隔内 CPU 使用率最高的读取形状。

表架构

列名 类型 说明
INTERVAL_END TIMESTAMP 所包含读取执行所处的时间间隔的结束时间。
REQUEST_TAG STRING 此读取操作的可选请求标记。如需详细了解如何使用标记,请参阅请求标记问题排查。具有相同标记字符串的多个读取的统计信息归为一行,其中“REQUEST_TAG”与该标记字符串匹配。
READ_TYPE STRING 指示读取操作是 PARTITIONED_READ 还是 READ。如果读取操作从 SectionRead API 获取分区令牌,则读取操作由 PARTITIONED_READ 读取类型表示,其他读取 API 则由 READ 表示。
READ_COLUMNS ARRAY<STRING> 读取的列集。这些按字母顺序排序。
FPRINT INT64 REQUEST_TAG 值的哈希值(如果存在);否则,READ_COLUMNS 值的哈希值。
EXECUTION_COUNT INT64 Spanner 在时间间隔内执行读取形状的次数。
AVG_ROWS FLOAT64 读取返回的平均行数。
AVG_BYTES FLOAT64 读取返回的数据字节数的平均值,不包括传输编码开销。
AVG_CPU_SECONDS FLOAT64 执行读取的 Spanner 服务器端 CPU 秒数(不包括预提取 CPU 和其他开销)。
AVG_LOCKING_DELAY_SECONDS FLOAT64 由于锁定而等待的平均秒数。
AVG_CLIENT_WAIT_SECONDS FLOAT64 因客户端没有像 Spanner 能快地生成数据的速度那样快速消耗数据而花费的平均秒数。
AVG_LEADER_REFRESH_DELAY_SECONDS FLOAT64 等待 Paxos 主要副本确认观察到所有写入的平均秒数。
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 作为读写事务的一部分运行读取操作的次数。此列可帮助您确定是否可以通过将读取移至只读事务来避免锁争用。

示例查询

本部分提供了几个可检索读取统计信息的示例 SQL 语句。您可以使用客户端库gcloud 命令行工具或 Google Cloud 控制台运行这些 SQL 语句。

列出指定时间段内每个读取形状的基本统计信息

以下查询返回最近 1 分钟时间间隔内顶部读取形状的原始数据。

SELECT fprint,
       read_columns,
       execution_count,
       avg_cpu_seconds,
       avg_rows,
       avg_bytes,
       avg_locking_delay_seconds,
       avg_client_wait_seconds
FROM spanner_sys.read_stats_top_minute
ORDER BY interval_end DESC LIMIT 3;
查询输出
fprint read_columns execution_count avg_cpu_seconds avg_rows avg_bytes avg_locking_delay_seconds avg_client_wait_seconds
125062082139 ["Singers.id", "Singers.name"] 8514387 0.000661355290396507 310.79 205 8.3232564943763752e-06 0
151238888745 ["Singers.singerinfo"] 3341542 6.5992827184280315e-05 12784 54 4.6859741349028595e-07 0
14105484 ["Albums.id", "Albums.title"] 9306619 0.00017855774721667873 1165.4 2964.71875 1.4328191393074178e-06 0

列出按最高 CPU 总使用率排序的读取形状

以下查询返回最近一小时内 CPU 使用率最高的读取形状:

SELECT read_columns,
       execution_count,
       avg_cpu_seconds,
       execution_count * avg_cpu_seconds AS total_cpu
FROM spanner_sys.read_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.read_stats_top_hour)
ORDER BY total_cpu DESC LIMIT 3;
查询输出
read_columns execution_count avg_cpu_seconds total_cpu
["Singers.id", "Singers.name"] 1647 0.00023380297430622681 0.2579
["Albums.id", "Albums.title"] 720 0.00016738889440282034 0.221314999999999
["Singers.singerinfo""] 3223 0.00037764625882302246 0.188053

聚合统计信息

SPANNER_SYS 还包含一些表,用于存储 Spanner 在特定时间段内捕获的聚合读取统计信息:

  • SPANNER_SYS.READ_STATS_TOTAL_MINUTE:1 分钟间隔内所有读取形状的汇总统计信息。
  • SPANNER_SYS.READ_STATS_TOTAL_10MINUTE:10 分钟间隔内所有读取形状的汇总统计信息。
  • SPANNER_SYS.READ_STATS_TOTAL_HOUR:1 小时间隔内所有读取形状的汇总统计信息。

聚合统计信息表具有以下属性:

  • 每个表包含表名指定的非重叠时间段长度的数据。

  • 间隔基于时钟时间。1 分钟的间隔以分钟结束,10 分钟的间隔以小时为单位,每 10 分钟结束一次,1 小时的间隔以小时结束。

    例如,在上午 11:59:30,SQL 查询可用的汇总读取统计信息的最近间隔为:

    • 1 分钟:上午 11:58:00–11:58:59
    • 10 分钟:上午 11:40:00–11:49:59
    • 1 小时:上午 10:00:00–10:59:59
  • 每行包含在指定间隔内在数据库中执行的所有读取形状的汇总统计信息。每个时间段只有一行。

  • SPANNER_SYS.READ_STATS_TOTAL_* 表中捕获的统计信息可能包含 Spanner 在 SPANNER_SYS.READ_STATS_TOP_* 表中未捕获的读取形状。

  • 这些表中的某些列在 Cloud Monitoring 中显示为指标。公开的指标包括:

    • 返回的行数
    • 读取执行次数
    • 读取 CPU 时间
    • 锁定延迟
    • 客户端等待时间
    • 主要副本刷新延迟
    • 返回的字节数

    如需了解详情,请参阅 Spanner 指标

表架构

列名 类型 说明
INTERVAL_END TIMESTAMP 所包含读取形状执行所处的时间间隔的结束时间。
EXECUTION_COUNT INT64 Spanner 在时间间隔内执行读取形状的次数。
AVG_ROWS FLOAT64 读取返回的平均行数。
AVG_BYTES FLOAT64 读取返回的数据字节数的平均值,不包括传输编码开销。
AVG_CPU_SECONDS FLOAT64 执行读取的 Spanner 服务器端 CPU 秒数(不包括预提取 CPU 和其他开销)。
AVG_LOCKING_DELAY_SECONDS FLOAT64 由于锁定而等待的平均秒数。
AVG_CLIENT_WAIT_SECONDS FLOAT64 由于节流而等待的平均秒数。
AVG_LEADER_REFRESH_DELAY_SECONDS FLOAT64 多地区配置中协调各实例读取所用的平均秒数。
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 作为读写事务的一部分运行读取的次数。此列可帮助您确定是否可以通过将某些读取移至只读事务来避免锁争用。

示例查询

本部分提供了几个可检索汇总读取统计信息的示例 SQL 语句。您可以使用客户端库gcloud 命令行工具或 Google Cloud 控制台运行这些 SQL 语句。

查找所有读取形状的 CPU 总使用率

以下查询返回最近一小时内读取形状使用的 CPU 小时数:

SELECT (avg_cpu_seconds * execution_count / 60 / 60)
  AS total_cpu_hours
FROM spanner_sys.read_stats_total_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.read_stats_total_hour);
查询输出
total_cpu_hours
0.00026186111111111115

查找指定时间段内的总执行次数

以下查询返回在最近 1 分钟间隔内执行的读取形状的总数:

SELECT interval_end,
       execution_count
FROM spanner_sys.read_stats_total_minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.read_stats_total_minute);
查询输出
interval_end execution_count
2020-05-28 11:02:00-07:00 12861966

数据保留

Spanner 至少会为每个表保留以下时间段内的数据:

  • SPANNER_SYS.READ_STATS_TOP_MINUTESPANNER_SYS.READ_STATS_TOTAL_MINUTE:前 6 个小时中的时间段。

  • SPANNER_SYS.READ_STATS_TOP_10MINUTESPANNER_SYS.READ_STATS_TOTAL_10MINUTE:前 4 天中的时间段。

  • SPANNER_SYS.READ_STATS_TOP_HOURSPANNER_SYS.READ_STATS_TOTAL_HOUR:前 30 天中的时间段。

使用读取统计信息排查 CPU 使用率过高的问题

如果您需要调查 Spanner 数据库的高 CPU 使用率,或者只想了解数据库上占用大量 CPU 的读取形状,Spanner 读取统计信息会派上用场。通过检查使用大量数据库资源的读取形状,Spanner 用户有望降低运营费用并可能缩短一般系统延迟时间。按照以下步骤执行操作,我们将向您展示如何使用读取统计信息来调查数据库中的高 CPU 使用率。

选择要调查的时间段

调查之初是查找您的应用开始出现高 CPU 使用率的时间。例如,在以下场景中,问题于 2020 年 5 月 28 日下午 5:20 左右开始出现。

收集所选时间段内的已读统计信息

选择开始调查的时间段后,我们将查看在约该时间的 READ_STATS_TOTAL_10MINUTE 表中收集的统计信息。此查询的结果可能有助于我们了解 CPU 和其他读取统计信息在该时间段内的变化情况。以下查询返回从 4:30 pm7:30 pm(含)的汇总读取统计信息。

SELECT
  interval_end,
  ROUND(avg_cpu_seconds,4) as avg_cpu_seconds,
  execution_count,
  avg_locking_delay_seconds
FROM SPANNER_SYS.READ_STATS_TOTAL_10MINUTE
WHERE
  interval_end >= "2020-05-28T16:30:00"
  AND interval_end <= "2020-05-28T19:30:00"
ORDER BY interval_end;

以下是我们通过查询返回的结果的一个示例。

interval_end avg_cpu_seconds execution_count avg_locking_delay_seconds
2020-05-28 16:40:00-07:00 0.0004 11111421 8.3232564943763752e-06
2020-05-28 16:50:00-07:00 0.0002 8815637 8.98734051776406e-05
2020-05-28 17:00:00-07:00 0.0001 8260215 6.039129247846453e-06
2020-05-28 17:10:00-07:00 0.0001 8514387 9.0535466616680686e-07
2020-05-28 17:20:00-07:00 0.0006 13715466 2.6801485272173765e-06
2020-05-28 17:30:00-07:00 0.0007 12861966 4.6859741349028595e-07
2020-05-28 17:40:00-07:00 0.0007 3755954 2.7131391918005383e-06
2020-05-28 17:50:00-07:00 0.0006 4248137 1.4328191393074178e-06
2020-05-28 18:00:00-07:00 0.0006 3986198 2.6973481999639748e-06
2020-05-28 18:10:00-07:00 0.0006 3510249 3.7577083563017905e-06
2020-05-28 18:20:00-07:00 0.0004 3341542 4.0940589703795433e-07
2020-05-28 18:30:00-07:00 0.0002 8695147 1.9914494947583975e-05
2020-05-28 18:40:00-07:00 0.0003 11679702 1.8331461539001595e-05
2020-05-28 18:50:00-07:00 0.0003 9306619 1.2527332321222135e-05
2020-05-28 19:00:00-07:00 0.0002 8520508 6.2268448078447915e-06
2020-05-28 19:10:00-07:00 0.0006 13715466 2.6801485272173765e-06
2020-05-28 19:20:00-07:00 0.0005 11947323 3.3029114639321295e-05
2020-05-28 19:30:00-07:00 0.0002 8514387 9.0535466616680686e-07

在这里,我们可以看到,平均 CPU 时间 avg_cpu_seconds突出显示的间隔中较高。值为 2020-05-28 19:20:00interval_end 具有较高的 CPU 时间,因此我们将在下一步中选择该间隔来进一步调查。

查找导致高 CPU 使用率的读取形状

我们来深入了解一下,我们现在查询 READ_STATS_TOP_10MINUTE 表来查找在上一步中选择的间隔。此查询的结果可以帮助指明哪些读取形状导致高 CPU 利用率。

SELECT
  read_columns,
  ROUND(avg_cpu_seconds,4) as avg_cpu_seconds,
  execution_count,
  avg_rows
FROM SPANNER_SYS.READ_STATS_TOP_10MINUTE
WHERE
  interval_end = "2020-05-28T19:20:00"
ORDER BY avg_cpu_seconds DESC LIMIT 3;

以下数据是我们从查询中获得的结果示例,返回按 avg_cpu_seconds 排列的前三大读取形状的相关信息。请注意,在我们的查询中使用 ROUNDavg_cpu_seconds 的输出限制为 4 位小数。

read_columns avg_cpu_seconds execution_count avg_rows
[TestHigherLatency._exists,TestHigherLatency.lang_status,TestHigherLatency.score,globalTagAffinity.shares]1 0.4192 1182 11650.42216582
[TestHigherLatency._exists,TestHigherLatency.lang_status,TestHigherLatency.likes,globalTagAffinity.score] 0.0852 4 12784
[TestHigherLatency._exists,TestHigherLatency.lang_status,TestHigherLatency.score,globalTagAffinity.ugcCount] 0.0697 1140 310.7921052631

1 _exists 是一个内部字段,用于检查特定行是否存在。

高 CPU 使用率的一个原因是您开始更频繁地执行一些读取形状 (execution_count)。或许读取返回的平均行数已增加 (avg_rows)。如果读取形状的任何属性均未显示任何值得关注的内容,您可以检查其他属性,例如 avg_locking_delay_secondsavg_client_wait_secondsavg_bytes

运用最佳实践来减少高 CPU 使用率

在完成上述步骤后,请考虑提供其中任何最佳做法是否有助于您解决问题。

  • Spanner 在时间间隔内执行读取形状的次数就是一个很好的指标,它需要通过基准来判断测量结果是否合理或是否预示着某个问题。为指标建立基准后,您可以检测和调查与正常行为的意外偏差的原因。

  • 如果 CPU 使用率在大多数情况下相对固定,但突然显示可能与用户请求或应用行为中的类似突然峰值相关联的峰值,则可能表示一切正常。

  • 尝试以下查询来查找排名靠前的读取形状(按 Spanner 针对每个读取形状执行的次数排序):

    SELECT interval_end, read_columns, execution_count
    FROM SPANNER_SYS.READ_STATS_TOP_MINUTE
    ORDER BY execution_count DESC
    LIMIT 10;
    
  • 如果您希望尽可能缩短读取延迟时间,尤其是在使用多区域实例配置时,请使用过时读取而不是强读取来减少或移除读取延迟时间的 AVG_LEADER_REFRESH_DELAY_SECONDS 组成部分。

  • 如果您只执行读取,并且可以使用单次读取方法来表示您的读取,则应该使用该单次读取方法。与读写事务不同,单次读取不会锁定,因此,如果您不写入数据,则应优先使用只读事务,而不是费用更高的读写事务。

后续步骤