Nebula Graph学习篇2_版本v2.6.1之前的bug导致OOM

2023-05-16

1、环境说明

测试服务器:16CPU、64G

Nebula版本:2.6.1

数据量:tag约为300w,edge约为10w

2、报错情况

基本情况就是执行nGQL查询命令报错,查看nebula-storaged.ERROR日志发现报错:Used memory hits the high watermark(0.800000) of total system memory.

文档给的解释是:Nebula Graph的system_memory_high_watermark_ratio参数指定了内存高水位报警机制的触发阈值,默认为0.8。系统内存占用率高于该值会触发报警机制,Nebula Graph会停止接受查询。

然后使用free -m 查看服务器内存占用情况,64G的内存只剩下1G不到,因此需要对内存占用情况进行一个排查

3、内存情况分析

# 1、找出nebula服务的进程:ps -ef | grep n* 

(base) root@Server-i-a1ed06ol8o:/usr/local/nebula/bin# ps -ef | grep n*
Binary file nebula-metad matches
Binary file nebula-storaged matches


# 2、对应的是三个进程
(base) root@Server-i-a1ed06ol8o:/usr/local/nebula/bin# ps -ef | grep nebula-graphd
root      8190     1  0 Feb17 ?        01:05:40 /usr/local/nebula/bin/nebula-graphd --flagfile /usr/local/nebula/etc/nebula-graphd.conf
root     26400 21159  0 15:28 pts/3    00:00:00 grep --color=auto nebula-graphd

# 查看nebula-storaged服务对应进程
(base) root@Server-i-a1ed06ol8o:/usr/local/nebula/bin# ps -ef | grep nebula-storaged
root      8205     1  0 Feb17 ?        23:54:50 /usr/local/nebula/bin/nebula-storaged --flagfile /usr/local/nebula/etc/nebula-storaged.conf
root     26404 21159  0 15:28 pts/3    00:00:00 grep --color=auto nebula-storaged

# 3、使用top -p 8205 查看nebula-graphd进程所占用的内存情况,发现内存占用达到了63% * 64G
PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                   8205 root      20   0 65.081g 0.039t   9220 S   0.0 64.0   1434:12 nebula-storaged 


 
 
 

也就是nebula-storaged占用大量服务器内存,通过查看nebula文档确定其不是内存数据库时,支持高可用,原话是:“如果提供 Graph 服务的服务器有一部分出现故障,其余服务器可以继续为客户端提供服务,而且 Storage 服务存储的数据不会丢失。服务恢复速度较快,甚至能做到用户无感知。”

即是数据是通过WAL技术存储在磁盘的,因此占用大量内存这种情况是反常的。

重启nebula服务之后内存降下来了,之后插入图谱关系、节点,发现内存又上去了,通过free -h 查看,发现cache buffer内存占了30多G…

猜想可能是大量插入数据的问题。

4、尝试解决思路

文档给的解释是:Nebula Graph的system_memory_high_watermark_ratio参数指定了内存高水位报警机制的触发阈值,默认为0.8。系统内存占用率高于该值会触发报警机制,Nebula Graph会停止接受查询。

依据文档针对该报错提供的解决方案,一是清理服务器内存,二是在所有Graph服务器的配置文件中增加system_memory_high_watermark_ratio参数,为其设置一个大于0.8的值,例如0.9

针对清理服务器内存,这个在测试服务器不太敢尝试,只能试试第二个解决方案。

按照文档修改配置文件,然后重启,重启之前为了保险,需要打个备份或者快照

1. 备份(br工具安装不成功,未成功备份)

# 备份所在目录:/home/nebula/backup

# 备份执行命令:$ ./bin/br backup full --meta "127.0.0.1:9559" --storage "local:///home/nebula/backup/"


2.快照

# //1、 生成快照
(root@nebula) [(none)]> create snapshot;
Execution succeeded (time spent 5848319/5847776 us)

Thu, 09 Jun 2022 16:32:08 CST

# // 2、显示快照
(root@nebula) [(none)]> show snapshots;
+--------------------------------+---------+------------------+
| Name                           | Status  | Hosts            |
+--------------------------------+---------+------------------+
| "SNAPSHOT_2022_06_09_16_32_03" | "VALID" | "127.0.0.1:9779" |
+--------------------------------+---------+------------------+
Got 1 rows (time spent 22805/23043 us)

