Giter VIP home page Giter VIP logo

tcpgoon's Introduction

tcpgoon

tcpgoon

Codacy Badge Build Status Go Report Card Coverage Status License

TLDR . Description . Usage . Execution using Docker . Installation . Help . Examples . Extra project information . Why do I want to test TCP connections? . Where does the project name come from? . Authors . Especial thanks to... . Development information . TO-DO . Project structure . README maintenance . Testing locally .

TL;DR

Tool to test concurrent connections towards a server listening to a TCP port

Description

  • Given a hostname, port, the number of connections (100 by default), a delay between connections (10ms by default) and an interval between stats updates to the standard output...
  • It will use goroutines to open TCP connections and try to read from them
  • The tool will exit once all connections have been dialed (successfully or not)
  • Exit status different from 0 represent executions where all connections were not established successfully, facilitating the integration in test suites.

Usage

Execution using Docker

See our public docker image and its documentation. The image is being updated continuously; you can bind to specific versions, or to the "latest" tag.

Installation

% go get github.com/dachad/tcpgoon

Help

% tcpgoon --help
tcpgoon tests concurrent connections towards a server listening on a TCP port

Usage:
  tcpgoon [command]

Available Commands:
  help        Help about any command
  run         Run tcpgoon test
  version     Show tcpgoon version

Flags:
  -h, --help   help for tcpgoon

Use "tcpgoon [command] --help" for more information about a command.
% tcpgoon run --help
Run tcpgoon test

Usage:
  tcpgoon run [flags] <host> <port>

Flags:
  -y, --assume-yes         Force execution without asking for confirmation
  -c, --connections int    Number of connections you want to open (default 100)
  -d, --debug              Print debugging information to the standard error
  -t, --dial-timeout int   Connection dialing timeout, in ms (default 5000)
  -h, --help               help for run
  -i, --interval int       Interval, in seconds, between stats updates (default 1)
  -s, --sleep int          Time you want to sleep between connections, in ms (default 10)

Examples

Note: depending on the number of connections you want to open, you may need to increase the number of file descriptors your user supports

Successful execution (connections were opened as expected):

% tcpgoon run myhttpsamplehost.com 80 --connections 4 --sleep 999 -y
Total: 4, Dialing: 0, Established: 0, Closed: 0, Error: 0, NotInitiated: 4
Total: 4, Dialing: 1, Established: 1, Closed: 0, Error: 0, NotInitiated: 2
Total: 4, Dialing: 1, Established: 2, Closed: 0, Error: 0, NotInitiated: 1
Total: 4, Dialing: 1, Established: 3, Closed: 0, Error: 0, NotInitiated: 0
Total: 4, Dialing: 0, Established: 4, Closed: 0, Error: 0, NotInitiated: 0
--- myhttpsamplehost.com(216.58.201.131):80 tcp test statistics ---
Total: 4, Dialing: 0, Established: 4, Closed: 0, Error: 0, NotInitiated: 0
--- tcpgoon execution statistics ---
Total established connections: 4
Max concurrent established connections: 4
Number of established connections on closure: 4
Response time stats for 4 successful connections min/avg/max/dev = 49.892ms/50.205ms/50.74ms/319µs

% echo $?
0

Unsuccessful execution (unable to open connections against the destination host:port):

% tcpgoon run myhttpsamplehost.com 81 --connections 4 --sleep 999 -t 1 -y
Total: 4, Dialing: 0, Established: 0, Closed: 0, Error: 0, NotInitiated: 4
Total: 4, Dialing: 1, Established: 0, Closed: 0, Error: 1, NotInitiated: 2
Total: 4, Dialing: 0, Established: 0, Closed: 0, Error: 3, NotInitiated: 1
Total: 4, Dialing: 0, Established: 0, Closed: 0, Error: 4, NotInitiated: 0
Total: 4, Dialing: 0, Established: 0, Closed: 0, Error: 4, NotInitiated: 0
--- myhttpsamplehost.com(216.58.201.131):81 tcp test statistics ---
Total: 4, Dialing: 0, Established: 0, Closed: 0, Error: 4, NotInitiated: 0
--- tcpgoon execution statistics ---
Total established connections: 0
Max concurrent established connections: 0
Number of established connections on closure: 0
Time to error stats for 4 failed connections min/avg/max/dev = 1ms/1.122ms/1.165ms/37µs

