内存配置

本页面介绍了 Neo4j 内存配置和使用的不同方面。Neo4j 服务器的 RAM 包含多个使用区域及一些子区域。

neo4j memory management
图 1. Neo4j 内存管理
操作系统内存

必须预留一部分内存用于运行操作系统本身的进程。无法显式配置应为操作系统预留的 RAM 量,因为这是在配置完 Neo4j 后剩余的可用 RAM。

对于专门运行 Neo4j 的服务器,1GB 是一个很好的起点。然而,在某些情况下,为操作系统预留的内存量会显著大于 1GB,例如拥有超大 RAM 的服务器。

如果您拥有向量索引,则需要确保为向量索引留出足够的内存以实现最佳性能,因为向量索引加载在操作系统内存中,而不是 Neo4j 页面缓存中。更多信息,请参见 向量索引内存配置

如果您没有为操作系统留出足够的空间,它将开始将内存交换到磁盘,这将严重影响性能。因此,通常建议为专用的 Neo4j 服务器关闭交换空间(swap)。

JVM 堆

JVM 堆是 Neo4j 用于存储已实例化 Java 对象的独立动态内存分配。Java 对象的内存由垃圾回收器(Garbage Collector)自动管理。特别重要的一点是,垃圾回收器会自动处理未使用对象的删除。有关垃圾回收器的工作原理及调优方法的更多信息,请参见 垃圾回收器调优

堆内存大小由参数 server.memory.heap.initial_sizeserver.memory.heap.max_size 决定。建议将这两个参数设置为相同的值,以避免不必要的完整垃圾回收(Full GC)暂停。

通常,为了提升性能,您应该配置足够大的堆以支撑并发操作。

原生内存

原生内存(有时称为堆外内存)是 Neo4j 直接从操作系统分配的内存。该内存会根据需要动态增长,且不受垃圾回收器的管理。

DBMS

数据库管理系统(DBMS)包含 Neo4j 实例的全局组件。例如:Bolt 服务器、日志服务、监控服务等。

数据库

系统中的每个数据库都会带来一定的开销。在部署了多个数据库的环境中,需要考虑此项开销。

事务

在执行事务时,Neo4j 会将尚未提交的数据、结果以及查询的中间状态保存在内存中。这部分所需的内存大小很大程度上取决于 Neo4j 的使用方式。例如,长时间运行的查询或非常复杂的查询通常需要更多的内存。事务的某些部分可以选择性地放置在堆外,但为了获得最佳性能,建议保留默认配置,即所有内容都在堆内。

此内存组可以通过设置 dbms.memory.transaction.total.max 进行限制。

页面缓存

页面缓存(Page Cache)用于缓存存储在磁盘上的 Neo4j 数据。将图数据和索引缓存到内存中,有助于避免昂贵的磁盘访问,从而实现最佳性能。

用于指定 Neo4j 允许为页面缓存使用多少内存的参数是:server.memory.pagecache.size

网络缓冲区

直接缓冲区(Direct Buffers)由 Neo4j 用于发送和接收数据。直接字节缓冲区对于提高性能非常重要,因为它们允许原生代码和 Java 代码共享数据而无需复制。然而,创建它们的开销很大,这意味着字节缓冲区通常在创建后会被重复使用。

其他共享缓冲区

这包括未指定的共享直接缓冲区。

JVM 开销

JVM 需要一些内存才能正常运行。例如:

  • 线程栈(Thread stacks) – 每个线程都有自己的调用栈。栈存储原始局部变量和对象引用,以及调用栈本身(方法调用的列表)。当栈帧移出上下文时,栈会被清理,因此这里不会执行 GC。

  • 元空间(Metaspace) – 元空间存储 Java 类定义和其他一些元数据。

  • 代码缓存(Code cache) – JIT 编译器将其生成的原生代码存储在代码缓存中,通过重用来提高性能。

有关更多详细信息以及限制 JVM 使用内存的方法,请查阅您的 JVM 文档。

注意事项

始终使用显式配置

为了很好地控制系统行为,建议始终在 neo4j.conf 中显式定义页面缓存和堆大小参数。否则,Neo4j 会在启动时根据可用系统资源计算一些启发式值。

初始内存建议

使用 neo4j-admin server memory-recommendation 命令获取关于如何分配特定内存量的初步建议。这些值可能需要根据每个特定的用例进行调整。

检查 DBMS 中所有数据库的内存设置

neo4j-admin server memory-recommendation 命令对于检查数据和索引的当前分布非常有用。

示例 1. 使用 neo4j-admin server memory-recommendation 检查所有数据库的内存设置

