Skip to content
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions core/src/main/scala/kafka/tools/ConsumerPerformance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ object ConsumerPerformance {
val totalBytesRead = new AtomicLong(0)
val consumerTimeout = new AtomicBoolean(false)
var metrics: mutable.Map[MetricName, _ <: Metric] = null
val joinGroupTimeInMs = new AtomicLong(0)
val fetchTimeInMs = new AtomicLong(0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't appear to be any reason for fetchTimeInMs to be an AtomicLong. We can use a regular long and just initialize it below.


if (!config.hideHeader) {
if (!config.showDetailedStats)
println("start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec")
println(s"start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec${if (!config.useOldConsumer) ", total.rebalance.time.ms, fetch.time.ms" else ""}")
else
println("time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec")
}
Expand All @@ -67,7 +69,8 @@ object ConsumerPerformance {
val consumer = new KafkaConsumer[Array[Byte], Array[Byte]](config.props)
consumer.subscribe(Collections.singletonList(config.topic))
startMs = System.currentTimeMillis
consume(consumer, List(config.topic), config.numMessages, 1000, config, totalMessagesRead, totalBytesRead)
consume(consumer, List(config.topic), config.numMessages, 1000,
config, totalMessagesRead, totalBytesRead, joinGroupTimeInMs, fetchTimeInMs)
endMs = System.currentTimeMillis

if (config.printMetrics) {
Expand Down Expand Up @@ -100,8 +103,14 @@ object ConsumerPerformance {
val elapsedSecs = (endMs - startMs) / 1000.0

@hachikuji hachikuji Jun 7, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the main point of this patch is to compute the throughput statistics based only on the time spent fetching, so maybe we can move this below and just use fetchTimeInMs.get / 1000.0? We could also report MB.sec as two separate values: total.MB.sec which uses the total time, and fetch.MB.sec which uses only the fetch time. Similarly for nMsg.sec.

if (!config.showDetailedStats) {
val totalMBRead = (totalBytesRead.get * 1.0) / (1024 * 1024)
println("%s, %s, %.4f, %.4f, %d, %.4f".format(config.dateFormat.format(startMs), config.dateFormat.format(endMs),
totalMBRead, totalMBRead / elapsedSecs, totalMessagesRead.get, totalMessagesRead.get / elapsedSecs))
println(s"%s, %s, %.4f, %.4f, %d, %.4f${if (!config.useOldConsumer) ", %s" else ""}".format(
config.dateFormat.format(startMs),
config.dateFormat.format(endMs),
totalMBRead,
totalMBRead / elapsedSecs,
totalMessagesRead.get,
totalMessagesRead.get / elapsedSecs,
if (!config.useOldConsumer) joinGroupTimeInMs.get.toString + ", " + fetchTimeInMs.get.toString else ""))
}

if (metrics != null) {
Expand All @@ -110,25 +119,36 @@ object ConsumerPerformance {

}

def consume(consumer: KafkaConsumer[Array[Byte], Array[Byte]], topics: List[String], count: Long, timeout: Long, config: ConsumerPerfConfig, totalMessagesRead: AtomicLong, totalBytesRead: AtomicLong) {
def consume(consumer: KafkaConsumer[Array[Byte], Array[Byte]], topics: List[String], count: Long, timeout: Long, config: ConsumerPerfConfig, totalMessagesRead: AtomicLong, totalBytesRead: AtomicLong, joinTime: AtomicLong, fetchTime: AtomicLong) {
var bytesRead = 0L
var messagesRead = 0L
var lastBytesRead = 0L
var lastMessagesRead = 0L
var joinStart = 0L
var totalRebalanceTimeExceptTheFirst = 0L

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what you're trying to do here. Why not just count all rebalances?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The time for the first rebalance happens before the fetch but the rest would happen during the fetch. That's why I removed the total time of other rebalances from the total fetch time. Does it make any sense?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hachikuji What do you think of the comment above?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand why you want to treat the first rebalance specially. Can you elaborate please? Intuitively, I expect that we count the total time for the test and subtract the total rebalance time to get the fetch time. Is there anything wrong with that?

var isFirstRebalance = true

// Wait for group join, metadata fetch, etc
val joinTimeout = 10000
val isAssigned = new AtomicBoolean(false)
consumer.subscribe(topics.asJava, new ConsumerRebalanceListener {
def onPartitionsAssigned(partitions: util.Collection[TopicPartition]) {
isAssigned.set(true)
val time = System.currentTimeMillis - joinStart
joinTime.addAndGet(time)
if (isFirstRebalance) {
isFirstRebalance = false
} else {
totalRebalanceTimeExceptTheFirst += time
}
}
def onPartitionsRevoked(partitions: util.Collection[TopicPartition]) {
isAssigned.set(false)
joinStart = System.currentTimeMillis
}})
val joinStart = System.currentTimeMillis()
val joinStartForFirstTime = System.currentTimeMillis()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are now reporting the join time separately, I don't think we need the loop below anymore. It was initially intended to discount the rebalance overhead, but now we account for that transparently.

while (!isAssigned.get()) {
if (System.currentTimeMillis() - joinStart >= joinTimeout) {
if (System.currentTimeMillis() - joinStartForFirstTime >= joinTimeout) {
throw new Exception("Timed out waiting for initial group join.")
}
consumer.poll(100)
Expand Down Expand Up @@ -165,6 +185,7 @@ object ConsumerPerformance {

totalMessagesRead.set(messagesRead)
totalBytesRead.set(bytesRead)
fetchTime.set(System.currentTimeMillis - startMs - totalRebalanceTimeExceptTheFirst)
}

def printProgressMessage(id: Int, bytesRead: Long, lastBytesRead: Long, messagesRead: Long, lastMessagesRead: Long,
Expand Down