Thu, 09 Jun 2022 16:32:26 CST

# //3、 快照所在目录地址
/usr/local/nebula/data/meta/nebula/0/SNAPSHOT_2021_03_09_09_10_52

# 4、快照恢复
当数据丢失需要通过快照恢复时,用户可以找到合适的时间点快照,将内部的文件夹data和wal分别拷贝到各自的上级目录(和checkpoints平级),覆盖之前的data和wal,然后重启集群即可。

确认快照生成之后就可以重启了。

重启之后使用free -m 查看内存情况,发现释放了近40G内存,执行nGQL命令也发现正常了。不过还是不能验证设置该参数能不能解决OOM问题,直觉告诉我不可以。

5、Nebula原理分析

负责nebulad的具体数据相关的存储,称为 Storage 服务。其运行在 nebula-storaged 进程,Nebula Graph 使用自行开发的 KVStore,Nebula Graph 使用 RocksDB作为本地存储引擎,实现了自己的 KVStore

(1)RocksDB存储引擎

首先需要了解RocksDB存储引擎,官网:http://rocksdb.org/docs/getting-started.html

RocksDB 库提供了一个持久的键值存储。键和值是任意字节数组。根据用户指定的比较器函数,键在键值存储中排序。

该库由 Facebook 数据库工程团队维护,基于LevelDB,由 Google 的 Sanjay Ghemawat 和 Jeff Dean 编写。

架构介绍:RocksDB 是一个键值存储接口的存储引擎库,其中键和值是任意字节流。RocksDB 将所有数据按排序顺序组织起来,常用的操作有Get(key), NewIterator(), Put(key, val), Delete(key), 和SingleDelete(key)

RocksDB 的三个基本结构是memtablesstfilelogfile。memtable是一种内存数据结构 - 新的写入被插入到memtable中,并且可以选择写入日志文件(又名。Write Ahead Log(WAL))。日志文件是存储上按顺序写入的文件。当 memtable 填满时,它会被刷新到存储上的sstfile,并且可以安全地删除相应的日志文件。对 sstfile 中的数据进行排序以方便查找键。

类似MySQL数据库中的WAL,将随机写先放进内存的memtable和logfile,然后合适的时候刷盘到sstfile,sstfile是一个多层的跳表结构。

请添加图片描述

然后大致确定了是使用索引查询大量数据的时候,index block需要加载进内存,导致内存占用上升,为了再次确定,决定对200w的节点数据进行lookup on 查询,然后在查看内存情况。

RocksDB对多数据插入的优化

在存在持续写入的情况下,需要压缩以提高空间效率、读取(查询)效率和及时删除数据。Compaction 移除已删除或覆盖的键值绑定,并重新组织数据以提高查询效率。如果配置,压缩可能发生在多个线程中。

整个数据库存储在一组sstfiles中。当一个memtable已满时,它的内容被写到 LSM 树的 Level-0 (L0) 中的一个文件中。RocksDB 在刷新到 L0 中的文件时会删除 memtable 中的重复和覆盖键。在compaction中,一些文件会定期读入并合并形成更大的文件,通常会进入下一个 LSM 级别(例如 L1,直到 Lmax)。

LSM 数据库的整体写入吞吐量直接取决于压缩发生的速度,尤其是当数据存储在 SSD 或 RAM 等快速存储中时。RocksDB 可以配置为从多个线程发出并发压缩请求。据观察,与单线程压缩相比,当数据库在 SSD 上时,多线程压缩的持续写入速率可能会提高 10 倍。

(2)RocksDB中的内存使用情况

Meta 如何存储 Schema

我们以 CREATE TAG 为例子,当我们建 tag 时,首先会往 meta 发一个请求,让它把这个信息写进去。写入形式非常简单,先获取 tagId,再保存 tag name。底层 RocksDB 存储的 key 便是 tagId 或者是 tag name,value 是它每一个字段里面的定义,比如说,第一个字段是年龄,类型是整型 int;第二个字段是名字,类型是 string。schema 把所有字段的类型和名字全部存在 value 里,以某种序列化形式写到 RocksDB 中。

