Optionally not creating go routines on HTTP requests

1,070 views
Skip to first unread message

am...@browserstack.com

unread,
Jul 3, 2014, 7:02:58 AM7/3/14
to golan...@googlegroups.com
If we look at the Server.Serve method: https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694, we see that on each HTTP request it creates a new go routine. This is not too great, if I get 1000s of incoming connections, it will create 1000s of go routines, and if each handler opens a file descriptor, or mysql connection etc, we can run out of them.

One fix for that would be for the handlers to implement some kind of limiting, so even if there are 1000s of go routine handlers created, only a handful are actually active, and rest are blocking on something.

But even then this is wasteful. I want network to take care of such things, I do not want my program to accept a connection at a rate it can not handle.

I suggest the following:
  1. Server struct be added a new flag, SpawnGoRoutines, default true. 
  2. defer l.Close() becomes if srv.SpawnGoRoutines { defer l.Close() }. 
  3. The go c.serve() becomes if srv.SpawnGoRoutines { go c.serve() } else { c.serve() }
I want to be able to create lets say 10 workers, who will all call srv.Serve(l net.Listener), thus ensuring that at any time only 10 http requests are being served. Also since no goroutines are being created and destroyed, it should be slightly better performance/gc wise. 

I have not tested this yet, but I do not see any reason it wont work.

Should I create work on this and submit a patch, or is it somehow wrong approach?

Matt Silverlock

unread,
Jul 3, 2014, 7:15:42 AM7/3/14
to golan...@googlegroups.com
Couple of quick comments:

* If you are opening a DB connection on every request there's already an issue: you should be creating a connection pool using database/sql's sql.Connect and your database driver;

* The same goes for files: there should be no need to open a file per-connection. Cache the contents or read them on application startup; whichever is appropriate.

Amit upadhyay

unread,
Jul 3, 2014, 7:29:33 AM7/3/14
to Matt Silverlock, golan...@googlegroups.com
Regarding file, every accepted TCP connection counts as an open file descriptor. If 1000s of connection come, I will be consuming 1000s of file descriptors. Which is a wastage as I am only handing a few connections at a time, depending on resources I have access to. 



--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/iwCz_pqu8R4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Amit Upadhyay
VP Engineering | BrowserStack
+91-9820-715-512 | amitu.com

Konstantin Khomoutov

unread,
Jul 3, 2014, 7:54:29 AM7/3/14
to Amit upadhyay, Matt Silverlock, golan...@googlegroups.com
On Thu, 3 Jul 2014 16:59:04 +0530
Amit upadhyay <am...@browserstack.com> wrote:

> Regarding file, every accepted TCP connection counts as an open file
> descriptor. If 1000s of connection come, I will be consuming 1000s of
> file descriptors. Which is a wastage as I am only handing a few
> connections at a time, depending on resources I have access to.

I think you just have to go one level deeper: instead of relying on the
default behaviour of net/http's Server.ListenAndServe(), implement a
custom listener and use it with Server.Serve. Your custom listener
would keep track of active goroutines serving clients' requests and/or
other resources and tear incoming requests down (or may be shovel them
to a single service goroutine which would response with HTTP 503 and
close the connection).

The documentation on the net package includes an example of a custom
listener. You might also copy-and-paste the listener from net/http,
and customize it.

Amit upadhyay

unread,
Jul 3, 2014, 7:58:37 AM7/3/14
to Konstantin Khomoutov, golan...@googlegroups.com
Yes, I tried going that route. But due to many methods/attributes being lowercased I realized either I copy entire net/http or modify them. The three changes I mentioned in original mail is the minimum change required for that kind of workflow to work. 

Brian Akins

unread,
Jul 3, 2014, 8:00:07 AM7/3/14
to Amit upadhyay, golan...@googlegroups.com
If you have 1000's of connected clients, then you must have 1000's of open file handles regardless of how many are "active" at a time.  This isn't "wasting" file handles, its just how network IO works. If you do not use HTTP keepalives then you can close the connection after sending the response.  There may be ways to avoid having a goroutine per client -- this behavior has bothered me, but it hasn't actually been an issue in practice.

Amit upadhyay

