GithubHelp home page GithubHelp logo

twitter-archive / iago Goto Github PK

View Code? Open in Web Editor NEW
1.3K 177.0 142.0 1.05 MB

A load generator, built for engineers

Home Page: http://twitter.github.com/iago/

License: Apache License 2.0

Scala 97.90% Java 0.46% Thrift 0.41% Shell 1.23%

iago's Introduction

Iago, A Load Generator

Build Status

Iago Quick Start

Please join [email protected] for updates and to ask questions.

If you are already familiar with the Iago Load Generation tool, follow these steps to get started; otherwise, start with the Iago Overview and perhaps Iago Philosophy, also known as "Why Iago?". For questions, please contact [email protected].

Iago Prerequisites

  1. Download and unpack the Iago distribution. We support Scala 2.10 and recommend you clone the latest master: master.

  2. Read the documentation.

Preparing Your Test

  1. Identify your transaction source; see Transaction Requirements and Sources of Transactions for more information.
  2. In Scala, extend the Iago server's RecordProcessor or ThriftRecordProcessor class, or in Java, extend LoadTest or ThriftLoadTest; see Implementing Your Test for more information.
  3. Create a launcher.scala file in your Iago config directory with the appropriate settings; see Configuring Your Test for more information.

Executing Your Test

Launch Iago from the distribution with java -jar iago_jar -f your_config. This will create the Iago processes for you and configure it to use your transactions. To kill a running job, add -k to your launch parameters: java -jar iago_jar -f your_config -k.

If you launch your Iago job on your local machine and an old Iago job is still running, it probably won't get far: it will attempt to re-use a port and fail. You want to kill the running job, as described above.

If you build via Maven, then you might wonder "How do I launch Iago 'from the distribution'?" The steps are:

% mvn package -DskipTests
% mkdir tmp; cd tmp
% unzip ../target/iago-version-package-dist.zip
% java -jar iago-version.jar -f config/my_config.scala

Don't assume that you can skip the package/unzip steps if you're just changing a config file. You need to re-package and unzip again.

If you are using Iago as a library, for example, in the case of testing over the Thrift protocol or building more complex tests with HTTP or Memcached/Kestrel, you should instead add a task to your project's configuration. See Configuring Your Test for more information.

Top

Iago Overview

Iago is a load generation tool that replays production or synthetic traffic against a given target. Among other things, it differs from other load generation tools in that it attempts to hold constant the transaction rate. For example, if you want to test your service at 100K requests per minute, Iago attempts to achieve that rate.

Because Iago replays traffic, you must specify the source of the traffic. You use a transaction log as the source of traffic, in which each transaction generates a request to your service that your service processes.

Replaying transactions at a fixed rate enables you to study the behavior of your service under an anticipated load. Iago also allows you to identify bottlenecks or other issues that may not be easily observable in a production environment in which your maximum anticipated load occurs only rarely.

Top

Supported Services

Iago can generate service requests that travel the net in different ways and are in different formats. The code that does this is in a Transport, a class that extends ParrotTransport. Iago comes with several Transports already defined. When you configure your test, you will need to set some parameters; to understand which of those parameters are used and how they are used, you probably want to look at the source code for your test's Transport class.

Your service is typically an HTTP or Thrift service written in either Scala or Java.

Top

Transaction Requirements

For replay, Iago recommends you scrub your logs to only include requests which meet the following requirements:

  • Idempotent, meaning that re-execution of a transaction any number of times yields the same result as the initial execution.
  • Commutative, meaning that transaction order is not important. Although transactions are initiated in replay order, Iago's internal behavior may change the actual execution order to guarantee the transaction rate. Also, transactions that implement Future responses are executed asynchronously. You can achieve ordering, if required, by using Iago as a library and initiating new requests in response to previous ones. Examples of this are available.

Top

Sources of Transactions

Transactions typically come from logs, such as the following:

  • Web server logs capture HTTP transactions.
  • Proxy server logs can capture transactions coming through a server. You can place a proxy server in your stack to capture either HTTP or Thrift transactions.
  • Network sniffers can capture transactions as they come across a physical wire. You can program the sniffer to create a log of transactions you identify for capture.

In some cases, transactions do not exist. For example, transactions for your service may not yet exist because they are part of a new service, or you are obligated not to use transactions that contain sensitive information. In such cases, you can provide synthetic transactions, which are transactions that you create to model the operating environment for your service. When you create synthetic transactions, you must statistically distribute your transactions to match the distribution you expect when your service goes live.

Top

Iago Architecture Overview

Iago consists of feeders and servers. A feeder reads your transaction source. A server formats and delivers requests to the service you want to test. The feeder contains a Poller object, which is responsible for guaranteeing cachedSeconds worth of transactions in the pipeline to the Iago servers.

Metrics are available in logs and in graphs as described in Metrics.

The Iago servers generate requests to your service. Together, all Iago servers generate the specified number of requests per minute. A Iago server's RecordProcessor object executes your service and maps the transaction to the format required by your service.

The feeder polls its servers to see how much data they need to maintain cachedSeconds worth of data. That is how we can have many feeders that need not coordinate with each other.

Ensuring that we go through every last message is important when we are writing traffic summaries in the record processor, especially when the data set is small. The parrot feeder shuts down due to running out of time, running out of data, or both. When the feeder runs out of data we

  • make sure that all the data in parrot feeder's internal queues are sent to the parrot server
  • make sure all the data held in the parrot servers cache is sent
  • wait until we get a response for all pending messages or until the reads time out

When the parrot feeder runs out of time (the duration configuration) the data in the feeder's internal queues are ignored, otherwise the same process as above occurs.

Top

Implementing Your Test

The following sections show examples of implementing your test in both Scala and Java. See Code Annotations for the Examples for information about either example.

Top

Scala Example

To implement a load test in Scala, you must extend the Iago server's RecordProcessor class to specify how to map transactions into the requests that the Iago server delivers to your service. The following example shows a RecordProcessor subclass that implements a load test on an EchoService HTTP service:

package com.twitter.example

import org.apache.thrift.protocol.TBinaryProtocol

import com.twitter.parrot.processor.RecordProcessor                                     // 1
import com.twitter.parrot.thrift.ParrotJob                                              // 2
import com.twitter.parrot.server.{ParrotRequest,ParrotService}                          // 3
import com.twitter.logging.Logger
import org.jboss.netty.handler.codec.http.HttpResponse

import thrift.EchoService

class EchoLoadTest(parrotService: ParrotService[ParrotRequest, HttpResponse]) extends RecordProcessor {
  val client = new EchoService.ServiceToClient(service, new TBinaryProtocol.Factory())  // 4
  val log = Logger.get(getClass)

  def processLines(job: ParrotJob, lines: Seq[String]) {                                // 5
    lines map { line =>
      client.echo(line) respond { rep =>
        if (rep == "hello") {
          client.echo("IT'S TALKING TO US")                                             // 6
        }
        log.info("response: " + rep)                                                    // 7
      }
    }
  }
}

Top

Scala Thrift Example

To implement a Thrift load test in Scala, you must extend the Iago server's Thrift RecordProcessor class to specify how to map transactions into the requests that the Iago server delivers to your service. The following example shows a ThriftRecordProcessor subclass that implements a load test on an EchoService Thrift service:

package com.twitter.example

import org.apache.thrift.protocol.TBinaryProtocol

import com.twitter.parrot.processor.ThriftRecordProcessor                               // 1
import com.twitter.parrot.thrift.ParrotJob                                              // 2
import com.twitter.parrot.server.{ParrotRequest,ParrotService}                          // 3
import com.twitter.logging.Logger

