炫“库”行动-人大金仓有奖征文,内存巨页引发OOM的经典案例
Posted beyondma
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了炫“库”行动-人大金仓有奖征文,内存巨页引发OOM的经典案例相关的知识,希望对你有一定的参考价值。
最近人大金仓的KingbaseES数据库火了,作为新一代的HTAP混合负载型数据库,KingbaseES凭借着优异的性能,在国产信创数据库中独领风骚,在各方面几乎全部领先于其它对手,近年来被广泛使用。但是数据库国产化替代的去O过程是非常艰苦的,在这个KingbaseES逐渐被各行各业所接受的时点上,因此这里笔者就分享一下在生产环境中实际使用KingbaseES碰到的问题,以帮助大家更好、更快的了解这款数据库的特性。
由于一些实际当中的具体情况涉及敏感信息,因此以下全部都是脱敏之后的描述,提供给大家参考。
问题现象-由于OOM机制造成的崩溃
简单来讲这是一个由于内存造成的Kingbase崩溃的问题。一般来讲我们在生产环境使用KingbaseES时所配备的服务器内存都很富裕,使用中会将KingbaseES默认的shared_buffers参数也就是共享内存缓冲区调教的比较高,并且关掉Linux的OOM以保证KingbaseES进程不会被操作系统的内存释放机制所杀掉。但是我们这样的配置策略上还是遇到了由于内存问题,造成KingbaseES无法正常启动的问题。具体现象如下:
- KingbaseES在运行一段时间之后就会崩溃。
- 如果关闭Linux操作系统的OOM,则操作系统有可能出现问题。
- 如果打开OOM则KingbaseES会被杀掉
- 通过查看系统运行情况确认KingbaseES使用的最大内存从未超过系统内存总量的85%,而且绝对内存的数量还很富裕。
问题分析过程-规避解决方案
首先进入到我们视线的是temp_buffers 参数的设置,temp_buffers设置每个数据库会话使用的临时缓冲区的最大内存。KingbaseES推荐使用的默认默认设置 8MB,但是我们在生产上的实际设置比8MB大得多。但我们后来实际排查了一下会话使用的SQL语句,存在着几个优化点,但在之前发现会话性能问题时没有深入分析,只是简单扩大缓存了事,这也是这个问题的直接原因。具体SQL的优化点如下:
1.没有谓词下推
SQL语句中where后的查询条件也被称为谓词条件,谓词条件的输出结果只有“真”或“假”两种,谓词条件出现在Where关键字后,用于缩小查询所返回的结果集范围。谓词下推多用于子查询优化中,更早应用谓词条件,可以起到提前过滤结果集的作用,使后续的表对象关联开销更低,具体如下:
优化前的SQL语句是:SELECT * FROM (SELECT AAA, BBB, CCC, SUM(DDD) FROM DDD_TABLE GROUP BY AAA, BBB, CCC) CCC_DDD WHERE CCC=1
优化后的语句为:SELECT * FROM (SELECT AAA, BBB, CCC, SUM(DDD) FROM DDD_TABLE WHERE CCC=1 GROUP BY AAA, BBB, CCC) CCC_DDD
而没有谓词下推也是造成会话缓存需求量较大的原因之一。
- 没有进行模糊查询的优化,之前的SQL语句在完成模糊匹配条件时,使用的是前定向方式如”%xxxx”,而前定向的方式无法使用索引,并由此造成了一定性能损失,而之前将这个性能问题定位成为了,缓存空间不够,而由这个错误结论做出的扩容客户端缓存的方案同样也是错误的。优化方案如下:
优化前:SELECT * FROM A WHERE A.NAME like ‘%xxx%’
优化后:SELECT * FROM A WHERE A.NAME like ‘w%xxx%’
当我们减少temp_buffers参数,使用KingbaseES官方推荐值8MB的设置以后,这个崩溃问题就没有再发生过了了,可以说问题到此被规避解决掉了。
问题分析过程-根因定位
后来在深入分析问题的时候,huge_pages也就是是否开启巨页这个选项进入了我们眼帘。这个参数的默认值是try,但我们按照其它数据库的运维经验直接这个开关打开成了on。而且按照我们Linux的基线,HugePage巨型页的大小被设置为默认值的10倍也就是20MB。
/cat/proc/MemInfo
Hugepagesize: 20480 kB
而这个巨型页恰恰也就是问题的根本原因。而要搞清这个问题,我们还要先从Linux的内存管理的模型说起。如果把计算机比成一个酒店,那内存就是客房,进程就是住户而Linux这样的操作系统就是酒店管家,从这个角度上内存逻辑地址、线性地址以及物理地址可以做如下方式理解:
逻辑地址:应用进程中直接访问的地址就是逻辑地址,逻辑地址的引入其实就是让进程之间彼此相互不会影响,都以为自己独享整个酒店的空间,而屏蔽了底层物理地址的硬件细节。逻辑地址层也就是内存对于应用进程的抽象层
线性地址(Linear Address)也叫虚拟地址(virtual address):这层的引入其实基本上是由于英特尔对于x86向前兼容的需要,按照原有的英特尔规划,线性地址是暴露给操作系统管理的,也就是应用所在的逻辑地址空间会映射到一个大的线性空间,方便操作系统统一调用管理。因为线性地址在操作系统看来是完全线性连续性,包括内存、IO设备等等在这个线性地址空间进行线性 映射从而屏蔽了底层的细节。所线性地址层是内存对操作系统的内存抽象层。
物理地址:这就是真正的CPU地址总线访问内存使用的址了,物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存、Bios等)。
在实际地址映射时,CPU要利用内存管理单元,先将为个逻辑地址转换成一个线性地址,再利用分页功能,转换为最终物理地址。也就是进程访问的逻辑地址可能都是0x0001,但是最终他们访问到的物理地址完全不同。而操作系统在进行物理内存分配时要做的是尽量保证内存分配的连续性,虽然在各应用进程的看到的连续地址也可以映射为不连续的物理地址上,但是这样做的代价就是大幅牺牲执行效率。因为CPU缓存一般都是针对物理内存做高速缓存的优化,而逻辑地址是CPU看不到也不关心的。因此一般操作系统都会保证将用户进程申请的内存区域,映射到连续的物理内存上去。
那么这就引出了内存管理的粒度也就是内存页大小的设置问题,如果页过大,那么就会出现申请的内存很小但分配的内存页却很大的情况,这会内存空间的浪费,如果页过小,记录内存页信息的页表象也就会非常多,反而浪费了内存并且牺牲效率。由于数据库一般都会用到很多连续的内存,把内存页调教的空间大一点,反而有利于数据库性能优化,因此一般来讲按照经验,数据库服务器上的内存页一般会开启HugePage也就是巨页模式。
但HugePage虽好,但也带来了潜在问题,那就是一旦应用进程产生了缺页中断时,操作系统会直接给你分配一个HugePage来满足你的需求,并且HugePage还不会被SWAPOUT交换到SWAP区去,因此HugePage模式强制开启再叠加HugePage大小增加与会话连接缓存增加等几个参数的配置,会使Linux无法分配出HugePage内存,并恰好触发Linux的OOM内存保护机制,从而造成问题。
问题小结
那么总结这个问题,我们可以得到以下的经验。
- 遇到问题尽量从根本上解决。像我们之前的做法遇到数据库会话效率低,不考虑优化SQL,而是直接调大缓存。这就造成了所有的会话,包括那些用不到那么多内存的会话也被强制分配给了很大的内存空间,造成了浪费不说,还隐藏了问题。
- 调整KingbaseES默认参数时一定要慎重。在需要调整KingbaseES的默认参数时一定要小心再小心,经过完善的测试才可以在生产应用。
- HugePage虽然很好但是却要小心使用。虽然巨页的引入有助于提升效率,但是参数调教还是需要操作系统与KingbaseES之间的长期磨合。
以上是关于炫“库”行动-人大金仓有奖征文,内存巨页引发OOM的经典案例的主要内容,如果未能解决你的问题,请参考以下文章
炫“库”行动-人大金仓有奖征文—金仓数据库的Windows安装教程
炫“库”行动-人大金仓有奖征文--改造TPCE测试工具dbt5,提升测试结果tpSE