如何找到哪些代码正在消耗我的 SQL Server 连接池?
我根据答案重写了以下内容。
我有一个网站会导致数据库服务器出现高 CPU 问题,导致服务器不可用。回收应用程序池可以解决该问题。根据服务器管理员 http ://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en 显示有活跃线程大约一个小时。
与数据库的交互非常简单,并且在我们将 Web 表单路由添加到应用程序之前就可以完成。
它们在整个应用程序中只包含这样的代码。 是的,这段代码并不完美,但问题并不是这段代码,因为在我们添加路由之前,没有任何问题。
private string GetPublishedParagraphs()
{
string query, paragraphs = "";
try
{
m_sql_connection = new SqlConnection(m_base_page.ConnectionString());
query = "select * from PublishedParagraphs where IDDataContent_page='" + m_IDDataContent_page + "'";
SqlDataAdapter da = new SqlDataAdapter(query, m_sql_connection);
DataSet ds = new DataSet();
da.Fill(ds, "paragraph");
if (ds.Tables["paragraph"].Rows.Count > 0)
paragraphs = (string)ds.Tables["paragraph"].Rows[0]["paragraphs"];
ds.Dispose();
da.Dispose();
}
finally
{
m_sql_connection.Close();
}
paragraphs = paragraphs.Replace("™", "™");
return paragraphs;
}
连接字符串如下所示:
server_name; User ID=server_user; Password=server_password
我们仔细检查了对数据库 Open() 的每次调用都紧随其后的是 Close()。 当我们在本地运行应用程序时,我们通过查看它们来测量没有打开的连接,并且连接计数不会增加:(
SELECT SPID,
STATUS,
PROGRAM_NAME,
LOGINAME=RTRIM(LOGINAME),
HOSTNAME,
CMD
FROM MASTER.DBO.SYSPROCESSES
WHERE DB_NAME(DBID) = 'TEST' AND DBID != 0
但是,如果我们不关闭连接,就会出现泄漏)
我们的应用程序与它运行时的区别有效的方法是通过 Web 表单添加 ASP.NET 路由。这也会调用数据库,但在连接打开后再次关闭连接。
我们不确定还可以检查什么。 各位程序员有什么想法吗?
解答
我们通过查询分析器发现了问题。这向我们展示了一个使用率很高的查询。将查询追溯到代码显示了一个一遍又一遍地调用数据库的无限循环。很难找到,因为循环是由机器人调用网站上不再存在的页面发起的。
I have rewritten the below based on the answers.
I have a website that causes HIGH CPU issues on the database server to the point where the server becomes unavailable. Recycling the app pool fixes the issue. According to the server administrator http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en shows there are threads that are active for about an hour.
The interactions with the database are very simple and worked prior to us adding web forms routing to the application.
They only consists of code like this throughout the application.
Yes, this code is not perfect, but its not this code that is an issue as prior to us adding routing, there were no problems.
private string GetPublishedParagraphs()
{
string query, paragraphs = "";
try
{
m_sql_connection = new SqlConnection(m_base_page.ConnectionString());
query = "select * from PublishedParagraphs where IDDataContent_page='" + m_IDDataContent_page + "'";
SqlDataAdapter da = new SqlDataAdapter(query, m_sql_connection);
DataSet ds = new DataSet();
da.Fill(ds, "paragraph");
if (ds.Tables["paragraph"].Rows.Count > 0)
paragraphs = (string)ds.Tables["paragraph"].Rows[0]["paragraphs"];
ds.Dispose();
da.Dispose();
}
finally
{
m_sql_connection.Close();
}
paragraphs = paragraphs.Replace("™", "™");
return paragraphs;
}
The connection string looks like:
server_name; User ID=server_user; Password=server_password
We have meticulously checked that every call to the database Open() is followed by a Close().
We have measured there are no open connections by viewing them as we run the application locally and the connection count does not increase via:
SELECT SPID,
STATUS,
PROGRAM_NAME,
LOGINAME=RTRIM(LOGINAME),
HOSTNAME,
CMD
FROM MASTER.DBO.SYSPROCESSES
WHERE DB_NAME(DBID) = 'TEST' AND DBID != 0
(However, if we don't Close connections, there is a leak)
The difference between our application from when it worked is the addition of asp.net routing via web forms. This calls the database too, but again closes connections after they are open.
We are not sure what else we can check for.
Any ideas fellow programmers?
ANSWER
We found the problem via Query Profiler. This showed us a query with high usage. Tracing the query back to the code showed an infinite loop calling the database over and over. It was difficult to find as the loop was initiated by a bot calling a page on the website that no longer existed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在您显示的代码中, ds 和 da .Dispose 位于 finally 块中。更好的是,使用 using () {} 结构来确保对象处置
构建自己的字符串作为查询的模式不仅是一个巨大的安全漏洞,而且效率非常低。请改用存储过程和参数。
进程的查询过于严格。如果您遇到导致连接被拒绝的资源问题,则不会仅限于单个数据库。我唯一要限制的是当前命令 -->其中 spid != @@spid
真的需要一些错误消息和上下文 - 在哪里可以看到它们?请告诉我们更多信息,我们可以提供帮助!
祝你好运!
首先,重要的附加信息!感谢您的跟进。
我建议,如果您确信您发布的代码与问题无关,请将其从问题中删除。然而,问题不仅仅是“不完美”的问题。正确处理内存密集型对象 - 最初的开发人员认为足够密集以包含 dispose() 方法 - 与数据库交互的对象 - 当您遇到无法解释的数据库问题时,这不是一个小问题,无论如何,我认为.
我做了一些谷歌搜索,发现此。虽然我不会说这就是问题所在,但它确实让我开始思考。当“线程活动大约一个小时”时,是在数据库服务器上还是在网络服务器上测量?我不熟悉这个工具,但是你能从这个工具发布日志吗?
在网络服务器上,您能够监视路由代码的操作吗?路由代码的编写/设置方式是否可以防止无限循环 - 请参阅问题和答案 此处文本。
在我的答案的早期版本中,我对您说过,仅查找特定数据库的 @ 连接对于您的任务来说限制太大。对您的问题的澄清并不表明您已更正此查询。我建议:
日志 - 在重新启动 Web 应用程序之前 10 分钟和之后 10 分钟的时间范围内,SQL Server 日志显示什么内容?
您是否尝试过,这个问题在开发中是否会重复?
请告诉我们以下声明对于您的应用程序的含义 - 错误消息或其他:“服务器不可用”
我强烈建议您使用探查器启动 SQL Server 跟踪。根据你在这个问题中所说的,这就是我将跟踪保存到表(在另一个sql服务器上)或保存到文件(在另一台机器上而不是sql服务器框上)的内容。此跟踪用于查找严重妨碍生产的问题。这不是您想要定期运行的东西。
我会捕获这些事件,
除了预设之外,我不会使用任何过滤器。
In the code you are showing, the ds and da .Dispose go in the finally block. Better yet, use the using () {} structure which ensures object disposal
the pattern of build your own string as a query isn't just a gaping security hole, it is also very inefficient. Use a stored procedure and a parameter instead.
the query for processes is overly restrictive. If you have a resource issue that is causing connections to be refused, it won't be limited to a single database. About the only thing I would restrict is the current command --> where spid != @@spid
REALLY need some error messages and context - where are they being seen? Tell us more and we can help!
Good luck!
First, great additional information! Thanks for the followup.
I would suggest that if you're so sure that the code you have posted has nothing to do with the problem that you remove it from the question. However, the problems aren't an issue of merely being "imperfect". Proper disposal of memory intensive objects - ones that the initial developers recognized as intensive enough to include the dispose() method - ones that interact with the database - while you are having unexplained problems with database isn't a small issue, in my opinion anyways.
I did some googling and found this. While I wouldn't go and say that this is the problem, it did get me to thinking. When "threads that are active for about an hour", is that being measured on the db server or on the web server? I'm not familiar with the tool, but are you able to post logs from this tool?
On the webserver, are you able to monitor the routing code's actions? Is the routing code written / setup in such a way as to protect against infinite loops - see the question and answers here text.
In the earlier version of my answer, I said to you that looking only @ connections for a particular database was too restrictive for your task. The clarifications to your question do not indicate that you have corrected this query. I would suggest:
Logs - what are the SQL Server Logs saying in the time span 10 minutes before and 10 minutes after you restart the web app?
Have you tried and is this issue repeatable in development?
Please tell us what the below statement means in terms of your application - an error message or other: "the server becomes unavailable"
I highly suggest that, you startup a trace of sql server using profiler. According to what you are saying in this question, this is what I would trace saving to table ( on another sql server ) or saving to file ( on another machine NOT the sql server box ). This trace is for finding a problem that is severely hampering production. It's not something that you would want running on a regular basis.
I would capture these events
I wouldn't use any filters other than the presets.
您是否尝试过在 SQL Server Management Studio 中运行“sp_who2”查询来查看有多少个活动数据库连接,因为代码看起来不错。
您可能希望将
m_sql_connection
变量的范围从类范围更改为成员范围。也许这可能是你的问题?Have you tried running the "sp_who2" query in SQL Server Management Studio to see how many active database connections there are as the code looks fine.
You might want to change the scope of the
m_sql_connection
variable from class scope to member scope. Perhaps that could be your issue?“应用程序池用完”是什么意思?你指的是连接池吗?
如果您的数据库似乎工作过度,也可能是因为用户可以自由控制您的 m_IDDataContent_page 变量。此数据访问代码容易受到 SQL 注入攻击。
what do you mean by "running out of application pool?" Do you mean the connection pool?
If your database seems to be getting overworked, it could also be because a user has free reign over your m_IDDataContent_page variable. This data access code is vulnerable to sql injection.