Connection pooling in .Net is a hidden feature. We as consumer developers, cannot directly feel how the pooling happens behind the scenes. .Net is allowing us to clear the connection pool. We create a new SqlConnection and Close it after use. When we create a connection it uses an internal pooling mechanism and a connection object is associated with the object that we create and the closed connections go back to the pool.
This post is not to educate about simple connection pooling instead it talks about an issue encountered in production.
Issue
There is a .Net 6 Web API hosted in Azure App Service. It mainly accesses an Azure SQL database and storage blobs. When the load slightly increased, it started showing the below error.
System.Data.SqlClient.SqlException (0x80131904): Resource ID : 2. The session limit for the database is 600 and has been reached. See 'https://docs.microsoft.com/azure/azure-sql/database/resource-limits-logical-server' for assistance.
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
Troubleshooting
Q&A about connection pooling
Before starting specific troubleshooting let's refresh the main points about connection pooling. Experts may skip this section
Are there many connection pools?
Yes, there are chances of having many connection pools. For each connection string, it creates and maintains a separate connection pool.
How many connections are in a pool?
By default 100 per pool. It is configurable through the connection string or via code
When all the connections are in use and a connection is requested from the pool what will happen?
Does the SQL Server know the consumers are keeping connections in the pool?
How to check the pooling status of our application?
Specific steps to troubleshoot the issue
Let us look at some specifics about this issue
What are the Azure SQL specs?
Standalone database, tier - S0
What is exec sp_who returns from the database?
Are there 600+ requests coming to the App Service per second?
Is there auto-scaling of app service instances?
Any other application is making connections to the same database?
Is the connection string or code have any customization of connection pool size?
What is the authentication mechanism for Azure SQL?
How many connection pools are there?
Will there be one connection pool per JWT considering JWT is part of the connection string?
Is there any Microsoft official documentation for the above answer?
For further clarification look at the source code of SqlConnectionPoolKey.CalculateHashCode()
Disclaimer
The actual root cause cannot be disclosed on social media such as this blog due to security, confidentiality, etc...
No comments:
Post a Comment