MongoDB tcmalloc 内存缓存分析

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

背景

image

image

从监控看 Secondary 使用的物理内存比 Primary 多 11GB 左右,

基本的内存分析可以先看团队另一位同学写的这个排查文档

用户没有设置在备库读,Secondary 基本没有流量,只有复制的流量,连接数也不多,基本排除是业务行为导致 Secondary 内存高,所以怀疑和 tcmalloc 分配器的缓存行为有关。

排查

查看Primary 和 Secondary 的 serverStatus.tcmalloc 输出,

Primary,

mgset-25489817:PRIMARY> db.serverStatus().tcmalloc
{
        "generic" : {
                "current_allocated_bytes" : NumberLong("16296822448"),
                "heap_size" : NumberLong("34201272320")
        },
        "tcmalloc" : {
                "pageheap_free_bytes" : 933314560,
                "pageheap_unmapped_bytes" : NumberLong("15870619648"),
                "max_total_thread_cache_bytes" : NumberLong(1073741824),
                "current_total_thread_cache_bytes" : 543050048,
                "total_free_bytes" : NumberLong(1100498976),
                "central_cache_free_bytes" : 557461008,
                "transfer_cache_free_bytes" : 4096,
                "thread_cache_free_bytes" : 543031184,
                "aggressive_memory_decommit" : 0,
                "pageheap_committed_bytes" : NumberLong("18330652672"),
                "pageheap_scavenge_count" : 22937964,
                "pageheap_commit_count" : 31247638,
                "pageheap_total_commit_bytes" : NumberLong("218141866151936"),
                "pageheap_decommit_count" : 23394903,
                "pageheap_total_decommit_bytes" : NumberLong("218123535499264"),
                "pageheap_reserve_count" : 9872,
                "pageheap_total_reserve_bytes" : NumberLong("34201272320"),
                "spinlock_total_delay_ns" : NumberLong("113428202936"),

Secondary,

mgset-25489817:SECONDARY> db.serverStatus().tcmalloc
{
        "generic" : {
                "current_allocated_bytes" : NumberLong("16552694552"),
                "heap_size" : NumberLong("33373687808")
        },
        "tcmalloc" : {
                "pageheap_free_bytes" : NumberLong("11787452416"),
                "pageheap_unmapped_bytes" : NumberLong("4039823360"),
                "max_total_thread_cache_bytes" : NumberLong(1073741824),
                "current_total_thread_cache_bytes" : 113279256,
                "total_free_bytes" : 993717480,
                "central_cache_free_bytes" : 879823248,
                "transfer_cache_free_bytes" : 614976,
                "thread_cache_free_bytes" : 113279256,
                "aggressive_memory_decommit" : 0,
                "pageheap_committed_bytes" : NumberLong("29333864448"),
                "pageheap_scavenge_count" : 2605518,
                "pageheap_commit_count" : 4694997,
                "pageheap_total_commit_bytes" : NumberLong("672231747584"),
                "pageheap_decommit_count" : 3544502,
                "pageheap_total_decommit_bytes" : NumberLong("642897883136"),
                "pageheap_reserve_count" : 25284,
                "pageheap_total_reserve_bytes" : NumberLong("33373687808"),
                "spinlock_total_delay_ns" : NumberLong("3132393632"),

我们重点关注 *_free_bytes 的输出项,其中,

  • pageheap_free_bytes:Number of bytes in free, mapped pages in page heap. These bytes can be used to fulfill allocation requests. They always count towards virtual memory usage, and unless the underlying memory is swapped out by the OS(线上目前没有开启 swap), they also count towards physical memory usage.
  • total_free_bytes = central_cache_free_bytes + transfer_cache_free_bytes + thread_cache_free_bytes注意这个total_free_bytes 是不包含pageheap_free_bytes的,见 tcmalloc 代码
  • 所以如果查看 tcmalloc cache 了多少内存,需要看 pageheap_free_bytes + total_free_bytes

最后,对比一下 Secondary 和 Primary 的 serverStatus 输出,可以看到total_free_bytes二者是差不多的,都在 1GB 左右,但是pageheap_free_bytes ,Secondary 比 Primary 多了 11GB 左右,和前面 OS 层面观察到的 RSS 差值一致

关于 central_cache_free_bytes 、thread_cache_free_bytes 、 thread_cache_free_bytes的含义也列一下,这个代码里面没有解释,在其他地方找到了,

  • central_cache_free_bytes, Number of free bytes in the central cache that have been assigned to size classes. They always count towards virtual memory usage, and unless the underlying memory is swapped out by the OS, they also count towards physical memory usage. This property is not writable.
  • transfer_cache_free_bytes, Number of free bytes that are waiting to be transfered between the central cache and a thread cache. They always count towards virtual memory usage, and unless the underlying memory is swapped out by the OS, they also count towards physical memory usage. This property is not writable.
  • thread_cache_free_bytes, Number of free bytes in thread caches. They always count towards virtual memory usage, and unless the underlying memory is swapped out by the OS, they also count towards physical memory usage. This property is not writable.

优化

阿里云 MongoDB 实现了一个 tcmallocRelease 命令(后端可执行,不对外部用户提供),背后是调用 tcmalloc 的ReleaseFreeMemory()进行 PageHeap 的回收,不过这个命令在执行过程中会锁住整个 PageHeap,可能导致其他需要分配内存的请求 hang 住,线上执行要小心。另外,如果对这部分 cache 住的内存不是特别敏感,不建议执行,毕竟不是真的浪费了,也减少了后续需要调用系统调用的次数。

此外,这个方法不影响 Central Cache 和 Thread Cache。关于tcmalloc cache 内存归还操作系统的策略和时机,比较复杂,详细的资料可以参考这个文章

我们在上述实例的Hidden 节点执行db.adminCommand({tcmallocRelease: 1})命令,可以观察到pageheap_free_bytes下降了 90%以上,

before,

mgset-25489817:SECONDARY> db.serverStatus().tcmalloc
{
        "generic" : {
                "current_allocated_bytes" : NumberLong("16549856240"),
                "heap_size" : NumberLong("34105942016")
        },
        "tcmalloc" : {
                "pageheap_free_bytes" : NumberLong("7499571200"),
                "pageheap_unmapped_bytes" : NumberLong("9387900928"),
                "max_total_thread_cache_bytes" : NumberLong(1073741824),
                "current_total_thread_cache_bytes" : 133710112,
                "total_free_bytes" : 668613648,
                "central_cache_free_bytes" : 534325360,
                "transfer_cache_free_bytes" : 578176,
                "thread_cache_free_bytes" : 133710112,

after,

mgset-25489817:SECONDARY> db.serverStatus().tcmalloc
{
        "generic" : {
                "current_allocated_bytes" : NumberLong("16546167280"),
                "heap_size" : NumberLong("34105942016")
        },
        "tcmalloc" : {
                "pageheap_free_bytes" : 38395904,
                "pageheap_unmapped_bytes" : NumberLong("16852795392"),
                "max_total_thread_cache_bytes" : NumberLong(1073741824),
                "current_total_thread_cache_bytes" : 134981800,
                "total_free_bytes" : 668583440,
                "central_cache_free_bytes" : 533437608,
                "transfer_cache_free_bytes" : 164032,
                "thread_cache_free_bytes" : 134981800,

image

官方 JIRA Issue

查了一下有几个,但是我们重点关注这个,https://jira.mongodb.org/browse/SERVER-37541 , 这个 issue 实际上是对今天这里讨论的问题的一个汇总,主要包括两方面的原因,

  1. Fragmentation,即碎片导致,这个问题大神 Bruce Lucas 开了一个 jira,但是 mongodb 团队反馈说是不在高优先级 list 上,所以 backlog 了(PS:优化内存碎片率是世界性难题,tcmalloc/jemalloc 都不能做到完美,可能要优化确实很困难)。
  2. 另外一个就是内存分配器的缓存行为,tcmalloc 在向操作系统归还内存时,是比较 "reluctant" 的,而且有时候还会达到一个临界点突然归还内存,导致性能抖动,可以配置server parameter tcmallocAggressiveMemoryDecommit 来进行更激进的内存回收,但是 MongoDB 团队测试发现有性能问题,所以默认没有开启。
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
5月前
|
测试技术 C语言 Perl
内存优化-使用tcmalloc分析解决内存泄漏和内存暴涨问题
其实我一直很想写关于tcmalloc的内存泄漏检测的文章,只是一直记不起来该如何下笔,有时项目太忙,在整理这方便的思考过少,另外遇到的问题也不是很多,直到最近用tcmalloc帮A项目排查...
|
6月前
|
缓存
HOperatorSet.Connection 有内存泄漏或缓存
HOperatorSet.Connection 有内存泄漏或缓存
|
6月前
|
存储 缓存
百度搜索:蓝易云 ,CPU、内存、缓存的关系详细解释!
总结起来,CPU、内存和缓存之间的关系可以概括为:CPU是计算机的处理器,内存是用于存储数据的设备,缓存则是位于CPU和内存之间的高速存储器,用于提高数据的读取速度。它们共同协作,以提供高效的计算机性能。
77 0
|
6月前
|
存储 缓存 Go
Go语言开发者必读:内存缓存技巧
Go语言开发者必读:内存缓存技巧
59 0
|
2月前
|
存储 缓存 算法
Golang高性能内存缓存库BigCache设计与分析
【2月更文挑战第4天】分析Golang高性能内存缓存库BigCache设计
64 0
|
8月前
|
缓存 关系型数据库 MySQL
高性能内存对象缓存Memcached
高性能内存对象缓存Memcached案例
|
4月前
|
存储 监控 NoSQL
数据存储与分析:办公室电脑屏幕监控的MongoDB应用实例
在当今数字时代,数据的存储和分析变得愈发重要,尤其是在办公环境中,对电脑屏幕进行监控成为一种日益普遍的需求。本文将介绍如何利用MongoDB数据库实现办公室电脑屏幕监控,并通过代码实例展示其应用。
219 0
|
4月前
|
存储 人工智能 NoSQL
多维数据实时分析,MongoDB给零售企业提供快速高效的数据洞察力
客户行为正在迅速演变,供应链正在重组,员工也正在以新的方式工作。企业需要提供更加个性化的客户体验,对市场趋势做出更快速的反应,监测和预防潜在问题。
多维数据实时分析,MongoDB给零售企业提供快速高效的数据洞察力
|
5月前
|
缓存 架构师 Linux
内存优化-如何使用tcmalloc来提升内存性能?提升的结果太不可思议
内存优化-如何使用tcmalloc来提升内存性能?提升的结果太不可思议
|
5月前
|
存储 缓存 Linux
系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理
虚拟内存的主要作用是提供更大的地址空间,使得每个进程都可以拥有大量的虚拟内存,而不受物理内存大小的限制。此外,虚拟内存还可以提供内存保护和共享的机制,保护每个进程的内存空间不被其他进程非法访问,并允许多个进程共享同一份物理内存数据,提高了系统的资源利用率。虚拟内存的实现方式有分段和分页两种,其中分页机制更为常用和灵活。分页机制将虚拟内存划分为固定大小的页,将每个进程的虚拟地址空间映射到物理内存的页框中。为了减少页表的大小和访问时间,采用了多级页表的方式,将大的页表划分为多个小的页表,只加载需要的页表项,节约了内存空间。
189 0
系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理