参数调优
为了在读取(尤其是写入)Neo4j 时获得最佳性能,请确保您已完成以下核对清单
调整批处理大小
将数据写入 Neo4j 是以批处理方式进行的事务操作;如果您想写入 100 万个节点,可以将其拆分为 40 个批次,每批 25,000 个。连接器的批处理大小由 batch.size 选项控制,默认设为一个相当低且保守的值。对于许多应用程序而言,这个值可能太低,可以通过更好地了解您的数据来提升性能。
批处理大小的权衡如下
-
批处理大小越大,整体摄取性能越好,因为这意味着更少的事务数和更少的总体事务开销。
-
当批处理大小过大,导致 Neo4j 的堆内存无法容纳时,可能会导致服务器内存溢出错误并引发失败。
| 当您在服务器可用内存范围内使用尽可能大的批处理大小,即可获得最佳写入吞吐量。 |
不可能选择一个适用于所有人的单一批处理大小,因为您的事务占用的内存量取决于属性和关系的数量以及其他因素。一个通用的积极建议值大约是 20,000 - 但如果您的数据较小,或者服务器内存充足,则可以增加该数字。如果数据库服务器较小,或者您推送的数据具有许多大属性,则应调低该数字。
调整 Neo4j 内存配置。
在 Neo4j 操作手册中,给出了关于如何设置服务器堆内存和页面缓存大小的重要建议。对于 Spark 而言,重要的是
-
堆内存影响事务的大小。堆内存越大,可使用的批处理大小就越大。
-
页面缓存影响数据库在任何给定时间驻留在 RAM 中的数据量。如果页面缓存远小于数据库大小,性能会受到影响。
调整并行度
Spark 的核心在于分区和并行性;常用的技术是将一批数据拆分为多个分区,供每台机器并行处理。在 Neo4j 中,并行性的工作方式大不相同,我们将在本章中进行描述。
Neo4j 中的写入并行度
| 对于大多数写入 Neo4j 的操作,强烈建议将您的 DataFrame 重新分区为仅一个分区。 |
在 Neo4j 中写入节点和关系时
-
写入关系会锁定两个节点。
-
写入节点会锁定该节点。
此外,在 Neo4j 因果集群模型中,只有集群领导者(Leader)可以写入数据。由于 Neo4j 的写入是垂直扩展的,因此实际的并行度仅限于领导者节点上的核心数。
建议写入使用单一分区的原因是它消除了写入之间的锁竞争。假设一个分区正在写入
(:Person { name: "Michael" })-[:KNOWS]->(:Person { name: "Andrea" })
同时另一个分区也在写入
(:Person { name: "Andrea" })-[:KNOWS]->(:Person { name: "Davide" })
关系写入锁定了“Andrea”节点——无论如何,这些写入都无法并行进行。因此,如果线程必须等待彼此的锁,增加并行度可能无法提高性能。在并行度过高的极端情况下,Neo4j 可能会因锁竞争错误而拒绝写入。
调整模式采样
由于采样过程可能成本高昂并影响数据提取作业的性能,因此正确调整采样参数至关重要。
APOC 采样
如果安装了 APOC,模式推断将使用 apoc.meta.nodeTypeProperties 和 apoc.meta.relTypeProperties 过程。
您可以分别通过 apoc.meta.nodeTypeProperties 和 apoc.meta.relTypeProperties 选项调整 sample 参数。例如
df.read
.format(classOf[DataSource].getName)
.option("labels", ":Product")
.option("apoc.meta.nodeTypeProperties", """{"sample": 10}""")
.load()
该选项支持除以下之外的所有配置参数
-
apoc.meta.nodeTypeProperties的includeLabels,因为标签由labels选项定义。 -
apoc.meta.relTypeProperties的includeRels,因为关系由relationship选项定义。