MongoDB tcmalloc 内存缓存分析

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介:

背景

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
目录
相关文章
|
2月前
|
Web App开发 监控 JavaScript
监控和分析 JavaScript 内存使用情况
【10月更文挑战第30天】通过使用上述的浏览器开发者工具、性能分析工具和内存泄漏检测工具,可以有效地监控和分析JavaScript内存使用情况,及时发现和解决内存泄漏、过度内存消耗等问题,从而提高JavaScript应用程序的性能和稳定性。在实际开发中,可以根据具体的需求和场景选择合适的工具和方法来进行内存监控和分析。
|
3月前
|
编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(上)
动态内存分配与管理详解(附加笔试题分析)
86 1
|
3月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
102 15
Android 系统缓存扫描与清理方法分析
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
77 1
|
2月前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
56 3
|
2月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
2月前
|
Web App开发 JavaScript 前端开发
使用 Chrome 浏览器的内存分析工具来检测 JavaScript 中的内存泄漏
【10月更文挑战第25天】利用 Chrome 浏览器的内存分析工具,可以较为准确地检测 JavaScript 中的内存泄漏问题,并帮助我们找出潜在的泄漏点,以便采取相应的解决措施。
407 9
|
2月前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
66 5
|
2月前
|
存储 缓存 监控
|
3月前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。