GPDB-内核特性-资源组内存管理机制-2

简介: GPDB-内核特性-资源组内存管理机制-2

GPDB-内核特性-资源组内存管理机制-2本次介绍资源组内存管理的实现。


1、资源组控制器的创建


资源组控制器由函数ResGroupControlInit创建:主要关注点:资源管理控制器pResGroupControl在共享内存中,hash表和slot池也在共享内存;资源组最多可以建100个,slot池大小为max_connections。


2、资源组控制器初始化


资源组控制器创建后,需要对其进行初始化,比如计算segment总内存等。该功能由InitResGroups完成。堆栈如:InitProcess->InitResManager->InitResGroups。

主要完成计算totalChunks、freeChunks、safeChunksThreshold100和完成CPU相关设置并将已有资源组加载到共享内存。计算方法前章节已有介绍。


3、创建资源组


资源组创建语句为:CREATE RESOURCE GROUP rgroup1 WITH (CPU_RATE_LIMIT=20, MEMORY_LIMIT=25, MEMORY_SHARED_QUOTA=60,MEMORY_SPILL_RATIO=20);由函数CreateResourceGroup完成创建。资源组的创建流程:


重点关注下如何将资源组加入共享内存中的AllocResGroupEntry函数:1)计算group->memExpected:资源组定义改组的总内存;2)从pResGroupControl->freeChunks链表中分配内存,有可能比group->memExpected小;3)将实际分配的内存chunk分配给slots和共享区,优先slots。slots的总配额为group->memQuotaGranted,共享区总配额为group->memSharedGranted


4、资源组SQL的分发与接收


Master需要将资源组创建SQL的执行计划发送给segment以供在segment上创建资源组。分发函数为CdbDispatchUtilityStatement。Segment由exec_mpp_query接收到该SQL执行计划后进行反序列化解析并执行。


5、资源组信息的分发与接收


开启一个事务时,会将其分配到资源组中。由此可以控制资源组内并发数。这个动作在master上控制。    StartTransaction        if (ShouldAssignResGroupOnMaster())            AssignResGroupOnMaster();

Master上开启事务,开启事务时分配资源组。若gp_resource_group_bypass开启或者是SET、RESET、SHOW命令则资源组为bypass模式,内存的限制为30MB。其他SQL则走上图中蓝色框内的分支:从资源组的空闲链表中找一个空闲的slot;若超出并发数或者没有空闲slot了,则将该进程加入等待队列,直到gp_resource_group_queuing_timeout超时退出,或者被唤醒。被唤醒时要么将其从资源组等待队列中删除,要么该进程上的slot没有等待时将其释放。开启事务,分配资源组后,在执行器执行时ExecutorStart会将该执行计划分发给segment。这就需要将执行计划序列化以便发送。

640.png


序列化执行计划时也会将资源组信息带进去,由函数SerializeResGroupInfo函数完成。QD上以bypass模式通过bypassedSlot.groupId分发资源组ID。Segment上接收该执行计划,并将资源组信息反序列化出来。由函数SwitchResGroupOnSegment完成。

3、资源组内存如何限制


资源组下,申请内存同样是gp_malloc函数申请,也就是内存上下文中申请。

当需要申请新的chunk时,需要判断下是否达到了红线,达到红线后先清理下再申请。红线即pResGroupControl->safeChunksThreshold100。申请块:VmemTracker_ReserveVmemChunks->ResGroupReserveMemory:

