hadoop之MapReduce调用R的一次失败的总结~(续二)

本文讲述了作者在使用Hadoop MapReduce过程中遇到的调用R失败的问题,尝试通过直接用JAVA API获取HBASE历史数据来避免R通过Thrift调用,但在升级HBASE版本和调整配置后,问题仍未解决。文章分享了作者的调试过程及遇到的错误,包括HBASE的版本兼容性、Master初始化问题和limit.conf的调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

路还得继续!

我重新构想了思路,直接用JAVA的API获取HBASE的历史数据,然后传递给R,这样可以避免了R通过thrift调用!

于是我重写了第二个版本的MapReduce,如下:

package mytest;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.NullOutputFormat;


public class MapRLanguage2 {
	
	 public static int mapNum = 12;
	 
	 public static final String RDIR_H="hdfs://bd110:9000/user/hadoop/";
	 
	 public static final String RDIR_L="/home/hadoop/yibei/R/";
	 
	  public static class RMapper extends Mapper<Object, Text, NullWritable, NullWritable>{
		    HTable table = null;
		    
		    public void setup(Context context
	              ) throws IOException, InterruptedException {
		        Configuration hbaseConf = HBaseConfiguration.create();
		        table = new HTable(hbaseConf, "kpinfo"); 
		    }
		  
		    public void cleanup(Context context
                    ) throws IOException, InterruptedException {
		    	table.close();
		    }
		  
		    //每个文件只有一行
		    public void map(Object key, Text value, Context context ) throws IOException, InterruptedException {
		    	String args[] = value.toString().split("\\|");
		        //先准备存入的文件名称 例如:[Map].cell.kpi
		        InputSplit inputSplit = context.getInputSplit();
		        String fileName =  ((FileSplit)inputSplit).getPath().getName();
		        //获取数据存入文件中 
		        String cellarr[] = args[2].split(",");
		        String kpiarr[] = args[3].split(",");
		        //获取开始时间
		        String datedir = context.getConfiguration().get("datedir");
		        for(int i=0;i<cellarr.length;i++){
		        	//创建文件
		        	for(int j=0;j<kpiarr.length;j++){
			        	File ldir = new File(RDIR_L+datedir+"/");
			        	ldir.mkdirs();
			        	File lfile = new File(RDIR_L+datedir+"/"+fileName+"."+cellarr[i]+"."+kpiarr[j]);
			        	lfile.createNewFile();
		        	}
		        }
		        //访问HBASE,获取历史历史数据
		        Scan scan = new Scan();
		        scan.addFamily("h".getBytes()); //扫描列簇
		        scan.setCaching(10000);//一次取1万
		        ResultScanner scanner = table.getScanner(scan);
		        //扫描列簇获取每一行的值
		        for(Result result: scanner){
		        	//扫描当前行的每一个字段 ,2个"h".getBytes()看似多余,其实不然,理解为获取根据a列簇扫描获取的行记录,当然可以获取b列簇的值
		        	for(Map.Entry<byte[], byte[]> entry : result.getFamilyMap("h".getBytes()).entrySet()){
		            	   String column = new String(entry.getKey());
		            	   String data = new String(entry.getValue());
		            	   System.out.println(column+","+data);
		            }
		        }
		        scanner.close();
		        //文件路径传入给R
//		    	Rengine re=new Rengine(new String[] { "--vanilla" }, false,null);
//		        if (!re.waitForR()) {
//		            System.out.println("Cannot load R");
//		            return;
//		        }
//		        re.eval("setwd('"+RDIR_L+"')");  
//		        re.eval("source('main2.R')"); 
//		        String rcmd="kpi.forecastByDBWithTime('"+args[4]+"','"+args[5]+"','"+args[6]+"','"+args[7]+"','"+args[1]+"','" + args[0] +"','" + args[2] +"','" + args[3] + "')";
//		        re.eval(rcmd);
//		        re.end();
		   }
	  }

