分布式数据存储倾斜快速检测

举报
along_2020 发表于 2020/07/10 17:00:47 2020/07/10
【摘要】 本文主要分享快速、准确识别数据存储倾斜的方法。

前言

数据存储倾斜(即图中1-4被占用存储资源不均衡)Shared nothing分布式架构下的重要难题,它破坏了MPP架构中各个节点对等的要求导致倾斜节点所需存储及计算资源都远大于其他节点,进而导致性能下降(木桶效应)、full diskoom等严重问题。

 

技术背景

目前各类分布式数据库厂商都有提供存储倾斜的检测工具,常用方法主要有计算表的COUNT,计算表的SIZE和通过统计信息计算这三种,下面以在GaussDB(DWS)分布式数据库产品为例,分别介绍这三种方式的优劣:

 

方法一:通过表的COUNT计算倾斜

方案:例如使用table_skewness函数,其内部通过统计表在各节点的COUNT数实现

postgres=# select dnname,num from table_skewness('mytable') order by dnname;
  dnname   | num
---------------+------
 datanode1  | 4800
 datanode2  | 5216
 datanode3  | 5792
 datanode4  | 5568
 datanode5  | 5152
 datanode6  | 5472
(6 rows)

优点:简单粗暴,适用表数据量小且UPDATE/DELETE少的表;

缺点:数据量大的场景计算表的COUNT比较耗时;脏数据占存储和SCAN消耗但不会统计;

 

方法二:通过表的SIZE计算倾斜(推荐)

方案:例如使用table_distribution函数,其内部通过统计表在各节点的SIZE大小实现

postgres=# select nodename,dnsize from table_distribution('public','mytable') order by nodename;
 nodename  | dnsize
-------------+--------
 datanode1 | 221184
 datanode2 | 229376
 datanode3 | 253952
 datanode4 | 253952
 datanode5 | 229376
 datanode6 | 253952
(6rows)

优点:实时性好;准确度高;相比计算COUNT速度快;

缺点:表对应数据文件多的场景性能会受影响,当前实测100+节点场景影响在可接受范围


方法三:通过统计信息计算倾斜

方案:使用pg_class中reltuples/relpages以及统计信息来计算倾斜

CREATE OR REPLACE FUNCTION PUBLIC.pgxc_analyzed_tuples
(
    OUT schemaname text,
    OUT tablename text,
    OUT dn_name text,
    OUT tuples real
)
RETURNS SETOF record
AS $$
DECLARE
    datanode_rd     record;
    fetch_tuples    record;
    fetch_dn        text;
    fetch_tuple_str text;
