forked from Ivasoft/traefik
Compare commits
8 Commits
v1.0.alpha
...
v1.0.alpha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9830086790 | ||
|
|
8393746e02 | ||
|
|
2314ad9bf9 | ||
|
|
3af21612b6 | ||
|
|
7674a82801 | ||
|
|
d63d2a8a26 | ||
|
|
a458018aa2 | ||
|
|
33cde6aacd |
@@ -16,7 +16,7 @@ It supports several backends ([Docker :whale:](https://www.docker.com/), [Mesos/
|
||||
|
||||
## Features
|
||||
|
||||
- It's fast
|
||||
- [It's fast](docs/index.md#benchmarks)
|
||||
- No dependency hell, single binary made with go
|
||||
- Simple json Rest API
|
||||
- Simple TOML file configuration
|
||||
|
||||
167
docs/index.md
167
docs/index.md
@@ -1062,128 +1062,71 @@ Note that Træfɪk *will not watch for key changes in the `/traefik_configuratio
|
||||
|
||||
## <a id="benchmarks"></a> Benchmarks
|
||||
|
||||
Here are some early Benchmarks between Nginx and Træfɪk acting as simple load balancers between two servers.
|
||||
Here are some early Benchmarks between Nginx, HA-Proxy and Træfɪk acting as simple load balancers between two servers.
|
||||
|
||||
- Nginx:
|
||||
|
||||
```sh
|
||||
$ docker run -d -e VIRTUAL_HOST=test1.localhost emilevauge/whoami
|
||||
$ docker run -d -e VIRTUAL_HOST=test1.localhost emilevauge/whoami
|
||||
$ docker run -d -e VIRTUAL_HOST=test.nginx.localhost emilevauge/whoami
|
||||
$ docker run -d -e VIRTUAL_HOST=test.nginx.localhost emilevauge/whoami
|
||||
$ docker run --log-driver=none -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ ab -n 20000 -c 20 -r http://test1.localhost/
|
||||
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
|
||||
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
|
||||
Licensed to The Apache Software Foundation, http://www.apache.org/
|
||||
$ wrk -t12 -c400 -d60s -H "Host: test.nginx.localhost" --latency http://127.0.0.1:80
|
||||
Running 1m test @ http://127.0.0.1:80
|
||||
12 threads and 400 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 162.61ms 203.34ms 1.72s 91.07%
|
||||
Req/Sec 277.57 107.67 790.00 67.53%
|
||||
Latency Distribution
|
||||
50% 128.19ms
|
||||
75% 218.22ms
|
||||
90% 342.12ms
|
||||
99% 1.08s
|
||||
197991 requests in 1.00m, 82.32MB read
|
||||
Socket errors: connect 0, read 0, write 0, timeout 18
|
||||
Requests/sec: 3296.04
|
||||
Transfer/sec: 1.37MB
|
||||
```
|
||||
|
||||
Benchmarking test1.localhost (be patient)
|
||||
Completed 2000 requests
|
||||
Completed 4000 requests
|
||||
Completed 6000 requests
|
||||
Completed 8000 requests
|
||||
Completed 10000 requests
|
||||
Completed 12000 requests
|
||||
Completed 14000 requests
|
||||
Completed 16000 requests
|
||||
Completed 18000 requests
|
||||
Completed 20000 requests
|
||||
Finished 20000 requests
|
||||
- HA-Proxy:
|
||||
|
||||
|
||||
Server Software: nginx/1.9.2
|
||||
Server Hostname: test1.localhost
|
||||
Server Port: 80
|
||||
|
||||
Document Path: /
|
||||
Document Length: 287 bytes
|
||||
|
||||
Concurrency Level: 20
|
||||
Time taken for tests: 5.874 seconds
|
||||
Complete requests: 20000
|
||||
Failed requests: 0
|
||||
Total transferred: 8900000 bytes
|
||||
HTML transferred: 5740000 bytes
|
||||
Requests per second: 3404.97 [#/sec] (mean)
|
||||
Time per request: 5.874 [ms] (mean)
|
||||
Time per request: 0.294 [ms] (mean, across all concurrent requests)
|
||||
Transfer rate: 1479.70 [Kbytes/sec] received
|
||||
|
||||
Connection Times (ms)
|
||||
min mean[+/-sd] median max
|
||||
Connect: 0 0 0.1 0 2
|
||||
Processing: 0 6 2.4 6 35
|
||||
Waiting: 0 5 2.3 5 33
|
||||
Total: 0 6 2.4 6 36
|
||||
|
||||
Percentage of the requests served within a certain time (ms)
|
||||
50% 6
|
||||
66% 6
|
||||
75% 7
|
||||
80% 7
|
||||
90% 9
|
||||
95% 10
|
||||
98% 12
|
||||
99% 13
|
||||
100% 36 (longest request)
|
||||
```
|
||||
$ docker run -d --name web1 -e VIRTUAL_HOST=test.haproxy.localhost emilevauge/whoami
|
||||
$ docker run -d --name web2 -e VIRTUAL_HOST=test.haproxy.localhost emilevauge/whoami
|
||||
$ docker run -d -p 80:80 --link web1:web1 --link web2:web2 dockercloud/haproxy
|
||||
$ wrk -t12 -c400 -d60s -H "Host: test.haproxy.localhost" --latency http://127.0.0.1:80
|
||||
Running 1m test @ http://127.0.0.1:80
|
||||
12 threads and 400 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 158.08ms 187.88ms 1.75s 89.61%
|
||||
Req/Sec 281.33 120.47 0.98k 65.88%
|
||||
Latency Distribution
|
||||
50% 121.77ms
|
||||
75% 227.10ms
|
||||
90% 351.98ms
|
||||
99% 1.01s
|
||||
200462 requests in 1.00m, 59.65MB read
|
||||
Requests/sec: 3337.66
|
||||
Transfer/sec: 0.99MB
|
||||
```
|
||||
|
||||
- Træfɪk:
|
||||
|
||||
```sh
|
||||
docker run -d -l traefik.backend=test1 -l traefik.frontend.rule=Host -l traefik.frontend.value=test1.docker.localhost emilevauge/whoami
|
||||
docker run -d -l traefik.backend=test1 -l traefik.frontend.rule=Host -l traefik.frontend.value=test1.docker.localhost emilevauge/whoami
|
||||
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/traefik.toml -v /var/run/docker.sock:/var/run/docker.sock containous/traefik
|
||||
$ ab -n 20000 -c 20 -r http://test1.docker.localhost/
|
||||
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
|
||||
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
|
||||
Licensed to The Apache Software Foundation, http://www.apache.org/
|
||||
|
||||
Benchmarking test1.docker.localhost (be patient)
|
||||
Completed 2000 requests
|
||||
Completed 4000 requests
|
||||
Completed 6000 requests
|
||||
Completed 8000 requests
|
||||
Completed 10000 requests
|
||||
Completed 12000 requests
|
||||
Completed 14000 requests
|
||||
Completed 16000 requests
|
||||
Completed 18000 requests
|
||||
Completed 20000 requests
|
||||
Finished 20000 requests
|
||||
|
||||
|
||||
Server Software: .
|
||||
Server Hostname: test1.docker.localhost
|
||||
Server Port: 80
|
||||
|
||||
Document Path: /
|
||||
Document Length: 312 bytes
|
||||
|
||||
Concurrency Level: 20
|
||||
Time taken for tests: 6.545 seconds
|
||||
Complete requests: 20000
|
||||
Failed requests: 0
|
||||
Total transferred: 8600000 bytes
|
||||
HTML transferred: 6240000 bytes
|
||||
Requests per second: 3055.60 [#/sec] (mean)
|
||||
Time per request: 6.545 [ms] (mean)
|
||||
Time per request: 0.327 [ms] (mean, across all concurrent requests)
|
||||
Transfer rate: 1283.11 [Kbytes/sec] received
|
||||
|
||||
Connection Times (ms)
|
||||
min mean[+/-sd] median max
|
||||
Connect: 0 0 0.2 0 7
|
||||
Processing: 1 6 2.2 6 22
|
||||
Waiting: 1 6 2.1 6 21
|
||||
Total: 1 7 2.2 6 22
|
||||
|
||||
Percentage of the requests served within a certain time (ms)
|
||||
50% 6
|
||||
66% 7
|
||||
75% 8
|
||||
80% 8
|
||||
90% 9
|
||||
95% 10
|
||||
98% 11
|
||||
99% 13
|
||||
100% 22 (longest request)
|
||||
$ docker run -d -l traefik.backend=test1 -l traefik.frontend.rule=Host -l traefik.frontend.value=test.traefik.localhost emilevauge/whoami
|
||||
$ docker run -d -l traefik.backend=test1 -l traefik.frontend.rule=Host -l traefik.frontend.value=test.traefik.localhost emilevauge/whoami
|
||||
$ docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/traefik.toml -v /var/run/docker.sock:/var/run/docker.sock containous/traefik
|
||||
$ wrk -t12 -c400 -d60s -H "Host: test.traefik.localhost" --latency http://127.0.0.1:80
|
||||
Running 1m test @ http://127.0.0.1:80
|
||||
12 threads and 400 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 132.93ms 121.89ms 1.20s 66.62%
|
||||
Req/Sec 280.95 104.88 740.00 68.26%
|
||||
Latency Distribution
|
||||
50% 128.71ms
|
||||
75% 214.15ms
|
||||
90% 281.45ms
|
||||
99% 498.44ms
|
||||
200734 requests in 1.00m, 80.02MB read
|
||||
Requests/sec: 3340.13
|
||||
Transfer/sec: 1.33MB
|
||||
```
|
||||
|
||||
@@ -35,6 +35,27 @@ type KvTLS struct {
|
||||
InsecureSkipVerify bool
|
||||
}
|
||||
|
||||
func (provider *Kv) watchKv(configurationChan chan<- types.ConfigMessage, prefix string) {
|
||||
for {
|
||||
chanKeys, err := provider.kvclient.WatchTree(provider.Prefix, make(chan struct{}) /* stop chan */)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to WatchTree %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for range chanKeys {
|
||||
configuration := provider.loadConfig()
|
||||
if configuration != nil {
|
||||
configurationChan <- types.ConfigMessage{
|
||||
ProviderName: string(provider.storeType),
|
||||
Configuration: configuration,
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Warnf("Intermittent failure to WatchTree KV. Retrying.")
|
||||
}
|
||||
}
|
||||
|
||||
func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage) error {
|
||||
storeConfig := &store.Config{
|
||||
ConnectionTimeout: 30 * time.Second,
|
||||
@@ -80,24 +101,7 @@ func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage) error
|
||||
}
|
||||
provider.kvclient = kv
|
||||
if provider.Watch {
|
||||
stopCh := make(chan struct{})
|
||||
chanKeys, err := kv.WatchTree(provider.Prefix, stopCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
<-chanKeys
|
||||
configuration := provider.loadConfig()
|
||||
if configuration != nil {
|
||||
configurationChan <- types.ConfigMessage{
|
||||
ProviderName: string(provider.storeType),
|
||||
Configuration: configuration,
|
||||
}
|
||||
}
|
||||
defer close(stopCh)
|
||||
}
|
||||
}()
|
||||
go provider.watchKv(configurationChan, provider.Prefix)
|
||||
}
|
||||
configuration := provider.loadConfig()
|
||||
configurationChan <- types.ConfigMessage{
|
||||
|
||||
@@ -2,8 +2,10 @@ package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/containous/traefik/types"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/libkv/store"
|
||||
"reflect"
|
||||
@@ -231,10 +233,60 @@ func TestKvLast(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type KvMock struct {
|
||||
Kv
|
||||
}
|
||||
|
||||
func (provider *KvMock) loadConfig() *types.Configuration {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestKvWatchTree(t *testing.T) {
|
||||
returnedChans := make(chan chan []*store.KVPair)
|
||||
provider := &KvMock{
|
||||
Kv{
|
||||
kvclient: &Mock{
|
||||
WatchTreeMethod: func() <-chan []*store.KVPair {
|
||||
c := make(chan []*store.KVPair, 10)
|
||||
returnedChans <- c
|
||||
return c
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
configChan := make(chan types.ConfigMessage)
|
||||
go provider.watchKv(configChan, "prefix")
|
||||
|
||||
select {
|
||||
case c1 := <-returnedChans:
|
||||
c1 <- []*store.KVPair{}
|
||||
<-configChan
|
||||
close(c1) // WatchTree chans can close due to error
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("Failed to create a new WatchTree chan")
|
||||
}
|
||||
|
||||
select {
|
||||
case c2 := <-returnedChans:
|
||||
c2 <- []*store.KVPair{}
|
||||
<-configChan
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("Failed to create a new WatchTree chan")
|
||||
}
|
||||
|
||||
select {
|
||||
case _ = <-configChan:
|
||||
t.Fatalf("configChan should be empty")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// Extremely limited mock store so we can test initialization
|
||||
type Mock struct {
|
||||
Error bool
|
||||
KVPairs []*store.KVPair
|
||||
Error bool
|
||||
KVPairs []*store.KVPair
|
||||
WatchTreeMethod func() <-chan []*store.KVPair
|
||||
}
|
||||
|
||||
func (s *Mock) Put(key string, value []byte, opts *store.WriteOptions) error {
|
||||
@@ -269,7 +321,7 @@ func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair,
|
||||
|
||||
// WatchTree mock
|
||||
func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
|
||||
return nil, errors.New("WatchTree not supported")
|
||||
return s.WatchTreeMethod(), nil
|
||||
}
|
||||
|
||||
// NewLock mock
|
||||
|
||||
@@ -31,6 +31,7 @@ git push --follow-tags -u origin master
|
||||
|
||||
# create docker image emilevauge/traefik (compatibility)
|
||||
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||
docker tag containous/traefik emilevauge/traefik:latest
|
||||
docker push emilevauge/traefik:latest
|
||||
docker tag emilevauge/traefik:latest emilevauge/traefik:${VERSION}
|
||||
docker push emilevauge/traefik:${VERSION}
|
||||
|
||||
Reference in New Issue
Block a user