unread,
Jul 3, 2014, 8:19:32 AM7/3/14
to Brian Akins, golan...@googlegroups.com
No, this is not how it works. As long as a connection stays with OS its not counted against our fd, afaik. Only when you .accept() it, that it start getting counted against your usage. 

If 1000s of clients try to connect, then I need not have 1000s of fd open, tho this is current go behaviour. Only if there are 1000s of clients connected (that is if I so chose to allow), then there should be 1000s of fd open.

This should be my choice to allow or not allow 1000s of connection. This is currently not possible. With the changes I suggest it would become possible, if I set SpawnGoRoutines to false, and run 5 goroutine, each calling Server.Serve(), there would be max of 5 connection, and there would be max of 5 fds because of incoming connections. Things remain in my control if I so chose. 

Further, its not just one goroutine per client, its one goroutine per http request. With keep alive there can be multiple http request per connection, and this is again wasteful. 



On Thu, Jul 3, 2014 at 5:29 PM, Brian Akins <br...@akins.org> wrote:
If you have 1000's of connected clients, then you must have 1000's of open file handles regardless of how many are "active" at a time.  This isn't "wasting" file handles, its just how network IO works. If you do not use HTTP keepalives then you can close the connection after sending the response.  There may be ways to avoid having a goroutine per client -- this behavior has bothered me, but it hasn't actually been an issue in practice.



Brian Akins

unread,
Jul 3, 2014, 8:29:50 AM7/3/14
to Amit upadhyay, golan...@googlegroups.com
if you do not call accept, then you are relying on the OS's backlog to "queue" the connections for you - this may be fine for your use case.  However, file handles are very "cheap" - tens of thousands of them are fine - even hundreds of thousands can be handled depending on what you are doing.

However, once you call accept, based on what you described, you would have to complete the entire request/response and then close the connection before calling accept again if you really wanted to keep open file handles to a minimum.  A relatively few amount of slow clients could "block" all of your goroutines.

James Bardin

unread,
Jul 3, 2014, 9:15:52 AM7/3/14
to golan...@googlegroups.com, flat...@users.sourceforge.net


On Thursday, July 3, 2014 7:58:37 AM UTC-4, Amit upadhyay wrote:
Yes, I tried going that route. But due to many methods/attributes being lowercased I realized either I copy entire net/http or modify them. The three changes I mentioned in original mail is the minimum change required for that kind of workflow to work. 


 Do you have an example of what you need that's not available? You can fully limit connections with a custom Listener. There's even one in the go.net repo http://godoc.org/code.google.com/p/go.net/netutil


nuss....@gmail.com

unread,
Jul 3, 2014, 9:22:06 AM7/3/14
to golan...@googlegroups.com, br...@akins.org
If you really wanted it, why not just wrap the net.Listener?
A simple (not really tested) example could look like this http://play.golang.org/p/D8zuXNFEXK 
It allows only 10 connections to be open at the same time. 

The only problem is, that if you have a client with a slow connection your throughput can decrease drastically.
This could probably be avoided by creating a goroutine that after a given time allows a new connection to be accepted, before the old one completes.

Amit upadhyay

unread,
Jul 3, 2014, 9:29:15 AM7/3/14
to Brian Akins, golan...@googlegroups.com
Yes. OS will also start rejecting connections if the OS queue becomes too big. This to me is better than accepting a connection and rejecting it, why make application do something OS is already designed to do?

File handles are cheap, but they are non deterministic with current net/http. Lets say I have an application, which runs in only a scenario that does not allow unlimited file descriptors, and if my app does not need too many file descriptors if only it handled requests in a controlled rate, eg 100 at a time, my entire application will crash if I get a burst of new connections. For internet services, crash is lot less preferable than rejecting connections we cant handle, wont you agree?

A relatively few slow clients can block, if I chose them to. If that was my concern, I would start spawning feeder goroutines, just for the purpose of feeding data to slow clients. 

The thing is, I want to be able to be in a little bit more control, and auto-create-goroutine-on-every-request behaviour of net/http is not allowing me that control. 

