Skip to content

Commit 80f6edd

Browse files
author
Benjamin M. Schwartz
authored
Merge pull request #56 from Jigsaw-Code/bemasc-metrics-bench
Add benchmarks for the metrics functions
2 parents f6622da + 3376a68 commit 80f6edd

File tree

6 files changed

+123
-6
lines changed

6 files changed

+123
-6
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "metrics/test-data"]
2+
path = third_party/maxmind
3+
url = https://github.com/maxmind/MaxMind-DB.git

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,16 @@ Run the iperf3 client tests listed above on port 10002.
108108

109109
You can mix and match the libev and go servers and clients.
110110

111-
## Benchmark
111+
## Tests and Benchmarks
112+
113+
Before running tests, you should first run
114+
```
115+
git submodule update --init
116+
```
117+
to download test data used by the GeoIP metrics tests. To run all tests, you can use
118+
```
119+
go test -v ./...
120+
```
112121

113122
You can benchmark the cipher finding code with
114123
```

metrics/metrics.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ type shadowsocksMetrics struct {
6363
udpRemovedNatEntries prometheus.Counter
6464
}
6565

66-
func NewShadowsocksMetrics(ipCountryDB *geoip2.Reader) ShadowsocksMetrics {
67-
m := &shadowsocksMetrics{
66+
func newShadowsocksMetrics(ipCountryDB *geoip2.Reader) *shadowsocksMetrics {
67+
return &shadowsocksMetrics{
6868
ipCountryDB: ipCountryDB,
6969
accessKeys: prometheus.NewGauge(prometheus.GaugeOpts{
7070
Namespace: "shadowsocks",
@@ -130,8 +130,16 @@ func NewShadowsocksMetrics(ipCountryDB *geoip2.Reader) ShadowsocksMetrics {
130130
Help: "Entries removed from the UDP NAT table",
131131
}),
132132
}
133+
}
134+
135+
// NewPrometheusShadowsocksMetrics constructs a metrics object that uses
136+
// `ipCountryDB` to convert IP addresses to countries, and reports all
137+
// metrics to Prometheus via `registerer`. `ipCountryDB` may be nil, but
138+
// `registerer` must not be.
139+
func NewPrometheusShadowsocksMetrics(ipCountryDB *geoip2.Reader, registerer prometheus.Registerer) ShadowsocksMetrics {
140+
m := newShadowsocksMetrics(ipCountryDB)
133141
// TODO: Is it possible to pass where to register the collectors?
134-
prometheus.MustRegister(m.accessKeys, m.ports, m.tcpOpenConnections, m.tcpProbes, m.tcpClosedConnections, m.tcpConnectionDurationMs,
142+
registerer.MustRegister(m.accessKeys, m.ports, m.tcpOpenConnections, m.tcpProbes, m.tcpClosedConnections, m.tcpConnectionDurationMs,
135143
m.dataBytes, m.timeToCipherMs, m.udpAddedNatEntries, m.udpRemovedNatEntries)
136144
return m
137145
}

metrics/metrics_test.go

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package metrics
22

33
import (
4+
"net"
45
"testing"
56
"time"
7+
8+
geoip2 "github.com/oschwald/geoip2-golang"
9+
"github.com/prometheus/client_golang/prometheus"
610
)
711

812
func TestMethodsDontPanic(t *testing.T) {
9-
ssMetrics := NewShadowsocksMetrics(nil)
13+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewPedanticRegistry())
1014
proxyMetrics := ProxyMetrics{
1115
ClientProxy: 1,
1216
ProxyTarget: 2,
@@ -22,3 +26,94 @@ func TestMethodsDontPanic(t *testing.T) {
2226
ssMetrics.AddUDPNatEntry()
2327
ssMetrics.RemoveUDPNatEntry()
2428
}
29+
30+
func BenchmarkGetLocation(b *testing.B) {
31+
var ipCountryDB *geoip2.Reader
32+
// The test data is in a git submodule that must be initialized before running the test.
33+
dbPath := "../third_party/maxmind/test-data/GeoIP2-Country-Test.mmdb"
34+
ipCountryDB, err := geoip2.Open(dbPath)
35+
if err != nil {
36+
b.Fatalf("Could not open geoip database at %v: %v", dbPath, err)
37+
}
38+
defer ipCountryDB.Close()
39+
40+
ssMetrics := NewPrometheusShadowsocksMetrics(ipCountryDB, prometheus.NewRegistry())
41+
testIP := net.ParseIP("217.65.48.1")
42+
testAddr := &net.TCPAddr{IP: testIP, Port: 12345}
43+
b.ResetTimer()
44+
// Repeatedly check the country for the same address. This is realistic, because
45+
// servers call this method for each new connection, but typically many connections
46+
// come from a single user in succession.
47+
for i := 0; i < b.N; i++ {
48+
ssMetrics.GetLocation(testAddr)
49+
}
50+
}
51+
52+
func BenchmarkOpenTCP(b *testing.B) {
53+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewRegistry())
54+
b.ResetTimer()
55+
for i := 0; i < b.N; i++ {
56+
ssMetrics.AddOpenTCPConnection("ZZ")
57+
}
58+
}
59+
60+
func BenchmarkCloseTCP(b *testing.B) {
61+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewRegistry())
62+
clientLocation := "ZZ"
63+
accessKey := "key 1"
64+
status := "OK"
65+
data := ProxyMetrics{}
66+
timeToCipher := time.Microsecond
67+
duration := time.Minute
68+
b.ResetTimer()
69+
for i := 0; i < b.N; i++ {
70+
ssMetrics.AddClosedTCPConnection(clientLocation, accessKey, status, data, timeToCipher, duration)
71+
}
72+
}
73+
74+
func BenchmarkProbe(b *testing.B) {
75+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewRegistry())
76+
clientLocation := "ZZ"
77+
status := "ERR_REPLAY"
78+
drainResult := "other"
79+
port := 12345
80+
data := ProxyMetrics{}
81+
b.ResetTimer()
82+
for i := 0; i < b.N; i++ {
83+
ssMetrics.AddTCPProbe(clientLocation, status, drainResult, port, data)
84+
}
85+
}
86+
87+
func BenchmarkClientUDP(b *testing.B) {
88+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewRegistry())
89+
clientLocation := "ZZ"
90+
accessKey := "key 1"
91+
status := "OK"
92+
size := 1000
93+
timeToCipher := time.Microsecond
94+
b.ResetTimer()
95+
for i := 0; i < b.N; i++ {
96+
ssMetrics.AddUDPPacketFromClient(clientLocation, accessKey, status, size, size, timeToCipher)
97+
}
98+
}
99+
100+
func BenchmarkTargetUDP(b *testing.B) {
101+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewRegistry())
102+
clientLocation := "ZZ"
103+
accessKey := "key 1"
104+
status := "OK"
105+
size := 1000
106+
b.ResetTimer()
107+
for i := 0; i < b.N; i++ {
108+
ssMetrics.AddUDPPacketFromTarget(clientLocation, accessKey, status, size, size)
109+
}
110+
}
111+
112+
func BenchmarkNAT(b *testing.B) {
113+
ssMetrics := NewPrometheusShadowsocksMetrics(nil, prometheus.NewRegistry())
114+
b.ResetTimer()
115+
for i := 0; i < b.N; i++ {
116+
ssMetrics.AddUDPNatEntry()
117+
ssMetrics.RemoveUDPNatEntry()
118+
}
119+
}

server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
3333
"github.com/op/go-logging"
3434
"github.com/oschwald/geoip2-golang"
35+
"github.com/prometheus/client_golang/prometheus"
3536
"github.com/prometheus/client_golang/prometheus/promhttp"
3637
"github.com/shadowsocks/go-shadowsocks2/core"
3738
"github.com/shadowsocks/go-shadowsocks2/shadowaead"
@@ -246,7 +247,7 @@ func main() {
246247
}
247248
defer ipCountryDB.Close()
248249
}
249-
m := metrics.NewShadowsocksMetrics(ipCountryDB)
250+
m := metrics.NewPrometheusShadowsocksMetrics(ipCountryDB, prometheus.DefaultRegisterer)
250251
err = runSSServer(flags.ConfigFile, flags.natTimeout, m, flags.replayHistory)
251252
if err != nil {
252253
logger.Fatal(err)

third_party/maxmind

Submodule maxmind added at d7d482e

0 commit comments

Comments
 (0)