方式很多,我使用的是Export与Import感觉还挺好用的,我使用的场景有几种,以下会分别说明:
我的需求是将老集群数据迁移到新集群,但是有两种情况:
1.两个集群网络能够联通;
2.两个集群网络不能联通。
先说能联通的情况及遇到的问题:
root登陆集群1.
执行以下命令,我的前提是我执行hbase shell是可以正常执行的。
hbase org.apache.hadoop.hbase.mapreduce.Export tablename hdfs://新集群IP:8020/test/tablename
我的这个表数据不多,因此导出速度很快,中间没有disable表。
之后登陆新进去执行导入操作
hbase org.apache.hadoop.hbase.mapreduce.Import tablename hdfs://新集群IP:8020/lwb/tablename
在这里我报了一个错误
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=root, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x
这个错误的意思是,root没有hdfs的权限,网上说2个办法1.给root权限,2修改hdfs参数之后重启。
我都没用,我是直接切换到了hdfs用户#su hdfs
这个用户我没设置密码,进行之后直接执行上边的导入命令,又异常了,导入失败
Error: org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException: Failed 1619 actions: tablename: 1619 times,
原因是我在新的hbase库中没创建表,于是我创建了表名是tablename的新表。
之后再执行导入,导入成功。
2.两个集群完全不联通的情况
1.将旧集群的表数据导出到旧集群本身的hdfs里
hbase org.apache.hadoop.hbase.mapreduce.Export tablename hdfs://旧集群IP:8020/test/tablename
2.下载hdfs文件,这里我是使用java程序下载的文件,代码如下.
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.io.IOUtils; public class HDFSTest { private static String HDFSUri = "hdfs://10.10.1.68:8020";//这里注意下载上传的时候,修改成旧集群和新集群的IP地址 public static void main(String[] args) throws Exception { String HDFSFile = "/lwb/FASTAChargeMsg"; String localFile = "D:\\FASTAChargeMsg"; // 连接fs System.setProperty("HADOOP_USER_NAME", "hdfs");// 这句必须加,否是会报权限错误,而hdfs是hadoop的用户名,这个账号是有权限操作hdfs的 FileSystem fs = getFileSystem(); System.out.println(fs.getUsed()); // 创建路径 // mkdir("/zhaojy2"); // // 验证是否存在 // System.out.println(existDir("/zhaojy2", false)); // // 上传文件到HDFS copyFileToHDFS("D:\\part-m-00002", "/lwb/FASTAGPRSMsg/part-m-00002"); // 下载文件到本地 // getFile("/lwb/FASTAGPRSMsg/part-m-00002", "D:\\part-m-00002"); // getFile(HDFSFile,localFile); // 删除文件 // rmdir("/lwb/FASTAGPRSMsg"); // // 读取文件 // readFile("/zhaojy/HDFSTest.txt"); } /** * 获取文件系统 * * @return FileSystem 文件系统 */ public static FileSystem getFileSystem() { // 读取配置文件 Configuration conf = new Configuration(); // 文件系统 FileSystem fs = null; String hdfsUri = HDFSUri; if (StringUtils.isBlank(hdfsUri)) { // 返回默认文件系统 如果在 Hadoop集群下运行,使用此种方法可直接获取默认文件系统 try { fs = FileSystem.get(conf); } catch (IOException e) { e.printStackTrace(); } } else { // 返回指定的文件系统,如果在本地测试,需要使用此种方法获取文件系统 try { URI uri = new URI(hdfsUri.trim()); fs = FileSystem.get(uri, conf); } catch (Exception e) { e.printStackTrace(); } } return fs; } /** * 创建文件目录 * * @param path * 文件路径 */ public static void mkdir(String path) { try { FileSystem fs = getFileSystem(); System.out.println("FilePath=" + path); // 创建目录 fs.mkdirs(new Path(path)); // 释放资源 fs.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 判断目录是否存在 * * @param filePath * 目录路径 * @param create * 若不存在是否创建 */ public static boolean existDir(String filePath, boolean create) { boolean flag = false; if (StringUtils.isEmpty(filePath)) { return flag; } try { Path path = new Path(filePath); // FileSystem对象 FileSystem fs = getFileSystem(); if (create) { if (!fs.exists(path)) { fs.mkdirs(path); } } if (fs.isDirectory(path)) { flag = true; } } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 本地文件上传至 HDFS * * @param srcFile * 源文件 路径 * @param destPath * hdfs路径 */ public static void copyFileToHDFS(String srcFile, String destPath) throws Exception { FileInputStream fis = new FileInputStream(new File(srcFile));// 读取本地文件 Configuration config = new Configuration(); FileSystem fs = FileSystem.get(URI.create(HDFSUri + destPath), config); Path p = new Path(HDFSUri + destPath); OutputStream os = fs.create(p); FsPermission permission = new FsPermission(FsAction.ALL, FsAction.ALL, FsAction.ALL); fs.setPermission(p, permission); // copy IOUtils.copyBytes(fis, os, 4096, true); System.out.println("拷贝完成..."); fs.close(); } /** * 从 HDFS 下载文件到本地 * * @param srcFile * HDFS文件路径 * @param destPath * 本地路径 */ public static void getFile(String srcFile, String destPath) throws Exception { // hdfs文件 地址 String file = HDFSUri + srcFile; Configuration config = new Configuration(); // 构建FileSystem FileSystem fs = FileSystem.get(URI.create(file), config); // 读取文件 InputStream is = fs.open(new Path(file)); IOUtils.copyBytes(is, new FileOutputStream(new File(destPath)), 2048, true);// 保存到本地 // 最后 // 关闭输入输出流 System.out.println("下载完成..."); fs.close(); } /** * 删除文件或者文件目录 * * @param path */ public static void rmdir(String path) { try { // 返回FileSystem对象 FileSystem fs = getFileSystem(); String hdfsUri = HDFSUri; if (StringUtils.isNotBlank(hdfsUri)) { path = hdfsUri + path; } System.out.println("path:" + path); // 删除文件或者文件目录 delete(Path f) 此方法已经弃用 System.out.println(fs.delete(new Path(path), true)); // 释放资源 fs.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 读取文件的内容 * * @param filePath * @throws IOException */ public static void readFile(String filePath) throws IOException { Configuration config = new Configuration(); String file = HDFSUri + filePath; FileSystem fs = FileSystem.get(URI.create(file), config); // 读取文件 InputStream is = fs.open(new Path(file)); // 读取文件 IOUtils.copyBytes(is, System.out, 2048, false); // 复制到标准输出流 fs.close(); } }
3.利用上边的程序将文件上传到新的集群上。
4.在新的集群上运行导入命令,与联通方式要注意的事项是一样的。
hbase org.apache.hadoop.hbase.mapreduce.Import tablename hdfs://新集群IP:8020/lwb/tablename
这里我测试的是一张表有300多万条数据,,大小在2G左右,导入和导出速度还可以。