如何排查 Amazon Redshift 中的集群或查询性能问题?

上次更新日期:2021 年 3 月 11 日

我的 Amazon Redshift 集群的查询性能发生降级。  如何进行问题排查并改进集群或查询性能?

简短描述

如果您在 Amazon Redshift 集群中遇到性能问题,请考虑以下方法:

  • 监控集群性能指标。
  • 查看 Amazon Redshift Advisor 的建议。
  • 查看查询执行警报和过多的磁盘使用情况。
  • 检查锁定问题和长时间运行的会话或事务。
  • 检查工作负载管理 (WLM) 配置。
  • 检查集群节点的硬件维护和性能。

解决方法

监控集群性能指标

如果您发现 Amazon Redshift 集群存在性能问题,请查看集群性能指标和图表。集群性能指标和图表可以帮助您缩小性能下降的可能根本原因。您可以在 Amazon Redshift 控制台查看性能数据,以比较集群性能随时间的变化。

这些指标增加可能表明 Amazon Redshift 集群上的工作负载和资源争用增加。有关监控性能指标的更多信息,请参阅使用 Amazon CloudWatch 指标监控 Amazon Redshift

在 Amazon Redshift 控制台中检查工作负载执行细分,以查看特定查询和执行时间。例如,如果您看到查询计划时间有所增加,可能表示查询在等待锁定

查看 Amazon Redshift Advisor 的建议

Amazon Redshift Advisor 提供有关如何改进和优化 Amazon Redshift 集群性能的建议。您可以在 Amazon Redshift 控制台中免费使用 Amazon Redshift Advisor。使用 Amazon Redshift Advisor 建议了解您的集群的潜在改进区域。这些建议基于常见使用模式和 Amazon Redshift 最佳实践。

查看查询执行警报和过多的磁盘使用情况

在查询执行期间,Amazon Redshift 会记录查询性能并指示查询是否有效执行。如果查询被确定为效率低下,Amazon Redshift 会记录查询 ID 并提供查询性能改进建议。这些建议记录在一个内部系统表 STL_ALERT_EVENT_LOG 中。

如果您观察发现较慢或效率低的查询,请检查 STL_ALERT_EVENT_LOG 条目。要从 STL_ALERT_EVENT_LOG 表中检索信息,请使用以下查询:

SELECT TRIM(s.perm_table_name) AS TABLE
    , (SUM(ABS(DATEDIFF(SECONDS, Coalesce(b.starttime, d.starttime, s.starttime), CASE
            WHEN COALESCE(b.endtime, d.endtime, s.endtime) > COALESCE(b.starttime, d.starttime, s.starttime)
            THEN COALESCE(b.endtime, d.endtime, s.endtime)
        ELSE COALESCE(b.starttime, d.starttime, s.starttime)
    END))) / 60)::NUMERIC(24, 0) AS minutes
    , SUM(COALESCE(b.ROWS, d.ROWS, s.ROWS)) AS ROWS
    , TRIM(SPLIT_PART(l.event, ':', 1)) AS event
    , SUBSTRING(TRIM(l.solution), 1, 60) AS solution
    , MAX(l.QUERY) AS sample_query
    , COUNT(DISTINCT l.QUERY)
FROM STL_ALERT_EVENT_LOG AS l
LEFT JOIN stl_scan AS s
    ON s.QUERY = l.QUERY AND s.slice = l.slice AND s.segment = l.segment
LEFT JOIN stl_dist AS d
    ON d.QUERY = l.QUERY AND d.slice = l.slice AND d.segment = l.segment 
LEFT JOIN stl_bcast AS b
    ON b.QUERY = l.QUERY AND b.slice = l.slice AND b.segment = l.segment 
WHERE l.userid > 1 AND l.event_time >= DATEADD(DAY, -7, CURRENT_DATE)
GROUP BY 1, 4, 5
ORDER BY 2 DESC, 6 DESC;

此查询列出了集群上运行的查询的查询 ID 以及最常见的问题和问题发生情况。

以下是查询的示例输出以及描述警报为什么被触发的信息:

table | minutes | rows |               event                |                        solution                        | sample_query | count
-------+---------+------+------------------------------------+--------------------------------------------------------+--------------+-------
NULL  |    NULL | NULL | Nested Loop Join in the query plan | Review the join predicates to avoid Cartesian products |      1080906 |     2

可以通过检查用于查询调整的诊断查询来查看查询性能。确保您的查询操作设计为高效运行。例如,并非所有联接操作都有效。嵌套循环联接是效率最低的联接类型,若有可能,必须避免,因为这种类型会大大增加查询执行时间。

确定执行嵌套循环的查询,以帮助您诊断问题。有关如何诊断常见磁盘使用问题的更多信息,请参阅如何使用 Amazon Redshift 排查磁盘使用量高或已满的问题?