BEGIN
    fetch_dn := 'SELECT node_name FROM pg_catalog.pgxc_node WHERE node_type=''D'' order by node_name';
    FOR datanode_rd IN EXECUTE(fetch_dn) LOOP
        dn_name         :=  datanode_rd.node_name;
        fetch_tuple_str := 'EXECUTE DIRECT ON (' || dn_name || ') ''SELECT n.nspname, c.relname, c.reltuples
                   FROM pg_catalog.pg_class c
                   INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
                   where c.oid >16384 AND c.relkind = ''''r'''' 
                   and n.nspname <> ''''cstore'''' and n.nspname <> ''''pmk'''' 
                   and n.nspname <> ''''pg_catalog''''''';
        FOR fetch_tuples IN EXECUTE(fetch_tuple_str) LOOP
            tuples    := fetch_tuples.reltuples;
            schemaname := fetch_tuples.nspname;
            tablename  := fetch_tuples.relname;
            return next;
        END LOOP;
	    RAISE INFO 'Finished fetching stats info from DataNode % at %',dn_name, clock_timestamp();
    END LOOP;
    return;
END; $$
LANGUAGE 'plpgsql'
ROWS 1000000;

postgres=# select dn_name,tuples from public.pgxc_analyzed_tuples() where tablename='mytable';
  dn_name | tuples
-------------+--------
 datanode1 | 4800
 datanode2 | 5216
 datanode3 | 5792
 datanode4 | 5568
 datanode5 | 5152
 datanode6 | 5472
(6 rows)

优点:计算过程不需要实时SCAN,只需要通过已有统计信息来计算,速度最快。

缺点:强依赖实时ANALYZE统计信息来保证实时性;不包含实际占用存储空间和SCAN 消耗的脏数据统计,准确度不如方法二。

 

小结

以上三种方法主要针对单个表的倾斜查询,各有优劣,这里比较推荐准确度最高速度居中的方法二,并基于此方法实现了系统视图PGXC_GET_TABLE_SKEWNESS用于查询库内所有表的存储分布情况,例:

postgres=# select * from PGXC_GET_TABLE_SKEWNESS;
schemaname | tablename | totalsize | avgsize  | maxratio | minratio | skewsize | skewratio | skewstddev
------------+------------+-------------+------------+------------+------------+-----------+------------+------------
 public  | orders  | 705413120 | 117568853 |  .167  |  .166  | 278528  |  0.000  |  95628
 public  | mytable  | 1441792  | 240299  |  .176  |  .153  | 32768  |  .023  |  15253
 public  | customer | 131579904 | 21929984 |  .167  |  .166  | 131072  |  .001  |  46050
 public  | part   | 101646336 | 16941056 |  .167  |  .166  | 114688  |  .001  |  38772
 public  | supplier | 8552448  | 1425408  |  .168  |  .166  | 16384  |  .002  |  8974
 public  | lineitem | 3351937024 | 558656171 |  .167  |  .166  | 1302528 |  0.000  |  516984
 public  | partsupp | 461922304 | 76987051 |  .167  |  .166  | 401408  |  .001  |  148130
(7 rows)

后面将语句基于table_distribution函数及PGXC_GET_TABLE_SKEWNESS视图,介绍如何在真实业务场景中及早、快速定位到存储倾斜的表。

 

实战场景

从早发现、快定位、勤检查三个角度,介绍如何在实际业务场景中最大程度避免数据存储倾斜带来的影响。


早发现:数据导入场景即时检测

当前我们支持在数据导入过程对DN导入行数进行统计,导入完成后计算倾斜率,超过一定阈值时,立即进行告警。倾斜率通过( DN导入行数最大值-DN导入行数最小值) /导入总行数计算,方法如下:

1、开启即时检测的参数

table_skewness_warning_rows:表倾斜告警最小行数,取值范围0 INT_MAX,默认值100000,表示当导入总行数超过该值与导入DN数之积时,才可能触发告警,避免小数据量导入的场景进行无意义的告警

table_skewness_warning_threshold表倾斜告警阈值,取值范围0~1.0,默认值为0,表示当DN返回行数的最小值和最大值的比例小于指定的倾斜告警阈值时,进行告警。

2、执行导入(INSERTCOPY

当导入数据出现倾斜,执行SQL和日志中会发出告警,告警信息包括表名、最小行数、最大行数、总行数、平均行数、倾斜率,以及提示信息(检查数据分布或者修改参数)。

WARNING: Skewness occurs, table name: xxx, min value: xxx, max value: xxx, sum value: xxx, avg value: xxx, skew ratio: xxx
HINT: Please check data distribution or modify warning threshold

 

快定位:磁盘满场景快速定位倾斜表

出现磁盘满场景,在表数量非常多的情况下,全量排查哪些表倾斜非常耗时,我们支持使用如下方式快速定位倾斜表:

1、查询近期发生过数据变更的表

通过pg_stat_get_last_data_changed_time(oid)函数查询出近期发生过数据变更的表,基于表的最后修改时间只在进行IUD操作的CN记录,要查询库内1(间隔可在函数中调整)内被修改的所有表,可以使用如下封装函数:

CREATE OR REPLACE FUNCTION get_last_changed_table(OUT schemaname text, OUT relname text) RETURNS setof record
AS $$
DECLARE
    row_data record;
    row_name record;
    query_str text;
    query_str_nodes text;
BEGIN
    query_str_nodes := 'SELECT node_name FROM pgxc_node where node_type = ''C''';
    FOR row_name IN EXECUTE(query_str_nodes) LOOP
       query_str := 'EXECUTE DIRECT ON (' || row_name.node_name || ') ''SELECT b.nspname,a.relname
               FROM pg_class a INNER JOIN pg_namespace b on a.relnamespace = b.oid where
               pg_stat_get_last_data_changed_time(a.oid) 
               BETWEEN current_timestamp - 1 AND current_timestamp;''';
      FOR row_data IN EXECUTE(query_str) LOOP
        schemaname = row_data.nspname;
        relname = row_data.relname;
        return next;
      END LOOP;
    END LOOP;
    return;
END; $$
LANGUAGE plpgsql;

2、查看近期数据变更的表的分布情况

postgres=# SELECT table_distribution(schemaname,relname) FROM get_last_changed_table() limit 6;
        table_distribution
-----------------------------------
 (public,mytable,datanode1,221184)
 (public,mytable,datanode2,229376)
 (public,mytable,datanode3,253952)
 (public,mytable,datanode4,253952)
 (public,mytable,datanode5,229376)
 (public,mytable,datanode6,253952)
(6 rows)

 

勤检查:常规数据倾斜巡检

1、在库中表个数比较少(<1W)场景

直接使用PGXC_GET_TABLE_SKEWNESS视图来查询当前库内所有表的数据倾斜情况。

2、在库中表个数非常多(>1W)场景

PGXC_GET_TABLE_SKEWNESS涉及全库查并计算非常全面的倾斜字段,所以可能会花费比较长的时间(小时级),建议参考PGXC_GET_TABLE_SKEWNESS视图定义,直接使用table_distribution()函数自定义输出,减少输出列进行计算优化,例如:

postgres=# SELECT schemaname,tablename,max(dnsize) AS maxsize, min(dnsize) AS minsize
postgres-# FROM pg_catalog.pg_class c
postgres-# INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
postgres-# INNER JOIN pg_catalog.table_distribution() s ON s.schemaname = n.nspname AND s.tablename =c.relname
postgres-# INNER JOIN pg_catalog.pgxc_class x ON c.oid = x.pcrelid AND x.pclocatortype = 'H'
postgres-# GROUP BY schemaname,tablename;
schemaname | tablename | maxsize | minsize
------------+-------------+-----------+-----------
 public  | orders   | 117686272| 117407744
 public  | mytable  | 253952  | 221184
 public  | customer  | 21979136 | 21848064
 public  | part    | 16982016 | 16867328
 public  | supplier  | 1433600 | 1417216
 public  | lineitem  | 559284224| 557981696
 public  | partsupp  | 77094912 | 76693504
(7 rows)

总结

分布式框架下的倾斜是个大课题,本文主要针对存储倾斜(不包含计算倾斜)重点分享我们在业务中如何尽快发现倾斜、定位倾斜,希望能给大家提供一些思路和帮助。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。