Also goroutines are cheap, but not free. You must see the temptation of not having to keep creating and destroying them. Someone is looking for 8KB of RAM, on every request, freeing it, and doing whatever else is required to create and destroy the goroutines. If I wanted I can pre launch 10000 goroutines handling http connections, woulnd you agree that this limit is far better than having to rely on application crashing when it runs out of fds or RAM? Slow clients will too demand RAM.



On Thu, Jul 3, 2014 at 5:59 PM, Brian Akins <br...@akins.org> wrote:
if you do not call accept, then you are relying on the OS's backlog to "queue" the connections for you - this may be fine for your use case.  However, file handles are very "cheap" - tens of thousands of them are fine - even hundreds of thousands can be handled depending on what you are doing.

However, once you call accept, based on what you described, you would have to complete the entire request/response and then close the connection before calling accept again if you really wanted to keep open file handles to a minimum.  A relatively few amount of slow clients could "block" all of your goroutines.



Amit upadhyay

unread,
Jul 3, 2014, 9:38:04 AM7/3/14
to James Bardin, golan...@googlegroups.com
I suppose customer listener would be another way of doing it, but it would be very round about way of doing things. The listener will provide accept method, which will keep a count of currently open connections, and either call accept new ones, or block till the count has gone below the threshhold. 

This adds more work to be done, and still spawns goroutines. My purpose is two folds, limiting resource usage, and improved performance. It will achieve only former. 


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/iwCz_pqu8R4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Konstantin Khomoutov

unread,
Jul 3, 2014, 9:58:44 AM7/3/14
to Amit upadhyay, James Bardin, golan...@googlegroups.com
On Thu, 3 Jul 2014 19:07:51 +0530
Amit upadhyay <am...@browserstack.com> wrote:

> I suppose customer listener would be another way of doing it, but it
> would be very round about way of doing things. The listener will
> provide accept method, which will keep a count of currently open
> connections, and either call accept new ones, or block till the count
> has gone below the threshhold.
>
> This adds more work to be done, and still spawns goroutines. My
> purpose is two folds, limiting resource usage, and improved
> performance. It will achieve only former.

Uh. Why?
Let's consider the example from the net package docs:

// Listen on TCP port 2000 on all interfaces.
l, err := net.Listen("tcp", ":2000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
// Wait for a connection.
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
// Handle the connection in a new goroutine.
// The loop then returns to accepting, so that
// multiple connections may be served concurrently.
go func(c net.Conn) {
// Echo all incoming data.
io.Copy(c, c)
// Shut down the connection.
c.Close()
}(conn)
}

Now consider your modifications to it:

1) No one forces you to call Accept() at the start of the next
iteration: for instance, make your listener block on some
communication object so that unblocking means "there's a free
resource so you might go forward and Accept().

2) No one forces you to run a goroutine even after Accept()
successfully returned.

For instance, I've proposed you to create a special *single*
goroutine to serve "rejects". You might accespt a connection
and then, if there's no resources available to really serve it,
send the connection to that "rejection goroutine" which would
send HTTP 503 to the client flush and close the connection.

This *might* block on slow clients, but either live with this
or allocate a pool of rejectors or cap their number.
Or just don't accept connections, as (1) suggests.

Amit upadhyay

unread,
Jul 3, 2014, 10:19:25 AM7/3/14
to Konstantin Khomoutov, golan...@googlegroups.com
I am talking in the context of  https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694, net/http does call Accept() at the start of iteration, and it does create a new goroutine. 

I want to be able to use rest of awesomeness of net/http, everything http related in go-world uses net/http. I want to be able to switch off goroutine creation. This is possible only if we modify net/http in the way I suggested in the original mail. 

Andy Balholm

unread,
Jul 3, 2014, 10:52:24 AM7/3/14
to am...@browserstack.com, golan...@googlegroups.com
I think it’s the wrong approach.

If the rate-limiting needs to be on the network level, you should do it on the network level. Write a custom type that implements net.Listener, and rate-limit that somehow.

Amit upadhyay

unread,
Jul 3, 2014, 11:15:53 AM7/3/14
to Andy Balholm, golan...@googlegroups.com
Imagine the horror if we suggested to someone to get away with TCP back-pressure, and do rate limiting using timers or some such. 

