0%

远程控制Hadoop

前言

最近事情好多,就没有更新大数据的相关资料,本次内容是使用命令行去控制Hadoop,进行HDFS的编程(java),教你如何打开hadoop的相关配置,实现像老师的Hadoop一样,以及介绍一些关于控制HDFS的API控制命令

参考文章

更改连接hadoop的用户名称

前提

服务器需要安装

  • ssh
  • vim

服务器之前应配置完之前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"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. See accompanying LICENSE file.
-->

<!-- Put site-specific property overrides in this file. -->
<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名称,方便在后续访问主机的时候能够进行访问到

  • sudo vim /etc/hostname

将里面的内容全部删除,更换成hadoop(此处名称可以自行定义,在后续操作中进行修改就行)

关闭服务器端关于namenode的安全模式

安全模式界面下,无法对namenode进行任何操作,因此我们需要对其进行关闭

在hadoop的根目录下,执行hdfs dfsadmin -safemode leave

确保自己的namenode和datanode的id号一致

由于在实际操作中,namenode 要与 datanode 进行通信,要求两个节点的clusterID要进行一致,因此我们可以通过进入到自己的namenode 与datanode中查看VERSION,对于我自己的机子来讲,在hadoop根目录下输入cat tmp/dfs/name/current/VERSIONcat 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编辑器

配置基本如下:

image-20211116224035747

示例代码

为了配置讲解方便,此处放出老师所给的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;

/**
* ����Ŀ¼
* @param folder
* @throws IOException
*/
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();
}
/**
* �ж��ļ���Ŀ¼�Ƿ����
* @param filename
* @return
* @throws IOException
*/
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;
}

/**
* ɾ���ļ���Ŀ¼
* @param folder
* @throws IOException
*/
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();
}
/**
* �������ļ�
* @param src
* @param dst
* @throws IOException
*/
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();
}
/**
* �����ļ�
* @param folder
* @throws IOException
*/
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();
}
/**
* �����ļ�
* @param file
* @param content
* @throws IOException
*/
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();
}
/**
* �����ļ���HDFS
* @param local
* @param remote
* @throws IOException
*/
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();
}
/**
* ��HDFS�������ļ���������
* @param remote
* @param local
* @throws IOException
*/
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();
}
/**
* �鿴�ļ��е�����
* @param remoteFile
* @return
* @throws IOException
*/
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;
}
//���ظ����ļ���λ��
/**
* Return an array containing hostnames, offset and size of
* portions of the given file.
*/
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/";
//这里的hadoop与上面的host一样

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");
}

/**
*
* @param conf

更新小项

在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.exists("文件路径或文件夹路径")

    通过执行命令,可以判断在HDFS中,是否存在此文件或者文件夹

创建一个文件夹

  • tool.mkdirs("文件夹路径");

    注意:此文件夹创建和系统创建一样,需要层层创建,不然会报错,并且目录下有同名文件夹之后,执行命令不会有任何操作

删除文件/文件夹

  • tool.rmr("文件夹路径");

    通过执行命令,可以删除文件/文件夹

    注意:此删除命令为linux下的rm -r,因此在删除时,会把路径下所有文件都会删除

更改文件/文件夹名称

  • tool.rename("/zhy/1","/zhy/2");

    将前者的名字更改成后者

查看文件夹下内容

  • tool.ls("/zhy");

    可以输出zhy文件夹下的内容

创建一个文件

  • tool.createFile();

    在指定目录下创建一个文件

····

运行代码

运行代码之后应该不会出现太多问题,如果有问题请留言联系我,方便进行后续讨论

尾言

由于配置过程较为困难,因此这里放出了我的hadoop的地址

1
2
3
4
hadoopIP地址:106.13.230.111
hadoop用户名:hadoop
hadoop端口:9870
hdfs端口:9000

由于此服务器为作业所用,所以到博客发布后两个月后,此服务器已经删除,就请各位自己搭建。

如有其他问题,欢迎留言进行讨论

-------------我也是有底线的哦如需更多,欢迎打赏-------------