最近开始学习Spark,因为原先分析收集的数据都是存储在hadoop和hbase中,经过这两天终于解决了问题。
这里不说集群搭建,直接说如何设置和代码上如何处理能从hbase中读取数据。
1. 在spark的环境启动环境中需要加入hbase lib目录下的所有jar包:
首先,在spark_home/lib目录下创建hbase目录,然后拷贝hbase_home/lib下所有jar包;
然后,修改spark_classpath,在spark_home/conf/spark-env.sh中添加上边拷贝过来的jar包,例如export SPARK_CLASSPATH=/usr/local/spark/spark-1.6.0-bin-hadoop2.6/lib/hbase/*
不添加的话就会出现unread block data的错误。
2. 运行spark任务的时候,如果出现这个异常:TaskSchedulerImpl: Initial job has not accepted any resources; check your cluster UI to ensure that workers are registered and have sufficient memory,需要检查几个方面的配置:
a. spark内存是否足够,可以增加spark worker内存,也可以降低任务使用的内存
在spark-env.sh中修改配置SPARK_WORKER_MEMORY可以修改worker的内存
或者在任务中设置spark.executor.memory修改任务使用的内存
b. 执行任务的时候,spark会为系统预留一部分内存,默认是几百M吧,具体值没有记下来,不过从worker日志是可以看到的,可以在任务中设置spark.testing.reservedMemory参数进行修改
3. 从hbase中读取数据时异常:org.apache.hadoop.hbase.security.AccessDeniedException: Insufficient permiss
这个可以明显看出是没有访问权限问题,从hbase日志中也可以看到类似security.UserGroupInformation: No groups available for user XXXXX的日志
因为我是在windows eclipse上直接提交的任务,我就直接在windows上创建了一个hadoop账户(和我hbase集群使用的账户一样),然后就解决问题。
最后,如果任务中设计到map/reduce方面的代码,是需要把代码打成jar包提交到spark上的,否则会抛出class not found的异常。
最后,附上我这次加的几行测试代码:
// 初始化JavaSparkContext
SparkConf sparkConf = new SparkConf().setAppName("test").setMaster("spark://OPENFIRE-DEV:7080")
.set("spark.executor.memory", "64m").set("spark.testing.reservedMemory", "102400");
JavaSparkContext sc = new JavaSparkContext(sparkConf);
// 这里我是从sprig容器中获取的HbaseUtil类,自己写的工具类,方便获取Configuration而已
HbaseUtil hbaseUtil = (HbaseUtil) factory.getBean("hbaseUtil");
Configuration hbaseConf = hbaseUtil.getConfiguration();
// 从Table: member_biz_log中读取Family: app_log中的数据
Scan scan = new Scan();
scan.addFamily(Bytes.toBytes("app_log"));
hbaseConf.set(TableInputFormat.INPUT_TABLE, "member_biz_log");
ClientProtos.Scan proto = ProtobufUtil.toScan(scan);
String ScanToString = Base64.encodeBytes(proto.toByteArray());
hbaseConf.set(TableInputFormat.SCAN, ScanToString);
JavaPairRDD<ImmutableBytesWritable, Result> myRDD = sc.newAPIHadoopRDD(hbaseConf, TableInputFormat.class,
ImmutableBytesWritable.class, Result.class);
// 随便乱写的测试代码
JavaPairRDD<String, Integer> result = myRDD
.mapToPair(new PairFunction<Tuple2<ImmutableBytesWritable, Result>, String, Integer>() {
private static final long serialVersionUID = -6214814960929421459L;
@Override
public Tuple2<String, Integer> call(
Tuple2<ImmutableBytesWritable, Result> immutableBytesWritableResultTuple2) throws Exception {
byte[] o = immutableBytesWritableResultTuple2._2().getValue(Bytes.toBytes("ERROR"),
Bytes.toBytes("logInfo"));
if (o != null) {
System.out.println(Bytes.toString(o));
return new Tuple2<String, Integer>(Bytes.toString(o), 1);
}
return null;
}
});
System.out.println(result.count());