	 public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
			String dbtbl  = "stat_plan_result_"+args[0].trim();
			String dbname = args[1].trim();
			String cells  = args[2].trim();
			String kpis   = args[3].trim();
			String hbtime = args[4].trim();
			String hetime = args[5].trim();
			String fbtime = args[6].trim();
			String fetime = args[7].trim();
			//2种思路,1种设置多少Size拆分一个Map使用FileInputFormat.setMaxInputSplitSize(),另1种利用每个文件一个Map的特性处理它。按文件处理也可以使用job.setInputFormatClass();
//			String cells="1,2,3,4,5,6,7,8,9,10,11,12,13,14";
			String cellarr[] = cells.split(",");
			String datedir = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
			String currentDir =RDIR_H+datedir+"/in/";
			String currentoutDir =RDIR_H+datedir+"/out/";
			if(cellarr.length<=mapNum){
				for(int i =0;i<cellarr.length;i++){
					//输出文件
					String filepath = currentDir+i;
			        FileSystem fs = FileSystem.get(URI.create(filepath), new Configuration());  
			        FSDataOutputStream out = fs.create(new Path(filepath));
			        out.write((dbtbl+"|"+dbname+"|"+cellarr[i]+"|"+kpis+"|"+hbtime+"|"+hetime+"|"+fbtime+"|"+fetime).getBytes("UTF-8"));
			        out.close();
				}
			}else{
				int s = cellarr.length/mapNum;
				int y = cellarr.length%mapNum;
				for(int i =0,j=y;i<mapNum;i++){
					//2种分配方案,1种是循环每个cell,加入文件。另1种是计算出,每次分配的数量。
					int cellNum=s;
					if(j>0){
						cellNum+=1;
						j--;
					}
					String celldata="";
					for(int k =0;k < cellNum; k++){
						//每个Map的小区,从cellarr中获取。
						int cellindex=k+i*s+(cellNum>s?i:y);
						celldata+=cellarr[cellindex]+",";
					}
					String filepath = currentDir+i;
			        FileSystem fs = FileSystem.get(URI.create(filepath), new Configuration());  
			        FSDataOutputStream out = fs.create(new Path(filepath));
			        out.write((dbtbl+"|"+dbname+"|"+celldata.substring(0,celldata.length()-1)+"|"+kpis+"|"+hbtime+"|"+hetime+"|"+fbtime+"|"+fetime).getBytes("UTF-8"));
			        out.close();
				}
			}
			Job job = Job.getInstance(new Configuration());
			job.getConfiguration().setInt("mapreduce.task.timeout", 0);//关闭超时
			job.getConfiguration().setBoolean("mapreduce.map.speculative", false);//关闭推测执行
			job.getConfiguration().setStrings("datedir", datedir);//设置一个目录
			job.setJarByClass(MapRLanguage2.class);  
			job.setMapperClass(RMapper.class); 
			//job.setOutputKeyClass(NullWritable.class);//和setMapOutputKeyClass的区别?也许是没有reduce的时候指的是一样的,有reduce的时候是只reduce的输出?
			//job.setOutputValueClass(NullWritable.class);//同上
			job.setNumReduceTasks(0);//没有Rudeuce输出
			job.setOutputFormatClass(NullOutputFormat.class);//不需要输出 可以关闭setOutputKeyClass和setOutputValueClass?
			FileInputFormat.addInputPath(job,new Path(currentDir));       
			FileOutputFormat.setOutputPath(job,new Path(currentoutDir));
			System.exit(job.waitForCompletion(true) ? 0 : 1);
	 } 
	 
}

但后台错误如故,我尝试修改代码做一些测试,发现程序是能够正常返回,甚至结果也是对的。我陷入苦恼。

我翻阅了大量的资料,并没有太多信息能给我灵感,查看官方HBASE文档显示:

HBASE-0.98 相对 HADOOP-2.6是NT(NOT TEST),于是我决定升级至HBASE1.1.1。

做一些简单的描述

下载解压后,进入conf目录

regionservers

bd107 
bd108

hbase-env.sh

 export JAVA_HOME=/usr/local/jdk1.7  --打开注释并修改对应位置

hbase-site.xml

<property>
  <name>hbase.cluster.distributed</name>           --开启分布式
  <value>true</value>
</property>
<property>
 <name>hbase.rootdir</name>                        --存入hdfs的位置
 <value>hdfs://bd110:9000/hbase1</value>
</property>
<property>
  <name>hbase.zookeeper.property.dataDir</name>    --zookeeper需要用的
  <value>/home/hadoop/zookeeperDir</value>
</property>
<property>
    <name>dfs.replication</name>                   --测试了一把,貌似可以把dfs的默认3份给覆盖变成2了
    <value>2</value>
</property>
<property>
    <name>hbase.zookeeper.quorum</name>            --哪些机器启动zookeeper,需要为奇数个
    <value>bd107,bd108,bd110</value>
</property>

然后修改环境变量,启动HBASE后测试。进入hbase shell,执行list操作。