I am not sure I understand the objections. I am not saying it is impossible to do it without the changes I am suggesting, but it would be bad performance wise. If it was C/C++, we would have been doing exactly what I am suggesting. If you had to send file over socket, you do not read all of it in memory, and write slowly, you read some, you block on write, and then you write again. This conserves memory. 

Similarly, you should not read all connections off OS queue, and put them in memory. Sure you can write customer listener, but then you will have to coordinate things. You will have to write custom Connection object too, to keep track of count of open connections. And in order to manage the count you will need some mutex somewhere. This is bad design.

We can avoid all that, avoid the needless goroutine creation and destruction, which no matter how many times you repeat its cheap, its not free. 

You can make things much cleaner, yet not reading off OS queue till you are ready to process is clean design, and faster, and the only cost is one extra member in a struct and an check before creation of goroutine. 

How is it a bad thing? 

Question I am not asking is just how to do it, I am asking would it make net/http better, or worse? Are you saying it will make it worse? 



James Bardin

unread,
Jul 3, 2014, 11:16:42 AM7/3/14
to golan...@googlegroups.com, flat...@users.sourceforge.net


On Thursday, July 3, 2014 10:19:25 AM UTC-4, Amit upadhyay wrote:
I am talking in the context of  https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694, net/http does call Accept() at the start of iteration, and it does create a new goroutine. 

I want to be able to use rest of awesomeness of net/http, everything http related in go-world uses net/http. I want to be able to switch off goroutine creation. This is possible only if we modify net/http in the way I suggested in the original mail. 



If you're limiting the number of accepted connections, there's not much else to optimize out. The Accept happens in a for loop regardless, so you're either spawning up to N simultaneous goroutines to handle the connections, or feeding connections to N continuous goroutines. At most you're decreasing your response time by the overhead of creating a goroutine, which is maybe a few hundred ns. That's going to be a hard optimization to sell.

IT's possible if you can show speed and memory benchmarks that warrant this change, there might be more reason to consider it. In the meantime it wouldn't be hard to fork the parts of http you need if you really want this. 

James Bardin

unread,
Jul 3, 2014, 11:21:55 AM7/3/14
to golan...@googlegroups.com, andyb...@gmail.com


On Thursday, July 3, 2014 11:15:53 AM UTC-4, Amit upadhyay wrote:

Similarly, you should not read all connections off OS queue, and put them in memory. Sure you can write customer listener, but then you will have to coordinate things. You will have to write custom Connection object too, to keep track of count of open connections. And in order to manage the count you will need some mutex somewhere. This is bad design.


Creating a net.Conn and a net.Listener aren't a big deal at all. I've done this numerous times for lower-level network programming. I personally think it's a really nice design, where I can implement a LimitedListener in a couple dozen lines of very straight-forward code, and just hand it off to an http.Server.

Amit upadhyay

unread,
Jul 3, 2014, 11:25:59 AM7/3/14
to James Bardin, golan...@googlegroups.com, Konstantin Khomoutov
:-)

Thanks for all the replies. I will take a stab at benchmarking to see if it really makes much of a difference.

The performance benefit I am seeing is not in goroutine creation/destruction, but in whatever we need to do to keep track of number of open connections, using some scheme with mutexes etc, may be that is cheap too.

Will report with what I find. 



--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/iwCz_pqu8R4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Andy Balholm

unread,
Jul 3, 2014, 12:34:41 PM7/3/14
to Amit upadhyay, golan...@googlegroups.com

On Jul 3, 2014, at 8:15 AM, Amit upadhyay <am...@browserstack.com> wrote:

> How is it a bad thing?
>
> Question I am not asking is just how to do it, I am asking would it make net/http better, or worse? Are you saying it will make it worse?

Yes, it would make net/http worse.

There is a possibility that your solution is the best approach in your use case. (I doubt it, but you know your use case better than I do.) But cases where it is the best approach are sure to be rare, and putting support for it in the standard library would just encourage people to do something that is almost always a bad idea, and make the API more complicated and harder to understand for everyone else.

Why is this approach usually a bad idea?

First, it is working against the design of net/http, which is pervasively concurrent.

