Skip to content

Commit 698d5d5

Browse files
github-vincent-miszczakbzed
authored andcommitted
add rate limiter
1 parent 7292ed6 commit 698d5d5

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ Usage of ./whisper-to-graphite:
1818
Hostname/IP of the graphite server (default "127.0.0.1")
1919
-port int
2020
graphite Port (default 2003)
21+
-pps int
22+
Number of maximum points per second to send (0 means rate limiter is disabled)
2123
-protocol string
2224
Protocol to use to transfer graphite data (tcp/udp/nop) (default "tcp")
2325
-workers int
24-
Workers to run in parallel (default 5)
26+
Workers to run in parallel (default 5)
27+
2528
```
2629

2730
Assuming you don't want to use this as testcase for your IO subsystem,

dump.go

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,65 @@ package main
33
import (
44
"errors"
55
"flag"
6-
"github.com/bzed/go-whisper"
7-
"github.com/marpaia/graphite-golang"
86
"log"
97
"math"
108
"os"
119
"path/filepath"
1210
"strconv"
1311
"strings"
1412
"sync"
13+
"time"
14+
15+
"github.com/bzed/go-whisper"
16+
"github.com/marpaia/graphite-golang"
1517
)
1618

19+
type rateLimiter struct {
20+
pointsPerSecond int64
21+
currentPoints int64
22+
full chan bool
23+
lock *sync.Mutex
24+
enabled bool
25+
}
26+
27+
func newRateLimiter(pointsPerSecond int64) *rateLimiter {
28+
rl := new(rateLimiter)
29+
rl.pointsPerSecond = pointsPerSecond
30+
rl.currentPoints = 0
31+
rl.full = make(chan bool)
32+
rl.lock = new(sync.Mutex)
33+
if pointsPerSecond == 0 {
34+
rl.enabled = false
35+
} else {
36+
rl.enabled = true
37+
go func() {
38+
for {
39+
time.Sleep(1 * time.Second)
40+
select {
41+
case <-rl.full:
42+
default:
43+
}
44+
}
45+
}()
46+
return rl
47+
}
48+
return rl
49+
}
50+
51+
func (rl *rateLimiter) limit(n int64) {
52+
if !rl.enabled {
53+
return
54+
}
55+
rl.lock.Lock()
56+
defer rl.lock.Unlock()
57+
58+
rl.currentPoints += n
59+
if rl.currentPoints >= rl.pointsPerSecond {
60+
rl.full <- true
61+
rl.currentPoints = 0
62+
}
63+
}
64+
1765
func convertFilename(filename string, baseDirectory string) (string, error) {
1866
absFilename, err := filepath.Abs(filename)
1967
if err != nil {
@@ -48,6 +96,7 @@ func sendWhisperData(
4896
graphiteConn *graphite.Graphite,
4997
fromTs int,
5098
toTs int,
99+
rateLimiter *rateLimiter,
51100
) error {
52101
metricName, err := convertFilename(filename, baseDirectory)
53102
if err != nil {
@@ -75,6 +124,7 @@ func sendWhisperData(
75124
metrics = append(metrics, graphite.NewMetric(metricName, v, int64(interval)))
76125

77126
}
127+
rateLimiter.limit(int64(len(metrics)))
78128
err = graphiteConn.SendMetrics(metrics)
79129
if err != nil {
80130
return err
@@ -107,8 +157,8 @@ func worker(ch chan string,
107157
graphitePort int,
108158
graphiteProtocol string,
109159
fromTs int,
110-
toTs int) {
111-
160+
toTs int,
161+
rateLimiter *rateLimiter) {
112162
defer wg.Done()
113163

114164
graphiteConn, err := graphite.GraphiteFactory(graphiteProtocol, graphiteHost, graphitePort, "")
@@ -121,7 +171,7 @@ func worker(ch chan string,
121171
case path := <-ch:
122172
{
123173

124-
err := sendWhisperData(path, baseDirectory, graphiteConn, fromTs, toTs)
174+
err := sendWhisperData(path, baseDirectory, graphiteConn, fromTs, toTs, rateLimiter)
125175
if err != nil {
126176
log.Println("Failed: " + path)
127177
log.Println(err)
@@ -170,6 +220,10 @@ func main() {
170220
"to",
171221
2147483647,
172222
"Ending timestamp to dump data up to")
223+
pointsPerSecond := flag.Int64(
224+
"pps",
225+
0,
226+
"Number of maximum points per second to send (0 means rate limiter is disabled)")
173227
flag.Parse()
174228

175229
if !(*graphiteProtocol == "tcp" ||
@@ -181,9 +235,10 @@ func main() {
181235
quit := make(chan int)
182236
var wg sync.WaitGroup
183237

238+
rl := newRateLimiter(*pointsPerSecond)
184239
wg.Add(*workers)
185240
for i := 0; i < *workers; i++ {
186-
go worker(ch, quit, &wg, *baseDirectory, *graphiteHost, *graphitePort, *graphiteProtocol, *fromTs, *toTs)
241+
go worker(ch, quit, &wg, *baseDirectory, *graphiteHost, *graphitePort, *graphiteProtocol, *fromTs, *toTs, rl)
187242
}
188243
go findWhisperFiles(ch, quit, *directory)
189244
wg.Wait()

0 commit comments

Comments
 (0)