Skip to content

Commit f00103c

Browse files
[Backport 2.x] Enhancing FS stats to include read / write time, io time and queue size (opensearch-project#10696)
* Enhancing FS stats to include read/write time, queue size and IO time (opensearch-project#10541) * Enhancing FS stats to include read / write time, io time and queue size Signed-off-by: Bharathwaj G <bharath78910@gmail.com> * 2.x specific changes Signed-off-by: Bharathwaj G <bharath78910@gmail.com> --------- Signed-off-by: Bharathwaj G <bharath78910@gmail.com>
1 parent 1970085 commit f00103c

6 files changed

Lines changed: 285 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55

66
## [Unreleased 2.x]
77
### Added
8+
- [Admission control] Add enhancements to FS stats to include read/write time, queue size and IO time ([#10696](https://github.com/opensearch-project/OpenSearch/pull/10696))
89

910
### Dependencies
1011
- Bumps jetty version to 9.4.52.v20230823 to fix GMS-2023-1857 ([#9822](https://github.com/opensearch-project/OpenSearch/pull/9822))

server/src/main/java/org/opensearch/monitor/fs/FsInfo.java

Lines changed: 174 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,14 @@ public static class DeviceStats implements Writeable, ToXContentFragment {
237237
final long previousWritesCompleted;
238238
final long currentSectorsWritten;
239239
final long previousSectorsWritten;
240+
final long currentReadTime;
241+
final long previousReadTime;
242+
final long currentWriteTime;
243+
final long previousWriteTime;
244+
final long currentQueueSize;
245+
final long previousQueueSize;
246+
final long currentIOTime;
247+
final long previousIOTime;
240248

241249
public DeviceStats(
242250
final int majorDeviceNumber,
@@ -246,6 +254,10 @@ public DeviceStats(
246254
final long currentSectorsRead,
247255
final long currentWritesCompleted,
248256
final long currentSectorsWritten,
257+
final long currentReadTime,
258+
final long currentWriteTime,
259+
final long currrentQueueSize,
260+
final long currentIOTime,
249261
final DeviceStats previousDeviceStats
250262
) {
251263
this(
@@ -259,7 +271,15 @@ public DeviceStats(
259271
currentSectorsRead,
260272
previousDeviceStats != null ? previousDeviceStats.currentSectorsRead : -1,
261273
currentWritesCompleted,
262-
previousDeviceStats != null ? previousDeviceStats.currentWritesCompleted : -1
274+
previousDeviceStats != null ? previousDeviceStats.currentWritesCompleted : -1,
275+
currentReadTime,
276+
previousDeviceStats != null ? previousDeviceStats.currentReadTime : -1,
277+
currentWriteTime,
278+
previousDeviceStats != null ? previousDeviceStats.currentWriteTime : -1,
279+
currrentQueueSize,
280+
previousDeviceStats != null ? previousDeviceStats.currentQueueSize : -1,
281+
currentIOTime,
282+
previousDeviceStats != null ? previousDeviceStats.currentIOTime : -1
263283
);
264284
}
265285

@@ -274,7 +294,15 @@ private DeviceStats(
274294
final long currentSectorsRead,
275295
final long previousSectorsRead,
276296
final long currentWritesCompleted,
277-
final long previousWritesCompleted
297+
final long previousWritesCompleted,
298+
final long currentReadTime,
299+
final long previousReadTime,
300+
final long currentWriteTime,
301+
final long previousWriteTime,
302+
final long currentQueueSize,
303+
final long previousQueueSize,
304+
final long currentIOTime,
305+
final long previousIOTime
278306
) {
279307
this.majorDeviceNumber = majorDeviceNumber;
280308
this.minorDeviceNumber = minorDeviceNumber;
@@ -287,6 +315,14 @@ private DeviceStats(
287315
this.previousSectorsRead = previousSectorsRead;
288316
this.currentSectorsWritten = currentSectorsWritten;
289317
this.previousSectorsWritten = previousSectorsWritten;
318+
this.currentReadTime = currentReadTime;
319+
this.previousReadTime = previousReadTime;
320+
this.currentWriteTime = currentWriteTime;
321+
this.previousWriteTime = previousWriteTime;
322+
this.currentQueueSize = currentQueueSize;
323+
this.previousQueueSize = previousQueueSize;
324+
this.currentIOTime = currentIOTime;
325+
this.previousIOTime = previousIOTime;
290326
}
291327

292328
public DeviceStats(StreamInput in) throws IOException {
@@ -301,6 +337,25 @@ public DeviceStats(StreamInput in) throws IOException {
301337
previousSectorsRead = in.readLong();
302338
currentSectorsWritten = in.readLong();
303339
previousSectorsWritten = in.readLong();
340+
if (in.getVersion().onOrAfter(Version.V_2_12_0)) {
341+
currentReadTime = in.readLong();
342+
previousReadTime = in.readLong();
343+
currentWriteTime = in.readLong();
344+
previousWriteTime = in.readLong();
345+
currentQueueSize = in.readLong();
346+
previousQueueSize = in.readLong();
347+
currentIOTime = in.readLong();
348+
previousIOTime = in.readLong();
349+
} else {
350+
currentReadTime = 0;
351+
previousReadTime = 0;
352+
currentWriteTime = 0;
353+
previousWriteTime = 0;
354+
currentQueueSize = 0;
355+
previousQueueSize = 0;
356+
currentIOTime = 0;
357+
previousIOTime = 0;
358+
}
304359
}
305360

306361
@Override
@@ -316,6 +371,16 @@ public void writeTo(StreamOutput out) throws IOException {
316371
out.writeLong(previousSectorsRead);
317372
out.writeLong(currentSectorsWritten);
318373
out.writeLong(previousSectorsWritten);
374+
if (out.getVersion().onOrAfter(Version.V_2_12_0)) {
375+
out.writeLong(currentReadTime);
376+
out.writeLong(previousReadTime);
377+
out.writeLong(currentWriteTime);
378+
out.writeLong(previousWriteTime);
379+
out.writeLong(currentQueueSize);
380+
out.writeLong(previousQueueSize);
381+
out.writeLong(currentIOTime);
382+
out.writeLong(previousIOTime);
383+
}
319384
}
320385

321386
public long operations() {
@@ -348,6 +413,39 @@ public long writeKilobytes() {
348413
return (currentSectorsWritten - previousSectorsWritten) / 2;
349414
}
350415

416+
/**
417+
* Total time taken for all read operations
418+
*/
419+
public long readTime() {
420+
if (previousReadTime == -1) return -1;
421+
return currentReadTime - previousReadTime;
422+
}
423+
424+
/**
425+
* Total time taken for all write operations
426+
*/
427+
public long writeTime() {
428+
if (previousWriteTime == -1) return -1;
429+
return currentWriteTime - previousWriteTime;
430+
}
431+
432+
/**
433+
* Queue size based on weighted time spent doing I/Os
434+
*/
435+
public long queueSize() {
436+
if (previousQueueSize == -1) return -1;
437+
return currentQueueSize - previousQueueSize;
438+
}
439+
440+
/**
441+
* Total time spent doing I/Os
442+
*/
443+
public long ioTimeInMillis() {
444+
if (previousIOTime == -1) return -1;
445+
446+
return (currentIOTime - previousIOTime);
447+
}
448+
351449
@Override
352450
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
353451
builder.field("device_name", deviceName);
@@ -356,9 +454,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
356454
builder.field(IoStats.WRITE_OPERATIONS, writeOperations());
357455
builder.field(IoStats.READ_KILOBYTES, readKilobytes());
358456
builder.field(IoStats.WRITE_KILOBYTES, writeKilobytes());
457+
builder.field(IoStats.READ_TIME, readTime());
458+
builder.field(IoStats.WRITE_TIME, writeTime());
459+
builder.field(IoStats.QUEUE_SIZE, queueSize());
460+
builder.field(IoStats.IO_TIME_MS, ioTimeInMillis());
359461
return builder;
360462
}
361-
362463
}
363464

364465
/**
@@ -373,13 +474,21 @@ public static class IoStats implements Writeable, ToXContentFragment {
373474
private static final String WRITE_OPERATIONS = "write_operations";
374475
private static final String READ_KILOBYTES = "read_kilobytes";
375476
private static final String WRITE_KILOBYTES = "write_kilobytes";
477+
private static final String READ_TIME = "read_time";
478+
private static final String WRITE_TIME = "write_time";
479+
private static final String QUEUE_SIZE = "queue_size";
480+
private static final String IO_TIME_MS = "io_time_in_millis";
376481

377482
final DeviceStats[] devicesStats;
378483
final long totalOperations;
379484
final long totalReadOperations;
380485
final long totalWriteOperations;
381486
final long totalReadKilobytes;
382487
final long totalWriteKilobytes;
488+
final long totalReadTime;
489+
final long totalWriteTime;
490+
final long totalQueueSize;
491+
final long totalIOTimeInMillis;
383492

384493
public IoStats(final DeviceStats[] devicesStats) {
385494
this.devicesStats = devicesStats;
@@ -388,18 +497,30 @@ public IoStats(final DeviceStats[] devicesStats) {
388497
long totalWriteOperations = 0;
389498
long totalReadKilobytes = 0;
390499
long totalWriteKilobytes = 0;
500+
long totalReadTime = 0;
501+
long totalWriteTime = 0;
502+
long totalQueueSize = 0;
503+
long totalIOTimeInMillis = 0;
391504
for (DeviceStats deviceStats : devicesStats) {
392505
totalOperations += deviceStats.operations() != -1 ? deviceStats.operations() : 0;
393506
totalReadOperations += deviceStats.readOperations() != -1 ? deviceStats.readOperations() : 0;
394507
totalWriteOperations += deviceStats.writeOperations() != -1 ? deviceStats.writeOperations() : 0;
395508
totalReadKilobytes += deviceStats.readKilobytes() != -1 ? deviceStats.readKilobytes() : 0;
396509
totalWriteKilobytes += deviceStats.writeKilobytes() != -1 ? deviceStats.writeKilobytes() : 0;
510+
totalReadTime += deviceStats.readTime() != -1 ? deviceStats.readTime() : 0;
511+
totalWriteTime += deviceStats.writeTime() != -1 ? deviceStats.writeTime() : 0;
512+
totalQueueSize += deviceStats.queueSize() != -1 ? deviceStats.queueSize() : 0;
513+
totalIOTimeInMillis += deviceStats.ioTimeInMillis() != -1 ? deviceStats.ioTimeInMillis() : 0;
397514
}
398515
this.totalOperations = totalOperations;
399516
this.totalReadOperations = totalReadOperations;
400517
this.totalWriteOperations = totalWriteOperations;
401518
this.totalReadKilobytes = totalReadKilobytes;
402519
this.totalWriteKilobytes = totalWriteKilobytes;
520+
this.totalReadTime = totalReadTime;
521+
this.totalWriteTime = totalWriteTime;
522+
this.totalQueueSize = totalQueueSize;
523+
this.totalIOTimeInMillis = totalIOTimeInMillis;
403524
}
404525

405526
public IoStats(StreamInput in) throws IOException {
@@ -414,6 +535,17 @@ public IoStats(StreamInput in) throws IOException {
414535
this.totalWriteOperations = in.readLong();
415536
this.totalReadKilobytes = in.readLong();
416537
this.totalWriteKilobytes = in.readLong();
538+
if (in.getVersion().onOrAfter(Version.V_2_12_0)) {
539+
this.totalReadTime = in.readLong();
540+
this.totalWriteTime = in.readLong();
541+
this.totalQueueSize = in.readLong();
542+
this.totalIOTimeInMillis = in.readLong();
543+
} else {
544+
this.totalReadTime = 0;
545+
this.totalWriteTime = 0;
546+
this.totalQueueSize = 0;
547+
this.totalIOTimeInMillis = 0;
548+
}
417549
}
418550

419551
@Override
@@ -427,6 +559,12 @@ public void writeTo(StreamOutput out) throws IOException {
427559
out.writeLong(totalWriteOperations);
428560
out.writeLong(totalReadKilobytes);
429561
out.writeLong(totalWriteKilobytes);
562+
if (out.getVersion().onOrAfter(Version.V_2_12_0)) {
563+
out.writeLong(totalReadTime);
564+
out.writeLong(totalWriteTime);
565+
out.writeLong(totalQueueSize);
566+
out.writeLong(totalIOTimeInMillis);
567+
}
430568
}
431569

432570
public DeviceStats[] getDevicesStats() {
@@ -453,6 +591,34 @@ public long getTotalWriteKilobytes() {
453591
return totalWriteKilobytes;
454592
}
455593

594+
/**
595+
* Sum of read time across all devices
596+
*/
597+
public long getTotalReadTime() {
598+
return totalReadTime;
599+
}
600+
601+
/**
602+
* Sum of write time across all devices
603+
*/
604+
public long getTotalWriteTime() {
605+
return totalWriteTime;
606+
}
607+
608+
/**
609+
* Sum of queue size across all devices
610+
*/
611+
public long getTotalQueueSize() {
612+
return totalQueueSize;
613+
}
614+
615+
/**
616+
* Sum of IO time across all devices
617+
*/
618+
public long getTotalIOTimeMillis() {
619+
return totalIOTimeInMillis;
620+
}
621+
456622
@Override
457623
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
458624
if (devicesStats.length > 0) {
@@ -470,11 +636,15 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
470636
builder.field(WRITE_OPERATIONS, totalWriteOperations);
471637
builder.field(READ_KILOBYTES, totalReadKilobytes);
472638
builder.field(WRITE_KILOBYTES, totalWriteKilobytes);
639+
640+
builder.field(READ_TIME, totalReadTime);
641+
builder.field(WRITE_TIME, totalWriteTime);
642+
builder.field(QUEUE_SIZE, totalQueueSize);
643+
builder.field(IO_TIME_MS, totalIOTimeInMillis);
473644
builder.endObject();
474645
}
475646
return builder;
476647
}
477-
478648
}
479649

480650
private final long timestamp;

server/src/main/java/org/opensearch/monitor/fs/FsProbe.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,25 @@ final FsInfo.IoStats ioStats(final Set<Tuple<Integer, Integer>> devicesNumbers,
109109

110110
List<FsInfo.DeviceStats> devicesStats = new ArrayList<>();
111111

112+
/**
113+
* The /proc/diskstats file displays the I/O statistics of block devices.
114+
* Each line contains the following 14 fields: ( + additional fields )
115+
*
116+
* 1 major number
117+
* 2 minor number
118+
* 3 device name
119+
* 4 reads completed successfully
120+
* 5 reads merged
121+
* 6 sectors read
122+
* 7 time spent reading (ms)
123+
* 8 writes completed
124+
* 9 writes merged
125+
* 10 sectors written
126+
* 11 time spent writing (ms)
127+
* 12 I/Os currently in progress
128+
* 13 time spent doing I/Os (ms) ---- IO use percent
129+
* 14 weighted time spent doing I/Os (ms) ---- Queue size
130+
*/
112131
List<String> lines = readProcDiskStats();
113132
if (!lines.isEmpty()) {
114133
for (String line : lines) {
@@ -123,6 +142,12 @@ final FsInfo.IoStats ioStats(final Set<Tuple<Integer, Integer>> devicesNumbers,
123142
final long sectorsRead = Long.parseLong(fields[5]);
124143
final long writesCompleted = Long.parseLong(fields[7]);
125144
final long sectorsWritten = Long.parseLong(fields[9]);
145+
// readTime and writeTime calculates the total read/write time taken for each request to complete
146+
// ioTime calculates actual time queue and disks are busy
147+
final long readTime = Long.parseLong(fields[6]);
148+
final long writeTime = Long.parseLong(fields[10]);
149+
final long ioTime = fields.length > 12 ? Long.parseLong(fields[12]) : 0;
150+
final long queueSize = fields.length > 13 ? Long.parseLong(fields[13]) : 0;
126151
final FsInfo.DeviceStats deviceStats = new FsInfo.DeviceStats(
127152
majorDeviceNumber,
128153
minorDeviceNumber,
@@ -131,6 +156,10 @@ final FsInfo.IoStats ioStats(final Set<Tuple<Integer, Integer>> devicesNumbers,
131156
sectorsRead,
132157
writesCompleted,
133158
sectorsWritten,
159+
readTime,
160+
writeTime,
161+
queueSize,
162+
ioTime,
134163
deviceMap.get(Tuple.tuple(majorDeviceNumber, minorDeviceNumber))
135164
);
136165
devicesStats.add(deviceStats);

server/src/test/java/org/opensearch/action/admin/cluster/node/stats/NodeStatsTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ public void testSerialization() throws IOException {
282282
assertEquals(ioStats.getTotalReadOperations(), deserializedIoStats.getTotalReadOperations());
283283
assertEquals(ioStats.getTotalWriteKilobytes(), deserializedIoStats.getTotalWriteKilobytes());
284284
assertEquals(ioStats.getTotalWriteOperations(), deserializedIoStats.getTotalWriteOperations());
285+
assertEquals(ioStats.getTotalReadTime(), deserializedIoStats.getTotalReadTime());
286+
assertEquals(ioStats.getTotalWriteTime(), deserializedIoStats.getTotalWriteTime());
287+
assertEquals(ioStats.getTotalQueueSize(), deserializedIoStats.getTotalQueueSize());
288+
assertEquals(ioStats.getTotalIOTimeMillis(), deserializedIoStats.getTotalIOTimeMillis());
285289
assertEquals(ioStats.getDevicesStats().length, deserializedIoStats.getDevicesStats().length);
286290
for (int i = 0; i < ioStats.getDevicesStats().length; i++) {
287291
FsInfo.DeviceStats deviceStats = ioStats.getDevicesStats()[i];
@@ -625,6 +629,10 @@ public static NodeStats createNodeStats(boolean remoteStoreStats) {
625629
randomNonNegativeLong(),
626630
randomNonNegativeLong(),
627631
randomNonNegativeLong(),
632+
randomNonNegativeLong(),
633+
randomNonNegativeLong(),
634+
randomNonNegativeLong(),
635+
randomNonNegativeLong(),
628636
null
629637
);
630638
deviceStatsArray[i] = new FsInfo.DeviceStats(
@@ -635,6 +643,10 @@ public static NodeStats createNodeStats(boolean remoteStoreStats) {
635643
randomNonNegativeLong(),
636644
randomNonNegativeLong(),
637645
randomNonNegativeLong(),
646+
randomNonNegativeLong(),
647+
randomNonNegativeLong(),
648+
randomNonNegativeLong(),
649+
randomNonNegativeLong(),
638650
previousDeviceStats
639651
);
640652
}

0 commit comments

Comments
 (0)