% echo $?
2

Extra project information

Why do I want to test TCP connections?

Stressing TCP connections against a server/application facilitates the detection of bottlenecks/issues limiting the capacity of this server/application to accept/keep a specific (and potentially) large number of parallel connections. Some examples of typical (configuration) issues:

  • OS configuration (TCP backlog, network drivers buffers),
  • number of file descriptors/processes the server can use,
  • application listener properties...

These limitations may pass unnoticed in actual application-l7 stress tests, given other bottlenecks can arise earlier than these limitations, or degradation scenarios and/or special conditions may not be reproduced during the stress tests execution, but in real life (lots of connections queued because of a dependency taking longer to reply than it usually does?)

hping is not an actual option for this use case given it won't complete a 3-way handshake, so the connection will not reach the accept() syscall of your server/application or fill up your TCP backlog.

Where does the project name come from?

Goon: /ɡuːn/ noun informal; noun: goon; plural noun: goons ;
...
2.
NORTH AMERICAN
a bully or thug, especially a member of an armed or security force.
...

thegoon

Authors

Especial thanks to...

Development information

TO-DO

We do use Github issues to track bugs, improvements and feature requests. Do not hesitate to raise new ones, or solve them for us by raising PRs ;)

Project structure

This project uses a layered topology, where cmd (complemented by cmdutil) takes care of commands/flags/arguments and uses mtcpclient, which owns and knows everything about "multiple TCP connections" (including reporting), while tcpclient only cares about managing single TCP connections. tcpserver is just there as a dependency for the other packages' tests.

A shared package (debugging) is also supplied just as a basic mechanism to control debug output.

README maintenance

Do not edit README.md directly, as your changes will be lost. Consider README.src.md and the execution (requires godepgraph and Graphviz) of:

% ./_script/readme_generator

Samples injected in the readme can be found in the _script/readme_generator_samples/ directory.

Dockerhub README requires manual maintenance, bringing relevant aspects from here and adapting cmdusage (by docker run...)

Testing locally

You can use the standard go test command, or use our scripts we also run as CI.

Main tests execution:

% ./_script/test

Emulation of a travis job execution using docker (of course, it needs docker):

% COVERALLS_TOKEN="myToken" ./_script/cibuild-docker

And also emulating a travis job deployment (it publishes new binaries providing successful tests and the right credentials, unless you also use the -r flag / dry-run):

% COVERALLS_TOKEN="myToken" ./_script/cibuild-docker -d

tcpgoon's People

Contributors

chadell avatar codacy-badger avatar dcaba 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

tcpgoon's Issues

flags improvements

I think we can improve how we recover arguments:

As, I think a milestone for this project, is to create debian/rpm packages and a docker image, and allow users to use this tool as any other you may have in your OS, and the default flags in golang are not posix compliant plus they dont support "short letters"...

Benchmark the solution...

... so we can provide some expectations in the README about max tcp connections we can test in a single instance

Default output should show summarized stats that auto-refresh

Provide "live stats" of the number of threads and the status of each connection (using channels? being refreshed every second [configurable]) rather than each thread informing its status (thats just for debug - too close to the implementation)

Coverage reporting, analysis and integration with PRs

As codacy is not progressing with bringing complete golang support (so its not monitoring and reporting code coverage for us, but out travis job), it'd be nice to consider the addition of coveralls (or maybe another?), that could run in parallel and also brings github integration (free for opensource projects). See http://docs.coveralls.io/go

Error management improvements

