GreenPlum 资源管理(基于linux cgroups)

   

目录

CPU和内存资源略

资源组对系统内存资源的隔离


      所有共享资源的系统都面临一个巨大的挑战—资源管理。当不同用户的多条语句同时在数据库中运行时,数据库需要巧妙地在这些用户这些语句中分配CPU、内存等资源,以便保证这些语句平稳运行。资源管理需要在公平性、确定性和最大资源利用率之间保持微妙的平衡,并且给予用户一些配置选择,以便适应不同的使用场景。公平性、确定性是指一个用户或者一个语句可以保证得到一部分资源,这部分资源在任何时候都不会被剥夺,这样用户的这个语句就相当于被保留了一个最小可用资源集合,不论这个语句执行得早与晚、快与慢,都至少可以获得这部分资源。最大资源利用率是指在系统相对空闲的时候,一个语句可以充分利用这些空闲的资源快速执行完毕。

CPU和内存资源略

CPU资源是可以按照时间片调度的。

相对来说,调整一个进程的CPU使用占比可以快速完成。而内存资源一旦被分配并且使用,释放要么需要很长时间完成,要么实现起来太复杂,所以动态调整内存资源比较困难。Greenplum 5实现了基于Linux cgroup的CPU资源管理,以及完全由Greenplum跟踪、记录和分配的内存资源管理,这一全新的资源管理称为资源组(ResourceGroup)

资源组充分权衡了不同的实现方式,根据CPU和内存资源的不同特点实现了公平而高效的管理。

cgroup是已经进入Linux内核的一个良好的资源分配特性,允许使用者创建不同的cgroup组,在配置文件中限定CPU的使用量。当用户将不同的进程对接到相应的cgroup组后,这些进程所能使用的CPU资源就会被限制在配置的数据之下或者附近,从而保证CPU资源在不同组之间的隔离。

cgroup还允许一个组的进程使用超出限额的CPU资源,只要系统其他组的CPU使用率低或者整个系统有空余的CPU资源。这个特性对数据库应用而言非常理想,资源组充分利用了这一特性,比如用户可以通过下面的SQL语句创建两个资源组:

对于这样的配置,用户tom1就和资源组rg1关联了,他的所有查询都将运行在资源组rg1中,用户tom2类似。这样当系统比较空闲时,例如rg2和其他组中没有语句运行时,用户tom1实际上可以使用更多的CPU资源,甚至可以超过资源组rg1定义的CPU资源限制50%,例如可能用到60%~70%。如果整个系统比较繁忙,其他组或者rg2都有足够多的语句在执行,那么rg1中的语句会立刻收缩对系统CPU的使用率,降低为受限的50%。这样就完美地解决了资源的最大利用率和公平性问题。从图中可以更加直观地观察这一特性。

资源组实现的这一CPU特性可以很好地照顾到各类负载,尤其是短查询。短查询是相对于长查询而言的,长查询是一个可以运行很多分钟甚至数小时的复杂查询,要耗费大量系统资源,甚至占用系统全部资源。而短查询则是一些毫秒或者秒级的短小查询,涉及的数据量较小,只需要少量CPU和内存资源就可以完成。对于一个支持混合负载的数据产品而言,系统中的长查询和短查询会不定期出现,很多用户的一个痛点是,当系统中运行着一个长查询时,这个语句有可能占用太多的系统CPU或者内存等资源,造成短查询无法获得哪怕很小部分的资源,表现为运行很慢、执行时间变长。在Greenplum里结合资源组就能避免这一问题。

对于上述的资源组rg1和rg2,如果在rg2中运行短查询,在rg1中运行长查询,那么在没有短查询时,长查询会使用更多CPU资源;

一旦有一个短查询到达rg2,那么长查询会立刻让出多占的CPU资源,短查询可以立刻享用自己应该使用的20%CPU资源。在我们的测试中,这种资源调整会在毫秒级完成

下图是一个测试数据汇总,可以看到,在有长查询和没有长查询时,短查询的执行时间几乎没有差别。如果用户将运行短查询的rg2的CPU资源设置得非常大(例如60%或者更高),那么在没有短查询时,其他组依然可以分享这部分CPU;当有短查询时,短查询可以享用绝大多数CPU资源来快速完成,从而实现一个偏向短查询的良好特性。

Greenplum 5.9中添加的一个新特性cpuset能够更好地保证短查询的资源。当用户创建一个类似下面这样的资源组rg3时,所有运行在rg3中的语句都会被调度到CPU核1上运行,而且rg3中的语句对CPU核1是独占的,其他组的语句只能被调度到其他核上。当有一个短查询需要在rg3中运行时,会立刻在核1上运行,而不用担心要先把大查询的进程调度出来。有客户测试了cpuset的特性,发现可以明显减少短查询的响应时间。

