分布式DB数据倾斜的原因和解法 - 阿里云HybridDB for PostgreSQL最佳实践

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介:

标签

PostgreSQL , Greenplum , query倾斜 , 存储倾斜 , OOM , disk full , 短板 , 数据分布


背景

对于分布式数据库来说,QUERY的运行效率取决于最慢的那个节点。

pic

当数据出现倾斜时,某些节点的运算量可能比其他节点大。除了带来运行慢的问题,还有其他的问题,例如导致OOM,或者DISK FULL等问题。

如何监控倾斜

1、监控数据库级别倾斜

postgres=#  select gp_execution_dbid(), datname, pg_size_pretty(pg_database_size(datname)) from gp_dist_random('pg_database') order by 2,1,pg_database_size(datname) desc;
 gp_execution_dbid |  datname  | pg_size_pretty 
-------------------+-----------+----------------
                 2 | postgres  | 42 GB
                 3 | postgres  | 42 GB
                 4 | postgres  | 42 GB
                 5 | postgres  | 42 GB
                 6 | postgres  | 42 GB
                 7 | postgres  | 42 GB
                 8 | postgres  | 42 GB
                 9 | postgres  | 42 GB
                10 | postgres  | 42 GB
... ...

2、监控表级倾斜

select gp_execution_dbid(), datname, pg_size_pretty(pg_total_relation_size('表名')) from gp_dist_random('gp_id') ;

出现数据倾斜的原因和解决办法

1、分布键选择不正确,导致数据存储分布不均。

例如选择的字段某些值特别多,由于数据是按分布键VALUE的HASH进行分布的,导致这些值所在的SEGMENT的数据可能比而其他SEGMENT多很多。

分布键的选择详见:

《Greenplum 最佳实践 - 数据分布黄金法则 - 分布列与分区的选择》

2、查询导致的数据重分布,数据重分布后,数据不均。

例如group by的字段不是分布键,那么运算时就需要重分布数据。

解决办法1:

由于查询带来的数据倾斜的可能性非常大,所以Greenplum在内核层面做了优化,做法是:

先在segment本地聚合产生少量记录,将聚合结果再次重分布,重分布后再次在segment聚合,最后将结果发到master节点,有必要的话在master节点调用聚合函数的final func(已经是很少的记录数和运算量)。

例子:

tbl_ao_col表是c1的分布键,但是我们group by使用了c398字段,因此看看它是怎么做的呢?请看执行计划的解释。

postgres=# explain analyze select c398,count(*),sum(c399),avg(c399),min(c399),max(c399) from tbl_ao_col group by c398;    
                                                                       QUERY PLAN                                                                           
--------------------------------------------------------------------------------------------------------------------------------------------------------    
 Gather Motion 48:1  (slice2; segments: 48)  (cost=123364.18..123582.28 rows=9693 width=96)    
 // 返回结果  
   Rows out:  10001 rows at destination with 120 ms to end, start offset by 1.921 ms.    
   ->  HashAggregate  (cost=123364.18..123582.28 rows=202 width=96)    
   // 重分布后再次聚合。  
	 Group By: tbl_ao_col.c398    
         Rows out:  Avg 208.4 rows x 48 workers.  Max 223 rows (seg17) with 0.001 ms to first row, 54 ms to end, start offset by 35 ms.    
         ->  Redistribute Motion 48:48  (slice1; segments: 48)  (cost=122928.00..123121.86 rows=202 width=96)    
         // 第一次聚合后,记录数以及降低到了几千行,因此重分布后即使出现倾斜,关系也不大。  
	       Hash Key: tbl_ao_col.c398    
               Rows out:  Avg 8762.2 rows x 48 workers at destination.  Max 9422 rows (seg46) with 31 ms to end, start offset by 63 ms.    
	       ->  HashAggregate  (cost=122928.00..122928.00 rows=202 width=96)    
               // 这一步是在segment节点聚合  
		     Group By: tbl_ao_col.c398    
                     Rows out:  Avg 8762.2 rows x 48 workers.  Max 8835 rows (seg2) with 0.004 ms to first row, 8.004 ms to end, start offset by 82 ms.    
                     ->  Append-only Columnar Scan on tbl_ao_col  (cost=0.00..107928.00 rows=20834 width=16)    
                           Rows out:  0 rows (seg0) with 28 ms to end, start offset by 64 ms.    
 Slice statistics:    
   (slice0)    Executor memory: 377K bytes.    
   (slice1)    Executor memory: 1272K bytes avg x 48 workers, 1272K bytes max (seg0).    
   (slice2)    Executor memory: 414K bytes avg x 48 workers, 414K bytes max (seg0).    
 Statement statistics:    
   Memory used: 128000K bytes    
 Settings:  optimizer=off    
 Optimizer status: legacy query optimizer    
 Total runtime: 122.173 ms    