检查锁定问题和长时间运行的会话或事务

在集群上运行查询之前,可能需要在查询执行中涉及的表上获取表级锁。在某些情况下,查询可能显示为“挂起”,或者查询执行时间突增。如果您观察到查询执行时间突增,可能因锁定问题造成。有关延迟查询执行时间的详细信息,请参阅为什么我的查询计划时间在 Amazon Redshift 中如此之长?

如果表当前被其他进程或查询锁定,则无法继续查询。因此,您不会看到您的查询显示在 STV_INFLIGHT 表中。相反,您正在运行的查询将显示在 STV_RECENTS 表中。

有时候,挂起查询因长时间运行的事务造成。为防止任何长时间运行的事务影响查询性能,请考虑以下提示:

  • 确定长时间运行的会话并立即终止它们。您可以使用 STL_SESSIONSSVV_TRANSACTIONS 表检查长时间运行的事务。
  • 设计您的查询,以便 Amazon Redshift 能够快速高效地处理查询。

注意:长时间运行的事务还会影响回收磁盘空间的 VACUUM 能力,从而导致 ghost 行或未提交的行数量增加。查询扫描的 Ghost 行会影响查询性能。

有关识别可能导致表锁定的长时间运行的会话的详细信息,请参阅如何在 Amazon Redshift 中检测和发布锁定?

检查工作负载管理 (WLM) 配置

根据您的 WLM 配置,查询可能会立即开始运行或花费一些时间排队。目标应始终是尽量减少查询排队等候执行的时间。如果您想定义您的队列,请检查您的 WLM 内存分配

要在几天内检查集群的 WLM 队列,请使用以下查询:

SELECT *, pct_compile_time + pct_wlm_queue_time + pct_exec_only_time + pct_commit_queue_time + pct_commit_time AS total_pcnt
FROM 
(SELECT IQ.*,
   ((IQ.total_compile_time*1.0 / IQ.wlm_start_commit_time)*100)::DECIMAL(5,2) AS pct_compile_time,
   ((IQ.wlm_queue_time*1.0 / IQ.wlm_start_commit_time)*100)::DECIMAL(5,2) AS pct_wlm_queue_time,
   ((IQ.exec_only_time*1.0 / IQ.wlm_start_commit_time)*100)::DECIMAL(5,2) AS pct_exec_only_time,
   ((IQ.commit_queue_time*1.0 / IQ.wlm_start_commit_time)*100)::DECIMAL(5,2) pct_commit_queue_time,
   ((IQ.commit_time*1.0 / IQ.wlm_start_commit_time)*100)::DECIMAL(5,2) pct_commit_time
  FROM 
    (SELECT trunc(d.service_class_start_time) AS DAY,
       d.service_class,
       d.node,
       COUNT(DISTINCT d.xid) AS count_all_xid,
       COUNT(DISTINCT d.xid) -COUNT(DISTINCT c.xid) AS count_readonly_xid,
       COUNT(DISTINCT c.xid) AS count_commit_xid,
       SUM(compile_us) AS total_compile_time,
       SUM(datediff (us,CASE WHEN d.service_class_start_time > compile_start THEN compile_start ELSE d.service_class_start_time END,d.queue_end_time)) AS wlm_queue_time,
       SUM(datediff (us,d.queue_end_time,d.service_class_end_time) - compile_us) AS exec_only_time,
       nvl(SUM(datediff (us,CASE WHEN node > -1 THEN c.startwork ELSE c.startqueue END,c.startwork)),0) commit_queue_time,
       nvl(SUM(datediff (us,c.startwork,c.endtime)),0) commit_time,
       SUM(datediff (us,CASE WHEN d.service_class_start_time > compile_start THEN compile_start ELSE d.service_class_start_time END,d.service_class_end_time) + CASE WHEN c.endtime IS NULL THEN 0 ELSE (datediff (us,CASE WHEN node > -1 THEN c.startwork ELSE c.startqueue END,c.endtime)) END) AS wlm_start_commit_time
     FROM 
       (SELECT node, b.*
          FROM (SELECT -1 AS node UNION SELECT node FROM stv_slices) a,
               stl_wlm_query b
         WHERE queue_end_time > '2005-01-01'
           AND exec_start_time > '2005-01-01') d
     LEFT JOIN stl_commit_stats c USING (xid,node)
     JOIN (SELECT query, MIN(starttime) AS compile_start, SUM(datediff (us,starttime,endtime)) AS compile_us
           FROM svl_compile
           GROUP BY 1) e USING (query)
    WHERE d.xid > 0
      AND d.service_class > 4
      AND d.final_state <> 'Evicted'
 GROUP BY trunc(d.service_class_start_time),
          d.service_class,
          d.node
 ORDER BY trunc(d.service_class_start_time),
          d.service_class,
          d.node) IQ)
