阿里云HybridDB for PostgreSQL内存与负载管理(resource queue)实践

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介:

标签

PostgreSQL , Greenplum , 阿里云HybridDB for PostgreSQL , 内存管理 , OOM , 操作系统内核参数 , 资源队列 , 数据库内存保护参数


背景

Greenplum是一个重计算和重资源的MPP数据库,可谓有多少资源就能消耗多少资源,带来的好处是处理速度变快了,坏处就是容易用超。

CPU、网络、硬盘用超的话,关系不大,因为大不了就是到硬件瓶颈,但是内存用超的话会带来较大的负面影响,例如操作系统OOM用户进程,导致数据库崩溃等。

如果要达到非常强壮的稳定性,Greenplum内存的配置非常的关键。(当然代码本身的质量也很关键)

如何避免OOM

OOM指遇到了进程申请内存不足的错误。例如

Out of memory (seg27 host.example.com pid=47093)  
VM Protect failed to allocate 4096 bytes, 0 MB available  
AI 代码解读

哪些情况会引发OOM

导致数据库OOM报错的原因可能有:

1、数据库节点的内存不足。

2、操作系统内存相关的内核参数配置不当。

3、数据倾斜,导致某些查询时,某个SEGMENT需要申请的内存超大。

4、查询倾斜,例如某些聚合、窗口函数的分组不是分布键,那么需要对数据进行重分布,重分布后导致某个SEGMENT的数据出现倾斜,导致某些查询是,某个SEGMENT需要申请的内存超大。

如何避免OOM

1、调整QUERY,使之需要更少的内存。

2、使用资源队列(Greenplum控制资源的一种手段),限制并发QUERY数。降低集群内同时运行的QUERY数,从而减少系统整体的内存资源的使用。

3、减少单个主机部署的SEGMENT数量,例如有128G内存的主机,部署16个和部署8个SEGMENT节点,每个节点能使用的内存相差了一倍。

4、增加单台主机的内存数。

5、设置数据库参数gp_vmem_protect_limit,限制单个SEGMENT可以使用的VMEM上限。单个主机的内存以及部署多少个SEGMENT决定了平均单个SEGMENT最多可以使用多少内存。

6、对于某些对内存使用量不可预知的SQL,通过在会话中设置statement_mem参数,限制单条SQL对内存的使用,从而避免单条SQL把内存吃光的情况。

7、也可以在库级别设置statement_mem参数。对这个数据库的所有会话生效。

8、使用资源队列(Greenplum控制资源的一种手段),限制这个资源组的内存使用上限,将数据库用户加入资源组,控制这些用户共同使用内存的上限。

如何配置内存相关参数

正确的配置(操作系统、数据库参数、资源队列管理)可以有效的降低OOM发生的概率。

1、加内存并不是最有效的方法,因为加内存还有成本问题,而且无法避免所有问题。

2、在计算单主机内单个SEGMENT的平均可使用内存时,不能只考虑primary segment,还需要考虑mirror segment,因为当集群出现主机故障时,会将SEGMENT切换到对应的MIRROR,此时,主机上跑的SEGMENT数就比平时更多了。

因此我们必须考虑到failover时,mirror需要占用的资源。

接下来我们分析一下操作系统内核配置、数据库配置。如何让数据库尽量的避免OOM。

操作系统内核参数

1、不要配置系统的huge page,因为Greenplum的PG版本较老,还没有支持huge page。而操作系统的huge page会锁定内存的分配,导致这部分内存不能被数据库节点使用。

2、vm.overcommit_memory,如果使用SWAP建议设置为2,如果不使用SWAP建议设置为0。