(22 rows)    

对于非分布键的分组聚合请求,Greenplum采用了多阶段聚合如下:

第一阶段,在SEGMENT本地聚合。(需要扫描所有数据,这里不同存储,前面的列和后面的列的差别就体现出来了,行存储的deform开销,在对后面的列进行统计时性能影响很明显。)

第二阶段,根据分组字段,将结果数据重分布。(重分布需要用到的字段,此时结果很小。)

第三阶段,再次在SEGMENT本地聚合。(需要对重分布后的数据进行聚合。)

第四阶段,返回结果给master,有必要的话master节点调用聚合函数的final func(已经是很少的记录数和运算量)。

3、内核只能解决一部分查询引入的数据重分布倾斜问题,还有一部分问题内核没法解决。例如窗口查询。

postgres=# explain select * from (select row_number() over (partition by c2 order by c3) as rn , * from tbl_ao_col) t where rn=1;  
                                                       QUERY PLAN                                                          
-------------------------------------------------------------------------------------------------------------------------  
 Gather Motion 48:1  (slice2; segments: 48)  (cost=5294619.34..5314619.34 rows=1000 width=3208)  
   ->  Subquery Scan t  (cost=5294619.34..5314619.34 rows=21 width=3208)  
         Filter: rn = 1  
         ->  Window  (cost=5294619.34..5302119.34 rows=20834 width=3200)  
               Partition By: tbl_ao_col.c2  
               Order By: tbl_ao_col.c3  
               ->  Sort  (cost=5294619.34..5297119.34 rows=20834 width=3200)  
                     Sort Key: tbl_ao_col.c2, tbl_ao_col.c3  
                     ->  Redistribute Motion 48:48  (slice1; segments: 48)  (cost=0.00..127928.00 rows=20834 width=3200)  
                     如果c2的数据倾斜很严重,会导致某个SEGMENT节点的数据过多。后面的计算截断可能造成OOM或者disk full。  
			   Hash Key: tbl_ao_col.c2  
                           ->  Append-only Columnar Scan on tbl_ao_col  (cost=0.00..107928.00 rows=20834 width=3200)  
 Settings:  optimizer=off  
 Optimizer status: legacy query optimizer  
(13 rows)  

使用窗口函数时,Greenplum需要先按窗口中的分组对数据进行重分布,这一次重分布就可能导致严重的倾斜。

实际上内核层优化才是最好的解决办法,例如以上窗口函数,由于我们只需要取c2分组中c3最小的一条记录。因此也可以在每个节点先取得一条,再重分布,再算。

不通过修改内核,还有什么方法呢?

3.1 Mapreduce任务就很好解决,Greenplum的mapreduce接口调用方法如下:

http://greenplum.org/docs/ref_guide/yaml_spec.html

3.2 通过写PL函数也能解决。例如

declare  
  v_c2 int;  
  v_t tbl_ao_col;  
begin  
  for v_c2 in select c2 from tbl_ao_col group by c2  
  loop  -- 引入多次扫描数据的成本,其实是不划算的,还是内核解决最棒。  
    select t into v_t from tbl_ao_col as t where c2=v_c2 order by c3 limit 1;    
    return next v_t;  
  end loop;  
end;  

小结

数据倾斜的原因可能是数据存储的倾斜,QUERY执行过程中数据重分布的倾斜。

数据倾斜可能引入以下后果:

1、计算短板

2、oom

3、disk full

数据倾斜的解决办法:

1、如果是存储的倾斜,通过调整更加均匀的分布键来解决。(也可以选择使用随机分布,或者使用多列作为分布键)。

