Recently I run in to the MAXUserPort issue I binged again to see if there are other bloggers that have this fixed. I saw a good post from Tristan Kingston ( I could not find my own post ;-(
MaxUserPort controls "outbound" TCP connections
MaxUserPort is used to limit the number of dynamic ports available to TCP/IP applications.
It’s never going to be an issue affecting inbound connections. MaxUserPort is not the right answer if you think you have an inbound connection problem.
(I don’t know why, I just know it is. Probably something to do with constraining resource use on 16MB machines, or something.)
To further simplify: it’s typically going to limit the number of outbound sockets that can be created. Note: that’s really a big fat generalization, but it’s one that works in 99% of cases.
If an application asks for the next available socket (a socket is a combination of an IP address and a port number), it’ll come from the ephemeral port range allowed by MaxUserPort. Typically, these "next available" sockets are used for outbound connections.
The default range for MaxUserPort is from 1024-5000, but the possible range is up to 65534.
When You Fiddle MaxUserPort
So, why would you change MaxUserPort?
In the web server context (equally applicable to other application servers), you’d usually need to look at MaxUserPort when:
– your server process is communicating with some type of other system (like a back-end database, or any TCP-based application server – quite often http web servers)
– you are not using socket pooling, and/or
– your request model is something like one request = one outbound TCP connection (or more!)
In this type of scenario, you can run out of ephemeral ports (between 1024 and MaxUserPort) very quickly, and the problem will scale with the load applied to the system, particularly if a socket is acquired and abandoned with every request.
When a socket is abandoned, it’ll take two minutes to fall back into the pool.
Discussions about how the design could scale better if it reused sockets rather than pooling tend to be unwelcome when the users are screaming that the app is slow, or hung, or whatever, so at this point, you’d have established that new request threads are hung waiting on an available socket, and just turn up MaxUserPort to 65534.
What Next? TcpTimedWaitDelay, natch
Once MaxUserPort is at 65534, it’s still possible for the rate of port use to exceed the rate at which they’re being returned to the pool! You’ve bought yourself some headroom, though.
So how do you return connections to the pool faster?
Glad you asked: you start tweaking TcpTimedWaitDelay.
By default, a connection can’t be reused for 2 times the Maximum Segment Lifetime (MSL), which works out to 4 minutes, or so the docs claim, but according to The Lore O’ The Group here, we reckon it’s actually just the TcpTimedWaitDelay value, no doubling of anything.
TcpTimedWaitDelay lets you set a value for the Time_Wait timeout manually.
As a quick aside: the value you specify has to take retransmissions into account – a client could still be transferring data from a server when a FIN is sent by the server, and the client then gets TcpTimedWaitDelay seconds to get all the bits it wants. This could be sucky in, for example, a flaky dial-up networking scenario, or, say, New Zealand, if the client needs to retransmit a whole lot… and it’s sloooow. (and this is a global option, as far as I remember).
30 seconds is a nice, round number that either quarters or eighths (depending on who you ask – we say quarter for now) the time before a socket is reusable (without the programmer doing anything special (say, SO_REUSEADDR)).
If you’ve had to do this, at this point, you should be thinking seriously about the architecture – will this scale to whatever load requirements you have?
The maths is straightforward:
If each connection is reusable after a minimum of N (TcpTimedWaitDelay) seconds
and you are creating more than X (MaxUserPort) connections in an N second period…
Your app is going to spend time "waiting" on socket availability…
Which is what techy types call "blocking" or "hanging". Nice*!