import thrift.EchoService

class EchoLoadTest(parrotService: ParrotService[ParrotRequest, Array[Byte]]) extends ThriftRecordProcessor(parrotService) {
  val client = new EchoService.ServiceToClient(service, new TBinaryProtocol.Factory())  // 4
  val log = Logger.get(getClass)

  def processLines(job: ParrotJob, lines: Seq[String]) {                                // 5
    lines map { line =>
      client.echo(line) respond { rep =>
        if (rep == "hello") {
          client.echo("IT'S TALKING TO US")                                             // 6
        }
        log.info("response: " + rep)                                                    // 7
      }
    }
  }
}

Top

Java Example

To implement a load test in Java, you must extend the Iago server's LoadTest class to specify how to map transactions into the requests that the Iago server delivers to your service. The LoadTest class provides Java-friendly type mappings for the underlying Scala internals. The following example shows a LoadTest subclass that implements a load test on an EchoService HTTP service:

package com.twitter.jexample;

import com.twitter.example.thrift.EchoService;
import com.twitter.parrot.processor.LoadTest;                                           // 1
import com.twitter.parrot.thrift.ParrotJob;                                             // 2
import com.twitter.parrot.server.ParrotRequest;                                         // 3

import com.twitter.parrot.server.ParrotService;                                         // 3
import com.twitter.util.Future;
import com.twitter.util.FutureEventListener;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.jboss.netty.handler.codec.http.HttpResponse;

import java.util.List;

public class EchoLoadTest extends LoadTest {
  EchoService.ServiceToClient client = null;

  public EchoLoadTest(ParrotService<ParrotRequest, HttpResponse> parrotService) {
    super(parrotService);
    client = new EchoService.ServiceToClient(service(), new TBinaryProtocol.Factory()); // 4
  }

  public void processLines(ParrotJob job, List<String> lines) {                         // 5
    for(String line: lines) {
      Future<String> future = client.echo(line);
      future.addEventListener(new FutureEventListener<String>() {
        public void onSuccess(String msg) {
          System.out.println("response: " + msg);
        }

      public void onFailure(Throwable cause) {
        System.out.println("Error: " + cause);
      }
     });
    }
  }
}

Top

Java Thrift Example

To implement a Thrift load test in Java, you must extend the Iago server's ThriftLoadTest class to specify how to map transactions into the requests that the Iago server delivers to your service. The ThriftLoadTest class provides Java-friendly type mappings for the underlying Scala internals. The following example shows a ThriftLoadTest subclass that implements a load test on an EchoService Thrift service:

package com.twitter.jexample;

import com.twitter.example.thrift.EchoService;
import com.twitter.parrot.processor.ThriftLoadTest;                                     // 1
import com.twitter.parrot.thrift.ParrotJob;                                             // 2
import com.twitter.parrot.server.ParrotRequest;                                         // 3
import com.twitter.parrot.server.ParrotService;                                         // 3
import com.twitter.util.Future;
import com.twitter.util.FutureEventListener;
import org.apache.thrift.protocol.TBinaryProtocol;

import java.util.List;

public class EchoLoadTest extends ThriftLoadTest {
  EchoService.ServiceToClient client = null;

  public EchoLoadTest(ParrotService<ParrotRequest, byte[]> parrotService) {
    super(parrotService);
    client = new EchoService.ServiceToClient(service(), new TBinaryProtocol.Factory()); // 4
  }

  public void processLines(ParrotJob job, List<String> lines) {                         // 5
    for(String line: lines) {
      Future<String> future = client.echo(line);
      future.addEventListener(new FutureEventListener<String>() {
        public void onSuccess(String msg) {
          System.out.println("response: " + msg);
        }

      public void onFailure(Throwable cause) {
        System.out.println("Error: " + cause);
      }
     });
    }
  }
}

Top

Code Annotations for the Examples

You define your Iago subclass to execute your service and map transactions to requests for your service:

  1. Import com.twitter.parrot.processor.RecordProcessor (Scala) or LoadTest (Java), whose instance will be executed by a Iago server.
  2. Import com.twitter.parrot.thrift.ParrotJob, which contains the Iago server class.
  3. Import com.twitter.parrot.server.ParrotService and com.twitter.parrot.server.ParrotRequest
  4. Create an instance of your service to be placed under test. Your service is a client of the Iago service.
  5. Define a processLines method to format the request and and execute your service.
  6. Optionally, you can initiate a new request based on the response to a previous one.
  7. Optionally, do something with the response. In this example, the response is logged.

Top

Configuring Your Test

To configure your test, create a launcher.scala file that that creates a ParrotLauncherConfig instance with the configuration parameters you want to set.

There are several parameters to set. A good one to figure out early is transport; that will in turn help you to find out what, e.g., responseType you need.

The following example shows parameters for testing a Thrift service:

import com.twitter.parrot.config.ParrotLauncherConfig

new ParrotLauncherConfig {
  distDir = "."
  jobName = "load_echo"
  port = 8080
  victims = "localhost"
  log = "logs/yesterday.log"
  requestRate = 1
  numInstances = 1
  duration = 5
  timeUnit = "MINUTES" // affects duration; does not affect requestRate

  imports = "import com.twitter.example.EchoLoadTest"
  responseType = "Array[Byte]"
  transport = "ThriftTransportFactory(this)"
  loadTest = "new EchoLoadTest(service.get)"
}

Note: For a sample configuration file, see config/launcher.scala within the Iago distribution.

You can specify any of the following parameters:

Parameter Description Required or
Default Value
createDistribution

You can use this field to create your own distribution rate, instead of having a constant flow. You will need to create a subclass of RequestDistribution and import it.

Example:

createDistribution = """createDistribution = {
  rate => new MyDistribution(rate)
}"""

""
customLogSource

A string with Scala code that will be put into the Feeder config. You can use this to get Iago to read in compressed files. Iago can read LZO compressed files using its built-in LzoFileLogSource.

Example:

customLogSource = """
  if(inputLog.endsWith(".lzo")) {
    logSource = Some(new com.twitter.parrot.feeder.LzoFileLogSource(inputLog))
  }"""
    

""
distDir

The subdirectory of your project you're running from, if any.

Example: distDir = "target"

"."
doConfirm

If set to false, you will not be asked to confirm the run.

Example: doConfirm = false

true
duration

An integer value that specifies the time to run the test in timeUnit units.

Example: duration = 5

 
feederXmx

Defines feeder heap size. Suggested not to be higher than 4 GB (will cause issues scheduling)

Example: feederXmx = 2048

1744
header

A string value that specifies the HTTP Host header.

Example: header = "api.yourdomain.com"

""
hostConnectionCoresize

Number of connections per host that will be kept open, once established, until they hit max idle time or max lifetime

Example: hostConnectionCoresize = 1

1
hostConnectionIdleTimeInMs

For any connection > coreSize, maximum amount of time, in milliseconds, between requests we allow before shutting down the connection

Example: hostConnectionIdleTimeInMs = 50000

60000
hostConnectionLimit

Limit on the number of connections per host

Example: hostConnectionLimit = 4

Integer.MAX_VALUE
hostConnectionMaxIdleTimeInMs

The maximum time in milliseconds that any connection (including within core size) can stay idle before shutdown

Example: hostConnectionMaxIdleTimeInMs = 500000

300000
hostConnectionMaxLifeTimeInMs

The maximum time in milliseconds that a connection will be kept open

Example: hostConnectionMaxLifeTimeInMs = 10000

Integer.MAX_VALUE
jobName

