Skip to content

Commit 3ec01b1

Browse files
authored
HDFS-15711. Add Metrics to HttpFS Server. (#2521) Contributed by Ahmed Hussein and Kihwal Lee
1 parent c2cecfc commit 3ec01b1

File tree

6 files changed

+352
-19
lines changed

6 files changed

+352
-19
lines changed

hadoop-hdfs-project/hadoop-hdfs-httpfs/src/main/java/org/apache/hadoop/fs/http/server/FSOperations.java

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.hadoop.fs.http.server;
1919

2020
import org.apache.hadoop.classification.InterfaceAudience;
21+
import org.apache.hadoop.conf.Configuration;
2122
import org.apache.hadoop.fs.BlockStoragePolicySpi;
2223
import org.apache.hadoop.fs.ContentSummary;
2324
import org.apache.hadoop.fs.FileChecksum;
@@ -47,7 +48,6 @@
4748
import org.apache.hadoop.hdfs.protocol.SnapshottableDirectoryStatus;
4849
import org.apache.hadoop.hdfs.protocol.SnapshotStatus;
4950
import org.apache.hadoop.hdfs.web.JsonUtil;
50-
import org.apache.hadoop.io.IOUtils;
5151
import org.apache.hadoop.lib.service.FileSystemAccess;
5252
import org.apache.hadoop.util.StringUtils;
5353
import org.json.simple.JSONArray;
@@ -73,7 +73,22 @@
7373
* FileSystem operation executors used by {@link HttpFSServer}.
7474
*/
7575
@InterfaceAudience.Private
76-
public class FSOperations {
76+
public final class FSOperations {
77+
78+
private static int bufferSize = 4096;
79+
80+
private FSOperations() {
81+
// not called
82+
}
83+
/**
84+
* Set the buffer size. The size is set during the initialization of
85+
* HttpFSServerWebApp.
86+
* @param conf the configuration to get the bufferSize
87+
*/
88+
public static void setBufferSize(Configuration conf) {
89+
bufferSize = conf.getInt(HTTPFS_BUFFER_SIZE_KEY,
90+
HTTP_BUFFER_SIZE_DEFAULT);
91+
}
7792

7893
/**
7994
* @param fileStatus a FileStatus object
@@ -436,10 +451,9 @@ public FSAppend(InputStream is, String path) {
436451
*/
437452
@Override
438453
public Void execute(FileSystem fs) throws IOException {
439-
int bufferSize = fs.getConf().getInt("httpfs.buffer.size", 4096);
440454
OutputStream os = fs.append(path, bufferSize);
441-
IOUtils.copyBytes(is, os, bufferSize, true);
442-
os.close();
455+
long bytes = copyBytes(is, os);
456+
HttpFSServerWebApp.get().getMetrics().incrBytesWritten(bytes);
443457
return null;
444458
}
445459

@@ -522,6 +536,7 @@ public FSTruncate(String path, long newLength) {
522536
@Override
523537
public JSONObject execute(FileSystem fs) throws IOException {
524538
boolean result = fs.truncate(path, newLength);
539+
HttpFSServerWebApp.get().getMetrics().incrOpsTruncate();
525540
return toJSON(
526541
StringUtils.toLowerCase(HttpFSFileSystem.TRUNCATE_JSON), result);
527542
}
@@ -638,16 +653,65 @@ public Void execute(FileSystem fs) throws IOException {
638653
fsPermission = FsCreateModes.create(fsPermission,
639654
new FsPermission(unmaskedPermission));
640655
}
641-
int bufferSize = fs.getConf().getInt(HTTPFS_BUFFER_SIZE_KEY,
642-
HTTP_BUFFER_SIZE_DEFAULT);
643656
OutputStream os = fs.create(path, fsPermission, override, bufferSize, replication, blockSize, null);
644-
IOUtils.copyBytes(is, os, bufferSize, true);
645-
os.close();
657+
long bytes = copyBytes(is, os);
658+
HttpFSServerWebApp.get().getMetrics().incrBytesWritten(bytes);
646659
return null;
647660
}
648661

649662
}
650663

664+
/**
665+
* These copyBytes methods combines the two different flavors used originally.
666+
* One with length and another one with buffer size.
667+
* In this impl, buffer size is determined internally, which is a singleton
668+
* normally set during initialization.
669+
* @param in the inputStream
670+
* @param out the outputStream
671+
* @return the totalBytes
672+
* @throws IOException the exception to be thrown.
673+
*/
674+
public static long copyBytes(InputStream in, OutputStream out)
675+
throws IOException {
676+
return copyBytes(in, out, Long.MAX_VALUE);
677+
}
678+
679+
public static long copyBytes(InputStream in, OutputStream out, long count)
680+
throws IOException {
681+
long totalBytes = 0;
682+
683+
// If bufferSize is not initialized use 4k. This will not happen
684+
// if all callers check and set it.
685+
byte[] buf = new byte[bufferSize];
686+
long bytesRemaining = count;
687+
int bytesRead;
688+
689+
try {
690+
while (bytesRemaining > 0) {
691+
int bytesToRead = (int)
692+
(bytesRemaining < buf.length ? bytesRemaining : buf.length);
693+
694+
bytesRead = in.read(buf, 0, bytesToRead);
695+
if (bytesRead == -1) {
696+
break;
697+
}
698+
699+
out.write(buf, 0, bytesRead);
700+
bytesRemaining -= bytesRead;
701+
totalBytes += bytesRead;
702+
}
703+
return totalBytes;
704+
} finally {
705+
// Originally IOUtils.copyBytes() were called with close=true. So we are
706+
// implementing the same behavior here.
707+
try {
708+
in.close();
709+
} finally {
710+
out.close();
711+
}
712+
}
713+
}
714+
651715
/**
652716
* Executor that performs a delete FileSystemAccess files system operation.
653717
*/
@@ -680,6 +744,7 @@ public FSDelete(String path, boolean recursive) {
680744
@Override
681745
public JSONObject execute(FileSystem fs) throws IOException {
682746
boolean deleted = fs.delete(path, recursive);
747+
HttpFSServerWebApp.get().getMetrics().incrOpsDelete();
683748
return toJSON(
684749
StringUtils.toLowerCase(HttpFSFileSystem.DELETE_JSON), deleted);
685750
}
@@ -748,6 +813,7 @@ public FSFileStatus(String path) {
748813
@Override
749814
public Map execute(FileSystem fs) throws IOException {
750815
FileStatus status = fs.getFileStatus(path);
816+
HttpFSServerWebApp.get().getMetrics().incrOpsStat();
751817
return toJson(status);
752818
}
753819

@@ -776,7 +842,6 @@ public JSONObject execute(FileSystem fs) throws IOException {
776842
json.put(HttpFSFileSystem.HOME_DIR_JSON, homeDir.toUri().getPath());
777843
return json;
778844
}
779-
780845
}
781846

782847
/**
@@ -814,6 +879,7 @@ public FSListStatus(String path, String filter) throws IOException {
814879
@Override
815880
public Map execute(FileSystem fs) throws IOException {
816881
FileStatus[] fileStatuses = fs.listStatus(path, filter);
882+
HttpFSServerWebApp.get().getMetrics().incrOpsListing();
817883
return toJson(fileStatuses, fs.getFileStatus(path).isFile());
818884
}
819885

@@ -905,6 +971,7 @@ public JSONObject execute(FileSystem fs) throws IOException {
905971
new FsPermission(unmaskedPermission));
906972
}
907973
boolean mkdirs = fs.mkdirs(path, fsPermission);
974+
HttpFSServerWebApp.get().getMetrics().incrOpsMkdir();
908975
return toJSON(HttpFSFileSystem.MKDIRS_JSON, mkdirs);
909976
}
910977

@@ -937,8 +1004,8 @@ public FSOpen(String path) {
9371004
*/
9381005
@Override
9391006
public InputStream execute(FileSystem fs) throws IOException {
940-
int bufferSize = HttpFSServerWebApp.get().getConfig().getInt(
941-
HTTPFS_BUFFER_SIZE_KEY, HTTP_BUFFER_SIZE_DEFAULT);
1007+
// Only updating ops count. bytesRead is updated in InputStreamEntity
1008+
HttpFSServerWebApp.get().getMetrics().incrOpsOpen();
9421009
return fs.open(path, bufferSize);
9431010
}
9441011

@@ -976,6 +1043,7 @@ public FSRename(String path, String toPath) {
9761043
@Override
9771044
public JSONObject execute(FileSystem fs) throws IOException {
9781045
boolean renamed = fs.rename(path, toPath);
1046+
HttpFSServerWebApp.get().getMetrics().incrOpsRename();
9791047
return toJSON(HttpFSFileSystem.RENAME_JSON, renamed);
9801048
}
9811049

@@ -1944,6 +2012,7 @@ public Void execute(FileSystem fs) throws IOException {
19442012
if (fs instanceof DistributedFileSystem) {
19452013
DistributedFileSystem dfs = (DistributedFileSystem) fs;
19462014
dfs.access(path, mode);
2015+
HttpFSServerWebApp.get().getMetrics().incrOpsCheckAccess();
19472016
} else {
19482017
throw new UnsupportedOperationException("checkaccess is "
19492018
+ "not supported for HttpFs on " + fs.getClass()

hadoop-hdfs-project/hadoop-hdfs-httpfs/src/main/java/org/apache/hadoop/fs/http/server/HttpFSServerWebApp.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@
2121
import org.apache.hadoop.classification.InterfaceAudience;
2222
import org.apache.hadoop.conf.Configuration;
2323
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
24+
import org.apache.hadoop.fs.http.server.metrics.HttpFSServerMetrics;
2425
import org.apache.hadoop.lib.server.ServerException;
2526
import org.apache.hadoop.lib.service.FileSystemAccess;
2627
import org.apache.hadoop.lib.servlet.ServerWebApp;
28+
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
29+
import org.apache.hadoop.util.JvmPauseMonitor;
30+
2731
import org.slf4j.Logger;
2832
import org.slf4j.LoggerFactory;
2933

@@ -56,6 +60,7 @@ public class HttpFSServerWebApp extends ServerWebApp {
5660
public static final String CONF_ADMIN_GROUP = "admin.group";
5761

5862
private static HttpFSServerWebApp SERVER;
63+
private static HttpFSServerMetrics metrics;
5964

6065
private String adminGroup;
6166

@@ -102,6 +107,7 @@ public void init() throws ServerException {
102107
LOG.info("Connects to Namenode [{}]",
103108
get().get(FileSystemAccess.class).getFileSystemConfiguration().
104109
getTrimmed(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY));
110+
setMetrics(getConfig());
105111
}
106112

107113
/**
@@ -110,9 +116,22 @@ public void init() throws ServerException {
110116
@Override
111117
public void destroy() {
112118
SERVER = null;
119+
if (metrics != null) {
120+
metrics.shutdown();
121+
}
113122
super.destroy();
114123
}
115124

125+
private static void setMetrics(Configuration config) {
126+
LOG.info("Initializing HttpFSServerMetrics");
127+
metrics = HttpFSServerMetrics.create(config, "HttpFSServer");
128+
JvmPauseMonitor pauseMonitor = new JvmPauseMonitor();
129+
pauseMonitor.init(config);
130+
pauseMonitor.start();
131+
metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);
132+
FSOperations.setBufferSize(config);
133+
DefaultMetricsSystem.initialize("HttpFSServer");
134+
}
116135
/**
117136
* Returns HttpFSServer server singleton, configuration and services are
118137
* accessible through it.
@@ -123,6 +142,14 @@ public static HttpFSServerWebApp get() {
123142
return SERVER;
124143
}
125144

145+
/**
146+
* gets the HttpFSServerMetrics instance.
147+
* @return the HttpFSServerMetrics singleton.
148+
*/
149+
public static HttpFSServerMetrics getMetrics() {
150+
return metrics;
151+
}
152+
126153
/**
127154
* Returns HttpFSServer admin group.
128155
*

0 commit comments

Comments
 (0)