Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
[release/2.2] Change HttpConnectionPool.GetConnectionAsync to do read-ahead outside of lock (#) #32568
Port #32495 to release/2.2.
Minimize the work done inside the lock in order to reduce contention. This means we need to reacquire the lock if the connection isn't usable, but in the fast path case where the connection is usable, we remove the syscalls from being performed while holding the lock.
Related to #31799
SocketsHttpHandler pools connections, and when it takes a connection from the pool, it checks to see whether the connection is still alive. That check is currently happening while a lock is held, which under heavy load and many short requests can result increased contention on the lock. This change moves that check to outside of the lock, so that in the fast path / common case, the lock is held for a very short period of time.
For microservices where many ASP.NET requests in turn make many HttpClient calls to other services, the contention can result in significantly reduced throughput than is otherwise possible. The benchmark results shown in #32495 (comment) highlight this impact.
This code path is critical to SocketsHttpHandler, used in the processing of all requests, so a mistake here could be impactful. But the change itself is minimal: it moves some checks from inside the lock to outside the lock. The net result is that for the common case, we still take the lock once, but we hold it for a much shorter period of time. In the less common case where we were able to grab a connection but then discover after releasing the lock and doing these checks that the connection is no longer valid (e.g. the server closed it after a timeout), we end up needing to loop around and take the lock again, for a small increase in cost on the uncommon path.