申请内存的顺序在函数groupIncMemUsage中:

    static int32
    groupIncMemUsage(ResGroupData *group, ResGroupSlotData *slot, int32 chunks)
    {
      int32      slotMemUsage;  /* 当前slot已使用chunk数*/
      int32      sharedMemUsage;  /* the total shared memory usage,
                        sum of group share and global share */
      int32      globalOveruse = 0;  /* the total over used chunks of global share*/
      /* slotMemUsage = slot->memUsage + chunks */
      slotMemUsage = pg_atomic_add_fetch_u32((pg_atomic_uint32 *) &slot->memUsage,chunks);
      /* sharedMemUsage >0:slot配额不够分配 */
      sharedMemUsage = slotMemUsage - slot->memQuota;
      if (sharedMemUsage > 0){
        /* share区分配数 */
        int32 deltaSharedMemUsage = Min(sharedMemUsage, chunks);
        /* oldSharedUsage = group->memSharedUsage
        *  group->memSharedUsage+=deltaSharedMemUsage
        */
        int32 oldSharedUsage = pg_atomic_fetch_add_u32((pg_atomic_uint32 *)
                                 &group->memSharedUsage,
                               deltaSharedMemUsage);
        /* 共享区空闲chunk数 */
        int32 oldSharedFree = Max(0, group->memSharedGranted - oldSharedUsage);
        /* 超出共享区分配数*/
        int32 deltaGlobalSharedMemUsage = Max(0, deltaSharedMemUsage - oldSharedFree);
        /* freeChunks -= deltaGlobalSharedMemUsage 全局共享区超出分配数 */
        int32 newFreeChunks = pg_atomic_sub_fetch_u32(&pResGroupControl->freeChunks,
                              deltaGlobalSharedMemUsage);
        /* globalOveruse >0:超出共享区分配数 */
        globalOveruse = Max(0, 0 - newFreeChunks);
      }
      /*分组已使用chunk数,不论在哪部分分配 */
      pg_atomic_add_fetch_u32((pg_atomic_uint32 *) &group->memUsage,chunks);
      return globalOveruse;
    }

    5、总结


    这里介绍了资源组内存分配如何执行,包括两种分配模式:bypass模式和资源组分配模式。尤其需要注意bypass模式,QE上它的内存分配限制仅10MB,QD上分配限制是30MB。Bypass模式仅适用于SET、RESET、SHOW语句,开始事务时分配资源组,然后将资源组信息分发到QE。可以看到同一个事务中的SQL语句都使用同一个资源组。

    目录
    相关文章
    |
    7月前
    |
    存储 算法 编译器
    【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
    【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
    169 0
    |
    6天前
    |
    算法 Linux
    深入探索Linux内核的内存管理机制
    本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
    |
    1月前
    |
    算法 Linux 开发者
    深入探究Linux内核中的内存管理机制
    本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
    |
    14天前
    |
    存储 算法 安全
    深入理解Linux内核的内存管理机制
    本文旨在深入探讨Linux操作系统内核的内存管理机制,包括其设计理念、实现方式以及优化策略。通过详细分析Linux内核如何处理物理内存和虚拟内存,揭示了其在高效利用系统资源方面的卓越性能。文章还讨论了内存管理中的关键概念如分页、交换空间和内存映射等,并解释了这些机制如何协同工作以提供稳定可靠的内存服务。此外,本文也探讨了最新的Linux版本中引入的一些内存管理改进,以及它们对系统性能的影响。
    |
    1月前
    |
    缓存 算法 Linux
    Linux内核中的内存管理机制深度剖析####
    【10月更文挑战第28天】 本文深入探讨了Linux操作系统的心脏——内核,聚焦其内存管理机制的奥秘。不同于传统摘要的概述方式,本文将以一次虚拟的内存分配请求为引子,逐步揭开Linux如何高效、安全地管理着从微小嵌入式设备到庞大数据中心数以千计程序的内存需求。通过这段旅程,读者将直观感受到Linux内存管理的精妙设计与强大能力,以及它是如何在复杂多变的环境中保持系统稳定与性能优化的。 ####
    36 0
    |
    7月前
    |
    算法 安全 Linux
    探索Linux内核的虚拟内存管理
    【5月更文挑战第20天】 在本文中,我们将深入探讨Linux操作系统的核心组成部分之一——虚拟内存管理。通过剖析其关键组件和运作机制,揭示虚拟内存如何提供高效的内存抽象,支持庞大的地址空间,以及实现内存保护和共享。文章将重点讨论分页机制、虚拟内存区域(VMAs)的管理、页面置换算法,并简要分析这些技术是如何支撑起现代操作系统复杂而多变的内存需求的。
    |
    2月前
    |
    存储 算法 C语言
    MacOS环境-手写操作系统-15-内核管理 检测可用内存
    MacOS环境-手写操作系统-15-内核管理 检测可用内存
    45 0
    |
    4月前
    |
    算法 安全 UED
    探索操作系统的内核空间:虚拟内存管理
    【7月更文挑战第50天】 在现代操作系统中,虚拟内存管理是核心功能之一,它允许操作系统高效地使用物理内存,并为应用程序提供独立的地址空间。本文将深入探讨操作系统虚拟内存管理的机制,包括分页、分段以及内存交换等关键技术,并分析它们如何共同作用以实现内存的有效管理和保护。通过理解这些原理,读者可以更好地把握操作系统的内部工作原理及其对应用程序性能的影响。
    |
    6月前
    |
    算法 Java
    垃圾回收机制(Garbage Collection,GC)是Java语言的一个重要特性,它自动管理程序运行过程中不再使用的内存空间。
    【6月更文挑战第24天】Java的GC自动回收不再使用的内存,关注堆中的对象。通过标记-清除、复制、压缩和分代等算法识别无用对象。GC分为Minor、Major和Full类型,针对年轻代、老年代或整个堆进行回收。性能优化涉及算法选择和参数调整。
    76 3
    |
    6月前
    |
    存储 Python
    Python成员属性的内存特性与底层内存优化方案
    这篇博客主要分享一下python成员属性的内存特性,也就是python底层节约内存的优化方案