分布与倾斜

分布与倾斜

Greenplum数据库依赖于跨节点的均匀数据分布。

在MPP无共享环境中,查询的总体响应时间由所有节点的完成时间来度量。 系统只能与最慢的节点一样快。 如果数据偏斜,具有更多数据的节点将花费更多时间来完成,因此每个节点必须具有大致相等的行数并执行大致相同的处理量。 如果一个节点具有比其他节点更多的处理数据,则可能导致性能不佳和内存不足。

大表做连接操作时,最佳分布至关重要。 要执行连接,匹配的行必须位于同一节点上。 如果数据未在同一连接列上分发,则其中一个表所需的行将动态重新分发到其他节点。 有些情况下,执行广播动作,每个节点将其各个行发送到所有其他节点上,而不是每个节点重新哈希数据并根据哈希值将行发送到适当的节点的重新分配。

本地(Co-located)连接

使用在所有节点上均匀分布表并导致本地连接的哈希分布可以提供显着的性能提升。 当连接的行位于同一节点时,可以在节点实例中完成大部分处理。 这些连接被称为本地或co-located连接。 本地连接最小化数据移动; 每个节点独立于其他节点运营,没有节点之间的网络流量或通信。

要做到经常进行连接的大型表进行本地连接,请在同一列上分布表。 本地连接要求连接的两端分布在相同的列上(并且顺序相同),并且在连接表时使用分布子句中的所有列。 分发列也必须是相同的数据类型 - 尽管不同数据类型的某些值可能看起来具有相同的表示,但它们以不同方式存储并且哈希值不同,因此它们存储在不同的节点上。

数据倾斜

数据倾斜可能是由于错误选择分布键或单个元组表插入或复制操作导致的数据分布不均匀。 出现在表级别的数据倾斜通常是查询性能不佳和内存不足情况的根本原因。 倾斜的数据会影响扫描(读取)性能,它也会影响所有其他查询执行操作,例如,连接和按操作分组。

验证分布以确保数据在初始加载后均匀分布非常重要。 在增量加载后继续验证分布同样重要。

以下查询显示每个节点的行数以及最小和最大行数的方差:

SELECT 'Example Table' AS "Table Name", 
    max(c) AS "Max Seg Rows", min(c) AS "Min Seg Rows", 
    (max(c)-min(c))*100.0/max(c) AS "Percentage Difference Between Max & Min" 
FROM (SELECT count(*) c, gp_segment_id FROM facts GROUP BY 2) AS a;
gp_toolkit schema里有两个view可以供你检查倾斜。
  • gp_toolkit.gp_skew_coefficients view通过计算存储在每个节点上的数据的变异系数(CV)来显示数据分布倾斜。 skccoeff列显示变异系数(CV),计算为标准差除以平均值。 它考虑了数据系列平均值附近的平均值和可变性。 值越低越好。 值越高表示数据倾斜越大。
  • gp_toolkit.gp_skew_idle_fractions view通过计算表扫描期间空闲的系统百分比来显示数据分布倾斜,这是计算倾斜的指示。 siffraction列显示在表扫描期间空闲的系统百分比。 这是数据分布不均匀或查询处理倾斜的指标。 例如,值0.1表示10%偏斜,值0.5表示50%偏斜,依此类推。 倾斜超过10%的表应评估其分配策略。

随机分布表的注意事项

当创建一个随机分布表(DISTRIBUTED RANDOMLY),Greenplum数据库以轮询方式将您插入或复制的数据分发到表中。 Greenplum数据库为每个插入或复制操作启动轮询周期的新实例。 因此,将随机分布的表中的单个元组插入分配给第一个节点,将导致数据偏斜。 Greenplum数据库更均匀地分布来自批量插入的数据。

复制表的注意事项

当您创建复制表(CREATE TABLE子句DISTRIBUTED REPLICATED)时,Greenplum数据库会将每个表行分发到每个节点实例。 复制表的数据均匀分布,因为每个节点具有相同的行。 使用复制表上的gp_segment_id系统列来验证均匀分布的数据的查询将失败,因为Greenplum数据库不允许查询引用复制表的系统列。

处理倾斜

当不成比例的数据流向一个或几个节点并由其处理时,则要处理倾斜结果。 它往往是Greenplum数据库性能和稳定性问题的罪魁祸首。 它可能发生在诸如连接,排序,聚合和各种OLAP操作之类的操作中。 处理倾斜在执行查询中发生,并且不容易检测数据倾斜。

