GaussDB(DWS)CBB组件之SysCache、RelCache、PartCache内存管控介绍

举报
疯狂朔朔 发表于 2022/04/02 15:45:38 2022/04/02
【摘要】 Cache是数据库高速运行的基础,GaussDB内核包括了众多的缓存,其中最重要的是SysCache、RelCache和PartCache。在本文中,将针对当前Cache内存的管控机制进行分析,着重介绍GaussDB内核将如何有效控制缓存占用。

在之前的文章中,详细介绍了Cache的工作原理:当用户连续执行SQL时,DWS内核会将该SQL所需要用到的元数据加载到SysCache、RelCache和PartCache中,以牺牲内存空间为代价,减少磁盘操作,提高查询性能。然而DWS内存空间并非无穷大,为保证数据库的高可用性,需要在内存空间紧张时主动清理Cache缓存,以有效释放内存占用。因此,这里产生了一个tradeoff:

  1. 何时失效Cache?
  2. 失效哪些Cache?

在本文中,我们将围绕这两个问题进行分析,介绍DWS是如何实现Cache内存管控的。

原始的内存降低手段--全失效

图1 Cache主动全失效流程图

如图所示,为Cache全失效流程图,每个CN线程和DN线程在接收到新请求或事务开始时,将做一次Cache占用判断,如果Cache占用超过256MB,则执行一次全失效,清空Cache。

该方法简单粗暴,能有效降低内存占用,凡是内存超过256MB的线程都会得到清理,但有以下几个问题:

  1. 该清理只在接收到新请求时才开始生效,若线程执行SQL过程较长,或SQL执行完毕以后,没有后续SQL执行,内存占用有可能无法得到及时释放。一旦该线程占用的内存资源无法释放,可能导致其他线程发生OOM错误。
    在这里,结合一个现场例子进行理解:
    在局点XXX的环境中,用户现场有个超大分区表,在用户业务脚本执行分区表查询操作后,单个线程的内存占用从0增长至200+MB,根据当时环境部署,一个节点包括一个CN进程和4个DN进程,也就是说共5个进程,每个进程都有200MB的内存无法及时回收,导致其他线程报OOM错误。
    分析该问题的原因,共有两点:
    其一是,在线程执行SQL过程中,内存需要进行及时释放,不要等到线程结束才统一释放;其二是,线程执行SQL结束以后,重新回归线程池,根据图一中Cache内存释放原理,此时回归线程池以后,内存并没有释放,需要等到该线程开始执行其他SQL时,才能进行内存释放。
  2. Cache全失效对性能有一定影响,有可能失效掉访问频繁的Cache,降低性能。
    在该方案中,内存失效方式比较暴力,不管Cache的访问频率,直接失效掉所有cache,然而这是不合理的,会影响性能。
    比如,对于pg_class中pg_attribute记录,该记录必然会频繁访问,失效掉该记录是不合理的,因为下一条SQL必然会加载该Cache。

为解决以上问题,我们在迭代过程中,逐渐实现了以下几个Cache内存管控机制。

定时内存降低手段--idle线程内存回收

为解决a)中的问题,我们设计了idle线程内存回收机制,其主要工作原理如下:

图2 内存清理信号发送流程图

图中左侧和右侧为两个线程,其中左侧线程在执行SQL过程中,在线程palloc内存过程中如果发生OOM错误,则该线程开始扫描其他线程的内存占用,对于内存占用超过64MB的线程,将发送内存清理信号,在其他线程(右侧线程)接收到信号以后,若该线程处于空闲状态,则执行内存清理。该方式有效解决了a)中线程结束后,无法清理的问题。

这里有几个关键点:

  • 在该内存释放机制中,为避免信号发送过于频繁,会在发送信号前将进行检测,60s内最多发送一次信号,防止信号爆炸。
  • 发送内存清理信号时机需要优化:其实该回收机制的主要目的是,在内存紧张时,主动通知(唤醒)其他idle线程执行内存清理,然而若等到palloc失败才开始通知,可能此时已经严重阻塞业务执行,应该更早通知其他线程进行缓存清理。

待实现的内存降低手段--LRU / Global Cache

这两种内存管控手段暂时还未实现,但作为内存管控方式之一,我们也可以单独拿出来分析一下。

  • LRU:该内存管控主要目的是末尾淘汰不常用的缓存,对于SysCache,其本质上就是一个队列;对于RelCache和PartCache,其实现逻辑是哈希表,通过对象的Oid进行哈希。综合考虑SysCache、RelCache和PartCache,可以发现,LRU内存管控是可能的,但实现LRU的前提是:1)如何评价Cache使用率;2)LRU性能影响分析。
  • Global Cache:DWS当前Cache为ThreadLocal类型,也就是说,每个线程维护自身Cache,然而在用户SQL任务并发较高的情况下,Cache会在线程间重复存储,占用额外的内存。因此,Global Cache的想法应运而生,该想法的主要目标是,取消掉Cache线程间的存储,所有Cache都通过指针,指向GlobalCache,以降低内存。然而,经过调查发现,Global Cache实现起来相对比较麻烦,其主要原因是,加锁频繁,在DDL频繁的情况下,严重影响性能。

至此,DWS内核Cache内存管控手段已经介绍完毕,如果小伙伴还有其他内存降低想法,欢迎留言讨论!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。