dcProfile := map[string]string{
"name": "Daniel Caballero",
"title": "Devops Engineer",
"mail": "dani(dot)caba at gmail(dot)com",
"company": &SchibstedPT,
"previously_at": []company{&NTTEurope, &Semantix, &Oracle},
"linkedin": http.Get("https://www.linkedin.com/in/danicaba"),
"extra": "Gestión DevOps de Arquitecturas IT@LaSalle",
}
$ cat /etc/security/limits.d/tomcat.conf
tomcat hard nofiles 10240
$ cat /etc/tomcat7/server.xml
...
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />
...
func connection_handler(id int, host string, port int, wg *sync.WaitGroup) {
fmt.Println("\t runner "+strconv.Itoa(id)+" is initiating a connection")
conn, err := net.Dial("tcp", host+":"+strconv.Itoa(port))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("\t runner "+strconv.Itoa(id)+" established the connection")
connBuf := bufio.NewReader(conn)
for{
str, err := connBuf.ReadString('\n')
if len(str)>0 {
fmt.Println(str)
}
if err!= nil {
break
}
}
fmt.Println("\t runner "+strconv.Itoa(id)+" got its connection closed")
wg.Done()
}
func run_threads(numberConnections int, delay int, host string, port int) {
runtime.GOMAXPROCS(numberConnections)
var wg sync.WaitGroup
wg.Add(numberConnections)
for runner:= 1; runner <= numberConnections ; runner++ {
fmt.Println("Initiating runner # "+strconv.Itoa(runner))
go connection_handler(runner, host, port, &wg)
time.Sleep(time.Duration(delay) * time.Millisecond)
fmt.Println("Runner "+strconv.Itoa(runner)+" initated. Remaining: "+strconv.Itoa(numberConnections-runner))
}
fmt.Println("Waiting runners to finish")
wg.Wait()
}
func main() {
hostPtr := flag.String("host", "localhost", "Host you want to open tcp connections against")
portPtr := flag.Int("port", 8888, "Port you want to open tcp connections against")
numberConnectionsPtr := flag.Int("connections", 100, "Number of connections you want to open")
delayPtr := flag.Int("delay", 10, "Number of ms you want to sleep between each connection creation")
flag.Parse()
run_threads(*numberConnectionsPtr, *delayPtr, *hostPtr, *portPtr )
fmt.Println("\nTerminating Program")
}
% ./tcpMaxConn -host ec2-54-229-56-140.eu-west-1.compute.amazonaws.com -port 8080 -connections 5
Initiating runner # 1
runner 1 is initiating a connection
Runner 1 initated. Remaining: 4
Initiating runner # 2
runner 2 is initiating a connection
Runner 2 initated. Remaining: 3
Initiating runner # 3
runner 3 is initiating a connection
Runner 3 initated. Remaining: 2
Initiating runner # 4
runner 4 is initiating a connection
Runner 4 initated. Remaining: 1
Initiating runner # 5
runner 5 is initiating a connection
Runner 5 initated. Remaining: 0
Waiting runners to finish
runner 2 established the connection
runner 1 established the connection
runner 4 established the connection
runner 3 established the connection
runner 5 established the connection
runner 2 got its connection closed
runner 1 got its connection closed
runner 4 got its connection closed
runner 5 got its connection closed
runner 3 got its connection closed
Terminating Program
No...
...is an easy job...
... but fragile.
If you break a single item, you hit the ground
Plus it may not manifest soon; you realize when:
... you are safe. Really?
Obvious, but...
Should application stress tests already cover this?
% ./tcpgoon --help
tcpgoon tests concurrent connections towards a server listening on a TCP port
Usage:
tcpgoon [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, --dial-timeout int Connection dialing timeout, in ms (default 5000)
-h, --help help for tcpgoon
-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)
-v, --verbose Print debugging information to the standard error
% ./tcpgoon myhttpsamplehost.com 80 --connections 10 --sleep 999 -y
Total: 10, Dialing: 0, Established: 0, Closed: 0, Error: 0, NotInitiated: 10
Total: 10, Dialing: 1, Established: 1, Closed: 0, Error: 0, NotInitiated: 8
Total: 10, Dialing: 1, Established: 2, Closed: 0, Error: 0, NotInitiated: 7
Total: 10, Dialing: 1, Established: 3, Closed: 0, Error: 0, NotInitiated: 6
Total: 10, Dialing: 1, Established: 4, Closed: 0, Error: 0, NotInitiated: 5
Total: 10, Dialing: 1, Established: 5, Closed: 0, Error: 0, NotInitiated: 4
Total: 10, Dialing: 1, Established: 6, Closed: 0, Error: 0, NotInitiated: 3
Total: 10, Dialing: 1, Established: 7, Closed: 0, Error: 0, NotInitiated: 2
Total: 10, Dialing: 1, Established: 8, Closed: 0, Error: 0, NotInitiated: 1
Total: 10, Dialing: 1, Established: 9, Closed: 0, Error: 0, NotInitiated: 0
Total: 10, Dialing: 0, Established: 10, Closed: 0, Error: 0, NotInitiated: 0
--- myhttpsamplehost.com:80 tcp test statistics ---
Total: 10, Dialing: 0, Established: 10, Closed: 0, Error: 0, NotInitiated: 0
Response time stats for 10 established connections min/avg/max/dev = 17.929ms/19.814ms/29.811ms/3.353ms
% echo $?
0
% tcpgoon -c 5000 -s 0 -y ec2-52-213-210-34.eu-west-1.compute.amazonaws.com 443
Total: 5000, Dialing: 0, Established: 0, Closed: 0, Error: 0, NotInitiated: 5000
Total: 5000, Dialing: 0, Established: 1020, Closed: 0, Error: 3980, NotInitiated: 0
--- ec2-52-213-210-34.eu-west-1.compute.amazonaws.com:443 tcp test statistics ---
Total: 5000, Dialing: 0, Established: 1020, Closed: 0, Error: 3980, NotInitiated: 0
Response time stats for 1020 established connections min/avg/max/dev = 116.443ms/313.739ms/549.88ms/111.426ms
Time to error stats for 3980 failed connections min/avg/max/dev = 105.145ms/145.092ms/316.247ms/39.371ms
Nothing especially interesting (a docker wrapper does exist so we can run travis logic locally):
./_script/test
./_script/formatting_checks
TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST:-""}
TRAVIS_BRANCH=${TRAVIS_BRANCH:-""}
if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" = "master" ]
then
echo "INFO: Merging to master... time to build and deploy redistributables"
docker_name="dachad/tcpgoon"
./_script/build "$docker_name"
./_script/deploy "$docker_name"
fi
But...
Are we testing this test? :)
Maybe. But goroutines do work very well in this scenario.
hping
does not work as...
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.
...
Please, do not read it as "TCP-Go-On". Its awful. Very.
Probably. Knifes are also dangerous. And you can buy knifes. We cannot prevent bad usage.
Depends on how many connections do you support in your client machine :) . No official benchmark/stress test yet, but able to open between 5k-10k without problems from my laptop.
Yes. And a public docker image is available to facilitate the job:
% WHALEBREW_INSTALL_PATH=$HOME/bin whalebrew install dachad/tcpgoon
🐳 Installed dachad/tcpgoon to /home/caba/bin/tcpgoon
% tcpgoon myhttpsamplehost.com 80 -c 2 -y
Total: 2, Dialing: 0, Established: 0, Closed: 0, Error: 0, NotInitiated: 2
Total: 2, Dialing: 0, Established: 2, Closed: 0, Error: 0, NotInitiated: 0
--- myhttpsamplehost.com:80 tcp test statistics ---
Total: 2, Dialing: 0, Established: 2, Closed: 0, Error: 0, NotInitiated: 0
Response time stats for 2 established connections min/avg/max/dev = 57.606ms/63.499ms/69.391ms/5.892ms
% echo $?
0
Not yet. Stress test ELBs is not the objective, so Service Discovery integration is required (& ongoing).