And retries should be configurable:

  • it may depend on how we are running the tool (in the mode of "open and keep X connections open", retrying makes sense. In the mode of "try to open up to X connections" it may not have sense)

First service discovery integration to pick one instance/IP - Eureka

In order to facilitate the consumption for services not statially tied to a single DNS (or maybe behind a load balancer we don't want to test), discovering and testing an individual instance from a service discovery would be great. Starting by eureka without auth will unlock its usage in Sch

@chadell , I'll take care if you don't mind

New execution modes?

Or just extra behavior that can be configured just with extra flags?

  • current mode with extra options in regards to connections closure-policy?
  • open up to X concurrent connections (keeping the old ones), but in less than X seconds (and retrying failed ones)
  • "open X connections per second" (keeping previous?) until one fails, so find the actual limit

We should start by creating a proposal of new "options/commands", comparing against just extending what we have, and see which ones looks cleaner/easier to understand..

Continuous integration / tests

It'd be nice to cover:

  • continuous unit testing
  • end to end tests against a tcp server (skeleton included), checking different conditions, and probably wrapping this with docker would be easier to maintain

Using travis would be nice!!

README autoupdater?

Some sections of the README (help, examples...) require update everytime we do map new functionality to the cmd flags... maybe we can create a test that, given a README.src skeleton appends the output of running the latest version of tcpgoon automatically in the right sections (markers may be needed) to generate the final README.md

User confirmation not properly processed when run as a container

When running tcpgoon in a container, the user confirmation is not properly processed:

****************************** WARNING ******************************
* You are going to run a TCP stress check with these arguments:
*	- Host: www.google.com
*	- TCP Port: 80
*	- # of concurrent connections: 5
*********************************************************************
Do you want to continue? (y/N): Response not processed```

Handle partial successful execution

We should be able to deal with executions that get partial success due several reasons (stressed server?) and present propers metrics and report.

Are the wait group we use in the tcpconnect and the closureMonitor overlapping?

In one hand, we have a tcpconnect function that supports a waitgroup to report how many connections have been processed, so they can be called inside goroutines and allow the caller to know when everything finished. Now we just decrease the waitgroup when a connection becomes closed. On the other hand, we have an external closure routine that monitors the status of connections and, with the current logic, once everything has progressed to established or errored, closes the program. I never liked this external monitor; this means delay and continuous polling...

The point is then... should we consolidate this in a single approach? Probably making the wg logic smarter, and consider a configurable "termination" policy, would be great.

This issue can be integrated with the new execution modes just as a consideration when implementing configurable termination policies.

Closure logic

The current version of this program:

  • tries to open as many connections as requested
  • keeps the connections open unless the other end closes the connections (normally by timeout) or refuses the connections
  • and, only when all connections are closed or errored, the program finishes

We should think about a better termination logic. Maybe:

  • a flag stating the number of seconds we want to keep each single connection open before forcing a closure in our end
  • or, maybe we can just start by: keep the program running until all connections are in the state "closed, errored or established", so there's no connections waiting to be dialed or dialing. When the program finishes, print a final report with some stats, including how long it took to reach this desired state.

In this stage, I'd bet for the second option

Per connection metrics and some stats in final report

Collecting the time it required an specific connection to dial (so until it becomes effectively established) its a nice metric, we could collect per metric (and incorporate this to the struct representing each connection status?), output it when debug is enabled, but in the normal one, just provide some summaries in the final report (as ping does), with avg/mean/dev...

Find a new project name

we shall find a better project name and binary name.
tcpMaxConn overlaps with a SNMP MIB object: {1 (iso). 3 (org). 6 (dod). 1 (internet). 2 (mgmt). 1 (mib-2). 6 (tcp). 4 (tcpMaxConn)}

Security check before execute

Because it's execution could became something like a SYN flood DoS, it would be great to show what's gonna do the program before just doing it.
Something like showing the parameters of the execution.
This behaviour could be avoided by using a -f / --force option when calling it

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.