前言 最近事情好多,就没有更新大数据的相关资料,本次内容是使用命令行去控制Hadoop,进行HDFS的编程(java),教你如何打开hadoop的相关配置,实现像老师的Hadoop一样,以及介绍一些关于控制HDFS的API控制命令
参考文章 更改连接hadoop的用户名称
前提 服务器需要安装
服务器之前应配置完之前hadoop系列的东西
过程 如何配置Hadoop进行远程操作 修改hdfs-site.xml
文件 由于在使用中,namenode会向datanode发送一个局域网ip地址,由于发送的是局域网地址,因此在外网环境下,无法对其进行访问,因此需要修改文件中的内容,向文件中增加几行代码,使其发送的是datanode主机的hostname,然后通过后续操作,使其直接指向外网IP地址
针对我自己服务器的编辑为:vim /usrl/local/hadoop/etc/hadoop/hdfs-site.xml
(如果没有权限前面加sudo)
在文件内添加如下内容:
1 2 3 4 <property > <name > dfs.client.use.datanode.hostname</name > <value > true</value > </property >
配置完成之后,总代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet type="text/xsl" href="configuration.xsl" ?> <configuration > <property > <name > dfs.replication</name > <value > 1</value > </property > <property > <name > dfs.client.use.datanode.hostname</name > <value > true</value > </property > <property > <name > dfs.namenode.name.dir</name > <value > file:/usr/local/hadoop/tmp/dfs/name</value > </property > <property > <name > dfs.datanode.data.dir</name > <value > file:/usr/local/hadoop/tmp/dfs/data</value > </property > </configuration >
配置主机hostname 我们需要将主机名称更改为自己的hadoop名称,方便在后续访问主机的时候能够进行访问到
将里面的内容全部删除,更换成hadoop
(此处名称可以自行定义,在后续操作中进行修改就行)
关闭服务器端关于namenode的安全模式 安全模式界面下,无法对namenode进行任何操作,因此我们需要对其进行关闭
在hadoop的根目录下,执行hdfs dfsadmin -safemode leave
确保自己的namenode和datanode的id号一致 由于在实际操作中,namenode 要与 datanode 进行通信,要求两个节点的clusterID
要进行一致,因此我们可以通过进入到自己的namenode 与datanode中查看VERSION,对于我自己的机子来讲,在hadoop根目录下输入cat tmp/dfs/name/current/VERSION
与cat tmp/dfs/data/current/VERSION
对两个版本号进行查看。
其他机子的namenode 和datanode节点需要根据自己的项目设置可以查看。
进入vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml
对两个的dir进行查看
修改自己的主机名称(百度云) 神奇的百度云教会了我一件事情,你自己的主机名在本地的hostname中进行更改,但是在百度云里面(暂且只发现了百度云的事情),你需要进入到百度云控制台,将自己的主机名称进行修改,否则无法生效
在系统本地配置运行环境 安装java环境 使用java编译器就需要先提前将java的环境配置成功,本次介绍Java环境为使用Java17,因此如果没有相关环境的需要自行去进行下载
客户端配置host 此处分windows与linux两种配置方式:
windows:
进入到C:\Windows\System32\drivers\etc
修改hosts内容,在最后一项添加:
127.0.0.1 hadoop #前面的那项是你自己服务器的ip地址,后面那项是之前设置的那个值
如果无法修改的话,参照这篇文章进行配置百度经验
linux:
sudo vim /etc/hosts
修改hosts内容,在最后一项添加:
127.0.0.1 hadoop #前面的那项是你自己服务器的ip地址,后面那项是之前设置的那个值
之后配置完成之后尝试在浏览器中输入hadoop:端口号
去访问自己的hadoop,端口号默认为9870,如果能正常启动就一切安好,如果不成就下方留言一起讨论2333
切换idea的java环境 由于需要使用到java17,因此需要更换idea的java编辑器
配置基本如下:
示例代码 为了配置讲解方便,此处放出老师所给的HDFS的java操作代码,此代码后期可能会同步更新到github中
在讲解中,我用到了代码中编写的Tool
库,这个库让HDFS运行代码变得简单了许多,因此下面的讲解将基于此库进行讲解
Tool库包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 package hadoopdemo;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URI;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.BlockLocation;import org.apache.hadoop.fs.FSDataInputStream;import org.apache.hadoop.fs.FSDataOutputStream;import org.apache.hadoop.fs.FileStatus;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IOUtils;import java.util.logging.Logger;public class Tools { private static final Logger logger = Logger.getLogger("io.saagie.example.hdfs.Tools" ); public Tools (String hdfs, Configuration conf) { this .hdfsPath = hdfs; this .conf = conf; } private String hdfsPath; private Configuration conf; public void mkdirs (String folder) throws IOException { Path path = new Path (folder); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); if (!fs.exists(path)) { fs.mkdirs(path); logger.info("Create: " + folder); } fs.close(); } public boolean exists (String filename) throws IOException { Path path = new Path (filename); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); boolean exists = fs.exists(path); fs.close(); return exists; } public void rmr (String folder) throws IOException { Path path = new Path (folder); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); fs.deleteOnExit(path); logger.info("Delete: " + folder); fs.close(); } public void rename (String src, String dst) throws IOException { Path name1 = new Path (src); Path name2 = new Path (dst); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); fs.rename(name1, name2); logger.info("Rename: from " + src + " to " + dst); fs.close(); } public void ls (String folder) throws IOException { Path path = new Path (folder); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); FileStatus[] list = fs.listStatus(path); logger.info("ls: " + folder); logger.info("==========================================================" ); for (FileStatus f : list) { System.out.printf("name: %s, folder: %s, size: %d\n" , f.getPath(), f.isDir(), f.getLen()); } logger.info("==========================================================" ); fs.close(); } public void createFile (String file, String content) throws IOException { FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); byte [] buff = content.getBytes(); FSDataOutputStream os = null ; try { os = fs.create(new Path (file)); os.write(buff, 0 , buff.length); logger.info("Create: " + file); } finally { if (os != null ) os.close(); } fs.close(); } public void copyFile (String local, String remote) throws IOException { FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); fs.copyFromLocalFile(new Path (local), new Path (remote)); logger.info("copy from: " + local + " to " + remote); fs.close(); } public void download (String remote, String local) throws IOException { Path path = new Path (remote); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); fs.copyToLocalFile(path, new Path (local)); logger.info("download: from" + remote + " to " + local); fs.close(); } public String cat (String remoteFile) throws IOException { Path path = new Path (remoteFile); FileSystem fs = FileSystem.get(URI.create(hdfsPath), conf); FSDataInputStream fsdis = null ; logger.info("cat: " + remoteFile); OutputStream baos = new ByteArrayOutputStream (); String str = null ; try { fsdis = fs.open(path); IOUtils.copyBytes(fsdis, baos, 4096 , false ); str = baos.toString(); } finally { IOUtils.closeStream(fsdis); fs.close(); } System.out.println(str); return str; } public void location () throws IOException { String folder = hdfsPath + "/" ; String file = "sample.txt" ; FileSystem fs = FileSystem.get(URI.create(hdfsPath), new Configuration ()); FileStatus f = fs.getFileStatus(new Path (folder + file)); BlockLocation[] list = fs.getFileBlockLocations(f, 0 , f.getLen()); System.out.println("File Location: " + folder + file); for (BlockLocation bl : list) { String[] hosts = bl.getHosts(); for (String host : hosts) { System.out.println("host:" + host); } } fs.close(); } }
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package hadoopdemo;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import org.apache.hadoop.mapreduce.Job;import java.io.File;import java.io.IOException;import java.net.URI;import java.util.logging.Logger;public class demo { private static final Logger logger = Logger.getLogger("io.saagie.example.hdfs.Main" ); private static final String HDFS = "hdfs://hadoop:9000/" ; public static void main (String[] args) throws Exception { Properties properties = System.getProperties(); properties.setProperty("HADOOP_USER_NAME" , "hadoop" ); Configuration conf = new Configuration (); conf.set("fs.defaultFS" ,HDFS); conf.set("fs.hdfs.impl" , org.apache.hadoop.hdfs.DistributedFileSystem.class.getName()); conf.set("fs.file.impl" , org.apache.hadoop.fs.LocalFileSystem.class.getName()); conf.set("dfs.client.use.datanode.hostname" ,"true" ); Tools tool = new Tools (HDFS, conf); if (tool.exists("/zhy/1" )) tool.rmr("/zhy/1" ); tool.mkdirs("/zhy/1" ); tool.ls("/zhy" ); }
更新小项 在github中并未出现的两行:
1 2 Properties properties = System.getProperties();properties.setProperty("HADOOP_USER_NAME" , "hadoop" );
由于Hadoop的权限问题,因此有两种方式可以解决此处问题,详情可以参考参考文档的更改连接hadoop的用户名称
文章进行解决,或者在上面的示例文件中相同位置加入这两行代码,其中hadoop采用的是你自己服务器端的用户名
解读代码 通过阅读代码大致可以发现,HDFS的API调用大概会出现 Tools tool = new Tools(HDFS, conf);
命令之后。因此通过点开tool的java编译,我们可以知道在HDFS的命令控制中,出现了如下的命令:
判断文件夹/文件是否存在
创建一个文件夹
删除文件/文件夹
更改文件/文件夹名称
查看文件夹下内容
tool.ls("/zhy");
可以输出zhy
文件夹下的内容
创建一个文件
tool.createFile();
在指定目录下创建一个文件
····
运行代码 运行代码之后应该不会出现太多问题,如果有问题请留言联系我,方便进行后续讨论
尾言 由于配置过程较为困难,因此这里放出了我的hadoop的地址
1 2 3 4 hadoopIP地址:106.13.230.111 hadoop用户名:hadoop hadoop端口:9870 hdfs端口:9000
由于此服务器为作业所用,所以到博客发布后两个月后,此服务器已经删除,就请各位自己搭建。
如有其他问题,欢迎留言进行讨论