A string value that specifies the the name of your test. This is used for two things:

  1. if the parrot feeder is configured to find its servers using zookeeper, and/or
  2. when using mesos it is part of the job names generated. A job name of "foo" results in mesos job sharding groups "parrot_server_foo" and "parrot_feeder_foo".

Example: jobName = "testing_tasty_new_feature"

Required
localMode

Should Iago attempt to run locally or to use the cluster via mesos?

Example: localMode = true

false
log

A string value that specifies the complete path to the log you want Iago to replay. If localMode=true then the log should be on your local file system. The log should have at least 1000 items or you should change the reuseFile parameter.

Example: log = "logs/yesterday.log"

If localMode=false (the default), then the parrot launcher will copy your log file when attempts to make a package for mesos. You can avoid this, and should, by storing your log file in HDFS.

Example: log = "hdfs://hadoop-example.com/yesterday.log"

Required
loggers

A List of LoggerFactories; allows you to define the type and level of logging you want

Example:

import com.twitter.logging.LoggerFactory
import com.twitter.logging.config._

new ParrotLauncherConfig { ... loggers = new LoggerFactory( level = Level.DEBUG, handlers = new ConsoleHandlerConfig() ) }

Nil
maxRequests

An integer value that specifies the total number of requests to submit to your service.

Example: maxRequests = 10000

Integer.MAX_VALUE
requestRate

An integer value that specifies the number of requests per second to submit to your service.

Example: requestRate = 10

Note: if using multiple server instances, requestRate is per-instance, not aggregate.

1
reuseFile

A boolean value that specifies whether or not to stop the test when the input log has been read through. Setting this value to true will result in Iago starting back at the beginning of the log when it exhausts the contents. If this is true, your log file should at least be 1,000 lines or more.

Example: reuseFile = false

true
scheme

A string value that specifies the scheme portion of a URI.

Example: scheme = "http"

http
serverXmx

Defines server heap size. Suggested not to be higher than 8 GB (will cause issues scheduling)

Example: serverXmx = 5000

4000
requestTimeoutInMs

(From the Finagle Documentation) The request timeout is the time given to a *single* request (if there are retries, they each get a fresh request timeout). The timeout is applied only after a connection has been acquired. That is: it is applied to the interval between the dispatch of the request and the receipt of the response.

Note that parrot servers will not shut down until every response from every victim has come in. If you've modified your record processor to write test summaries this can be an issue.

Example: requestTimeoutInMs = 3000 // if the victim doesn't respond in three seconds, stop waiting

30000 // 30 seconds
reuseConnections

A boolean value that specifies whether connections to your service's hosts can be reused. A value of true enables reuse. Setting this to false greatly increases your use of ephemeral ports and can result in port exhaustion, causing you to achieve a lower rate than requested

This is only implemented for FinagleTransport.

Example: reuseConnections = false

true
thriftClientId

If you are making Thrift requests, your clientId

Example: thriftClientId = "projectname.staging"

""
timeUnit

A string value that specifies time unit of the duration. It contains one of the following values:

  • "MINUTES"
  • "HOURS"
  • "DAYS"

Example: timeUnit = "MINUTES"

 
traceLevel

A com.twitter.logging.Level subclass. Controls the level of "debug logging" for servers and feeders.

Example:

traceLevel = com.twitter.logging.Level.TRACE

Level.INFO
verboseCmd

A boolean value that specifies the level of feedback from Iago. A value of true specifies maximum feedback.

Example: verboseCmd = true

false

[Specifying Victims]

The point of Iago is to load-test a service. Iago calls these "victims".

Victims may be a

  1. single host:port pair
  2. list of host:port pairs
  3. a zookeeper serverset

Note that ParrotUdpTransport can only handle a single host:port pair. The other transports that come with Iago, being Finagle based, do not have this limitation.

     
Parameter Description Required or
Default Value
victims

A list of host:port pairs:

  victims="example.com:80 example2.com:80"  

A zookeeper server set:

  victims="/some/zookeeper/path"  
Required
port

An integer value that specifies the port on which to deliver requests to the victims.

The port is used for two things: to provide a port if none were specified in victims, and to provide a port for the host header using a FinagleTransport.

Example: port = 9000

Required
victimClusterType

When victimClusterType is "static", we set victims and port. victims can be a single host name, a host:port pair, or a list of host:port pairs separated with commas or spaces.

When victimClusterType is "sdzk" (which stands for "service discovery zookeeper") the victim is considered to be a server set, referenced with victims, victimZk, and victimZkPort.

Default: "static"
victimZk

the host name of the zookeeper where your serverset is registered

Default is "sdzookeeper.local.twitter.com"

victimZkPort

The port of the zookeeper where your serverset is registered

Default: 2181

[Extension Point Parameters]

Alternative Use: You can specify the following extension point parameters to configure projects in which Iago is used as both a feeder and server. The Iago feeder provides the log lines to your project, which uses these log lines to form requests that the Iago server then handles:

Parameter Description Required or
Default Value
imports

Imports from this project to Iago

Example: If ProjectX includes Iago as a dependency, you would specify:
import org.jboss.netty.handler.codec.http.HttpResponse
import com.twitter.projectX.util.ProcessorClass

import org.jboss.netty.handler.codec.http.HttpResponse
import com.twitter.parrot.util.LoadTestStub
requestType

The request type of requests from Iago.

Examples:

  • ParrotRequest for most services (including HTTP and Thrift)

ParrotRequest
responseType

The response type of responses from Iago.

Examples:

  • HttpResponse for an HTTP service
  • Array[Byte] for a Thrift service

HttpResponse
transport

The kind of transport to the server, which matches the responseType you want.

Example:transport = "ThriftTransportFactory(this)"

The Thrift Transport will send your request and give back Future[Array[Byte]].

FinagleTransport
loadTest

Your processor for the Iago feeder's lines, which converts the lines into requests and sends them to the Iago server.

Example: new LoadTestStub(service.get)

new LoadTestStub(service.get)

Top

[Sending Large Messages]

By default, the parrot feeder sends a thousand messages at a time to each connected parrot server until the parrot server has twenty seconds worth of data. This is a good strategy when messages are small (less than a kilobyte). When messages are large, the parrot server will run out of memory. Consider an average message size of 100k, then the feeder will be maintaining an output queue for each connected parrot server of 100 million bytes. For the parrot server, consider a request rate of 2000, then 2000 * 20 * 100k = 4 gigabytes (at least). The following parameters help with large messages:

Parameter Description Required or
Default Value
batchSize

how many messages the parrot feeder sends at one time to the parrot server. For large messages, setting this to 1 is recommended.

Default: 1000
cachedSeconds

How many seconds worth of data the parrot server will attempt to cache. Setting this to 1 for large messages is recommended. The consequence is that, if the parrot feeder garbage-collects, there will be a corresponding pause in traffic to your service unless cachedSeconds is set to a value larger than a typical feeder gc. This author has never observed a feeder gc exceeding a fraction of a second.

Default is 20

Top

[Weighted Requests]

Some applications must make bulk requests to their service. In other words, a single meta-request in the input log may result in several requests being satisfied by the victim. A weight field to ParrotRequest was added so that the RecordProcessor can set and use that weight to control the send rate in the RequestConsumer. For example, a request for 17 messages would be given a weight of 17 which would cause the RequestConsumer to sample the request distribution 17 times yielding a consistent distribution of load on the victim.

Top

[Metrics]

Iago uses Ostrich to record its metrics. Iago is configured so that a simple graph server is available as long as the parrot server is running. If you are using localMode=true, then the default place for this is

  http://localhost:9994/graph/

One metric of particular interest is

  http://localhost:9994/graph/?g=metric:client/request_latency_ms