如果单个节点失败,即不是主机上的所有节点,则可能是处理倾斜问题。 识别处理倾斜目前是一个手动过程。 首先查看分裂文件。 如果存在倾斜,但不足以导致分裂,则不会成为性能问题。 如果确定存在倾斜,则找到导致倾斜的查询。 以下是要使用的步骤和命令。 (更改名称,例如传递给gpssh的主机文件名):

  1. 找到要监视倾斜处理的数据库的OID:
    SELECT oid, datname FROM pg_database;
    示例输出:
      oid  |  datname
    -------+-----------
     17088 | gpadmin
     10899 | postgres
         1 | template1
     10898 | template0
     38817 | pws
     39682 | gpperfmon
    (6 rows)
    
  2. 运行gpssh命令检测集群所有节点的文件大小。 使用先前命令将<OID>替换为数据库的OID:
    [gpadmin@mdw kend]$ gpssh -f ~/hosts -e \
        "du -b /data[1-2]/primary/gpseg*/base/<OID>/pgsql_tmp/*" | \
        grep -v "du -b" | sort | awk -F" " '{ arr[$1] = arr[$1] + $2 ; tot = tot + $2 }; END \
        { for ( i in arr ) print "Segment node" i, arr[i], "bytes (" arr[i]/(1024**3)" GB)"; \
        print "Total", tot, "bytes (" tot/(1024**3)" GB)" }' -
    示例输出:
    Segment node[sdw1] 2443370457 bytes (2.27557 GB)
    Segment node[sdw2] 1766575328 bytes (1.64525 GB)
    Segment node[sdw3] 1761686551 bytes (1.6407 GB)
    Segment node[sdw4] 1780301617 bytes (1.65804 GB)
    Segment node[sdw5] 1742543599 bytes (1.62287 GB)
    Segment node[sdw6] 1830073754 bytes (1.70439 GB)
    Segment node[sdw7] 1767310099 bytes (1.64594 GB)
    Segment node[sdw8] 1765105802 bytes (1.64388 GB)
    Total 14856967207 bytes (13.8366 GB)

    如果磁盘使用率存在显着且持续的差异,则应调查正在执行的查询是否存在可能的倾斜(上面的示例输出未显示出明显的倾斜)。 在监控系统中,总会存在一些倾斜,但通常是短暂的,持续时间很短。

  3. 如果出现显着且持续的偏斜,则下一个任务是识别违规查询。

    上一步中的命令汇总了全部节点。 这次,找到实际的节点目录。 您可以从master执行此操作,也可以登录到上一步中标识的特定节点。 以下是从master运行的示例。

    此示例专门查看排序文件。 并非所有分裂文件或倾斜情况都是由排序文件引起的,因此您需要自定义命令:
    $ gpssh -f ~/hosts -e
        "ls -l /data[1-2]/primary/gpseg*/base/19979/pgsql_tmp/*" 
        | grep -i sort | awk '{sub(/base.*tmp\//, ".../", $10); print $1,$6,$10}' | sort -k2 -n
    如下是该命令的输出:
    [sdw1] 288718848
          /data1/primary/gpseg2/.../pgsql_tmp_slice0_sort_17758_0001.0[sdw1] 291176448
          /data2/primary/gpseg5/.../pgsql_tmp_slice0_sort_17764_0001.0[sdw8] 924581888
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0010.9[sdw4] 980582400
          /data1/primary/gpseg18/.../pgsql_tmp_slice10_sort_29425_0001.0[sdw6] 986447872
          /data2/primary/gpseg35/.../pgsql_tmp_slice10_sort_29602_0001.0...[sdw5] 999620608
          /data1/primary/gpseg26/.../pgsql_tmp_slice10_sort_28637_0001.0[sdw2] 999751680
          /data2/primary/gpseg9/.../pgsql_tmp_slice10_sort_3969_0001.0[sdw3] 1000112128
          /data1/primary/gpseg13/.../pgsql_tmp_slice10_sort_24723_0001.0[sdw5] 1000898560
          /data2/primary/gpseg28/.../pgsql_tmp_slice10_sort_28641_0001.0...[sdw8] 1008009216
          /data1/primary/gpseg44/.../pgsql_tmp_slice10_sort_15671_0001.0[sdw5] 1008566272
          /data1/primary/gpseg24/.../pgsql_tmp_slice10_sort_28633_0001.0[sdw4] 1009451008
          /data1/primary/gpseg19/.../pgsql_tmp_slice10_sort_29427_0001.0[sdw7] 1011187712
          /data1/primary/gpseg37/.../pgsql_tmp_slice10_sort_18526_0001.0[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0001.0[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0002.1[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0003.2[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0004.3[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0005.4[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0006.5[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0007.6[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0008.7[sdw8] 1573741824
          /data2/primary/gpseg45/.../pgsql_tmp_slice10_sort_15673_0009.8

    扫描此输出显示主机sdw8上的节点gpseg45是罪魁祸首,因为其排序文件比输出中的其他文件大。

  4. 使用ssh登录到有问题的节点并切换到root。 使用lsof命令找到排序文件所属进程的PID:
    [root@sdw8 ~]# lsof /data2/primary/gpseg45/base/19979/pgsql_tmp/pgsql_tmp_slice10_sort_15673_0002.1
    COMMAND  PID    USER    FD   TYPE DEVICE  SIZE        NODE        NAME
    postgres 15673  gpadmin 11u  REG  8,48    1073741824  64424546751 /data2/primary/gpseg45/base/19979/pgsql_tmp/pgsql_tmp_slice10_sort_15673_0002.1
    PID, 15673, 也是文件名的一部分,但并不是总是这样。
  5. 使用ps命令找到PID并确认数据库和连接信息:
    [root@sdw8 ~]# ps -eaf | grep 15673
    gpadmin  15673 27471 28 12:05 ?        00:12:59 postgres: port 40003, sbaskin bdw
            172.28.12.250(21813) con699238 seg45 cmd32 slice10 MPPEXEC SELECT
    root     29622 29566  0 12:50 pts/16   00:00:00 grep 15673
  6. 在master上,检查上一个命令(sbaskin),连接(con699238)和命令(cmd32)中用户的pg_log日志文件。 具有这三个值的日志文件中的行应该是包含查询的行,但有时,命令编号可能略有不同。 例如,ps输出可能显示cmd32,但在日志文件中它是cmd34。 如果查询仍在运行,则用户和连接的最后一个查询是违规查询。

几乎在所有情况下处理倾斜的解决方法是重写查询。 创建临时表可以消除倾斜。 临时表可以随机分配以强制进行两阶段聚合。