WHERE node < 0 ORDER BY 1,2,3;

此查询提供事务总数 (xid)、执行时间、列队时间和提交队列详细信息。您可以检查提交队列详细信息,以查看频繁提交是否会影响工作负载性能。

要检查在特定时间点运行的查询的详细信息,请使用以下查询:

select b.userid,b.query,b.service_class,b.slot_count,b.xid,d.pid,d.aborted,a.compile_start,b.service_class_start_time,b.queue_end_time,b.service_class_end_time,c.startqueue as commit_startqueue,c.startwork as commit_startwork,c.endtime as commit_endtime,a.total_compile_time_s,datediff(s,b.service_class_start_time,b.queue_end_time)
    as wlm_queue_time_s,datediff(s,b.queue_end_time,b.service_class_end_time) as wlm_exec_time_s,datediff(s, c.startqueue, c.startwork) commit_queue_s,datediff(s, c.startwork, c.endtime) commit_time_s,undo_time_s,numtables_undone,datediff(s,a.compile_start,nvl(c.endtime,b.service_class_end_time))
    total_query_s ,substring(d.querytxt,1,50) as querytext from (select query,min(starttime) as compile_start,max(endtime) as compile_end,sum(datediff(s,starttime,endtime)) as total_compile_time_s from svl_compile group by query) a left join stl_wlm_query
    b using (query) left join (select * from stl_commit_stats where node=-1) c using (xid) left join stl_query d using(query) left join (select xact_id_undone as xid,datediff(s,min(undo_start_ts),max(undo_end_ts)) as undo_time_s,count(distinct table_id)
    numtables_undone from stl_undone group by 1) e on b.xid=e.xid
WHERE '2011-12-20 13:45:00' between compile_start and service_class_end_time;

将“2011-12-20 13:45:00”替换为您想要检查队列和已完成查询的特定时间和日期。

查看集群节点硬件性能

在您的集群维护时段中,可能会进行补丁、内部配置更改和节点替换等维护任务。如果在维护时段期间替换了节点,集群可能很快就可用。但是,在替换的节点上恢复数据可能需要一些时间。这个过程被称为混合。在混合的过程中,您的集群性能可能会下降。

要确定哪些事件(例如混合)影响了集群性能,请检查 Amazon Redshift 集群事件。您的集群事件会告知您任何节点替换操作和/或已执行的任何其他集群操作

要监控混合过程,请使用 STV_UNDERREPPED_BLOCKS 表。可以使用以下查询检索需要混合的数据块:

SELECT COUNT(1) FROM STV_UNDERREPPED_BLOCKS;

注意:混合过程的持续时间取决于集群的工作负载。要衡量集群混合过程的进度,请按特定时间间隔检查数据块。

要检查特定节点的运行状况,请使用以下查询将其性能与其他节点进行比较:

SELECT day
  , node
  , elapsed_time_s
  , sum_rows
  , kb
  , kb_s
  , rank() over (partition by day order by kb_s) AS rank
FROM (
  SELECT DATE_TRUNC('day',start_time) AS day
    , node
    , sum(elapsed_time)/1000000 AS elapsed_time_s
    , sum(rows) AS sum_rows
    , sum(bytes)/1024 AS kb
    , (sum(bytes)/1024)/(sum(elapsed_time)/1000000) AS "kb_s"
  FROM svl_query_report r
    , stv_slices AS s 
  WHERE r.slice = s.slice 
    AND elapsed_time > 1000000 
  GROUP BY day
    , node 
  ORDER BY day
    , node
);

以下是示例查询输出:

day    node    elapsed_time_s    sum_rows         kb         kb_s  rank
...
4/8/20     0      3390446     686216350489    21570133592    6362    4
4/8/20     2      3842928     729467918084    23701127411    6167    3
4/8/20     3      3178239     706508591176    22022404234    6929    7
4/8/20     5      3805884     834457007483    27278553088    7167    9
4/8/20     7      6242661     433353786914    19429840046    3112    1
4/8/20     8      3376325     761021567190    23802582380    7049    8
...This output indicates that the node 7 processed 19429840046 Kb of data for 6242661 amount of seconds, which is a lot slower than the other nodes.

行数(列“sum_rows”)与处理的字节数(例如“kb”)之间的比率大致相同。“kb_s”列中的行数与行数也大致相同,具体取决于您的硬件性能。如果您观察到某个特定节点在一段时间内处理的数据较少,则性能低可能表明存在底层硬件问题。要确认存在底层硬件问题,请查看节点的性能图表。


这篇文章对您有帮助吗?


您是否需要账单或技术支持?