Request latency is the time it takes to queue the request for sending until the response is received. See the Finagle User Guide for more about the individual metrics.

Other metrics of interest:

Statistic Description
connection_duration duration of a connection from established to closed?
connection_received_bytes bytes received per connection
connection_requests Number of connection requests that your client did, ie. you can have a pool of 1 connection and the connection can be closed 3 times, so the "connection_requests" would be 4 (even if connections = 1)
connection_sent_bytes bytes send per connection
connections is the current number of connections between client and server
handletime_us time to process the response from the server (ie. execute all the chained map/flatMap)
pending Number of pending requests (ie. requests without responses)
request_concurrency is the current number of connections being processed by finagle
request_latency_ms the time of everything between request/response.
request_queue_size Number of requests waiting to be handled by the server

[Raggiana]

Raggiana is a simple standalone Finagle stats viewer.

You can use Raggiana to view the stats log, parrot-server-stats.log, generated by Iago.

You can clone it from

https://github.com/twitter/raggiana

or, just use it directly at

http://twitter.github.io/raggiana

Top

[Tracing]

Parrot works with Zipkin, a distributed tracing system.

Top

[What Files Are Created?]

The Iago launcher creates the following files

config/target/parrot-feeder.scala
config/target/parrot-server.scala
scripts/common.sh
scripts/parrot-feeder.sh
scripts/parrot-server.sh

The Iago feeder creates

parrot-feeder.log
gc-feeder.log

The Iago server creates

parrot-server.log
parrot-server-stats.log
gc-server.log 

The logs are rotated by size. Each individual log can be up to 100 megabytes before being rotated. There are 6 rotations maintained.

The stats log, parrot-server-stats.log, is a minute-by-minute dump of all the statistics (or Metrics) maintained by the Iago server. Each entry is for the time period since the previous one. That is, all entries in parrot-server-stats.log need to be accumulated to match the final values reported by http://localhost:9994/stats.txt.

Top

Using Iago as a Library

While Iago provides everything you need to target your API with a large distributed loadtest with just a small log processor, it also exposes a library of classes for log processing, traffic replay, & load generation. These can be used in your Iago configuration or incorporated in your application as a library.

parrot/server:

  • ParrotRequest: Parrot's internal representation of a request
  • ParrotTransport (FinagleTransport, KestrelTransport, MemcacheTransport, ParrotUdpTransport, ThriftTransport): Interchangeable transport layer for requests to be sent. Parrot contains transport implementations for the following protocols: HTTP (FinagleTransport), Kestrel, Memcache, raw UDP and Thrift.
  • RequestConsumer: Queues ParrotRequests and sends them out on a ParrotTransport at a rate determined by RequestDistribution
  • RequestQueue: A wrapper/control layer for RequestConsumer
  • ParrotService (ParrotThriftService): Enqueues ParrotRequests to a RequestQueue. ParrotThriftService implements finagle's Service interface for use with finagle thrift clients.

parrot/util:

  • RequestDistribution: A function specifying the time to arrival of the next request, used to control the request rate. Instances include
    • UniformDistribution: Sends requests at a uniform rate
    • PoissonProcess: Sends requests at approximatly constant rate randomly varying using a poisson process. This is the default.
    • SinusoidalPoissonProcess: Like PoissonProcess but varying the rate sinusoidally.
    • SlowStartPoissonProcess: Same as PoissonProcess but starting with a gradual ramp from initial rate to final rate. It will then hold steady at the final rate until time runs out.
    • InfiniteRampPoissonProcess: a two staged ramped distribution. Ideal for services that need a warm-up period before ramping up. The rate continues to increase until time runs out.

You may also find the LogSource and RequestProcessor interfaces discussed earlier useful.

Examples:

// Make 1000 HTTP requests at a roughly constant rate of 10/sec

// construct the transport and queue
val client =
  ClientBuilder()
    .codec(http())
    .hosts("twitter.com:80")
    .build()