ERROR: Can't get master address from ZooKeeper; znode data == null                  --第一个错误

ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing          --第二个错误
        at org.apache.hadoop.hbase.master.HMaster.checkInitialized(HMaster.java:2177)
        at org.apache.hadoop.hbase.master.MasterRpcServices.getTableDescriptors(MasterRpcServices.java:821)
        at org.apache.hadoop.hbase.protobuf.generated.MasterProtos$MasterService$2.callBlockingMethod(MasterProtos.java:48468)
        at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2112)
        at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:101)
        at org.apache.hadoop.hbase.ipc.RpcExecutor.consumerLoop(RpcExecutor.java:130)
        at org.apache.hadoop.hbase.ipc.RpcExecutor$1.run(RpcExecutor.java:107)
        at java.lang.Thread.run(Thread.java:745)

这2个错误网上都能检索到蛮多,反正我也是莫名其妙就好了。

第一个错误,印象中,重启hbase 就可以。

第二个错误,很奇怪,Master is initializing 既然ing结尾,是不是告诉你hbase正在初始化,叫你等待?反正我检索了下资料,啥也没干,再次执行命令突然就好了。


接着重新建表,写了一个Mapreduce用来导入数据,这个测试倒是很正常,代码如下。

package mytest;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.NullOutputFormat;

public class ImportCSV {

	
	//['rtime','rnc','mo','R99_UL_User','R99_DL_User','HSDPA_Users','HSUPA_Users','R99_UL_throughput','R99_DL_throughput','HSDPA_Throughput','HSUPA_Throughput','R99_UL_volume_PS','R99_DL_volume_PS','HSDPA_volume','HSUPA_volume']
	  public static class CSVMapper extends Mapper<Object, Text, NullWritable, NullWritable>{
		    
		    HTable table = null;
		    
		    public void setup(Context context
	              ) throws IOException, InterruptedException {
		        Configuration hbaseConf = HBaseConfiguration.create();
		        table = new HTable(hbaseConf, Bytes.toBytes("kpinfo")); 
		    }
		  
		    public void cleanup(Context context
                  ) throws IOException, InterruptedException {
		    	table.close();
		    }
		    
		    public void map(Object key, Text value, Context context ) throws IOException, InterruptedException {
		    	String args[] = value.toString().split("\t");
		    	Put put = new Put(Bytes.toBytes(args[2]+"_"+args[0].replaceAll("-", "").replaceAll(":", "").replace(" ", "")));// 设置rowkey
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("R99_UL_User"), Bytes.toBytes(args[3]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("R99_DL_User"), Bytes.toBytes(args[4]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("HSDPA_Users"), Bytes.toBytes(args[5]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("HSUPA_Users"), Bytes.toBytes(args[6]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("R99_UL_throughput"), Bytes.toBytes(args[7]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("R99_DL_throughput"), Bytes.toBytes(args[8]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("HSDPA_Throughput"), Bytes.toBytes(args[9]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("HSUPA_Throughput"), Bytes.toBytes(args[10]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("R99_UL_volume_PS"), Bytes.toBytes(args[11]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("R99_DL_volume_PS"), Bytes.toBytes(args[12]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("HSDPA_volume"), Bytes.toBytes(args[13]));
		    	put.add(Bytes.toBytes("h"),Bytes.toBytes("HSUPA_volume"), Bytes.toBytes(args[14]));
		    	table.put(put);  
		   }
	  }
	  
		 public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
				Job job = Job.getInstance(new Configuration());
				job.getConfiguration().setInt("mapreduce.task.timeout", 0);//关闭超时
				job.getConfiguration().setBoolean("mapreduce.map.speculative", false);//关闭推测执行
				job.setJarByClass(ImportCSV.class);  
				job.setMapperClass(CSVMapper.class); 
				job.setNumReduceTasks(0);//没有Rudeuce输出
				job.setOutputFormatClass(NullOutputFormat.class);//不需要输出 无法输出结果 --可以关闭setOutputKeyClass和setOutputValueClass?
				FileInputFormat.addInputPath(job,new Path("/user/hadoop/csv/in"));       
				//FileOutputFormat.setOutputPath(job,new Path("/user/hadoop/csv/out"));
				System.exit(job.waitForCompletion(true) ? 0 : 1);
		 } 
}

一切看似那么美好,但最终测试,问题仍然没有解决。


tips:

有一个关于limit.conf的问题,我曾自己推算过:

这个表有4个Region,一个列簇应该只有一个Store,每个Store里面有多少个StoreFile,我还不不知道怎么去确认它。

就算并发Map数为10,根据公式测算,也远远达不到瓶颈。况且抛出的错误,也并未指向limit.conf。

但是我还是对它也进行了一次修改如下:

cat /etc/security/limits.conf
hadoop  -  nofile 32768
hadoop  -  nproc  32768

修改后注销,ulimit -a 测试通过重启后hadoop相关服务测试,问题如故!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值