Second, rate-limiting in a system like this should usually be done close to the resource that is in short supply. If you’re running short on file descriptors for TCP sockets, rate-limit in Listen. If you need to limit database connections, use a semaphore (or whatever) around the part of your handler that accesses the database; then the network communication can run at full concurrency, and clients just have to wait while they’re trying to access the database—you get full utilization of the database connection.

Amit upadhyay

unread,
Jul 3, 2014, 12:56:50 PM7/3/14
to James Bardin, Andy Balholm, golan...@googlegroups.com
Here is the change I was talking about, and https://gist.github.com/amitu/259529fcefe84fef2cc1. All tests pass. 

To me this appears like an all round improvement in net/http. Not only should it be included, but encouraged too. 

Amit upadhyay

unread,
Jul 3, 2014, 1:02:18 PM7/3/14
to James Bardin, Andy Balholm, golan...@googlegroups.com
I have tried to benchmark it with ab, but ab is telling really bad story irrespective of my changes, sometimes it give 5-6K req/sec, and sometimes less than 100 req/sec.

What would be right way to benchmark it?

James Bardin

unread,
Jul 3, 2014, 1:14:58 PM7/3/14
to Amit upadhyay, golan...@googlegroups.com
On Thu, Jul 3, 2014 at 1:01 PM, Amit upadhyay <am...@browserstack.com> wrote:
I have tried to benchmark it with ab, but ab is telling really bad story irrespective of my changes, sometimes it give 5-6K req/sec, and sometimes less than 100 req/sec.