val transport = new FinagleTransport(FinagleService(client))
val consumer = new RequestConsumer(() => new PoissionProcess(10)
// add 1000 requests to the queue
for (i <- (1 to 1000)) {
  consumer.offer(new ParrotRequest(uri= Uri("/jack/status/20", Nil))
}
// start sending
transport.start()
consumer.start()
// wait for the comsumer to exhaust the queue
while(consumer.size > 0) {
  Thread.sleep(100)
}
// shutdown
consumer.shutdown()
transport.close()
// Call a thrift service with a sinusoidally varying rate

// Configure cluster for the service using zookeeper
val zk = "zookeeper.example.com"
val zkPort = 2181
val path = "my/env/role/service"
val zookeeperClient = new ZooKeeperClient(Amount.of(1, Time.SECONDS),
  Seq(InetSocketAddress.createUnresolved(zk, zkPort)).asJava)
val serverSet = new ServerSetImpl(zookeeperClient, path)
val cluster = new ZookeeperServerSetCluster(serverSet)

// create transport and queue
val client =
  ClientBuilder()
    .codec(ThriftClientFramedCodec)
    .cluster(cluster)
    .build()
val transport = new ThriftTransport(client)
val createDistribution = () => new SinusoidalPoisionProccess(10, 20, 60.seconds)
val queue = new RequestQueue(new RequestConsumer(createDistribution, transport), transport)
// create the service and processor
val service = transport.createService(queue)
val processor = new EchoLoadTest(service)
// start sending
transport.start()
consumer.start()
// Fill the queue from a logfile
val source = new LogSourceImpl("some_file.txt")
while (source.hasNext) {
  processor.processLines(Seq(source.next))
}
// wait for the comsumer to exhaust the queue
while(consumer.size > 0) {
  Thread.sleep(100)
}
// shutdown
consumer.shutdown()
transport.close()

Top

[ChangeLog]

2013-06-25 release 0.6.7

  • graceful shutdown for small log sources
  • dropped vestigial parser config
  • weighted parrot requests
  • supporting large requests (BlobStore): new configurations cachedSeconds & mesosRamInMb
  • launcher changes: configurable proxy, create config directory if needed, and handle errors better (don't hang)
  • serversets as victims
  • make local logs work with non-local distribution directories
  • kestrel transport transactional get support
  • check generated config files before launch
  • LzoFileLogSource for iago
  • Thrift over TLS
  • traceLevel config

Top

[Contributing to Iago]

Iago is open source, hosted on Github here. If you have a contribution to make, please fork the repo and submit a pull request.

iago's People

Contributors

caniszczyk avatar fedeoasi avatar julianrendell avatar jwaldrop avatar jwstric2 avatar lahosken avatar madster26 avatar michaeldiamant avatar raphaelfeng avatar techabstraction avatar tquan avatar travisbrown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

iago's Issues

mvn package failing on echo example

y@local:~/workspace/iago/examples/echo{master} $ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building iago-echo 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-finagle-thrift-plugin:0.0.9:compile (thrift-sources) @ iago-echo ---
[INFO] Generated thrift files up to date, skipping compile.
[INFO]
[INFO] --- maven-build-properties-plugin:0.0.2:compile (default) @ iago-echo ---
[INFO] writing build properties to /Users/y/workspace/iago/examples/echo/target/generated-resources/com/twitter/iago-echo/build.properties
[INFO] version: 1.0
[INFO] build_branch_name: refs/heads/master
[INFO] build_revision: f52d586
[INFO] name: iago-echo
[INFO] build_name: 20141004-021134
[INFO] build_last_few_commits: f52d586 (HEAD, origin/master, origin/HEAD, master) Merge pull request #34 from madster26/patch-1
1a30fa4 Fix bug in ParrotCluster shutdown
82db1ba Merge pull request #33 from eliocapelati/patch-1
4ac838d Just a small fix on README
520696d Merge pull request #32 from jwstric2/master
ac4ca1c Added PUT support. Request body supported added for PUT as it will contain a newly-updated representation of an original resource or even possibly a new resource.
01d69ed Merge pull request #27 from ExpediaInc/xforwardedfor
f153d80 Merge pull request #29 from fedeoasi/double-bracket
d41612b Use single brackets instead of double in common.sh
d8308fd didn't realize package-dist was not release so including a copy here
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ iago-echo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/y/workspace/iago/examples/echo/src/main/resources
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] Copying 1 resource
[INFO]
[INFO] --- scala-maven-plugin:3.0.1:add-source (scala-compile-first) @ iago-echo ---
[INFO] Add Source directory: /Users/y/workspace/iago/examples/echo/src/main/scala
[INFO] Add Test Source directory: /Users/y/workspace/iago/examples/echo/src/test/scala
[INFO]
[INFO] --- scala-maven-plugin:3.0.1:compile (scala-compile-first) @ iago-echo ---
[INFO] Checking for multiple versions of scala
[WARNING] Expected all dependencies to require Scala version: 2.9.2
[WARNING] com.twitter:iago:0.6.14 requires scala version: 2.10.3
[WARNING] Multiple versions of scala libraries detected!
[INFO] includes = [/*.scala,/*.java,]
[INFO] excludes = []
[INFO] /Users/y/workspace/iago/examples/echo/src/main/java:-1: info: compiling
[INFO] /Users/y/workspace/iago/examples/echo/target/generated-sources/thrift/gen-java:-1: info: compiling
[INFO] /Users/y/workspace/iago/examples/echo/src/main/scala:-1: info: compiling
[INFO] Compiling 5 source files to /Users/y/workspace/iago/examples/echo/target/classes at 1412413895641
[ERROR] error: error while loading Await, class file needed by Await is missing.
[INFO] reference type InterruptedException of object package refers to nonexisting symbol.
[ERROR] error: error while loading Awaitable, class file needed by Awaitable is missing.
[INFO] reference type InterruptedException of object package refers to nonexisting symbol.
[ERROR] two errors found
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.985 s
[INFO] Finished at: 2014-10-04T02:11:38-07:00
[INFO] Final Memory: 10M/81M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.alchim31.maven:scala-maven-plugin:3.0.1:compile (scala-compile-first) on project iago-echo: wrap: org.apache.commons.exec.ExecuteException: Process exited with an error: 1(Exit value: 1) -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Iago distribution is no longer created

Since commit 198ed12 that changed the pom to refer to the aggregator parent pom, the build no longer produces iago-package-dist.zip

Steps to recreate:

  1. Clone the repo, eg git clone https://github.com/twitter/iago.git
  2. Change into the repo directory, eg cd iago
  3. Run mvn -DskipTests install
  4. iago-package-dist.zip is not created in target directory

ParrotServerImpl::start doesn't call config.recordProcessor.start()

Looking at the recordprocessor trait (https://github.com/twitter/iago/blob/master/src/main/scala/com/twitter/parrot/processor/RecordProcessor.scala) I assume that that start method is intended to be called before the test starts, and shutdown after.

In playing with the example code I can see code I add to shutdown being executed but not so for start.

Looking at ParrotServerImpl (https://github.com/twitter/iago/blob/master/src/main/scala/com/twitter/parrot/server/ParrotServer.scala) and comparing start to shutdown:

 def start(): Future[Void] = {
    status.setStatus(ParrotState.STARTING)
    transport.start(config)
    queue.start()
    thriftServer.start(this, config.parrotPort)
    clusterService.start(config.parrotPort)
    status.setStatus(ParrotState.RUNNING)
    log.info("using record processor %s", config.recordProcessor.getClass().getName())
    Future.Void
  }

  def shutdown(): Future[Void] = {

    /* Calling ServiceTracker.shutdown() causes all the Ostrich threads to go away. It also results
     * in all its managed services to be shutdown. That includes this service. We put a guard
     * here so we don't end up calling ourselves twice.
     */

    if (isShutdown.compareAndSet(false, true)) {
      Future {
        status.setStatus(ParrotState.STOPPING)
        log.trace("server: shutting down")
        clusterService.shutdown()
        queue.shutdown()
        shutdownTransport
        status.setStatus(ParrotState.SHUTDOWN)
        config.recordProcessor.shutdown()
        ServiceTracker.shutdown()
        thriftServer.shutdown()
        log.trace("server: shut down")
        done.setValue(null)
      }
    }
    done
  }

then I think start should look like:

 def start(): Future[Void] = {
    status.setStatus(ParrotState.STARTING)

    config.recordProcessor.start()

    transport.start(config)
    queue.start()
    thriftServer.start(this, config.parrotPort)
    clusterService.start(config.parrotPort)
    status.setStatus(ParrotState.RUNNING)
    log.info("using record processor %s", config.recordProcessor.getClass().getName())
    Future.Void
  }

And in shutdown should the status.setStatus(ParrotState.SHUTDOWN) be after config.recordProcessor.shutdown()? (Maybe not if it is strictly indicating the parrot system's state and excluding the user supplied load test logic.)

My apologies for this not being a pull request, but I'm completely new to Iago, Scala, and Maven; I've yet to figure out how to use a local custom version of Iago from my own test project.

Thanks in advance,

Julian

mvn package error

[ERROR] Plugin com.twitter:maven-finagle-thrift-plugin:0.0.2 or one of its dependencies could not be resolved: Failed to read artifact descriptor for com.twitter:maven-finagle-thrift-plugin:jar:0.0.2: Could not transfer artifact com.twitter:maven-finagle-thrift-plugin:pom:0.0.2 from/to

Unit tests failure - Error shutting down Parrot: com.twitter.util.TimeoutException

I'm not sure if this forum topic is related, but looks fairly close. https://groups.google.com/forum/#!topic/iago-users/v2jJ0r1EVgQ

I have hit this before and bypassed it with skip tests when first starting to use Iago but moving into production would like to see if someone could help evaluate why this may be occuring. Full log below, this pull was from 7/7/2014.

[EnvInject] - Loading node environment variables.
Building on master in workspace /auto/jenkins-triad/onec/jenkinsData/jobs/Build_and_Install_Iago/workspace
[workspace] $ /bin/sh -xe /tmp/hudson2558274277321874614.sh


T E S T S

Running com.twitter.parrot.config.ConfigSpec
DEBUG com.twitter.parrot.util 20:40:52.186 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:53.608 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:53.902 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:54.156 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:54.395 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:54.624 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:54.856 logging to console enabled
DEBUG com.twitter.parrot.util 20:40:55.110 logging to console enabled
Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.818 sec
Running com.twitter.parrot.feeder.ParrotFeederSpec
DEBUG com.twitter.parrot.util 20:40:56.572 logging to console enabled
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.454 sec
Running com.twitter.parrot.integration.EndToEndSpec
DEBUG com.twitter.parrot.util 20:40:57.699 logging to console enabled
DEBUG org.jboss.netty.channel.socket.nio 20:40:58.385 Using select timeout of 500
DEBUG org.jboss.netty.channel.socket.nio 20:40:58.386 Epoll-bug workaround enabled = false
INFO finagle 20:40:58.425 Finagle version 6.11.1 (rev=83de11a66b498351418433bcad00cbf4b7dc495c) built at 20140122-140449
DEBUG com.twitter.parrot.server 20:40:59.164 starting RequestQueue
TRACE com.twitter.parrot.server 20:40:59.174 RequestConsumer: beginning run
TRACE com.twitter.parrot.server 20:40:59.380 created a parrot server on port 51367
INFO com.twitter.parrot.server 20:40:59.386 using record processor com.twitter.parrot.integration.TestRecordProcessor
DEBUG com.twitter.parrot.util 20:41:00.620 logging to console enabled
INFO com.twitter.parrot.feeder 20:41:00.647 Starting ParrotPoller
INFO com.twitter.parrot.util 20:41:00.654 Connecting to Parrots
INFO com.twitter.parrot.util 20:41:00.665 Connecting to parrot server at localhost:51367
INFO com.twitter.parrot.feeder 20:41:00.715 Awaiting 1 servers to stand up and be recognized.
INFO com.twitter 20:41:02.242 Context: added handler com.twitter.finagle.tracing.TraceContext
DEBUG com.twitter.parrot.feeder 20:41:02.316 pollParrot: depth is 0.000000 for localhost:51367
TRACE com.twitter.parrot.util 20:41:02.358 RemoteParrot: setting rate 1000
INFO com.twitter.parrot.server 20:41:02.372 setting rate 1000 RPS
TRACE com.twitter.parrot.util 20:41:02.399 RemoteParrot: rate set
TRACE com.twitter.parrot.util 20:41:02.402 RemoteParrot: creating consumer
TRACE com.twitter.parrot.util 20:41:02.416 RemoteParrot: consumer created
INFO com.twitter.parrot.feeder 20:41:02.416 Queue is empty for server localhost:51367
DEBUG com.twitter.parrot.feeder 20:41:02.419 Reading 20 log lines.
TRACE com.twitter.parrot.util 20:41:02.429 RemoteParrot: Queuing batch for localhost:51367 with 6 requests
TRACE com.twitter.parrot.feeder 20:41:02.429 parrot[localhost:51367] adding requests of size=6 to the queue
TRACE com.twitter.parrot.feeder 20:41:02.430 parrot[localhost:51367] added requests of size=6 to the queue
INFO com.twitter.parrot.feeder 20:41:02.430 ParrotFeeder.runLoad: exiting because log exhausted
INFO com.twitter.parrot.feeder 20:41:02.444 Lines played: 0 failed: 0
TRACE com.twitter.parrot.feeder 20:41:02.444 ParrotFeeder: shutting down ...
DEBUG com.twitter.parrot.util 20:41:02.448 ParrotClusterImpl: shutting down
TRACE com.twitter.parrot.util 20:41:03.417 RemoteParrot.sendRequest: parrot[localhost:51367] sending requests of size=6 to the server
TRACE com.twitter.parrot.server 20:41:03.458 sendRequest: calling process lines with 6 lines
TRACE com.twitter.parrot.integration 20:41:03.458 SimpleRecordProcessor.processLines: processing 6 lines
TRACE com.twitter.parrot.integration 20:41:03.478 SimpleRecordProcessor.processLines: line is about
TRACE com.twitter.parrot.integration 20:41:03.489 SimpleRecordProcessor.processLines: line is about/contact
TRACE com.twitter.parrot.integration 20:41:03.489 SimpleRecordProcessor.processLines: line is about/security
TRACE com.twitter.parrot.integration 20:41:03.489 SimpleRecordProcessor.processLines: line is tos
TRACE com.twitter.parrot.integration 20:41:03.490 SimpleRecordProcessor.processLines: line is privacy
TRACE com.twitter.parrot.integration 20:41:03.490 SimpleRecordProcessor.processLines: line is about/resources
TRACE com.twitter.parrot.server 20:41:03.490 sendRequest: done calling process lines with 6 lines
TRACE com.twitter.parrot.server 20:41:03.494 exiting sendRequest
DEBUG com.twitter.parrot.server 20:41:03.509
DEBUG com.twitter.parrot.server 20:41:03.509 ===================== HttpRequest ======================
DEBUG com.twitter.parrot.server 20:41:03.509 DefaultHttpRequest(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.509 GET about HTTP/1.1
DEBUG com.twitter.parrot.server 20:41:03.509 Host: :80
DEBUG com.twitter.parrot.server 20:41:03.509 Cookie:
DEBUG com.twitter.parrot.server 20:41:03.509 User-Agent: com.twitter.parrot
DEBUG com.twitter.parrot.server 20:41:03.509 X-Parrot: true
DEBUG com.twitter.parrot.server 20:41:03.509 X-Forwarded-For: 121.183.188.75
DEBUG com.twitter.parrot.server 20:41:03.509 ========================================================
TRACE com.twitter.parrot.util 20:41:03.525 RemoteParrot.sendRequest: parrot[localhost:51367] done sending requests of size=6 to the server
INFO com.twitter.parrot.feeder 20:41:03.539 FeedConsumer.sendRequest: wrote batch of size 6 to localhost:51367 rps=0.00000 depth=5.00000 status=Some(Running) lines=6
TRACE com.twitter.parrot.server 20:41:03.590 shutting down
DEBUG com.twitter.parrot.server 20:41:03.633
DEBUG com.twitter.parrot.server 20:41:03.633 ===================== HttpRequest ======================
DEBUG com.twitter.parrot.server 20:41:03.633 DefaultHttpRequest(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.633 GET about/contact HTTP/1.1
DEBUG com.twitter.parrot.server 20:41:03.633 Host: :80
DEBUG com.twitter.parrot.server 20:41:03.633 Cookie:
DEBUG com.twitter.parrot.server 20:41:03.633 User-Agent: com.twitter.parrot
DEBUG com.twitter.parrot.server 20:41:03.633 X-Parrot: true
DEBUG com.twitter.parrot.server 20:41:03.633 X-Forwarded-For: 242.197.45.135
DEBUG com.twitter.parrot.server 20:41:03.633 ========================================================
DEBUG com.twitter.parrot.server 20:41:03.635
DEBUG com.twitter.parrot.server 20:41:03.635 ===================== HttpRequest ======================
DEBUG com.twitter.parrot.server 20:41:03.635 DefaultHttpRequest(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.635 GET about/security HTTP/1.1
DEBUG com.twitter.parrot.server 20:41:03.635 Host: :80
DEBUG com.twitter.parrot.server 20:41:03.635 Cookie:
DEBUG com.twitter.parrot.server 20:41:03.635 User-Agent: com.twitter.parrot
DEBUG com.twitter.parrot.server 20:41:03.635 X-Parrot: true
DEBUG com.twitter.parrot.server 20:41:03.635 X-Forwarded-For: 123.201.85.51
DEBUG com.twitter.parrot.server 20:41:03.635 ========================================================
DEBUG com.twitter.parrot.server 20:41:03.639
DEBUG com.twitter.parrot.server 20:41:03.639 ===================== HttpRequest ======================
DEBUG com.twitter.parrot.server 20:41:03.639 DefaultHttpRequest(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.639 GET tos HTTP/1.1
DEBUG com.twitter.parrot.server 20:41:03.639 Host: :80
DEBUG com.twitter.parrot.server 20:41:03.639 Cookie:
DEBUG com.twitter.parrot.server 20:41:03.639 User-Agent: com.twitter.parrot
DEBUG com.twitter.parrot.server 20:41:03.639 X-Parrot: true
DEBUG com.twitter.parrot.server 20:41:03.639 X-Forwarded-For: 55.170.27.176
DEBUG com.twitter.parrot.server 20:41:03.639 ========================================================
DEBUG com.twitter.parrot.server 20:41:03.642
DEBUG com.twitter.parrot.server 20:41:03.642 ===================== HttpRequest ======================
DEBUG com.twitter.parrot.server 20:41:03.642 DefaultHttpRequest(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.642 GET privacy HTTP/1.1
DEBUG com.twitter.parrot.server 20:41:03.642 Host: :80
DEBUG com.twitter.parrot.server 20:41:03.642 Cookie:
DEBUG com.twitter.parrot.server 20:41:03.642 User-Agent: com.twitter.parrot
DEBUG com.twitter.parrot.server 20:41:03.642 X-Parrot: true
DEBUG com.twitter.parrot.server 20:41:03.642 X-Forwarded-For: 245.74.216.181
DEBUG com.twitter.parrot.server 20:41:03.642 ========================================================
DEBUG com.twitter.parrot.server 20:41:03.643
DEBUG com.twitter.parrot.server 20:41:03.643 ===================== HttpRequest ======================
DEBUG com.twitter.parrot.server 20:41:03.643 DefaultHttpRequest(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.643 GET about/resources HTTP/1.1
DEBUG com.twitter.parrot.server 20:41:03.643 Host: :80
DEBUG com.twitter.parrot.server 20:41:03.643 Cookie:
DEBUG com.twitter.parrot.server 20:41:03.643 User-Agent: com.twitter.parrot
DEBUG com.twitter.parrot.server 20:41:03.643 X-Parrot: true
DEBUG com.twitter.parrot.server 20:41:03.643 X-Forwarded-For: 149.5.79.2
DEBUG com.twitter.parrot.server 20:41:03.643 ========================================================
TRACE com.twitter.parrot.server 20:41:03.668 RequestConsumer shut down in 72.1 milliseconds
TRACE com.twitter.parrot.server 20:41:03.668 RequestQueue: shutdown
DEBUG com.twitter.parrot.server 20:41:03.739 Response: Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.739 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.server 20:41:03.739 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.server 20:41:03.739 server: tfe
DEBUG com.twitter.parrot.server 20:41:03.739 Connection: close
DEBUG com.twitter.parrot.server 20:41:03.739 Content-Length: 0)
DEBUG com.twitter.parrot.integration 20:41:03.777 response was Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.integration 20:41:03.777 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.integration 20:41:03.777 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.integration 20:41:03.777 server: tfe
DEBUG com.twitter.parrot.integration 20:41:03.777 Connection: close
DEBUG com.twitter.parrot.integration 20:41:03.777 Content-Length: 0)
DEBUG com.twitter.parrot.server 20:41:03.811 Response: Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.811 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.server 20:41:03.811 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.server 20:41:03.811 server: tfe
DEBUG com.twitter.parrot.server 20:41:03.811 Connection: close
DEBUG com.twitter.parrot.server 20:41:03.811 Content-Length: 0)
DEBUG com.twitter.parrot.integration 20:41:03.812 response was Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.integration 20:41:03.812 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.integration 20:41:03.812 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.integration 20:41:03.812 server: tfe
DEBUG com.twitter.parrot.integration 20:41:03.812 Connection: close
DEBUG com.twitter.parrot.integration 20:41:03.812 Content-Length: 0)
DEBUG com.twitter.parrot.server 20:41:03.820 Response: Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.820 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.server 20:41:03.820 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.server 20:41:03.820 server: tfe
DEBUG com.twitter.parrot.server 20:41:03.820 Connection: close
DEBUG com.twitter.parrot.server 20:41:03.820 Content-Length: 0)
DEBUG com.twitter.parrot.integration 20:41:03.820 response was Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.integration 20:41:03.820 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.integration 20:41:03.820 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.integration 20:41:03.820 server: tfe
DEBUG com.twitter.parrot.integration 20:41:03.820 Connection: close
DEBUG com.twitter.parrot.integration 20:41:03.820 Content-Length: 0)
DEBUG com.twitter.parrot.server 20:41:03.825 Response: Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.825 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.server 20:41:03.825 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.server 20:41:03.825 server: tfe
DEBUG com.twitter.parrot.server 20:41:03.825 Connection: close
DEBUG com.twitter.parrot.server 20:41:03.825 Content-Length: 0)
DEBUG com.twitter.parrot.integration 20:41:03.825 response was Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.integration 20:41:03.825 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.integration 20:41:03.825 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.integration 20:41:03.825 server: tfe
DEBUG com.twitter.parrot.integration 20:41:03.825 Connection: close
DEBUG com.twitter.parrot.integration 20:41:03.825 Content-Length: 0)
DEBUG com.twitter.parrot.server 20:41:03.827 Response: Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.server 20:41:03.827 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.server 20:41:03.827 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.server 20:41:03.827 server: tfe
DEBUG com.twitter.parrot.server 20:41:03.827 Connection: close
DEBUG com.twitter.parrot.server 20:41:03.827 Content-Length: 0)
DEBUG com.twitter.parrot.integration 20:41:03.828 response was Return(DefaultHttpResponse(chunked: false)
DEBUG com.twitter.parrot.integration 20:41:03.828 HTTP/1.1 404 Not Found
DEBUG com.twitter.parrot.integration 20:41:03.828 date: Tue, 08 Jul 2014 00:41:03 UTC
DEBUG com.twitter.parrot.integration 20:41:03.828 server: tfe
DEBUG com.twitter.parrot.integration 20:41:03.828 Connection: close
DEBUG com.twitter.parrot.integration 20:41:03.828 Content-Length: 0)
ERROR com.twitter.parrot.util 20:41:08.589 Error shutting down Parrot: com.twitter.util.TimeoutException
ERROR com.twitter.parrot.util 20:41:08.589 com.twitter.util.TimeoutException: 5.seconds
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.util.Promise.ready(Promise.scala:498)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.util.Promise.result(Promise.scala:503)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.util.Promise$Chained.result(Promise.scala:182)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.util.Await$.result(Awaitable.scala:75)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.util.Future.get(Future.scala:648)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.util.RemoteParrot.waitFor(RemoteParrot.scala:160)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.util.RemoteParrot.shutdown(RemoteParrot.scala:120)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.util.ParrotClusterImpl$$anonfun$shutdown$4.apply(ParrotCluster.scala:325)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.util.ParrotClusterImpl$$anonfun$shutdown$4.apply(ParrotCluster.scala:323)
ERROR com.twitter.parrot.util 20:41:08.589 at scala.collection.immutable.Set$Set1.foreach(Set.scala:74)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.util.ParrotClusterImpl.shutdown(ParrotCluster.scala:323)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.feeder.ParrotFeeder.shutdown(ParrotFeeder.scala:91)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.parrot.feeder.ParrotFeeder$$anonfun$start$1.apply$mcV$sp(ParrotFeeder.scala:78)
ERROR com.twitter.parrot.util 20:41:08.589 at com.twitter.ostrich.admin.BackgroundProcess$$anon$1.run(BackgroundProcess.scala:34)
TRACE com.twitter.parrot.feeder 20:41:08.594 ParrotFeeder: shut down
WARNING com.twitter.parrot.integration 20:41:26.338 EndToEndSpec: timed out in 24.0 seconds
INFO com.twitter.parrot.integration 20:41:26.338 EndToEndSpec: done waiting for the parrot server to finish. 6 lines read, 6 lines sent to victim, 5 responses back
DEBUG com.twitter.parrot.util 20:41:27.980 logging to console enabled
DEBUG com.twitter.parrot.server 20:41:27.984 starting RequestQueue
TRACE com.twitter.parrot.server 20:41:27.985 created a parrot server on port 57875
INFO com.twitter.parrot.server 20:41:27.986 using record processor com.twitter.parrot.integration.TestRecordProcessor
TRACE com.twitter.parrot.server 20:41:27.986 RequestConsumer: beginning run
DEBUG com.twitter.parrot.util 20:41:28.525 logging to console enabled
INFO com.twitter.parrot.feeder 20:41:28.526 Starting ParrotPoller
INFO com.twitter.parrot.util 20:41:28.526 Connecting to Parrots
INFO com.twitter.parrot.util 20:41:28.526 Connecting to parrot server at localhost:57875
INFO com.twitter.parrot.feeder 20:41:28.543 Awaiting 1 servers to stand up and be recognized.
ERROR com.twitter.parrot.feeder 20:41:34.533 Exception polling parrot[localhost:57875] - 5.seconds
TRACE com.twitter.parrot.util 20:41:34.534 RemoteParrot: setting rate 5
ERROR com.twitter.ostrich.admin 20:41:39.536 Spawned thread background (Thread[background,5,main]) died with a terminal exception
ERROR com.twitter.ostrich.admin 20:41:39.536 com.twitter.util.TimeoutException: 5.seconds
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.util.Promise.ready(Promise.scala:498)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.util.Promise.result(Promise.scala:503)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.util.Promise$Chained.result(Promise.scala:182)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.util.Await$.result(Awaitable.scala:75)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.util.Future.get(Future.scala:648)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.util.RemoteParrot.waitFor(RemoteParrot.scala:160)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.util.RemoteParrot.setRate(RemoteParrot.scala:89)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.feeder.ParrotFeeder.com$twitter$parrot$feeder$ParrotFeeder$$initialize(ParrotFeeder.scala:195)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.feeder.ParrotFeeder$$anonfun$com$twitter$parrot$feeder$ParrotFeeder$$runLoad$1.apply(ParrotFeeder.scala:159)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.feeder.ParrotFeeder$$anonfun$com$twitter$parrot$feeder$ParrotFeeder$$runLoad$1.apply(ParrotFeeder.scala:156)
ERROR com.twitter.ostrich.admin 20:41:39.536 at scala.collection.immutable.Set$Set1.foreach(Set.scala:74)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.feeder.ParrotFeeder.com$twitter$parrot$feeder$ParrotFeeder$$runLoad(ParrotFeeder.scala:156)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.parrot.feeder.ParrotFeeder$$anonfun$start$1.apply$mcV$sp(ParrotFeeder.scala:76)
ERROR com.twitter.ostrich.admin 20:41:39.536 at com.twitter.ostrich.admin.BackgroundProcess$$anon$1.run(BackgroundProcess.scala:34)
ERROR com.twitter.parrot.feeder 20:41:40.534 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:41:46.535 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:41:52.536 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:41:58.537 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:04.538 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:10.539 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:16.540 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:22.541 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:28.542 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:34.543 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:40.544 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:46.545 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:52.547 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:42:58.548 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:43:04.549 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:43:10.550 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:43:16.550 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:43:22.551 Exception polling parrot[localhost:57875] - 5.seconds
ERROR com.twitter.parrot.feeder 20:43:28.552 Exception polling parrot[localhost:57875] - 5.seconds
......