资源组对系统内存资源的隔离

对于rg1和rg2,它们会分别使用系统的30%和20%内存。各自组的语句使用的内存总和如果超过了配额,将会抢占使用整个系统的全局共享内存。如果全局共享内存已经用完,那么这个语句将会失败,从而保证整个集群的安全。系统的全局共享内存是创建资源组后剩余的没有分配的内存,这部分共享内存给混合负载提供了一定的灵活度。如果用户可以很好地预测每个组的内存需求,就可以把系统内存在各个组之间分配完,这样每个组的内存使用只能限制在自己组的限额内。如果用户的业务和每个组的负载不完全确定,或者会有不定期出现的巨大查询需要特别多的内存资源时,可以预留部分共享内存在所有组之间共享。这部分不确定但可能需要大量内存资源的语句,若使用完自己组内的内存份额,就可以使用这部分共享资源来继续执行。对于组内各个语句之间的内存分配,资源组也会充分权衡各种因素。在创建资源组时,可以通过

  • memory_shared_quota
  • memory_spill_ratio

对组内的内存使用进行微调,例如:

memory_shared_quota将一个资源组内的内存分为两部分:

  1. 组内各语句共享部分
  2. 每个语句独占的固定部分

  • 左半部分描绘了同一个节点上4个Segment可以使用的内存比例,空白部分的内存比例等于1-gp_resource_group_memory_limit,是预留给操作系统和Greenplum后台进程的,灰色部分的总和是gp_resource_group_memory_limit,然后平均分配给各个Segment。
  • 右半部分描绘了一个Segment上不同资源组的内存分配。每个Segment上都会有内建的admin_group和default_group。对于用户创建的rg_sample组,又用灰色展示了其共享内存和各个并发事务预留内存的关系。因为这个资源组定义的并发度为8,所以共有8个预留的固定内存段。同时,这个资源组的memory_shared_quota为50,意味着其总内存的50%是共享内存,其他50%是预留的固定内存,被8个事务均分。

每条运行的语句将会独占一部分固定内存,如Transaction slot #1所示,在语句开始执行后,会优先使用属于自己的这部分固定内存,之后使用组内共享的部分,最后才使用全局共享的部分。这样的多级资源配置可以在资源的隔离和共享方面达到很好的平衡,从而满足不同使用场景的内存需求。

resource group的另一个配置属性memory_spill_ratio将影响单个语句的内存使用量。对于rg_sample组,这个属性设为30,意味着当语句开始执行时,会计算该语句可以使用的内存量,并为其分配30%作为初始用量。当语句的执行计划生成后,会根据这个配置在不同的算子(例如表扫描算子或者排序算子)之间进行内存分配。缺省时,对于普通的操作只需要分配100KB的内存,对于哈希关联或者排序这样非常需要内存的操作,会平均分配其余内存。在执行哈希关联或者排序时,如果内存使用量超过为其分配的内存,那么该算子的运行开始利用外部文件来存储部分中间结果,从而缓解对内存的使用,这个过程称为spill。通常,在这个过程中,该算子的内存使用量还会保持上升,这就是为什么memory_spill_ratio要设为30并且可调,而不总是100%。memory_spill_ratio也是一个可以在会话中设置的GUC(即Global User Configuration,中文为全局用户配置,是可以在Master、Segment,或者所有节点设定的一些配置)。设置后,会对同一会话中的后续语句生效,这样用户可以允许一些语句使用更多或者更少的内存。

从图7-4可以看到,资源组借助不同的方式,在节点、Segment、用户组、用户、事务语句、语句内不同算子之间实现了细粒度的内存资源管理

在节点、Segment、用户组和事务语句之间实现了细粒度的CPU资源管理。这些设计充分权衡了资源使用的效率并保证了资源使用的隔离,同时考虑了资源使用中确定性和不确定的情况,对事务型短查询和分析型长查询都可以提供很好的支持,完全可以满足不同负载下对资源的使用需求和约束管理。

磁盘和网络I/O也是大家普遍关心的共享资源。在Greenplum中,磁盘访问和网络访问都是由执行引擎同步驱动的,所以当CPU资源在不同组之间出现分配限制后,理论上磁盘和网络I/O也得到了对应的分配限制。当然,现代计算机往往有很多核,在这些核上并行运行不同的进程时,它们使用的I/O资源可能不是完全按照CPU的比例来分配的。对于这部分可能的需求,Greenplum社区在持续跟踪用户的反馈,有可能在以后的版本中支持对这两种资源的管理。

猜你喜欢

转载自blog.csdn.net/MyySophia/article/details/113796280