2、如果是QUERY造成的倾斜,Greenplum内核对group by已经做了优化,即使分组字段不是分布键,通过多阶段聚合,可以消除影响。

3、如果是窗口函数QUERY造成的倾斜,目前内核没有对这部分优化,首先会对窗口函数的分组字段所有数据进行重分布,如果这个分组字段数据有严重倾斜,那么会造成重分布后的某些节点数据量过大。解决办法有mapreduce或pl函数。

参考

《Greenplum 内存与负载管理最佳实践》

《Greenplum 最佳实践 - 数据分布黄金法则 - 分布列与分区的选择》

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
23天前
|
存储 关系型数据库 分布式数据库
电子好书发您分享《PolarDB分布式版架构介绍PolarDB分布式版架构介绍》
**《PolarDB分布式版架构介绍》电子书分享:** 探索阿里云PolarDB分布式设计,采用计算存储分离,借助GMS、CN组件实现大规模扩展。[阅读更多](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.3b3b2ccbVVjjt0)
19 3
|
1月前
|
Docker 容器 关系型数据库
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
本期课程将于4月11日19:00开始直播,内容包括源码编译基础知识和实践操作,课程目标是使学员掌握源码编译部署技能,为未来发展奠定基础,期待大家在课程中取得丰富的学习成果!
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
|
12天前
|
Cloud Native 关系型数据库 分布式数据库
电子好书发您分享《使用云起实验室体验PolarDB分布式版》
探索PolarDB分布式数据库!通过《使用云起实验室体验PolarDB分布式版》电子书,实践阿里云的云原生数据库。立即阅读:[阿里云电子书](https://developer.aliyun.com/ebook/8335/116575?spm=a2c6h.26392459.ebook-detail.5.abd645c0KlShdd)
38 7
|
15天前
|
运维 关系型数据库 分布式数据库
PolarDB产品使用合集之在选择分布式数据库时,主要考虑是什么
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
20天前
|
关系型数据库 分布式数据库 数据库
电子好书发您分享《PolarDB分布式版架构介绍》
阅读阿里云电子书《PolarDB分布式版架构介绍》,深入理解这款高性能数据库的分布式架构设计。书中通过图文并茂的方式揭示了PolarDB在分布式场景下的核心特性和技术优势,适合数据库爱好者和云计算从业者学习。[阅读链接](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.4ab72ccbIzDq2Q)
|
21天前
|
存储 SQL 关系型数据库
电子好书发您分享《PolarDB分布式版架构介绍》
**PolarDB分布式版详解:** 阿里云的PolarDB采用计算存储分离架构,利用GMS进行元数据管理,CN处理分布式SQL。结合PolarFS,实现高效存储与计算,支持大规模扩展。[阅读完整架构介绍](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.5b912ccbE20nqg)
|
24天前
|
存储 Cloud Native 关系型数据库
电子好书发您分享《PolarDB分布式版架构介绍 PolarDB分布式版架构介绍》
探索阿里云PolarDB分布式版的架构深度解析,该书详述了这款高性能云原生数据库的设计理念与技术特点,包括存储计算分离、水平扩展及分布式事务支持。[阅读电子书](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.35da2ccbye9KOt)
17 3
|
29天前
|
存储 SQL 关系型数据库
电子好书发您分享《PolarDB分布式版架构介绍》
**《PolarDB分布式版架构介绍》电子书分享:** 深入解析阿里云PolarDB分布式数据库的存储计算分离架构,采用GMS进行元数据管理,保证高可用。计算节点CN处理SQL,结合RDMA技术实现高效通信。[阅读更多](https://developer.aliyun.com/ebook/8332/116553?spm=a2c6h.26392459.ebook-detail.5.357b2ccbiQpsD1)
10 1
|
1月前
|
消息中间件 NoSQL Kafka
云原生最佳实践系列 5:基于函数计算 FC 实现阿里云 Kafka 消息内容控制 MongoDB DML 操作
该方案描述了一个大数据ETL流程,其中阿里云Kafka消息根据内容触发函数计算(FC)函数,执行针对MongoDB的增、删、改操作。
|
10月前
|
SQL Cloud Native 关系型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
780 1

相关产品

  • 云原生数据库 PolarDB