使用JanusGraph的OLAP记录
本文主要描述在windows的idea中使用 JanusGraph的spark on yarn任务分析,主要用于学习和交流。
环境配置:
- 19个RegionServer组成的HBase集群。
- 每个节点由7块磁盘组成
- 每个节点2个物理CPU,逻辑CPU核数40核
对于普通的查询 例如:g.V().count()
对于图库中点数量少的情况可以使用,对于量大的请款已经无法满足,不是慢而是根本就查不出来。
如下在一个存了半年的通联关系的图库中使用查询命令,直接报错。
首先在在命令行使用properties文件开启graph:
[hadoop@master bin]$ ./gremlin.sh
gremlin> graph=JanusGraphFactory.open('conf/njm-graph.properties')
==>standardjanusgraph[hbase:[IP地址]]
gremlin> g=graph.traversal()
在 njm-graph.properties
配置文件中个使用HBase作为后端存储,使用ES作为索引。
紧接着使用如下语句,查询点个数,等了非常长的时间,直接报错,试了好几次都是如下情况:
gremlin> g.V().count()
11:04:19 WARN org.janusgraph.graphdb.transaction.StandardJanusGraphTx - Query requires iterating over all vertices [()]. For better performance, use indexes
java.io.IOException: Failed to get result within timeout, timeout=60000ms
Type ':help' or ':h' for help.
Display stack trace? [yN]12:45:19 WARN org.apache.hadoop.hbase.client.ConnectionManager$HConnectionImplementation - This client just lost it's session with ZooKeeper, closing it. It will be recreated next time someone needs it
org.apache.hadoop.hbase.shaded.org.apache.zookeeper.KeeperException$SessionExpiredException: KeeperErrorCode = Session expired
at org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher.connectionEvent(ZooKeeperWatcher.java:702)
at org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher.process(ZooKeeperWatcher.java:613)
at org.apache.hadoop.hbase.shaded.org.apache.zookeeper.ClientCnxn$EventThread.processEvent(ClientCnxn.java:522)
at org.apache.hadoop.hbase.shaded.org.apache.zookeeper.ClientCnxn$EventThread.run(ClientCnxn.java:498)
使用OLAP的方式(什么是OLAP/OLTP这里不解释)
如下的方式为,在window的 idea中提交任务,使用spark on yarn的方式进行查询。命令行的方式也已经测试通了,这里就不记录了,毕竟生产中不会使用命令行。
而且这里直接使用 spark on yarn 的方式,官网中介绍了spark独立集群的方式,这里就不记录了,毕竟生产中spark on yarn用的多一些。
需要的配置文件及配置:
1. hadoop集群默认的配置文件3个:
core-site.xml
hdfs-site.xml
yarn-site.xml
将如上3个文件拷贝到项目的resources
目录下,在最开始测试的时候会出现一个报错,需要将core-size.xml
中的最后一个注释掉,否则会报找不到文件:
2. pom.xml
在引用依赖时一定要注意,你引用的依赖中包含guava的依赖,一定要主要看你本地依赖和服务器集群上的guava的版本,##最好保持一致##。
前期也是解决guava依赖冲突,花了很长时间。
org.apache.hadoop
hadoop-yarn-server-web-proxy
2.5.0
servlet-api
javax.servlet
guava
com.google.guava
org.janusgraph
janusgraph-core
0.3.0
guava
com.google.guava
org.janusgraph
janusgraph-hadoop
0.3.0
logback-classic
ch.qos.logback
org.apache.tinkerpop
gremlin-core
3.3.3
org.apache.tinkerpop
spark-gremlin
3.3.3
guava
com.google.guava
org.apache.tinkerpop
hadoop-gremlin
3.3.3
org.apache.spark
spark-yarn_2.11
2.2.0
guava
com.google.guava
org.apache.hbase
hbase-shaded-client
1.2.6
org.apache.hbase
hbase-shaded-server
1.2.6
com.jcabi
jcabi-log
0.14
javax.servlet
servlet-api
2.5
org.janusgraph
janusgraph-hbase
0.3.0
3. read-hbase-hadoop.properties
这个配置文件是从JanusGraph的安装包目录/datas/disk22/janusgraph-0.3.0-hadoop2/conf/hadoop-graph
中拷贝出来的,主要是配置后端存储
及序列化等配置,这里使用的是HBase+ES的配置,这个目录下有cassandra的配置,可以根据需要获取。
配置如下,其中spark.yarn.jars
配置非常重要:
#
# Hadoop Graph Configuration
#
gremlin.graph=org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph
gremlin.hadoop.graphReader=org.janusgraph.hadoop.formats.hbase.HBaseInputFormat
gremlin.hadoop.graphWriter=org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoOutputFormat
gremlin.hadoop.jarsInDistributedCache=true
gremlin.hadoop.inputLocation=none
gremlin.hadoop.outputLocation=output
gremlin.spark.persistContext=true
gremlin.hadoop.defaultGraphComputer=org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer
janusgraphmr.ioformat.conf.storage.backend=hbase
janusgraphmr.ioformat.conf.storage.hostname=IP地址
janusgraphmr.ioformat.conf.storage.hbase.ext.zookeeper.znode.parent=/hbase-unsecure
janusgraphmr.ioformat.conf.storage.hbase.table=graph_table
# 这个配置非常重要,原始配置文件中没有,这个指定的目录为spark的jar包,可以从集群spark目录中直接获取
# 我这里的目录为: /usr/hdp/current/spark2-client/jars/ 224个jar包直接上传就对了
spark.yarn.jars=hdfs://IP地址:8020/user/hadoop/janusgraph/spark_jars/*.jar
#这里指定提交任务到yarn
spark.master=yarn
#spark的client模式,也就是提交任务后我本地作为JobManager,任务计算完成后会返回结果给我本地
spark.submit.deployMode=client
spark.executor.memory=20g
spark.executor.cores=6
spark.executor.instances=20
spark.driver.memory=1g
#序列化
spark.serializer=org.apache.spark.serializer.KryoSerializer
spark.kryo.registrator=org.apache.tinkerpop.gremlin.spark.structure.io.gryo.GryoRegistrator
4. 代码
在代码中需要指定一个 HADOOP_GREMLIN_LIBS
配置,官网中还介绍了一种方式,在spark集群的每个节点上指定一个相同的目录
然后将需要依赖的jar包放上去,很明显没有指定一个hdfs路径方便。
public class GraphComputeApp {
private static final Logger LOGGER = LoggerFactory.getLogger(GraphComputeApp.class);
private final static String PROPERTY_FILE_PATH = "hadoop-graph/src/main/resources/read-hbase-hadoop.properties";
public static void main(String[] args) throws Exception {
//System.setProperty("user.name", "hadoop");
System.setProperty("HADOOP_USER_NAME", "hadoop");
//这个配置非常重要,这个指定一个HDFS路径,路径中存放jar包为JanusGraph安装目录解压后的依赖目录 janusgraph-0.3.0-hadoop2/lib
//将目录中的jar包上传到hdfs上,任务运行时需要的依赖
System.setProperty("HADOOP_GREMLIN_LIBS", "hdfs://ip:8020/user/hadoop/janusgraph/spark-yarn/jars/");
Graph graph = GraphFactory.open(PROPERTY_FILE_PATH);
GraphTraversalSource g = graph.traversal().withComputer(SparkGraphComputer.class);
long count = g.V().count().next();
LOGGER.info(count + "-----g.V().count()-------------------------------");
long count_E = g.E().count().next();
LOGGER.info(count_E + "-----g.E().count()-------------------------------");
graph.close();
}
}
5. 运行
做好各项配置后,直接在idea上运行main方法,在yarn上可以看到:
spark上任务进度:
在idea中可以看到如下日志:
[task-result-getter-0]2019-12-19 14:45:02 [INFO ] task-result-getter-0 | Finished task 2.0 in stage 0.0 (TID 52) in 48487 ms on slave23 (executor 19) (1/98) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[dispatcher-event-loop-1]2019-12-19 14:45:15 [INFO ] dispatcher-event-loop-1 | Added broadcast_0_piece0 in memory on slave12:14785 (size: 34.8 KB, free: 10.5 GB) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[dispatcher-event-loop-3]2019-12-19 14:45:17 [INFO ] dispatcher-event-loop-3 | Added broadcast_0_piece0 in memory on slave13:55393 (size: 34.8 KB, free: 10.5 GB) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[task-result-getter-1]2019-12-19 14:46:17 [INFO ] task-result-getter-1 | Finished task 1.0 in stage 0.0 (TID 51) in 122944 ms on slave20 (executor 7) (2/98) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[task-result-getter-2]2019-12-19 14:58:31 [INFO ] task-result-getter-2 | Finished task 3.0 in stage 0.0 (TID 53) in 857171 ms on slave5 (executor 3) (3/98) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[task-result-getter-3]2019-12-19 15:03:14 [INFO ] task-result-getter-3 | Finished task 5.0 in stage 0.0 (TID 55) in 1140160 ms on newslave200 (executor 18) (4/98) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[task-result-getter-0]2019-12-19 15:09:29 [INFO ] task-result-getter-0 | Finished task 72.0 in stage 0.0 (TID 19) in 1518252 ms on slave20 (executor 7) (5/98) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
[task-result-getter-1]2019-12-19 15:11:18 [INFO ] task-result-getter-1 | Finished task 0.0 in stage 0.0 (TID 50) in 1623848 ms on slave14 (executor 10) (6/98) | org.apache.spark.internal.Logging$class.logInfo(Logging.scala:54)
省略很多行......
因为我在hbase上的这张表非常大,有98个分区。
执行过程非常慢,最终输出结果:
库中点的个数:351677990
库中边的个数:2139729335
耗时 5个多小时,因为是测试环境,还有很多数据在入库,还有其他表的操作查询及入库,所有还有很大的优化空间。
可以看到yarn上任务完成:
有了初始化一个这样的graph后,可以做各种各样的图分析,也可以直接使用Gremlin提供的各种开箱即用图算法进行分析。