Add aggregate statistics to cassandra-stress

Patch by Ryan McGuire, reviewed by brandonwilliams for CASSANDRA-5243
This commit is contained in:
Brandon Williams 2013-02-12 15:12:59 -06:00
parent dd4d798dcd
commit c1e5b0ffaf
3 changed files with 152 additions and 3 deletions

View File

@ -108,6 +108,7 @@ public class Session implements Serializable
availableOptions.addOption("Z", "compaction-strategy", true, "CompactionStrategy to use.");
availableOptions.addOption("U", "comparator", true, "Column Comparator to use. Currently supported types are: TimeUUIDType, AsciiType, UTF8Type.");
availableOptions.addOption("tf", "transport-factory", true, "Fully-qualified TTransportFactory class name for creating a connection. Note: For Thrift over SSL, use org.apache.cassandra.stress.SSLTransportFactory.");
availableOptions.addOption("ns", "no-statistics", false, "Turn off the aggegate statistics that is normally output after completion.");
availableOptions.addOption("ts", SSL_TRUSTSTORE, true, "SSL: full path to truststore");
availableOptions.addOption("tspw", SSL_TRUSTSTORE_PW, true, "SSL: full path to truststore");
availableOptions.addOption("prtcl", SSL_PROTOCOL, true, "SSL: connections protocol to use (default: TLS)");
@ -138,6 +139,7 @@ public class Session implements Serializable
private boolean enable_cql = false;
private boolean use_prepared = false;
private boolean trace = false;
private boolean captureStatistics = true;
private final String outFileName;
@ -405,6 +407,11 @@ public class Session implements Serializable
timeUUIDComparator = false;
}
if (cmd.hasOption("ns"))
{
captureStatistics = false;
}
if(cmd.hasOption(SSL_TRUSTSTORE))
encOptions.truststore = cmd.getOptionValue(SSL_TRUSTSTORE);
@ -582,6 +589,11 @@ public class Session implements Serializable
return use_prepared;
}
public boolean outputStatistics()
{
return captureStatistics;
}
/**
* Create Keyspace with Standard and Super/Counter column families
*/

View File

@ -89,6 +89,8 @@ public class StressAction extends Thread
int interval = client.getProgressInterval();
int epochIntervals = client.getProgressInterval() * 10;
long testStartTime = System.currentTimeMillis();
StressStatistics stats = new StressStatistics(client, output);
while (!terminate)
{
@ -142,6 +144,14 @@ public class StressAction extends Thread
keyDelta / interval,
latency.getMedian(), latency.get95thPercentile(), latency.get999thPercentile(),
currentTimeInSeconds));
if (client.outputStatistics()) {
stats.addIntervalStats(total,
opDelta / interval,
keyDelta / interval,
latency,
currentTimeInSeconds);
}
}
}
@ -156,11 +166,14 @@ public class StressAction extends Thread
if (consumer.getReturnCode() == FAILURE)
returnCode = FAILURE;
if (returnCode == SUCCESS)
if (returnCode == SUCCESS) {
if (client.outputStatistics())
stats.printStats();
// marking an end of the output to the client
output.println("END");
else
output.println("END");
} else {
output.println("FAILURE");
}
}

View File

@ -0,0 +1,124 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.cassandra.stress;
import com.yammer.metrics.stats.Snapshot;
import java.io.PrintStream;
import org.apache.commons.lang.time.DurationFormatUtils;
/**
* Gathers and aggregates statistics for an operation
*/
public class StressStatistics
{
private Session client;
private PrintStream output;
private long durationInSeconds;
/** The sum of the interval_op_rate values collected by tallyAverages */
private int tallyOpRateSum;
/** The number of interval_op_rate values collected by tallyAverages */
private int tallyOpRateCount;
/** The sum of the interval_key_rate values collected by tallyAverages */
private int tallyKeyRateSum;
/** The number of interval_key_rate values collected by tallyAverages */
private int tallyKeyRateCount;
/** The sum of the latency values collected by tallyAverages */
private double tallyLatencySum;
/** The number of latency values collected by tallyAverages */
private int tallyLatencyCount;
/** The sum of the 95%tile latency values collected by tallyAverages */
private double tally95thLatencySum;
/** The number of 95%tile latency values collected by tallyAverages */
private int tally95thLatencyCount;
/** The sum of the 99.9%tile latency values collected by tallyAverages */
private double tally999thLatencySum;
/** The number of 99.9%tile latency values collected by tallyAverages */
private int tally999thLatencyCount;
public StressStatistics(Session client, PrintStream out)
{
this.client = client;
this.output = out;
tallyOpRateSum = 0;
tallyOpRateCount = 0;
}
/**
* Collect statistics per-interval
*/
public void addIntervalStats(int totalOperations, int intervalOpRate,
int intervalKeyRate, Snapshot latency,
long currentTimeInSeconds)
{
this.tallyAverages(totalOperations, intervalKeyRate, intervalKeyRate,
latency, currentTimeInSeconds);
}
/**
* Collect interval_op_rate and interval_key_rate averages
*/
private void tallyAverages(int totalOperations, int intervalOpRate,
int intervalKeyRate, Snapshot latency,
long currentTimeInSeconds)
{
//Skip the first and last 10% of values.
//The middle values of the operation are the ones worthwhile
//to collect and average:
if (totalOperations > (0.10 * client.getNumKeys()) &&
totalOperations < (0.90 * client.getNumKeys())) {
tallyOpRateSum += intervalOpRate;
tallyOpRateCount += 1;
tallyKeyRateSum += intervalKeyRate;
tallyKeyRateCount += 1;
tallyLatencySum += latency.getMedian();
tallyLatencyCount += 1;
tally95thLatencySum += latency.get95thPercentile();
tally95thLatencyCount += 1;
tally999thLatencySum += latency.get999thPercentile();
tally999thLatencyCount += 1;
}
durationInSeconds = currentTimeInSeconds;
}
public void printStats()
{
output.println("\n");
if (tallyOpRateCount > 0) {
output.println("Averages from the middle 80% of values:");
output.println(String.format("interval_op_rate : %d",
(tallyOpRateSum / tallyOpRateCount)));
output.println(String.format("interval_key_rate : %d",
(tallyKeyRateSum / tallyKeyRateCount)));
output.println(String.format("latency median : %.1f",
(tallyLatencySum / tallyLatencyCount)));
output.println(String.format("latency 95th percentile : %.1f",
(tally95thLatencySum / tally95thLatencyCount)));
output.println(String.format("latency 99.9th percentile : %.1f",
(tally999thLatencySum / tally999thLatencyCount)));
}
output.println("Total operation time : " + DurationFormatUtils.formatDuration(
durationInSeconds*1000, "HH:mm:ss", true));
}
}