有一次使用hadoop客户端运行hadoop的fsck,客户端报错,显示socket错误,连不上,rd童鞋耻笑说没有配置http地址,教训我等fsck是依靠http的一个工具,好吧,谁让咱他妈的不懂呢,现在就来看看fsck到底是咋实现的。
elif [ "$COMMAND" = "fsck" ] ; then
CLASS=org.apache.hadoop.hdfs.tools.DFSck
还是查看hadoop脚本,fsck工具的启动入口在org.apache.hadoop.hdfs.tools.DFSck,
public static void main(String[] args) throws Exception {
// -files option is also used by GenericOptionsParser
// Make sure that is not the first argument for fsck
int res = -1;
if ((args.length == 0 ) || ("-files".equals(args[0])))
printUsage();
else
res = ToolRunner.run(new DFSck(new Configuration()), args);
System.exit(res);
}
从main可以看到,fsck的实现是DFSck,它实现工具类接口,重写run方法。从构造方法看,它运行需要hdfs的配置文件,告诉它namenode的信息,还要告诉它用户传入的参数。这些废话就不多说了,进去看看吧。
String proto = "http://";
if(UserGroupInformation.isSecurityEnabled()) {
System.setProperty("https.cipherSuites", Krb5AndCertsSslSocketConnector.KRB5_CIPHER_SUITES.get(0));
proto = "https://";
}//根据是否开启了安全属性,选择http协议或者https,果然是通过web
final StringBuffer url = new StringBuffer(proto);
url.append(NameNode.getInfoServer(getConf())).append("/fsck?ugi=").append(ugi.getShortUserName()).append("&path=");
//从这里/fsck可以看出,namenode实现了fsck的servlet,这个fsck命令行脚本只不过去向这个接口提交请求。
String dir = "/";
// find top-level dir first
for (int idx = 0; idx < args.length; idx++) {
if (!args[idx].startsWith("-")) { dir = args[idx]; break; }
}
url.append(URLEncoder.encode(dir, "UTF-8"));
for (int idx = 0; idx < args.length; idx++) {
if (args[idx].equals("-move")) { url.append("&move=1"); }
else if (args[idx].equals("-delete")) { url.append("&delete=1"); }
else if (args[idx].equals("-files")) { url.append("&files=1"); }
else if (args[idx].equals("-openforwrite")) { url.append("&openforwrite=1"); }
else if (args[idx].equals("-blocks")) { url.append("&blocks=1"); }
else if (args[idx].equals("-locations")) { url.append("&locations=1"); }
else if (args[idx].equals("-racks")) { url.append("&racks=1"); }
}
URL path = new URL(url.toString());
SecurityUtil.fetchServiceTicket(path);
URLConnection connection = path.openConnection();
InputStream stream = connection.getInputStream();
从上面的代码可以看出,这个工具类实现比较简单,就是调用namenode的fsck这个接口,采用servlet的方式,然后把用户的参数拼成url去提交request。然后拿到结果打印到屏幕上。我擦,当时不配http地址当然没法执行了啊!看一下getInfoServer方法吧就知道了。
public static String getInfoServer(Configuration conf) {
String http = UserGroupInformation.isSecurityEnabled() ? "dfs.https.address"