Class Ramp

java.lang.Object
org.acemq.workloads.Ramp

public final class Ramp extends Object
Steps the offered rate up until something gives, to find the highest rate a broker sustains.

 RampReport ramp = Ramp.of(workload)
         .startAt(1_000)
         .stepBy(1_000)                 // or .stepByPercent(25)
         .stepFor(Duration.ofSeconds(20))
         .warmupEachStep(Duration.ofSeconds(5))
         .maxRate(100_000)
         .refine(3)
         .run("amqp://localhost");

 ramp.highestSustainedRate();   // the last step that met every rule and objective
 ramp.stoppedBy();              // which rule ended it
 

Every step is an ordinary run

Each step is the workload run at one fixed rate through the same open-loop engine as any other run: latency is measured from when each message was due, so a broker that stalls shows up as latency rather than as a generator that quietly slowed down with it. A ramp is not a second engine with a moving rate; it is a loop over runs, so every step is judged by exactly the rules a single run is.

What stops it

  • a step with an INVALID finding — the generator could not offer the rate, or the broker raised a resource alarm. The ceiling found is then not the broker's, and the report says so;
  • a step with a FAILED finding — an objective was missed, or a rule loaded from the file fired;
  • kept-pace, added to every step: what was delivered fell more than tolerance(double) short of what was offered. Without it a slow consumer would never stop a ramp, because a queue that fills is only a warning;
  • a share of failed publishes above maxErrorRate(double) (zero by default, so any failed publish stops it);
  • maxRate(long), reached without anything firing. The ceiling is then "at least this", and the report says that rather than inventing a number.

Warnings never stop a ramp. Short steps warn that they were short, on every step.

Refinement

refine(int) bisects between the last good step and the first bad one. A refinement step that comes straight after an overloaded one inherits whatever backlog that step left in the queue, which can only make it look worse, never better: the ceiling it reports can be low, not high.

  • Method Details

    • of

      public static Ramp of(Workload workload)
      Parameters:
      workload - what to run at each step: topology, publishers, consumers, rules. Its rate, if it has one, is the default starting rate — each step replaces it, and an unthrottled workload is ramped like any other — its warm-up the default per step and its duration the default step length
      Returns:
      a ramp over it
    • startAt

      public Ramp startAt(long rate)
      Parameters:
      rate - the first step's offered rate, in messages a second
      Returns:
      this
    • stepBy

      public Ramp stepBy(long messagesPerSecond)
      Parameters:
      messagesPerSecond - how much each step adds
      Returns:
      this
    • stepByPercent

      public Ramp stepByPercent(double percent)
      Parameters:
      percent - how much each step adds, as a share of the step before, e.g. 25
      Returns:
      this
    • stepFor

      public Ramp stepFor(Duration duration)
      Parameters:
      duration - the measured window of each step
      Returns:
      this
    • warmupEachStep

      public Ramp warmupEachStep(Duration duration)
      Parameters:
      duration - how long each step runs before it is measured
      Returns:
      this
    • maxRate

      public Ramp maxRate(long rate)
      Parameters:
      rate - no step is offered more than this; reaching it without a rule firing ends the ramp with "at least this"
      Returns:
      this
    • maxErrorRate

      public Ramp maxErrorRate(double fraction)
      Parameters:
      fraction - the share of publishes that may fail before a step counts as bad, 0 to 1
      Returns:
      this
    • tolerance

      public Ramp tolerance(double fraction)
      Parameters:
      fraction - how far the delivered rate may fall short of the offered one, 0 to 1; default 0.05
      Returns:
      this
    • refine

      public Ramp refine(int steps)
      Parameters:
      steps - how many bisection steps to run between the last good and the first bad rate
      Returns:
      this
    • ceilingAtLeast

      public Ramp ceilingAtLeast(long rate)
      Parameters:
      rate - an objective for the ramp as a whole: the highest sustained rate must reach it
      Returns:
      this
    • stop

      public void stop()
      Ends the ramp after the step now running. Safe from any thread.
    • workload

      public Workload workload()
    • start

      public long start()
    • ceilingAtLeast

      public long ceilingAtLeast()
    • run

      public RampReport run(String brokerUrl)
      Parameters:
      brokerUrl - an AMQP URL
      Returns:
      what each step measured, and where it stopped
    • run

      public RampReport run(String brokerUrl, org.acemq.amqp.security.Security security)
      Parameters:
      brokerUrl - an AMQP URL
      security - which certificates to believe, or null to let the URL decide
      Returns:
      what each step measured, and where it stopped
    • run

      Runs the ramp with each step run by the caller — the command line uses this so a step can be stopped by a signal and still report.
      Parameters:
      runner - runs one step's workload and returns its report
      Returns:
      what each step measured, and where it stopped
    • check

      public Ramp check()
      Checks the settings hang together, without running anything.
      Returns:
      this
      Throws:
      IllegalArgumentException - naming what is missing or contradictory
    • toString

      public String toString()
      Overrides:
      toString in class Object