NWNU-Sun | 技术沉思录

代码是诗,bug是谜

   ::  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  77 随笔 :: 49 文章 :: 6 评论 :: 40763 阅读

1.背景

公司产业使用nebula图数据库的过程中总是遇到报错内存Used memory(178593436KB) hits the high watermark(0.800000) of total system memory(196268364KB), 导出无法执行数据操作

2.问题排查

查询官网博客发现解决办法是调整该参数 --system_memory_high_watermark_ratio = 0.9 ,默认为0.8,该参数的主要作用是判定系统使用内存占比超过80%时触发,导致数据库无法查询。那么在代码中是如何判断的,如下

image-20250208162945881

3.具体分析

system_memory_high_watermark_ratio 是一个用于设置系统内存高水位线比例的标志(flag),在代码中主要用于判断系统内存的使用是否达到了设定的高水位线,以此来监控系统内存的使用情况,避免内存过度使用引发的问题。

在不同的场景下,system_memory_high_watermark_ratio 会被用于不同的判断逻辑:

  • MemoryUtils::hitsHighWatermark 函数中,该比例用于判断当前系统内存的使用量是否超过了设定的高水位线。如果超过了,说明系统内存使用量已经达到了一个较高的水平,可能需要采取一些措施,如限制内存分配、记录日志或者抛出异常等。
  • Iterator::hitsSysMemoryHighWatermark 函数和 Executor::checkMemoryWatermark 函数中,会根据 MemoryUtils::kHitMemoryHighWatermark 的值(该值是在 MemoryUtils::hitsHighWatermark 函数中根据 system_memory_high_watermark_ratio 判断后设置的)来决定是否抛出异常或返回错误状态,从而避免在内存使用过高的情况下继续执行可能会导致内存耗尽的操作。

代码中根据服务器的哪些信息去判断

代码中根据服务器的不同信息来判断内存使用是否达到高水位线,具体取决于服务器是否为容器化环境(通过 FLAGS_containerized 标志判断):

  • 非容器化环境(FLAGS_containerizedfalse

在非容器化环境下,代码通过读取 /proc/meminfo 文件来获取系统内存信息:

FileUtils::FileLineIterator iter("/proc/meminfo", &reMemAvailable);
std::vector<uint64_t> memorySize;
for (; iter.valid(); ++iter) {
  auto& sm = iter.matched();
  memorySize.emplace_back(std::stoul(sm[2].str(), nullptr) << 10);
}
std::sort(memorySize.begin(), memorySize.end());
if (memorySize.size() >= 2u) {
  total = memorySize.back();
  available = memorySize[memorySize.size() - 2];
} else {
  return false;
}
  • total:表示系统的总内存大小,通过读取 /proc/meminfo 文件并解析其中的信息,将最大的内存值作为总内存。
  • available:表示系统当前可用的内存大小,通过读取 /proc/meminfo 文件并解析其中的信息,将第二大的内存值作为可用内存。
  • 容器化环境(FLAGS_containerizedtrue

在容器化环境下,代码通过读取 cgroup 文件来获取内存信息:

bool cgroupsv2 = FileUtils::exist(FLAGS_cgroup_v2_controllers);
std::string statPath =
    cgroupsv2 ? FLAGS_cgroup_v2_memory_stat_path : FLAGS_cgroup_v1_memory_stat_path;
FileUtils::FileLineIterator iter(statPath, &reTotalCache);
uint64_t cacheSize = 0;
for (; iter.valid(); ++iter) {
  auto& sm = iter.matched();
  cacheSize += std::stoul(sm[2].str(), nullptr);
}

std::string limitPath =
    cgroupsv2 ? FLAGS_cgroup_v2_memory_max_path : FLAGS_cgroup_v1_memory_max_path;
auto limitStatus = MemoryUtils::readSysContents(limitPath);
NG_RETURN_IF_ERROR(limitStatus);
uint64_t limitInBytes = std::move(limitStatus).value();

std::string usagePath =
    cgroupsv2 ? FLAGS_cgroup_v2_memory_current_path : FLAGS_cgroup_v1_memory_current_path;
auto usageStatus = MemoryUtils::readSysContents(usagePath);
NG_RETURN_IF_ERROR(usageStatus);
uint64_t usageInBytes = std::move(usageStatus).value();

total = static_cast<double>(limitInBytes);
available = static_cast<double>(limitInBytes - usageInBytes + cacheSize);
  • total:表示容器的内存限制大小,通过读取 cgroup 中的 memory.max 文件(cgroups v2)或 memory.limit_in_bytes 文件(cgroups v1)来获取。
  • available:表示容器当前可用的内存大小,通过读取 cgroup 中的 memory.current 文件(cgroups v2)或 memory.usage_in_bytes 文件(cgroups v1)来获取,并加上缓存大小(通过解析 memory.stat 文件获取)。

4.最终判断逻辑

无论在容器化环境还是非容器化环境下,最终都会根据以下公式判断内存使用是否达到高水位线:

auto hits = (1 - available / total) > FLAGS_system_memory_high_watermark_ratio;

如果 hitstrue,则表示系统内存使用已经达到了高水位线,会记录相应的日志信息。

posted on   匿名者nwnu  阅读(16)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示