E.Advanced 04.Bulk Loading janusgraph批量写入

Bulk Loading

用于高效导入大量的图数据到janusgraph,有一些配置参数和工具用于bulk loading。而小量数据通过独立事务,属于传统的transactional loading

举例一下场景用到 bulk loading:

  • 引入janusgraph到一个已有环境,存在已有数据需要融合或副本到新的janusgraph cluster。
  • 使用janusgraph作为ETL过程的end point。
  • 增加已存在或外部的图数据集(如RDF datasets)到一个运行中的janusgraph cluster。
  • 通过graph分析job的结果数据,更新janusgraph的图中。

下面关于bulk loading高效配置参数和工具,请在生效前仔细留意每个参数的约束和前提条件,避免数据丢失或数据不正确。

除了下面提到的特定优化,也需考虑提高storage后端和index后端的写入性能。

Configuration Options

Batch Loading

激活 storage.batch-loading 配置项将在大多数情况下最大化提高bulk loading效果。激活的同时意味着禁用了jannusgraph内部多处的数据一致性校验。同时最重要的是,也禁用了locking。反过来看,janusgraph会假设load的数据已经是保证一致性了,因而禁用janusgraph自检会提高性能。

在许多bulk loading场景,先确保数据一致性再loading数据,会比loading数据到db同时确保数据一致性好很多。因此storage.batch-loading配置项会在这时有作用。

例如,考虑这种使用场景,bulk loading用户信息到janusgraph,假设username字段是唯一索引定义,必须保证graph中的唯一性。当从另一个数据库中导入用户信息,username已经由之前db有了唯一性保证。如果之前的数据没有保证唯一性,也可以用sortby username并去重来较简单的实现,如hadoop做filter。这之后就可以激活storage.batch-loading,janusgraph不再检查username是否重复,来大大减少bulk loading的耗时。

重要:激活storage.batch-loading需要用户确保load的自身数据一致性,且与graph中已有数据不重复。特别是,当激活storage.batch-loading时,并发创建type可能带来数据完整性问题。因此,强烈建议在设置storage.batch-loading时禁用自动type创建。

Optimizing ID Allocation

ID Block Size

每个新增vertex或edge会分配一个唯一的id。janusgraph的id pool manager指定id blocks给janusgraph实例。id block的指定是昂贵的,因为需要保证全局唯一可分配blocks。增加ids.block-size可以减少指定的次数,但也潜在留下更多id未分配而浪费的可能。
对事务的数据写入,默认的block sizes是有理由的,但是在bulk loading时,顶点和边增加的更加频繁和快速,因此会推荐考虑将block size增大10倍,或者取决于每个机器需要增加的顶点数量。

关键规则:设置ids.block-size为预期下每个janusgraph 实例每小时增加的顶点数量。
重要:所有janusgraph实例必须被配置为同样的ids.block-size,确保id分配。因此,修改这个值时请确保所有的janusgraph实例已经关闭。

ID Acquisition Process

当很多janusgraph实例并行的很快的分配id blocks, 实例间将不可避免出现分配冲突,且减慢id分配的过程。此外,当janusgraph认为失败并抛出异常时,bulk loads进一步堆积过来的写load会进一步减慢id分配的过程。所以有三个配置项可以优化来避免发生这种情况。

  1. ids.authority.wait-time 配置id pool manager等待1个id block应用程序的时间(单位毫秒),等待storage后端确认。这个时间越短,在一个拥挤的storage集群中,一个应用程序越容易fail。(default=300ms)
关键规则:设置这个值,参考storage后端在load压力下,读写时间sum和的95分位值。
重要:这个值应该相同在所有janusgraph实例。
  1. ids.renew-timeout 配置id pool manager请求指派1个新的id block等待的时间(单位毫秒),等待超过则failing。
关键规则:设置这个值应该合理的大一些,不要特别大而在不可恢复的错误中等待太久。增大这个值的缺点是janusgraph将在storage后端不可用时,尝试很久。

Optimizing Writes and Reads

Buffer Size

janusgraph会缓存写操作,并分成较少的批次执行他们,来减少提交到storage后端的总请求数量。每批次的写操作数量由参数storage.buffer-size控制。当在较短时间内执行大量的写操作,有可能会让storage后端被写操作的请求超载。这时,增加storage.buffer-size能通过提高每次请求包含的写操作,降低总请求次数,来避免错误。

然后,提高缓存size会增加写操作的延时,和每次写操作出错的可能。因此,在事务load情况不建议增大这个值,且在bulk loading应谨慎增大。

Read and Write Robustness

在bulk loading中,集群的load在读写操作会有更大fail的可能性(特别是如果buffer size如上增大时)。
storage.read-attemptsstorage.write-attempts参数增加重试次数来提高操作做健壮性,配置janusgraph会尝试多少次到storage后端来执行1次读写操作,直到放弃。如果是大量load,建议增大重试次数。

storage.attempt-wait规定janusgraph重试间等待的时间(单位毫秒)。更大的等待时长可以确保重试操作不会进一步增加后端的负载。

Strategies

Parallelizing the Load

通过多个机器并行bulk loading,如果janusgraph的storage后端集群足够强大来服务大量并发请求,load时间会大幅度减少。如MapReduce或Spark来执行bulk loading。 JanusGraph with TinkerPop’s Hadoop-Gremlin

如果不使用hadoop来并行bulk loading,这里也有一些高级向导用于高效并行处理:

  • 一些情况,graph数据能被分解到多个分开的子图。这些子图通过多个机器并行独立的load。(举例:用BatchGraph)
  • 如果graph不能被分解,常常可以通过下面几个步骤load来收益,最后2步可以在多机器并行处理:
    1. 确保vertex和edge去重了,一致性保证;
    2. 设置batch-loading=true,还有上面提到的其他参数也可尽量优化。
    3. 增加所有顶点和其属性到graph(不包括edge)。维护所有vertex id到一个支持分布式读写的map里,map里记录对象原主键id和vertex id(64位long id)之间的映射关系。
    4. 增加所有edge,使用map来查找vertex id,通过id取回vertex建立edge。

Q&A

如何在batch loading中避免如下错误:

java.io.IOException: ID renewal thread on partition [X] did not complete in time.
这个异常可能的引起原因是,id分配阶段因storage后端压力太大而重复超时。参考上面ID Allocation Optimization

你可能感兴趣的:(E.Advanced 04.Bulk Loading janusgraph批量写入)