==============================================================      
.    
overcommit_memory:      
.    
This value contains a flag that enables memory overcommitment.      
.    
When this flag is 0,       // 比较友好,允许申请的内存空间通常不能超过"总内存-不可释放内存(RSS部分)"的部分。超过时申请内存才会报错。      
the kernel attempts to estimate the amount      
of free memory left when userspace requests more memory.      
.    
When this flag is 1,       // 比较暴力,因为大多数进程不管三七二十一,先使用malloc申请一打开空间,但是不使用它或者是只使用部分。所以设置为2时,不管什么情况都允许malloc申请成功,除非遇到真的内存不足的情况。  
the kernel pretends there is always enough memory until it actually runs out.      
.    
When this flag is 2,       // 最友好,在计算允许申请的内存空间时,将SWAP也算进去,也就是说申请大量内存时,可能触发SWAP但是允许你申请成功。  
                           // 在开启SWAP的时候,建议设置为2。GPDB官网也推荐设置为2。主要是防止OOM。  
the kernel uses a "never overcommit"      
policy that attempts to prevent any overcommit of memory.      
Note that user_reserve_kbytes affects this policy.      
.    
This feature can be very useful because there are a lot of      
programs that malloc() huge amounts of memory "just-in-case"      
and don't use much of it.      
.    
The default value is 0.      
.    
See Documentation/vm/overcommit-accounting and      
security/commoncap.c::cap_vm_enough_memory() for more information.      
.    
==============================================================      
.    
overcommit_ratio:      
.    
When overcommit_memory is set to 2,   // 当设置为2时,允许申请的内存地址范围不能超过“swap+内存大小*overcommit_ratio”  
the committed address space is not permitted to exceed     
      swap + this percentage of physical RAM.      
See above.      
.    
==============================================================     
AI 代码解读

3、overcommit_ratio,越大允许用户进程申请的内存空间越大,但是给操作系统保留的空间就越小。需要一个公式来计算。具体参考后面的例子。

数据库参数

1、gp_vmem_protect_limit

控制每个segment上,所有进程可以申请到的最大内存。如果这个值太高,可能触发系统的OOM或者更严重的问题。如果设置太低,则可能导致系统有足够内存的情况下,SQL确无法运行。

后面有设置公式。

2、runaway_detector_activation_percent

这个参数默认为90,是一个百分比值。当任一SEGMENT使用的内存超过(runaway_detector_activation_percent*gp_vmem_protect_limit/100)时,主动terminate QUERY。防止OOM。

terminate 的顺序从使用最多内存的QUERY依次开始,直到内存降低到(runaway_detector_activation_percent*gp_vmem_protect_limit/100)以下。

通过 gp_toolkit.session_level_memory_consumption 视图可以观察每个会话的内存使用情况,以及runaway的信息。

3、statement_mem

默认为125MB。设置单条SQL最多可以申请的内存,当超过这个内存时,写spill file文件。

建议的设置为单个SEGMENT的保护内存乘以0.9除以期望的最大SQL并行运行的值。

(gp_vmem_protect_limit * 0.9) / max_expected_concurrent_queries  
AI 代码解读

注意1,statement_mem在会话中设置,如果当前并行度很低,某个会话需要RUN一条需要大量内存的QUERY,可以在会话中设置一下。

注意2,statement_mem比较适合低并发的环境对内存的使用控制。对于高并发的环境,如果使用statement_mem来控制内存,你会发现每条QUERY可以使用的内存极少,不利于高并发情况下少量对内存需求多的QUERY的性能。建议高并发的情况下,使用资源队列(resource queue)来控制内存的使用上限。

4、gp_workfile_limit_files_per_query

限制每个QUERY可以使用的最大spill文件数(当QUERY申请的内存超过statement_mem的限制时,使用spill file(workfiles),类似操作系统的swap空间)。当使用的spill file超过限制时,QUERY会被terminate。

默认为0,表示无限制。

5、gp_workfile_compress_algorithm

设置spill file的压缩算法。Valid values are "NONE", "ZLIB".

设置压缩,CPU换空间,或CPU换IO能力。当磁盘紧张、磁盘spill file有写入瓶颈时可以设置压缩。

内存参数计算例子

