1背景AnalyticDBforPostgreSQL(简称ADBPG)是阿里云数据库团队基于PostgreSQL内核(简称PG)打造的云原生数据仓库产品。在数据实时交互分析、HTAP、ETL、BI报表生成等业务场景中,ADBPG具有独特的技术优势,广泛应用于金融、物流、互联网等行业。OtoT,替代自建Greenplum基准云数仓产品。数据仓库产品是数据分析系统的重要组成部分之一,各种在线业务对数据仓库产品的稳定性和可用性都有很高的要求。缺乏有效的资源管理机制会导致数据库产品的稳定性下降,出现连接数超过OS限制、内存不足、进程卡顿等问题,影响产品的可用性.资源队列(ResourceQueue)是ADBPG的一种资源管理方式,可以限制数据库的CPU、内存等资源,对多租户资源限制和数据库的稳定运行有一定的作用。顾名思义,ResourceQueue以队列的形式管理数据库集群上运行的SQL的资源。对于每个用户,他所有的连接只能属于一个队列。并且对于每个队列可以管理多个用户连接。不显示指定资源队列的用户将属于默认资源队列管理。通过限制每个队列的资源总量,我们可以达到限制某类业务或某类用户使用资源总量的目的。我们以ADBPG在线交易平台客户A为例,介绍ResourceQueue的使用。客户A基于ADBPG构建数据仓库,每天运行三类业务:以交易数据存储为代表的实时业务;用于支持决策分析的报表业务;用于实时大屏展示的可视化业务。根据三类业务的不同特点,我们按照以下策略配置资源队列。客户A实时业务的典型代表是交易数据通过Kafka->Flink->ADBPG链路实时写入ADBPG。这类业务的典型特点是峰值并发比较大,单条SQL的资源消耗小。在没有实施资源队列限制之前,业务高峰期查询并发量的突然增加往往会把数据库连接填满,导致高可用检测查询执行失败,导致实例不可用。对于这类业务,我们将其关联到CPU权重高、并发限制大(在安全阈值内)、单条SQL内存占有率低的队列。既保证了数据的快速存储,又防止了流量泛滥导致的系统不稳定。客户A的另一类典型业务是报表和ETL业务。此类业务会在实时业务的淡峰期进行调度,生成报表,提供决策支持。此类业务数据量大,内存消耗大,产生大量临时文件。对于这类业务,我们将其关联到低CPU权重、低并发限制、高内存占有率的队列,在满足业务需求的同时控制内存使用上限;此外,客户还支持基于ADBPG数据仓库的数据实时可视化展示。这种可视化方案往往并发度非常稳定,但是对查询延迟有一定的要求。对于这类业务,我们将其资源队列设置为高CPU权重,低并发限制,宽泛的优化器查询计划消耗份额,最大程度为其生成良好的查询计划,保证业务稳定性。接下来,本文将介绍如何使用ResourceQueue、状态监控及其实现机制。2ResourceQueue简介ResourceQueue支持SQL配置,支持四种资源限制:并发限制、CPU限制、内存限制、查询计划限制。用户可以通过SQL在数据库中定义多个资源队列,并为每个资源队列设置资源限制。在一个数据库中,每个资源队列可以关联一个或多个数据库用户,每个数据库用户只能属于一个资源队列。另外,并不是所有提交到资源队列的SQL都会受到queuelimit的限制。数据库只会限制SQL类型的资源利用率,例如SELECT、SELECTINTO、CREATETABLEASSELECT、DECLARECURSOR、INSERT、UPDATE和DELETE。另外,EXPLAINANALYZE命令执行过程中运行的SQL也会被排除在资源队列之外。资源队列支持的资源限制配置如下:通过SQL语句定义一个新的资源队列:CREATERESOURCEQUEUEetlWITH(ACTIVE_STATEMENTS=3,MEMORY_LIMIT='1GB',PRIORITY=LOW,MAX_COST=-1.0);ACTIVE_STATEMENTS:队列中允许同时运行的查询数,即队列中允许并发查询的最大并发值。数据库允许超过ACTIVE_STATEMENTS个数但小于最大数据库连接数MAX_CONNECTIONS个的链接连接到数据库,但是这些SQL连接不会立即开始运行,而是会排队。MAX_COST:查询计划成本限制。数据库优化器将计算每个查询的成本。如果总成本超过资源队列设置的MAX_COST的值,则查询将被拒绝。ADBPG默认配置为0,即无限制。MemoryLimit:ADBPG可以通过设置statement_mem来确定每个Segment上每个SQL使用的内存上限。MemoryLimit既没有默认值也不能指定。当没有配置MEMORY_LIMIT参数时,一个SQL在一个资源队列中允许的内存大小由statement_mem参数决定:如果一个资源队列没有设置MEMORY_LIMIT,分配给每个资源的内存大小是statement_mem的服务器配置参数,一个资源队列的可用内存大小是根据statement_mem和ACTIVE_STATEMENTS计算出来的。当资源队列设置了MEMORY_LIMIT时,单个SQL使用的内存量将由队列中的平均分配值(MEMORY_LIMIT/ACTIVE_STATEMENTS)和statement_mem中的最大值决定。具体计算方法参见后面的实现章节。可以在资源队列上并行执行的查询数量受该队列可用内存的限制。例如:对于队列etl,设置STATEMENTS=3,MEMORY_LIMIT=2.1G;那么,如果没有设置statement_mem,每个查询默认使用700MB内存。SQL1进入队列并使用700MB内存。此时队列剩余内存为1.4G;SQL2进入队列并将statement_mem设置为1.0GB。此时队列剩余内存为0.4GB;此时队列的剩余内存不能满足SQL3的内存使用要求(默认700GB),那么虽然队列中的并行查询数还没有达到队列限制,但是SQL3仍然无法执行,需要等待线。PRIORITY:运行在数据库上的SQL会根据所在资源队列的优先级设置来共享可用的CPU资源。当来自高优先级队列的语句进入活动运行语句组时,它会获得更高份额的可用CPU,同时减少具有较低优先级设置的队列中已运行语句的份额。查询的相对大小或复杂性不影响CPU分配。如果一个简单、低成本的查询与一个大型、复杂的查询并发运行,并且它们具有相同的优先级设置,它们将被分配相等份额的可用CPU资源。当新查询激活时,CPU份额将重新计算,但具有相同优先级的查询仍将获得相同数量的CPU。例如,管理员创建了三个资源队列:streaming、etl、prod,并相应地配置了如下优先级:streaming-低优先级etl-高优先级prod-最大优先级当数据库中只有etl队列有查询时1运行时与2同时,它们拥有相同的CPU份额,因为它们具有相同的优先级设置:上图中显示的百分比是近似值。高、低和中优先级队列的CPU使用率并不总是用这些比率准确计算。当流式队列中的查询开始运行时,etl队列中的两个查询仍然保持相等的CPU份额,而低优先级的查询3将以较低的CPU份额运行。当查询在最高优先级队列prod中排队时,它的CPU使用率会根据其最大优先级设置进行调整。这可能是一个非常简单的查询,但在完成之前,它会占用大部分CPU。其他查询优先使用较低的CPU份额。三ResourceQueue使用3.1创建资源队列ADBPG允许用户使用SQL创建资源队列并指定各种资源限制。使用CREATERESOURCEQUEUE命令创建一个新的资源队列。创建具有并发限制的队列设置了ACTIVE_STATEMENTS的资源队列限制了分配给队列的角色执行的并发查询的数量。使用(ACTIVE_STATEMENTS=3)创建资源队列etl;这意味着对于分配给etl资源队列的所有角色,在任何给定时刻,系统上只能运行三个活动查询。如果队列已经有三个查询在运行,并且一个参与者在队列上提交第四个查询,则第四个查询不能运行,直到一个槽被释放。创建具有内存限制的队列具有MEMORY_LIMIT设置的资源队列控制通过该队列提交的所有查询的总内存。当与ACTIVE_STATEMENTS结合使用时,为每个查询分配的默认内存量为:MEMORY_LIMIT/ACTIVE_STATEMENTS。例如,要创建一个活动查询限制为10且总内存限制为2000MB的资源队列(每个查询将在执行时分配200MB的段主机内存):CREATERESOURCEQUEUEetlWITH(ACTIVE_STATEMENTS=10,MEMORY_LIMIT='2000MB');此外,gp_vmem_protect_limit参数将限制在一个Segment上分配的内存总大小。该参数具有更高的优先级。如果此参数超过限制,查询可能会被取消。设置优先级为了控制资源队列对可用CPU资源的消耗,用户可以分配一个合适的优先级。ALTERRESOURCEQUEUEetlWITH(PRIORITY=LOW);ALTERRESOURCEQUEUEetlWITH(PRIORITY=MAX);3.2为资源队列分配角色(用户)一旦资源队列被创建,用户必须为他们合适的资源队列分配角色(用户).如果角色没有显式分配给资源队列,它们将进入默认资源队列pg_default。使用ALTERROLE或CREATEROLE命令将角色分配给资源队列。例如:ALTERROLEnameRESOURCEQUEUEqueue_name;使用登录资源队列创建角色名称;从资源队列中删除角色所有用户都必须分配给资源队列。如果没有显式分配给特定的队列,用户将进入默认的资源队列pg_default。如果用户想从资源队列中删除一个角色并将其放入默认队列,则可以将角色的队列分配更改为无。例如:ALTERROLErole_nameRESOURCEQUEUEnone;3.3修改资源队列创建资源队列后,用户可以使用ALTERRESOURCEQUEUE命令改变队列限制,或者使用DROPRESOURCEQUEUE命令删除资源队列。修改资源队列配置ALTERRESOURCEQUEUE命令更改资源队列限制。要更改资源队列的限制,请为队列指定所需的新值。例如:ALTERRESOURCEQUEUEetlWITH(ACTIVE_STATEMENTS=5);ALTERRESOURCEQUEUEetlWITH(PRIORITY=MAX);删除资源队列DROPRESOURCEQUEUE命令可以删除资源队列。要删除资源队列,队列不能分配角色,也不能有任何语句在其中等待。删除资源队列等;四、资源队列状态监控4.1查看队列中的语句和资源队列状态gp_toolkit.gp_resqueue_status视图允许用户查看负载管理资源队列的状态和活动。对于特定的资源队列,它显示了有多少查询正在等待运行以及有多少当前在系统中处于活动状态。查看系统中创建的资源队列,其限制属性和当前状态:SELECT*FROMgp_toolkit.gp_resqueue_status;4.2查看资源队列统计信息如果要跟踪资源队列统计信息和性能,用户可以使用pg_stat_resqueues系统视图来查看收集到的资源队列使用情况统计信息。选择*来自pg_stat_resqueues;4.3查看分配给资源队列的角色要查看分配给资源队列的角色,在pg_roles和gp_toolkit.gp_resqueue_status系统目录表上执行以下查询:SELECTrolname,rsqnameFROMpg_roles,gp_toolkit.gp_resqueue_statusWHEREpg_roles。rolresqueue=gp_toolkit.gp_resqueue_status.queueid;4.4查看资源队列的等待查询用户可以看到所有资源队列当前活跃和等待的查询:SELECT*FROMgp_toolkit.gp_locks_on_resqueueWHERElorwaiting='true';如果这个查询没有返回结果的话,说明资源队列中当前没有语句在等待。4.5查看活动语句的优先级查看当前正在执行的语句,提供优先级、sessionID等信息:SELECT*FROMgp_toolkit.gp_resq_priority_statement;4.6重置活动语句的优先级用户可以使用函数gp_adjust_priority(session_id,statement_count,priority)来调整当前正在执行的语句的优先级。使用此功能,用户可以提高或降低任何查询的优先级。例如:SELECTgp_adjust_priority(12,10000,'LOW');该函数的参数中,session_id代表会话id,statement_count代表会话中要调整的SQL的序号,priority为调整的优先级。可以通过gp_resq_priority_statement视图查询上述已有语句的信息。从gp_toolkit.gp_resq_priority_statement中选择*;五ResourceQueue实现ADBPG数据库是MPP架构,分为一个或多个Master和多个Segment。数据可以在多个段之间随机分布、散列和复制。在ADBPG中,ResourceQueue的资源限制级别是语句级别,即在整个SQL执行过程中的任何时刻,无论是否在事务中,都会受到资源队列的限制。上文提到,ResourceGroup支持并发、CPU、内存等限制,本节将详细介绍限制这些资源的实现细节。5.1并发限制ADBPG数据库是一个多进程模型。分布式数据库的每个节点都会启动多个子进程,每个子进程通过共享内存、共享信号量、共享消息队列实现进程间通信。ResourceQueue是基于分布式锁实现的。ADBPG中的所有SQL连接都会首先到达Master节点。经过解析和优化,当他们到达执行者级别时,他们会首先尝试获取类型为ResQueueLock的独占锁。在单个ADBPG节点中,同一时间只能有一个进程获取ResQueueLock类型的独占锁,并且每个进程只会包含一个线程。上文提到,ResourceGroup支持并发、CPU、内存等限制,本节将详细介绍限制这些资源的实现细节。5.1并发限制ADBPG数据库是一个多进程模型。分布式数据库的每个节点都会启动多个子进程,每个子进程通过共享内存、共享信号量、共享消息队列实现进程间通信。ResourceQueue是基于分布式锁实现的。ADBPG中的所有SQL连接都会首先到达Master节点。经过解析和优化,当他们到达执行者级别时,他们会首先尝试获取类型为ResQueueLock的独占锁。在单个ADBPG节点中,同一时间只能有一个进程获取ResQueueLock类型的独占锁,并且每个进程只会包含一个线程。对于ResourceQueue中的SQL,可以使用的内存上限计算如下:1)如果没有设置资源队列的memory_limit值,则直接取数据库的statement_mem值;2)如果设置了资源队列的内存限制值,则根据资源队列设置的memory_limit值计算资源组可以使用的内存总量;总量除以资源队列设置的并发数,得到单条SQL语句可以使用的上限。然后取这个上限和statement_mem的最大值作为SQL使用内存的上限。5.3CPU限制ResourceQueue的CPU限制是一个很有意思的实现。ADBPG针对ResourceQueueCPUlimiting的功能,推出了一个专门的进程:sweeper进程,用于监控各个后台进程的CPU使用率,调整各个后台进程的CPU份额。这个进程是一个高度独立于数据库的进程。它不加载任何缓存或资源,也不能启动事务或检查系统表。它的活动是不断地读写共享内存,并计算每个进程的CPU使用率。更改CPU分配份额。每个真正执行SQL的后台进程(backend)都会根据计算出的CPUshare进入休眠一定时间,从而调整每条SQL的实际CPU使用率。这个进程的主要过程如上,它的过程也很简单,就是不断的sweep和sleep。每个真正执行SQL的后端进程在启动时都会在共享内存中注册一些状态,并在执行过程中执行getrusage等系统调用来更新CPU使用状态;清扫进程将使用这些共享内存状态和设置的资源队列CPU利用率值更新共享内存中相应后端进程的CPU份额(targetCPU)。后端运行时,会根据CPU份额调用BackoffBackend休眠一段时间,从而调整整体的CPU利用率。在运行过程中,分布式数据库的每个计算节点都会有一个sweeper进程来调整每个节点的CPU调用,使得资源队列的CPU配置全局有效。6.总结资源管理对于数据库集群的多租户管理和资源的细粒度分配具有重要价值。ResourceQueue可以对分布式数据库进行全面的资源管控,在多租户隔离和保障数据库整体平稳运行方面具有一定的价值。除了ResourceQueue这种资源管理方式,ADBPG还支持ResourceGroup这种资源管理方式,可以进行更细粒度的资源控制。ResourceGroup目前在专有云环境中可用,未来将逐步在公有云中提供能力。后面我们会介绍ResourceGroup的基本用法和最佳实践。
