3

I have a golang utility that uploads a lot of data via https to OpenStack Object Storage. I'm running it on Ubuntu Linux, and I would like to ensure that its maximum upload bandwidth does not exceed 2,500KB/s, preferably without affecting other users on the same system (i.e. slowing down the ethernet interface).

How can I do this, preferably without altering my source code? I've tried a few approaches so far:

  1. Traffic Shaping: I've been unable to figure out the appropriate network shaping techniques to affect a single process, though I know that should be possible with iptables and tc. Any guidance on how to do this would be appreciated. My networking background isn't very extensive.
  2. Flowrate Limiting: I tried using the flowrate package in go to rate-limit my writes to the upload. This didn't have any discernable effect. I think this doesn't work because the github.com/ncw/swift.ObjectCreateFile.Write() method doesn't upload the data as it is recieved, but rather when it is closed. I could be mistaken about this though.
  3. trickle: I tried the trickle command, but it isn't compatible with golang executables (see this question)
Community
  • 1
  • 1
  • Maybe look into [ionice](https://linux.die.net/man/1/ionice) – Basile Starynkevitch Nov 02 '16 at 20:39
  • ionice would work if the machine that I'm running on were the only machine on the network. As it is, I don't want to flood the network with traffic. I know that there are network balancing solutions that could handle that end, but those aren't an option for me. I need to constrain my usage, rather than my io priority. That being said, ionice would be a great fit under different constraints. – Christopher Waldon Nov 02 '16 at 21:13
  • perhaps try `import "C"` to trigger dynamic linking? This http://blog.hashbangbash.com/2014/04/linking-golang-statically/ shows an example and how libc is then linked in - perhaps trickle would work then. – danmux Nov 03 '16 at 01:26
  • @danmux It'd be nice if that worked, but [this answer](http://stackoverflow.com/a/40387514/7106084) explains why it doesn't. Thanks for the suggestion though. – Christopher Waldon Nov 03 '16 at 02:08
  • What about reverse proxy? – Tinwor Nov 03 '16 at 07:04
  • 1
    Check out this answer: http://stackoverflow.com/questions/27187617/how-would-i-limit-upload-and-download-speed-from-the-server-in-golang – Nebril Nov 03 '16 at 11:07
  • @Tinwor Reverse proxy is possible, but my application isn't a webserver. It's a CLI utility. I'd need to remap every domain that my util needs to talk to through the proxy (or that's how I think it would work). That feels like a fragile solution, and it also requires a lot of system configuration. That being said, I'll probably try it later today. Thanks! – Christopher Waldon Nov 03 '16 at 11:59
  • 1
    @Nebril I used the flowrate package to achieve the same thing, but it didn't help because I'm too abstracted from the upload. I'm using the `github.com/ncw/swift` library for the upload, which isn't exposing the actual HTTP requests. It gives me an `io.WriteCloser` that I can write the data into, but I think it waits for me to call `Close()` for it to perform the upload. Since it waits, rate-limiting writing into that interface doesn't help, which is why I'm looking for a solution external to my code. – Christopher Waldon Nov 03 '16 at 13:49
  • @ChristopherWaldon: the swift [`Connection`](https://godoc.org/github.com/ncw/swift#Connection) uses and http.RoundTripper as the Transport, which means that you have full access to wrap the underlying network connection as needed. – JimB Nov 03 '16 at 16:57

2 Answers2

2

It turns out that you can wrap the Golang process in a Docker container and then rate-limit the Docker container's network interface (from inside of the container) with the tc utility. See this answer for an example Dockerfile to do just that.

Community
  • 1
  • 1
1

If you can control how you actually run the utility, you can use trickle

sudo apt-get install trickle #since you're on Ubuntu
trickle -u (upload limit in KB/s) -d (download limit in KB/s) executable

Here is some additional documentation about it https://wiki.archlinux.org/index.php/Trickle

Nebril
  • 3,153
  • 1
  • 33
  • 50
  • 2
    I've tried trickle and it isn't compatible with golang executables. See [this answer](http://stackoverflow.com/a/40387514/7106084) for details. Thanks for the suggestion though. – Christopher Waldon Nov 03 '16 at 19:00
  • Sorry to hear that! I would probably try to create an iptables rule to tag packets sent by your process and then use tc to shape traffic tagged by this rule, but I am unable to provide you with an exact solution at this time. – Nebril Nov 03 '16 at 19:18