Unable to run echo example

when i try to run
mvn package

i get the following error
venkat@venkat-ThinkPad-E520:~/work/code/git/iago/examples/echo$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building iago-echo 1.0
[INFO] ------------------------------------------------------------------------
Downloading: http://artifactory.local.twitter.com/repo/com/twitter/maven-build-properties-plugin/0.0.2/maven-build-properties-plugin-0.0.2.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.485s
[INFO] Finished at: Thu Jul 11 01:11:07 PDT 2013
[INFO] Final Memory: 2M/61M
[INFO] ------------------------------------------------------------------------
[ERROR] Plugin com.twitter:maven-build-properties-plugin:0.0.2 or one of its dependencies could not be resolved: Failed to read artifact descriptor for com.twitter:maven-build-properties-plugin:jar:0.0.2: Could not transfer artifact com.twitter:maven-build-properties-plugin:pom:0.0.2 from/to artifactory (http://artifactory.local.twitter.com/repo): artifactory.local.twitter.com: Unknown host artifactory.local.twitter.com -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginResolutionException

it is trying to pull up from twitter internal repo

Customize parrot-server-stats.log periodicity

As per the documentation parrot-server-stats.log is a minute-by-minute dump of all the statistics. I would like to set it to something more frequent, say, 5 seconds.
I spent a little bit searching for parrot-server-stats in the codebase but all I found is the LoggerFactory construction, which didn't tell me much.
With a little more digging I found this code block which looks interesting:

var admin = AdminServiceFactory(
  adminPort,
  statsNodes = StatsFactory(
    reporters = JsonStatsLoggerFactory(
    period = 1.minute,
    serviceName = statsName) :: TimeSeriesCollectorFactory()))(runtime)

The class name looks very related, and the period matches. Although changing it did not change the periodicity. Interestingly enough, the admin variable is not used.
Am I on a wrong path?

Iago doesn't build under Windows

The issue is that the maven-finagle-thrift-plugin doesn't ship a Windows thrift executable, so the thrift bindings are impossible to generate (the error message is a very unhelpful NPE in plexus-utils trying to copy the binary out of the jar).

The work-around issue for Iago is to ship a separate thrift dependency that doesn't require people to generate thrift bindings on Windows.

Iago does not always shut down

It seems that if there are any server-under-test connection timeouts (or other errors?) then Iago will never exit.

See this for an example.

I've also tried rebuilding Iago with the latest versions of Finagle, (see this commit in my fork of Iago) but that didn't help this problem. I also tried updating some of the other Twitter packages but got compilation errors.

Unable to build (ubuntu, maven 3)

Hi, I've cloned master and attempted mvn clean install but I get a build failure object scala not found:

[INFO] Compiling 59 source files to /home/nlong/projects/iago/target/classes at 1385489310036 [ERROR] error: error while loading <root>, error in opening zip file [ERROR] error: scala.tools.nsc.MissingRequirementError: object scala not found. [INFO] at scala.tools.nsc.symtab.Definitions$definitions$.getModuleOrClass(Definitions.scala:655) [INFO] at scala.tools.nsc.symtab.Definitions$definitions$.getModule(Definitions.scala:605) [INFO] at scala.tools.nsc.symtab.Definitions$definitions$.ScalaPackage(Definitions.scala:145) [INFO] at scala.tools.nsc.symtab.Definitions$definitions$.ScalaPackageClass(Definitions.scala:146) [INFO] at scala.tools.nsc.symtab.Definitions$definitions$.AnyClass(Definitions.scala:176) [INFO] at scala.tools.nsc.symtab.Definitions$definitions$.init(Definitions.scala:814) [INFO] at scala.tools.nsc.Global$Run.<init>(Global.scala:697) [INFO] at scala.tools.nsc.Main$.process(Main.scala:105) [INFO] at scala.tools.nsc.Main$.main(Main.scala:123) [INFO] at scala.tools.nsc.Main.main(Main.scala) [INFO] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [INFO] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [INFO] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [INFO] at java.lang.reflect.Method.invoke(Method.java:606) [INFO] at scala_maven_executions.MainHelper.runMain(MainHelper.java:161) [INFO] at scala_maven_executions.MainWithArgsInFile.main(MainWithArgsInFile.java:26) [INFO] [ERROR] error: fatal error: object scala not found. [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.537s [INFO] Finished at: Tue Nov 26 18:08:30 GMT 2013 [INFO] Final Memory: 12M/302M [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal net.alchim31.maven:scala-maven-plugin:3.0.1:compile (scala-compile-first) on project iago: wrap: org.apache.commons.exec.ExecuteException: Process exited with an error: 1(Exit value: 1) -> [Help 1]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.