在 Spark 数据导入中的一些实践细节
Posted Nebula Graph Community
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在 Spark 数据导入中的一些实践细节相关的知识,希望对你有一定的参考价值。
谣言
盐水漱口能预防感染?
钟南山院士团队公开辟谣:「盐水漱口有利于清洁口腔和咽喉,对于咽喉炎有帮助。但是新型冠状病毒侵犯的部位在呼吸道,漱口没有办法清洁呼吸道。其次,目前尚无任何研究结果提示盐水对新型冠状病毒有杀灭作用。」
本文由合合信息大数据团队柳佳浩撰写
图谱业务随着时间的推移愈发的复杂化,逐渐体现出了性能上的瓶颈:单机不足以支持更大的图谱。然而,从性能上来看,Neo4j 的原生图存储有着不可替代的性能优势,这一点是之前调研的 JanusGraph、Dgraph 等都难以逾越的鸿沟。即使 JanusGraph 在 OLAP 上面非常出色,对 OLTP 也有一定的支持,但是 GraphFrame 等也足以支撑其 OLAP 需求,更何况在 Spark 3.0 会提供 Cypher 支持的情况下,图谱的 OLAP 需求相比 OLTP 有更多途径可以解决。这个时候,Nebula Graph 的“横空出世”无疑是对分布式 OLTP 效率低下现状的一种突破。
之前在各类调研、部署后,特别是从 JanusGraph 的 OLTP 效率最终测试发现无法满足线上需求之后,我们不再对同一图谱可以同时进行 OLAP 和 OLTP 进行强制性要求,而 Nebula Graph 的架构刚好符合图谱方面的需要:
分布式——shared-nothing 分布式架构
服务的高可用(即在非人为情况下,图谱可以稳定提供服务)——局部失败服务可用、有快照机制
保证可扩展性——支持线性扩容,由于开源、支持二次开发
Nebula Graph 集群
3 台 32 c(实际限制了16 c)
400 G 内存(实际配置了 100 G)
SSD
版本信息:Nebula Graph 版本1.0.0(当时测试比较早)。
网络环境:万兆。
图谱大小:十亿级别节点(属性较少),百亿级别边(有向,无属性或带权值)。
Spark 集群
版本信息:Spark 2.1.0
打包 sst.generator(Spark 生成 sst 所需要的包)。
配置 Nebula Graph 集群,Nebula Graph 集群正常启动,创建图谱。
Spark 配置文件 config.conf (可以参考文档《Spark 导入工具》)进行配置。
排查 Spark 集群是否存在冲突的包。
Spark 启动时使用配置文件和 sst.generator 快乐地导入。
数据校验。
一些细节
批量导入前推荐先建立索引。
这里推荐先建立索引的原因是:批量导入仅在非线上图谱进行,虽然建立索引可以选择是否在提供服务的同时进行,但是为了防止后续 REBUILD 出现问题,这边可以优先建好索引。带来的问题就是在批量导入结点时相对较慢。
推荐用 int 型节点 ID(可以使用 Snowflake 算法 等),如果节点的 ID 不是 int 型,这里可以通过在节点/边中加入 policy: "uuid" 来设置自动生成 uuid。
如果使用的是单独的 Spark 集群可能不会出现 Spark 集群有冲突包的问题,该问题主要是 sst.generator 中存在可能和 Spark 环境内的其他包产生冲突,解决方法是 shade 掉这些冲突的包,或者改名。
Spark 调优方面:可以根据实际情况调整参数,尽量降低 memory 以节约资源,相对的可以适当提高并行度加速。
导入结果
十亿级别节点(属性较少),百亿级别边(有向,无属性或带权值),提前建好索引的情况下大约消耗 20 小时左右导入全图。
关于 PR
因为在较早的版本使用了 Spark 导入,自然也有一些不太完善的地方,这边也提出了一些拙见,对 SparkClientGenerator.scala 略作了修改。
最早在使用 Spark Writer(现:Exchange) 写入 Nebula Graph 时,发现错列的问题。
通过看源码发现 SparkClientGenerator.scala 存在 BUG,读取的是配置文件的位置而非 parquet/json 文件的位置,修复后提了我第一个 PR#2187,有幸通过
后续发现使用 SparkClientGenerator 自动生成 uuid/hash 功能时,存在会出现重复的双引号的问题,导致无法导入。
这块可以说是由于解决问题的想法不同,提交了好多次。重复引号的问题归根结底是对类型转化的时候添加了一次双引号,我这边发现有个 extraIndexValue 的方法可以把用户自填的非 string 类型的转成 string 类型,我这边想着可能会有用户想把非 string 型的 index 转成 uuid/hash(比如 array),所以修改的比较多。
但是和官方 @darionyaphet 沟通后,发现我这种做法其实是对数据源进行了修改,用户传 array 等不支持的类型时,应该报错而不是转换类型(这个确实,一开始只考虑到了逻辑上跑通以及自己这边业务的使用,没考虑通用性)。重新修改,提交 PR #2258,通过。经过这次 PR 我也学到了很多。
之后发现 nebula-python 也有和官方 thrift 冲突的问题,本来想 shade 后提 PR,但是觉得这个改动太大了,所以直接提给官方,近期也修复了。
Nebula Graph 旁白:欢迎社区小伙伴来 GitHub 给我们提 PR,GitHub 传送门:https://github.com/vesoft-inc/nebula/issues
因为之前调研过 JanusGraph,Nebula Graph 给我的第一印象就是:暗坑相对较少、社区反馈非常及时。在测试后 Nebula Graph 又用她的效率证明了自己,成为了分布式图谱的首选项。
Nebula Graph 社区、群组、PR 官方反馈非常及时,这是图谱迅速、茁壮成长的不可替代的重要因素,也希望可以后续可以继续见证 Nebula Graph 的成长,继续为 Nebula Graph 生态的完善添砖加瓦!
喜欢这篇文章?来来来,给我们的 GitHub:https://github.com/vesoft-inc/nebula 点个 star 表鼓励啦~~ 以上是关于在 Spark 数据导入中的一些实践细节的主要内容,如果未能解决你的问题,请参考以下文章 33_redis在实践中的一些常见问题以及优化思路(包含linux内核参数优化) 如何让 Spark SQL 导入没有“L”后缀的 Long?