Don't use `ab` for one -- `wrk` or `weighttp` are some that work very well. If you're testing via TCP, you need to make sure the machine you're using is properly tuned to handle the loa, otherwise you're just benchmarking your network configuration. (using ab over loopback on OSX just isn't going to work). 

 
What would be right way to benchmark it?


First, use the testing package's benchmark utilities and test the implementation without the network overhead. Testing while including the network is very difficult, but emulating real-life configurations is usually the most useful.

Sugu Sougoumarane

unread,
Jul 3, 2014, 11:55:24 PM7/3/14
to golan...@googlegroups.com
I feel like the thread veered off in the wrong direction. The original question was related to limiting server resource usage. If that's still the primary concern, limiting goroutines or incoming connections would be the wrong way to go.
You can probably find many related discussions about this topic. Go's connections as well as goroutines are very cheap. Instead, you should directly limit the resources you're constrained by. For example, if you're worried about db connections, you should create a connection pool and use that instead.

If you're worried about getting blown by millions of incoming connections, set a ulimit.

minux

unread,
Jul 4, 2014, 10:53:20 AM7/4/14
to am...@browserstack.com, golang-nuts
On Thu, Jul 3, 2014 at 7:02 AM, <am...@browserstack.com> wrote:
If we look at the Server.Serve method: https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694, we see that on each HTTP request it creates a new go routine. This is not too great, if I get 1000s of incoming connections, it will create 1000s of go routines, and if each handler opens a file descriptor, or mysql connection etc, we can run out of them.
The problem is you shouldn't create new mysql connections for each request.
Solve this, and the performance will be even better.
As others have said, concurrency control is easy if you implement a custom Listener.

use channel to distribute heavier work to worker goroutines (or even other machines), and
you can control the number of worker goroutines.

One fix for that would be for the handlers to implement some kind of limiting, so even if there are 1000s of go routine handlers created, only a handful are actually active, and rest are blocking on something.

But even then this is wasteful. I want network to take care of such things, I do not want my program to accept a connection at a rate it can not handle.

I suggest the following:
  1. Server struct be added a new flag, SpawnGoRoutines, default true. 
  2. defer l.Close() becomes if srv.SpawnGoRoutines { defer l.Close() }. 
  3. The go c.serve() becomes if srv.SpawnGoRoutines { go c.serve() } else { c.serve() }
I want to be able to create lets say 10 workers, who will all call srv.Serve(l net.Listener), thus ensuring that at any time only 10 http requests are being served. Also since no goroutines are being created and destroyed, it should be slightly better performance/gc wise. 

I have not tested this yet, but I do not see any reason it wont work.

Should I create work on this and submit a patch, or is it somehow wrong approach?
No, this is going backwards.

Amit upadhyay

unread,
Jul 4, 2014, 11:52:21 AM7/4/14
to minux, golang-nuts
I disagree. Let me repeat, unconditionally creating goroutine in net/http is a mistake. Fixing it is not a step backward, its a step forward. Dont get me wrong, its very convenient, but for applications with resource contraint, like very light memory foot print, or fd limits etc, it would be good if my patch was accepted. 

Sure fds are cheap, but creating them when its not needed is a *mistake*. Sure goroutines are cheap, but again, creating them when not needed is a mistake.

As it stands net/http will make the server crash if ulimit is low and it gets a burst of connection. This should be fixed. I am surprised nobody else is seeing this. If resources are cheap for you, you do not dismiss a patch that makes a library more efficient, do you? And saying this will make it worse? Have I entered some twilight zone?

akwillis

unread,
Jul 4, 2014, 12:00:31 PM7/4/14
to golan...@googlegroups.com, am...@browserstack.com
kind of reminds of the 10k problem and why select, poll, and other mechanisms were created.

Matt Harden

unread,
Jul 4, 2014, 1:33:06 PM7/4/14
to Amit upadhyay, minux, golang-nuts
On Fri, Jul 4, 2014 at 10:51 AM, Amit upadhyay <am...@browserstack.com> wrote:
As it stands net/http will make the server crash if ulimit is low and it gets a burst of connection.

That's not true. Ulimit is used to limit the resources available to a given process, to prevent it crashing the system. If the nfiles ulimit is reached for a particular process, the process is unable to open new file descriptors, thus protecting the rest of the system.
 
This should be fixed. I am surprised nobody else is seeing this. If resources are cheap for you, you do not dismiss a patch that makes a library more efficient, do you? And saying this will make it worse? Have I entered some twilight zone?



On Fri, Jul 4, 2014 at 8:22 PM, minux <mi...@golang.org> wrote:

On Thu, Jul 3, 2014 at 7:02 AM, <am...@browserstack.com> wrote:
If we look at the Server.Serve method: https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694, we see that on each HTTP request it creates a new go routine. This is not too great, if I get 1000s of incoming connections, it will create 1000s of go routines, and if each handler opens a file descriptor, or mysql connection etc, we can run out of them.
The problem is you shouldn't create new mysql connections for each request.
Solve this, and the performance will be even better.
As others have said, concurrency control is easy if you implement a custom Listener.

use channel to distribute heavier work to worker goroutines (or even other machines), and
you can control the number of worker goroutines.

One fix for that would be for the handlers to implement some kind of limiting, so even if there are 1000s of go routine handlers created, only a handful are actually active, and rest are blocking on something.

But even then this is wasteful. I want network to take care of such things, I do not want my program to accept a connection at a rate it can not handle.

I suggest the following:
  1. Server struct be added a new flag, SpawnGoRoutines, default true. 
  2. defer l.Close() becomes if srv.SpawnGoRoutines { defer l.Close() }. 
  3. The go c.serve() becomes if srv.SpawnGoRoutines { go c.serve() } else { c.serve() }
I want to be able to create lets say 10 workers, who will all call srv.Serve(l net.Listener), thus ensuring that at any time only 10 http requests are being served. Also since no goroutines are being created and destroyed, it should be slightly better performance/gc wise. 

I have not tested this yet, but I do not see any reason it wont work.

Should I create work on this and submit a patch, or is it somehow wrong approach?
No, this is going backwards.




--
Amit Upadhyay
VP Engineering | BrowserStack

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

andrewc...@gmail.com

unread,
Jul 4, 2014, 6:16:24 PM7/4/14
to golan...@googlegroups.com
Write/configure a proxy which levels out the burst if your system cant handle this. you need a load balancer.


On Thursday, July 3, 2014 11:02:58 PM UTC+12, am...@browserstack.com wrote:
If we look at the Server.Serve method: https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694, we see that on each HTTP request it creates a new go routine. This is not too great, if I get 1000s of incoming connections, it will create 1000s of go routines, and if each handler opens a file descriptor, or mysql connection etc, we can run out of them.

Amit upadhyay

unread,
Jul 5, 2014, 6:09:58 AM7/5/14
to Matt Harden, minux, golang-nuts
Yes. And the go server will crash. 

Amit upadhyay

unread,
Jul 5, 2014, 6:10:19 AM7/5/14
to andrewc...@gmail.com, golang-nuts
And if you want to write such proxy, stay away from go?

Come on guys. Think. 


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/iwCz_pqu8R4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Tamás Gulácsi

unread,
Jul 5, 2014, 8:10:12 AM7/5/14
to golan...@googlegroups.com
No. Please LISTEN (read) what everybody writes and even the doc contains: net/http.ListenAndServe is a convenience function, you don't need to use it, you can write your own loop which callsAccept and Serve as you wish.

Amit upadhyay

unread,
Jul 5, 2014, 8:49:29 AM7/5/14
to Tamás Gulácsi, golang-nuts
I am listening :-(

It is not possible for me to call c.serve(), c.setState(), srv.newConn(). https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694

If I have re-implement c.serve() for example without virtually reimplementing entire net/http.

The simplest way is my patch: https://gist.github.com/amitu/259529fcefe84fef2cc1


On Sat, Jul 5, 2014 at 5:40 PM, Tamás Gulácsi <tgula...@gmail.com> wrote:
No. Please LISTEN (read) what everybody writes and even the doc contains: net/http.ListenAndServe is a convenience function, you don't need to use it, you can write your own loop which callsAccept and Serve as you wish.
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/iwCz_pqu8R4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Amit upadhyay

unread,
Jul 5, 2014, 8:50:35 AM7/5/14
to Tamás Gulácsi, golang-nuts
* It is not possible to re-implement c.serve() for example without virtually reimplementing entire net/http.


On Sat, Jul 5, 2014 at 5:40 PM, Tamás Gulácsi <tgula...@gmail.com> wrote:
No. Please LISTEN (read) what everybody writes and even the doc contains: net/http.ListenAndServe is a convenience function, you don't need to use it, you can write your own loop which callsAccept and Serve as you wish.
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/iwCz_pqu8R4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jesse McNelis

unread,
Jul 5, 2014, 8:58:09 AM7/5/14
to Amit upadhyay, Tamás Gulácsi, golang-nuts
On Sat, Jul 5, 2014 at 10:49 PM, Amit upadhyay <am...@browserstack.com> wrote:
> I am listening :-(
>
> It is not possible for me to call c.serve(), c.setState(), srv.newConn().
> https://code.google.com/p/go/source/browse/src/pkg/net/http/server.go#1694.

Yep, you don't do that.
You create your own net.Listener that limits the number of active
connections that are accepted.
You create a http://golang.org/pkg/net/http/#Server and set it's
ConnState callback to a function to signal to the listener that a
connection has disconnected and it can accept another.
You call http://golang.org/pkg/net/http/#Server.Serve with your own
net.Listener and you're done.

Stopping the http server from spawning goroutines is absurd because
the cost of the goroutine is less than the cost of the tcp connection
itself.

Aram Hăvărneanu

unread,
Jul 5, 2014, 9:04:33 AM7/5/14
to akwillis, golang-nuts, am...@browserstack.com
On Fri, Jul 4, 2014 at 6:00 PM, akwillis <akwi...@gmail.com> wrote:
> kind of reminds of the 10k problem and why select, poll, and other
> mechanisms were created.

Select(2) and poll(2) were created in 1983, the c10k problem was
defined in 1999, 16 years later!

--
Aram Hăvărneanu

Amit upadhyay

unread,
Jul 5, 2014, 9:10:04 AM7/5/14
to Jesse McNelis, Tamás Gulácsi, golang-nuts
Thanks Jesse,

I will try to implement it and come back. 

Alan Shreve

unread,
Jul 8, 2014, 10:44:25 PM7/8/14
to Amit upadhyay, Jesse McNelis, Tamás Gulácsi, golang-nuts
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Amit upadhyay

unread,
Jul 9, 2014, 3:02:57 AM7/9/14
to Alan Shreve, Jesse McNelis, Tamás Gulácsi, golang-nuts
Thanks. Its indeed useful. 
Reply all
Reply to author
Forward
0 new messages