估算数据库文件的总大小。

bin/neo4j-admin server memory-recommendation
...
...
...
# Total size of lucene indexes in all databases: 6690m
# Total size of data and native indexes in all databases: 17050m

您可以看到 Lucene 索引占用了大约 6.7GB 的数据,数据卷和原生索引合计占用了大约 17GB。

利用这些信息,您可以对内存配置进行完整性检查

  • 将数据卷和原生索引的值与 server.memory.pagecache.size 的值进行比较。

  • 对于使用堆外事务状态的情况,请估算事务工作负载,并确定留给 dbms.tx_state.max_off_heap_memory 的内存量。

  • 将 Lucene 索引的值与分配 server.memory.pagecache.sizeserver.memory.heap.initial_size 后剩余的内存量进行比较。

在某些生产系统中,对内存的访问是有限的,必须在不同区域之间进行权衡。因此,建议执行一定量的测试和调整,以确定可用内存的最佳分配方式。
限制事务内存使用建议

所有事务的测量堆使用量仅为估计值,实际的堆利用率可能略大或略小。在某些情况下,估算算法在检测内存图中更深层级的共享对象时存在局限性,可能导致高估。这是因为基于内存使用量的聚合估算给出了一个保守的估计,其中所有参与对象的身份均未知,且不能假设为共享。例如,当您在非常大的列表上使用 UNWIND,或者扩展可变长度或最短路径模式时,计算出的结果路径之间共享了许多关系。

在这种情况下,如果您遇到查询被终止的问题,可以禁用事务内存限制并重新执行该查询。如果实际的堆使用量并未过大,它可能会在不触发内存溢出(OOM)错误的情况下成功运行。

容量规划

在许多用例中,尽可能多地缓存数据和索引是有利的。以下示例说明了估算页面缓存大小的方法,无论您是已经在生产环境中运行还是在规划未来的部署。

示例 2. 估算现有 Neo4j 数据库的页面缓存

首先,估算数据和索引的总大小,然后乘以某个系数(例如 20%)以预留增长空间。

bin/neo4j-admin server memory-recommendation
...
...
...
# Total size of lucene indexes in all databases: 6690m
# Total size of data and native indexes in all databases: 35050m

您可以看到数据卷和原生索引合计占用大约 35GB。在您的具体用例中,您估计 20% 的空间足以作为增长预留。

server.memory.pagecache.size = 1.2 * (35GB) = 42GB

通过在 neo4j.conf 中添加以下内容来配置页面缓存

server.memory.pagecache.size=42GB
示例 3. 估算新 Neo4j 数据库的页面缓存

在规划未来的数据库时,运行一个包含部分数据的导入操作会很有帮助,然后将得出的存储大小增量乘以该比例,再加上一定的百分比以应对增长。

  1. 运行 memory-recommendation 命令查看所有当前数据库中数据和索引的总大小。

    bin/neo4j-admin server memory-recommendation
    ...
    ...
    ...
    # Total size of lucene indexes in all databases: 6690m
    # Total size of data and native indexes in all databases: 35050m
  2. 导入 1/100 的数据,并再次测量所有数据库的数据卷和原生索引大小。

    bin/neo4j-admin server memory-recommendation
    ...
    ...
    ...
    # Total size of lucene indexes in all databases: 6690m
    # Total size of data and native indexes in all databases: 35400m

    您可以看到数据卷和原生索引合计占用大约 35.4GB。

  3. 将得出的存储大小增量乘以该比例。

    35.4GB - 35GB = 0.4GB * 100 = 40GB

  4. 将该数字乘以 1.2 以扩大结果,并预留 20% 的增长空间。

    server.memory.pagecache.size = 1.2 * (40GB) = 48GB

  5. 通过在 neo4j.conf 中添加以下内容来配置页面缓存

    server.memory.pagecache.size=48G

限制事务内存使用

通过使用 dbms.memory.transaction.total.max 设置,您可以为服务器上运行的所有事务配置全局最大内存使用量。此设置必须配置得足够低,以确保不会出现内存耗尽的情况。如果您在高事务负载下遇到 OutOfMemory 消息,请尝试降低此限制。

Neo4j 还提供以下设置来确保公平性,这有助于提高多租户部署中的稳定性。

当达到任何限制时,事务将被终止,而不会影响数据库的整体运行状况。

为了帮助配置这些设置,您可以使用以下命令列出当前的使用情况

CALL dbms.listPools()
SHOW TRANSACTIONS

或者,您可以在 query.log 中监控每个查询的内存使用情况。