gp_vmem,gp_vmem_protect_limit,vm.overcommit_ratio,设置举例:

环境如下:

主机配置:  
  
Total RAM = 256GB  
  
SWAP = 64GB  
  
部署配置:  
8 primary segments and 8 mirror segments per host, in blocks of 4 hosts (4台主机)  
  
当挂掉一台主机时,8PRIMARY要分摊到剩余的3台主机,最多单台额外承担3PRIMARY。所以是8+3=11。  
Maximum number of primaries per host during failure is 11  
AI 代码解读

1、首先计算给gpdb的总内存

(给操作系统保留 "7.5G + 5%内存" 的余量,算出整个系统给应用软件的实际可用内存。),然后(实际可用内存 除以 1.7的经验系数)

gp_vmem = ((SWAP + RAM)(7.5GB + 0.05 * RAM)) / 1.7  
        = ((64 + 256) - (7.5 + 0.05 * 256)) / 1.7   
        = 176  
AI 代码解读

2、计算overcommit_ratio,用到了一个经验系数0.026。

vm.overcommit_ratio = (RAM - (0.026 * gp_vmem)) / RAM   
                    = (256 - (0.026 * 176)) / 256   
                    = .982  
  
Set vm.overcommit_ratio to 98.  
AI 代码解读

3、计算每个segment的内存使用上线保护参数:gp_vmem_protect_limit,除以挂掉一台节点后单台节点需要运行的primary数。

gp_vmem_protect_limit calculation  
gp_vmem_protect_limit = gp_vmem / maximum_acting_primary_segments  
                      = 176 / 11   
                      = 16GB  
                      = 16384MB  
AI 代码解读

资源队列的使用

Greenplum resource queue可以用来限制“并发的QUERY数、总的内存使用”。当QUERY运行时,会添加到对应的队列中,使用的资源将记录到对应的队列中,对应队列的资源控制限制对该队列内的所有会话起作用。

Greenplum资源队列控制资源的思想和Linux 的CGROUP非常类似。

一、创建资源队列的语法:

Command:     CREATE RESOURCE QUEUE  
Description: create a new resource queue for workload management  
Syntax:  
CREATE RESOURCE QUEUE name WITH (queue_attribute=value [, ... ])   
where queue_attribute is:  
   ACTIVE_STATEMENTS=integer  
        [ MAX_COST=float [COST_OVERCOMMIT={TRUE|FALSE}] ]  
        [ MIN_COST=float ]  
        [ PRIORITY={MIN|LOW|MEDIUM|HIGH|MAX} ]  
        [ MEMORY_LIMIT='memory_units' ]  
|  MAX_COST=float [ COST_OVERCOMMIT={TRUE|FALSE} ]   
        [ ACTIVE_STATEMENTS=integer ]  
        [ MIN_COST=float ]  
        [ PRIORITY={MIN|LOW|MEDIUM|HIGH|MAX} ]  
        [ MEMORY_LIMIT='memory_units' ]  
AI 代码解读

解释

1、ACTIVE_STATEMENTS ,允许同时运行(active状态)的SQL数。 -1不限。

2、MEMORY_LIMIT 'memory_units kB, MB or GB' , 设置资源队列中所有SQL允许的最大内存使用量。 -1不限(但是受前面提到的数据库或系统参数限制,触发OOM错误。)。

SQL的内存使用限制不仅受资源队列限制,同时还受到参数限制:

2.1 参数gp_resqueue_memory_policy=none时,限制同Greenplum Database releases prior to 4.1。

2.2 参数gp_resqueue_memory_policy=auto时,如果设置了会话的statement_mem参数,或者设置了statement_mem参数时,单条QUERY允许申请的内存将突破资源队列的MEMORY_LIMIT限制。

例子

=> SET statement_mem='2GB';  
=> SELECT * FROM my_big_table WHERE column='value' ORDER BY id;  
=> RESET statement_mem;  
AI 代码解读