这里说下,meta 和 storage 两个 service 底层都是 RocksDB 采用 kv 存储,只不过提供了不一样的接口,比如说,meta 提供的接口,可能就是保存某个 tag,以及 tag 上有哪些属性;或者是机器或者 space 之类的元信息,包括像用户权限、配置信息都是存在 meta 里。storage 也是 kv 存储,不过存储的数据是点边数据,提供的接口是取点、取边、取某个点所有出边之类的图操作。整体上,meta 和 storage 在 kv 存储层代码是一模一样,只不过往上暴露的对外接口是不一样的。

参考github文档:https://github.com/facebook/rocksdb/wiki/Memory-usage-in-RocksDB

RocksDB中会影响内存使用的组件有

  • 块缓存:RocksDB 的缓存是两层的:块缓存(块缓存是 RocksDB 缓存未压缩数据块的地方。可直接拿到未压缩的数据。)和页缓存(包含压缩数据)。与直觉相反,减小块缓存大小不会增加 IO。节省的内存可能会用于页面缓存,因此将缓存更多数据。但是,CPU 使用率可能会增加,因为 RocksDB 需要解压缩它从页面缓存中读取的页面。可以通过设置 BlockBasedTableOptions 的 block_cache 属性来配置块缓存的大小
  • 索引和布隆过滤器:大内存用户,关于布隆过滤器就是判断key是否一定不存在sst文件,每个分区的索引和过滤器始终存储在块缓存中。顶级索引可以通过配置存储在堆或块缓存中。
  • 内存表:您可以将 memtables 视为内存中的写入缓冲区。每个新的键值对首先写入内存表。Memtable 大小由选项控制write_buffer_size。除非使用许多列族和/或数据库实例,否则它通常不会占用大量内存。
  • 有迭代器固定的块:由迭代器固定的块通常对整体内存使用贡献不大。但是,在某些情况下,当您同时发生 100k 读取事务时,可能会对内存造成压力。

6、最终原因以及解决方案

参考Nebula社区出现同样问题的文章,也是V2.6.1版本:https://discuss.nebula-graph.com.cn/t/topic/7903/2、https://discuss.nebula-graph.com.cn/t/topic/7975

我的和下面这种情况比较类似(nebula graph 2.6.1),甚至比他这个更严重,发生OOM的时候大概占了60G内存…

请添加图片描述

然后nebula的工作人员说内存持续升高的原因可能是因为v2.6.1版本的一个bug:https://github.com/vesoft-inc/nebula/pull/3806

请添加图片描述

回想博主之前的操作,也就是创建tag的和导入数据分开操作的,每次增量更新选中NULL.xlsx空文件,会执行语句inert vertex xxx(....) values;。该语句频繁多次的执行应该就是导致OOM的原因。

