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语句都使用同一个资源组。

    目录
    相关文章
    |
    3月前
    |
    存储 算法 编译器
    【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
    【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
    119 0
    |
    3月前
    |
    算法 安全 Linux
    探索Linux内核的虚拟内存管理
    【5月更文挑战第20天】 在本文中,我们将深入探讨Linux操作系统的核心组成部分之一——虚拟内存管理。通过剖析其关键组件和运作机制,揭示虚拟内存如何提供高效的内存抽象,支持庞大的地址空间,以及实现内存保护和共享。文章将重点讨论分页机制、虚拟内存区域(VMAs)的管理、页面置换算法,并简要分析这些技术是如何支撑起现代操作系统复杂而多变的内存需求的。
    |
    2月前
    |
    算法 Java
    垃圾回收机制(Garbage Collection,GC)是Java语言的一个重要特性,它自动管理程序运行过程中不再使用的内存空间。
    【6月更文挑战第24天】Java的GC自动回收不再使用的内存,关注堆中的对象。通过标记-清除、复制、压缩和分代等算法识别无用对象。GC分为Minor、Major和Full类型,针对年轻代、老年代或整个堆进行回收。性能优化涉及算法选择和参数调整。
    36 3
    |
    1月前
    |
    设计模式 并行计算 安全
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    28 0
    |
    2月前
    |
    存储 Python
    Python成员属性的内存特性与底层内存优化方案
    这篇博客主要分享一下python成员属性的内存特性,也就是python底层节约内存的优化方案
    |
    2月前
    |
    Rust 安全 开发者
    探索Rust语言的内存安全特性
    【6月更文挑战第8天】Rust语言针对内存安全问题提供了创新解决方案,包括所有权系统、借用规则和生命周期参数。所有权系统确保值与其所有者绑定,防止内存泄漏;借用规则保证同一时间只有一个可变引用或多个不可变引用,消除数据竞争和野指针;生命周期参数则强化了引用的有效范围,提升安全性。通过这些特性,Rust帮助开发者编写出更健壮、安全的高性能软件,有望成为系统编程领域的领头羊。
    |
    3月前
    |
    机器学习/深度学习 算法 Linux
    xenomai内核解析--实时内存管理--xnheap
    Xenomai是一个实时操作系统(RTOS)层,用于Linux,旨在提供确定性的任务调度和服务。其内存管理机制包括一个名为xnheap的内存池,确保内存分配和释放的时间确定性,以满足硬实时系统的严格需求。
    124 0
    xenomai内核解析--实时内存管理--xnheap
    |
    3月前
    |
    缓存 算法 安全
    探索Linux内核的虚拟内存管理
    【5月更文挑战第29天】 在现代操作系统中,虚拟内存是支持多任务处理和内存保护的关键组件。本文深入分析了Linux操作系统中的虚拟内存管理机制,包括其地址空间布局、分页系统以及内存分配策略。我们将探讨虚拟内存如何允许多个进程独立地访问它们自己的地址空间,同时由操作系统管理物理内存资源。此外,文章还将涉及虚拟内存所带来的性能影响及其优化方法。
    |
    3月前
    |
    算法 安全 Linux
    深度解析:Linux内核内存管理机制
    【4月更文挑战第30天】 在操作系统领域,内存管理是核心功能之一,尤其对于多任务操作系统来说更是如此。本文将深入探讨Linux操作系统的内核内存管理机制,包括物理内存的分配与回收、虚拟内存的映射以及页面替换算法等关键技术。通过对这些技术的详细剖析,我们不仅能够理解操作系统如何高效地利用有限的硬件资源,还能领会到系统设计中的性能与复杂度之间的权衡。