注意,还有一个系统参数max_statement_mem,这个可以理解为SEGMENT级别的内存使用安全控制阀,单个QUERY申请的memory不能超过max_statement_mem。

意思是你可以随便改会话级的statement_mem参数,但是不要随便改max_statement_mem参数。

建议的max_statement_mem设置:

(seghost_physical_memory) / (average_number_concurrent_queries)  
AI 代码解读

2.3 参数gp_resqueue_memory_policy=eager_free时,表示数据库在评估SQL对内存的申请渴望时,分阶段统计,也就是说一个SQL可能总共需要申请1G内存,但是每个阶段只申请100MB,所以需要的内存实际上是100MB。

使用eager_free策略,可以降低QUERY报内存不足的可能性。

3、MAX_COST float,设置为浮点或指数((for example 100.0),(for example 1e+2)),-1不限制。

表示资源组允许同时执行的QUERY加起来的COST上限。COST是SQL执行计划中的总成本。

4、COST_OVERCOMMIT boolean,当系统空闲时,是否允许(TRUE)超过max_cost的限制。

5、MIN_COST float,(资源超限时,是需要排队的)但是,当QUERY的成本低于min_cost时,不需要排队,直接运行。(也就是说小查询,就让他跑吧。)

6、PRIORITY={MIN|LOW|MEDIUM|HIGH|MAX},指当前资源队列的优先级,当资源紧张时,优先将CPU资源分配给高优先级的资源队列。(处于高优先级的资源队列中的SQL,可以获得更高优先级的CPU资源)。建议将实时性要求高的查询对应的用户分配到高优先级的资源队列中。

类似LINUX CGROUP中的CPU资源组,real time task和普通task的时间片策略。

二、修改资源队列限制举例:

ALTER RESOURCE QUEUE myqueue WITH (MAX_COST=-1.0, MIN_COST= -1.0);  
AI 代码解读

三、如何将用户放到资源队列中,举例:

ALTER ROLE sammy RESOURCE QUEUE poweruser;  
AI 代码解读

四、资源队列相关参数

1、gp_resqueue_memory_policy,资源队列的内存管理策略,前面讲了用法。

2、gp_resqueue_priority,是否使用资源队列的优先级。ON使用,OFF不使用。不使用资源队列优先级时,所有队列公平对待。

3、gp_resqueue_priority_cpucores_per_segment,每个SEGMENT可以使用的CPU核数,例如8核的机器,跑了2个PRIMARY SEGMENT,则配置为4。master 上面如果没有其他节点,配置为8。

当发生CPU抢占时,优先级高的资源组中运行的SQL,优先分配CPU资源。

4、gp_resqueue_priority_sweeper_interval,CPU时间片统计间隔,SQL执行时,计算它的share值(根据优先级以及计算gp_resqueue_priority_cpucores_per_segment出来)。

越小越频繁,优先级设置带来的效果越好。但是overhead越大。

五、建议的资源队列使用方法:

1、GPDB默认的资源队列为pg_default,如果不创建队列,那么所有的用户都会被指定给pg_default。这是非常不建议的。

建议的做法是为每个用户创建一个资源队列。(因为通常一个数据库用户对应一个业务。不同的数据库用户可能对应不同的业务或者使用者(例如业务用户、分析师用户、开发者、DBA等)。)

2、超级用户发起的SQL请求不受资源队列的限制,仅仅受前面讲到的参数的限制。因此如果要使用resource queue来限制资源的使用,那么就不建议业务使用超级用户来执行QUERY。

3、ACTIVE_STATEMENTS表示资源队列中,允许同时执行的SQL。(注意当QUERY的成本低于min_cost时,不需要排队,直接运行。)

4、MEMORY_LIMIT,设置资源队列中所有SQL允许的最大内存使用量。前面讲了突破方法,statement_mem设置的优先级更高,可以突破resource queue的限制。

注意所有资源队列的内存加起来不要超过gp_vmem_protect_limit的限制。