最终解决方案升级nebula的版本为v2.6.2及其以上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Nebula Graph学习篇2_版本v2.6.1之前的bug导致OOM 的相关文章

  • DSP28335笔记 —— 定时器

    DSP28335笔记 定时器 相比于STM32 xff0c DSP28335的定时器好像真的简单了好多 xff0c 从定时器个数来讲只有3个 xff0c 时钟源只能是系统时钟 xff0c 而且计数方向也只有向下计数 单纯且善良的定时器 xf
  • C语言线程基本函数

    学习笔记 xff1a C语言线程基本函数 学习内容 xff1a 线程常用基本函数 xff1a pthread create 创建线程pthread exit 退出当前线程pthread join 等待其他线程结束pthread self 自
  • 《大话设计模式》笔记——简单工厂模式

    前言 我 xff08 长胖的阿诏 xff09 是新入行的嵌入式程序员 xff0c 所以用C语言做示例演示 xff0c 我看到书上都是 C 语言的代码 xff0c 所以我只能先领会精神 xff0c 再通过C语言复刻 在我的资源里好像没有见过用
  • 《大话设计模式》笔记——策略模式

    策略模式 34 我 34 的理解 策略模式 是指同一个对象在不同情况下的策略行为有所差异 xff0c 继续以之前的四则运算为例 加 减 乘 除 就是两个参数在不同情况下计算过程的差异性行为 所以在某种程度上 xff0c 策略模式可能比简单工
  • md文件目录生成器

    md文件目录生成器 目录 md文件目录生成器 md文件目录生成器 step1 下载脚本文件 step1 下载脚本文件 step2 生成脚本文件 step2 生成脚本文件 step3 设置环境变量 step3 设置环境变量 step4 可以用
  • Python __file__ 详解

    这个功能纠结了一下午 xff0c 做了测试以后总算是明白了 file 表示显示文件当前的位置 但是 xff1a 如果当前文件包含在sys path里面 xff0c 那么 xff0c file 返回一个相对路径 xff01 如果当前文件不包含
  • 48.HTTP基本认证与摘要认证

    文章目录 基本认证摘要认证 转载请注明原始出处 xff1a http blog csdn net a464057216 article details 52705855 后续此博客不再更新 xff0c 欢迎大家搜索关注微信公众号 测开之美
  • CircleProgressBar 圆形进度条,支持多种属性

    效果图 xff1a xff0c 直接从新项目里面摘出来的 xff0c 给自己做个记录 所以就不多加说明 xff0c 1 自定义控件 xff1a 网上摘录修改 public class CircleProgressBar extends Vi
  • c语言入门这一篇就够了-学习笔记(一万字)

    内容来自慕课网 xff0c 个人学习笔记 加上了mtianyan标签标记知识点 C语言入门 gt Linux C语言编程基本原理与实践 gt Linux C语言指针与内存 gt Linux C语言结构体 https www imooc co
  • GPS接收机(一)概述

    概述 接下来的几篇博客包括如下内容 1 xff0c 圆极化天线 xff1a 包括圆极化天线的设计 xff0c 场路协同仿真 xff08 电磁场和电路 xff09 xff0c 相位中心的计算 2 xff0c 低噪放 xff1a 包括低噪放的设
  • ERROR: invalid message type: fl_com/sensor_connect_state. If this is a valid message type, perhaps y

    ERROR invalid message type fl com sensor connect state If this is a valid message type perhaps you need to type rosmake
  • libcurl进行post

    libcurl进行post main函数 xff0c 初始化和清理curl 全局初始化curl curl global init CURL GLOBAL ALL std string url 61 34 http xxxx 34 std s
  • STL几个容器的比较

    vector xff1a 连续内存 xff0c 随机访问数据成员快 xff0c 但是频繁的插入 xff08 需要移动要插入的元素的后面的所有元素 xff09 或者扩容 vector扩容后会清掉原来的数据 xff0c 拷贝到新的申请的大的内存
  • STL注意问题

    1 由于继承的存在 xff0c 拷贝会导致分割 那就是说 xff0c 如果你以基类对象建立一个容器 xff0c 而你试图插入派生类对象 xff0c 那么当对象 xff08 通过基类的拷贝构造函数 xff09 拷入容器的时候对象的派生部分会被
  • CAN总线通信协议详讲

    CAN简介 CAN是Controller Area Network 的缩写 xff08 以下称为CAN xff09 xff0c 是ISO国际标准化的串行通信协议 由德国电气商博世公司在1986 年率先提出 此后 xff0c CAN 通过IS
  • gazebo仿真——controller配置(transmission/hardwareInterface标签)

    参考roswiki controller官方说明 本文作为古月大神的补充ROS探索总结 xff08 三十一 xff09 ros control 为了在gazebo中实现机器人关节的控制 xff0c 需要求建立一个controller控制器
  • NDK--CMakeLists配置第三方so库

    当我们创建一个NDK工程时 xff0c 会自动创建一个CMakeLists txt的文件 xff0c 在AS中c 43 43 的编译器是使用LLVM xff0c 规则为cmake xff0c 今天来学习下cmake的基本套路 首先 xff0
  • postman插件下载安装教程(详细)

    一 前言 postman是一款强大网页接口调试工具 xff0c 我们在平时开发过程中经常会使用到 xff0c 一般使用最多的是postman的客户端 xff0c 实际上postman在谷歌浏览器上也提供了插件 xff0c 可以不必要安装客户
  • CMake交叉编译简单教程

    首先要安装cmaek 然后安装交叉编译链 一 CMake简介 xff1a CMake是一个跨平台的安装 编译 工具 可以通过简单的语句来描述所有平台的安装 编译过程 他能够输出各种各样的 makefile 或者 project 文件 二 C
  • 锂电池的常见接口

    我们在做一些小型化便携式设备的时候 xff0c 经常会用到锂电池 xff0c 常见的锂电池接口如图 xff1a

随机推荐