5、通过配置资源队列的优先级,可以区分不同的业务。例如出报表的业务优先级最高,其次是普通业务,其次是分析师。这样的情况,我们可以创建3个资源队列,分别使用MEDIUM|HIGH|MAX的优先级。

6、如果每个时间段的资源需求不一样,可以写一个CRONTAB任务,定时的调整资源队列的限制。

例如白天分析师的优先级更高,晚上处理报表的队列优先级更高。

目前Greenplum还不支持按时间段来设置资源限制,所以只能外部部署任务,alter resource queue来实现。

7、通过gp_toolkit提供的视图,可以观察资源队列的资源使用。

gp_toolkit.gp_resq_activity              
  
gp_toolkit.gp_resq_activity_by_queue     
  
gp_toolkit.gp_resq_priority_backend      
  
gp_toolkit.gp_resq_priority_statement    
  
gp_toolkit.gp_resq_role                  
  
gp_toolkit.gp_resqueue_status  
AI 代码解读

参考

http://greenplum.org/docs/best_practices/workloads.html

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
打赏
0
0
0
1
20702
分享
相关文章
|
8月前
|
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
117 6
Java内存管理:垃圾收集器的工作原理与调优实践
在Java的世界里,内存管理是一块神秘的领域。它像是一位默默无闻的守护者,确保程序顺畅运行而不被无用对象所困扰。本文将带你一探究竟,了解垃圾收集器如何在后台无声地工作,以及如何通过调优来提升系统性能。让我们一起走进Java内存管理的迷宫,寻找提高应用性能的秘诀。
Java 内存模型解析与实践
在Java的世界中,理解内存模型对于编写高效、线程安全的代码至关重要。本文将深入探讨Java内存模型的核心概念,并通过实例分析其对并发编程的影响,旨在为读者提供一套实用的策略和思考方式来优化多线程应用的性能与安全性。
113 0
Java内存模型的深入理解与实践
本文旨在深入探讨Java内存模型(JMM)的核心概念,包括原子性、可见性和有序性,并通过实例代码分析这些特性在实际编程中的应用。我们将从理论到实践,逐步揭示JMM在多线程编程中的重要性和复杂性,帮助读者构建更加健壮的并发程序。
深入理解计算机内存管理:优化策略与实践
深入理解计算机内存管理:优化策略与实践
ChatGPT高效提问—prompt实践(漏洞风险分析-重构建议-识别内存泄漏)
ChatGPT高效提问—prompt实践(漏洞风险分析-重构建议-识别内存泄漏)
141 0
阿里云云原生数据仓库 AnalyticDB PostgreSQL 版已完成和开源LLMOps平台Dify官方集成
近日,阿里云云原生数据仓库 AnalyticDB PostgreSQL 版已完成和开源LLMOps平台Dify官方集成。
【C语言】深度解析:动态内存管理的机制与实践
【C语言】深度解析:动态内存管理的机制与实践
106 0
Rust在网络爬虫中的应用与实践:探索内存安全与并发处理的奥秘
【8月更文挑战第31天】网络爬虫是自动化程序,用于从互联网抓取数据。随着互联网的发展,构建高效、安全的爬虫成为热点。Rust语言凭借内存安全和高性能特点,在此领域展现出巨大潜力。本文探讨Rust如何通过所有权、借用及生命周期机制保障内存安全;利用`async/await`模型和`tokio`运行时处理并发请求;借助WebAssembly技术处理动态内容;并使用`reqwest`和`js-sys`库解析CSS和JavaScript,确保代码的安全性和可维护性。未来,Rust将在网络爬虫领域扮演更重要角色。
190 1
PolarDB产品使用问题之如何进行PostgreSQL(简称PG)的全量和增量备份管理
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 推荐镜像

    更多
    AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等

    登录插画

    登录以查看您的控制台资源

    管理云资源
    状态一览
    快捷访问