Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool如果应用程序遇到了下面错误信息,那么意味着连接池(connection pool)的连接数量由于一些原因导致其超过了Max Pool Size参数的限制。 英文错误信息: Timeout expire

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool

如果应用程序遇到了下面错误信息,那么意味着连接池(connection pool)的连接数量由于一些原因导致其超过了Max Pool Size参数的限制。

 

英文错误信息:

 

Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached

 

中文错误信息:

 

超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。

 

 

 

在介绍这个错误前,我们必须搞清楚一些概念,后续再展开分析这个问题出现的原因,以及出现后如何解决问题。

 

 

 

连接池(Connection Pool)

 

对于共享资源,有一个很著名的设计模式:资源池(resource pool)。该模式正是为解决资源频繁分配、释放所造成的问题。数据库连接池(connection pool)的基本思想就是为数据库连接建立一个缓冲池。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需要从缓冲池中取出一个连接,使用完毕后再放回去。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。避免重复多次的打开数据库连接而造成的性能的下降问题和系统资源的浪费问题。

 

 

连接池相关参数

 

由于访问数据库的驱动很多,不同驱动的连接池参数等可能有所差异,具体以实际情况为准,我们以ADO.NET为例,来分析一个连接数据库的连接配置,providerName=”System.Data.SqlClient” 这里没有设置Max Pool SizePooing等参数,那么其实都是取其对应的默认值。其中pooling参数默认情况下为true,Max Pool Size值为100

 

<add name="xxxx" connectionString="Data Source = 192.168.xxx.xxx;Initial Catalog=xxx;User ID=xxxx;Password=xxxx;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient" /> 

代码100分

 

 

Keyword

Default

Description

Max Pool Size

100

The maximum number of connections that are allowed in the pool.

Valid values are greater than or equal to 1. Values that are less than Min Pool Size generate an error.

Min Pool Size

0

The minimum number of connections that are allowed in the pool.

Valid values are greater than or equal to 0. Zero (0) in this field means no minimum connections are initially opened.

Values that are greater than Max Pool Size generate an error.

Pooling

“true”

When the value of this key is set to true, any newly created connection will be added to the pool when closed by the application. In a next attempt to open the same connection, that connection will be drawn from the pool.

Connections are considered the same if they have the same connection string. Different connections have different connection strings.

The value of this key can be “true”, “false”, “yes”, or “no”.

PoolBlockingPeriod

Auto

Sets the blocking period behavior for a connection pool. See PoolBlockingPeriod property for details.

 

Keyword

Default

Description

Max Pool Size

100

池中允许的最大连接数。

有效值大于或等于1 小于最小池大小的值会生成错误。

Min Pool Size

0

池中允许的最小连接数。

有效值大于或等于0 此字段中的零(0)表示最初没有打开最小值连接。

大于最大池大小的值会生成错误。

Pooling

“true”

如果此项的值设置为 true,则在应用程序关闭时,将向池中添加任何新创建的连接。 在下一次尝试打开相同的连接时,该连接将从池中提取。

 

如果连接具有相同的连接字符串,则将其视为相同。 不同连接具有不同的连接字符串。

 

此键的值可以为 “true”“false”“yes” “no”

PoolBlockingPeriod

Auto

设置连接池的阻塞期行为。 有关详细信息,请参阅 PoolBlockingPeriod 属性。

 

 

 

 

 

 

 

错误出现的原因:

 

 

If we try to obtain connections more than max pool size, then ADO.NET waits for Connection Timeout for the connection from the pool. If even after that connection is not available, we get the following exception.

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached”

 

The timeout expired. The timeout expired prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached

 

When you open an SQL Connection object, it always takes from an available pool of connections. When you close the connection, asp.net will release the connection to the pool of connections so that next connection object can use it.If you open connections with out closing them and when the pool reaches maximum connections, it will throw the specified error. Make sure you are not opening connection inside loop, if you open connection make sure you are closing it immedietly after you execute the query.

 

错误的原因其实就是连接池中的连接被用完了,后面的请求建立数据库连接时,连接池中没有可用的资源(连接),那么就分配到等待连接池分配的队列中,而其等待的时间超过了参数Connection Timeout”的值,就抛出这个异常信息。

 

 

错误的解决方案:

 

 

 

1:业务量突然暴增,当前并发请求连接数据的数量超过了连接池的最大连接数(默认情况下,最大连接数是100),出现这种情况时,必须调整数据库连接字符串参数Max Pool Size值为一个合适的值。这种情况一般较少见。

 

 

 

Connection Pooling and the “Timeout expired” exception FAQ这篇文章中有代码模拟这种情况,这里就不做展开了。有兴趣的自己模拟一下即可。

 

 

代码100分  SqlConnection[] connectionArray = new SqlConnection[101];

      for (int i = 0; i <= 100; i++)

代码100分      {

                  connectionArray[i] = new SqlConnection("Server=.\SQLEXPRESS ;Integrated security=sspi;connection timeout=5");

                  connectionArray[i].Open();

      }

 

 

 

2 leaking connections问题导致。

 

 

其实这里个人理解为数据库连接没有正常关闭。有些是代码逻辑问题导致,有些是没有正确处理异常问题。

 

 

案例1

 

这个案例来自Connection Pooling and the “Timeout expired” exception FAQ,它模拟的是一种逻辑异常问题。如果开发人员这样写代码的话,那么即使出现异常,但是数据库连接永远不会释放(sqlconnection1.Close()永远不会执行)

 

using System;

using System.Data;

using System.Data.SqlClient;

 

public class Repro

{

    public static int Main(string[] args)

    {

        Repro repro = new Repro();

        for (int i = 0; i <= 5000; i++)

        {

            try{ Console.Write(i+" ");    repro.LeakConnections(); }

            catch (SqlException){}

        }

 

        return 1;

    }

    public void LeakConnections()

    {    

        SqlConnection sqlconnection1 = new SqlConnection("Server=.\SQLEXPRESS ;Integrated security=sspi;connection timeout=5");

        sqlconnection1.Open();

        SqlCommand sqlcommand1 = sqlconnection1.CreateCommand();

        sqlcommand1.CommandText = "raiserror ("This is a fake exception", 17,1)";

        sqlcommand1.ExecuteNonQuery();  //this throws a SqlException every time it is called.

        sqlconnection1.Close(); //We are calling connection close, and we are still leaking connections (see above comment for explanation)

    }

}

解决方法:

 

    我们要保证每次调用连接的同时都在使用过后通过close()dispose()对其执行了关闭.最简单的办法就是使用using,类似下面这样的代码

 

public void DoesNotLeakConnections()

      {

                  Using (SqlConnection sqlconnection1 = new SqlConnection("Server=.\SQLEXPRESS ;Integrated security=sspi;connection timeout=5")) {

                              sqlconnection1.Open();

                              SqlCommand sqlcommand1 = sqlconnection1.CreateCommand();

                              sqlcommand1.CommandText = "raiserror ("This is a fake exception", 17,1)";

                              sqlcommand1.ExecuteNonQuery(); //this throws a SqlException every time it is called.

                              sqlconnection1.Close(); //Still never gets called.

                  } // Here sqlconnection1.Dispose is _guaranteed_

      }

 

案例2

 

案例2来自官方文档Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool,其实我也见过几起类似这样的案例。有现成的例子,就没必要自己构造这样的案例。

 

static void Main(string[] args)

 

        {

 

            string connString = @"Data Source=<your server>;Initial Catalog=Northwind;Integrated Security=True; Max Pool Size=20; Connection Timeout=10";

 

            try

 

            {

 

                for (int i = 0; i < 50; i++)

 

                {

 

                    // Create connection, command and open the connection

 

                    SqlConnection sc = new SqlConnection(connString);

 

                    SqlCommand sCmd = new SqlCommand("SELECT * FROM Shippers", sc);

 

                    sc.Open();

 

                    // Print info

 

                    Console.WriteLine("Connections open: {0}", i.ToString());

 

                    // This will cause the error to show.

 

                    SqlDataReader sdr = sCmd.ExecuteReader();

 

                    sdr.Close();

 

 

 

                    // Replacing the two rows above with these will remove the error

 

                    //SqlDataReader sdr = sCmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);

 

                    //sdr.Close();

 

 

 

                    // -- or --

 

                    // Explicity close the connection

 

                    //sc.Close();

 

                }

 

 

 

                    // -- or --

 

                    // Run all in a Using statement (in this case, replace the whole for loop with the loop below.).

 

 

 

                    //for (int i = 0; i < 50; i++)

 

                    //{

 

                    //    using (SqlConnection sc = new SqlConnection(connString))

 

                    //    {

 

                    //        SqlCommand sCmd = new SqlCommand("SELECT * FROM Shippers", sc);

 

                    //        sc.Open();

 

                    //        Console.WriteLine("Conns opened " + i.ToString());

 

                    //        SqlDataReader sdr = sCmd.ExecuteReader();

 

                    //        sdr.Close();

 

                    //    }

 

                    //}

 

 

 

            }

 

            catch (Exception e)

 

            {

 

                Console.WriteLine(e);

 

            }

 

        }

 

3:通过visual Studio中的sql debugging 来打开或关闭连接的, 这个参考Connection Pooling and the “Timeout expired” exception FAQ的详细介绍。个人倒是没有遇到过这种情况。

 

 

 

个人的一些经验体会,遇到这些问题后,我们首先应该监控数据库的连接数量信息,类似下面这样的SQL,根据实际情况来调整(例如,有些程序的IIS部署在某个应用服务器上,我们通过hostname基本上就能定位)

 

 

SELECT  hostname ,

        COUNT(*) AS connection_sum

FROM    sys.sysprocesses

GROUP BY hostname

ORDER BY 2 DESC;

 

 

SELECT  loginame ,

        COUNT(*) AS connection_sum

FROM    sys.sysprocesses

GROUP BY loginame

ORDER BY 2 DESC;

 

 

然后要跟开发人员协作检查连接数据库的配置信息(连接字符串设置),例如Max Pool Size的大小设置,然后就是最麻烦的问题,怎么定位到root cause呢? 这就需要开发人员去检查了。已经脱离了DBA的掌控了。个人经验(不做开发多年了,经验都过时了),如果突然出现这个问题,并且有源代码版本控制管理,最好找出最近的修改部分,进行细致的检查验证,基本上就能定位到问题根源了。但是能否做到细致检查,因人而异。这个往往最难掌控,跟个人的态度、经验、能力有很大关系。

 

 

 

 

参考资料:

 

https://docs.microsoft.com/zh-cn/archive/blogs/angelsb/connection-pooling-and-the-timeout-expired-exception-faq

 

https://blogs.msdn.microsoft.com/spike/2008/08/25/timeout-expired-the-timeout-period-elapsed-prior-to-obtaining-a-connection-from-the-pool/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/9518.html

(0)
上一篇 2023-02-06
下一篇 2023-02-06

相关推荐

  • redis如何保证高可用_mongodb高可用方案

    redis如何保证高可用_mongodb高可用方案redis可以使用哨兵机制和主从架构部署来保证高可用,任何一个实例宕机,自动会进行主备切换。哨兵的含义就是监控redis系统的运行状态。可以启动多个哨兵,去监控redis数据库的运行状态。

    2022-12-20
    156
  • sql列拆分行_sql数组拆分

    sql列拆分行_sql数组拆分今天由于工作需要,需要把数据把列根据指定的内容拆分数据 其中一条数据实例 select id , XXXX FROM BIZ_PAPER where id ='4af210ec675927fa

    2023-03-11
    178
  • mysql在win下移植

    mysql在win下移植 背景:由于电脑太多垃圾了,重装了系统;但是mysql又不想重装,里面的数据还有用 步骤 把原来的MySQL安装文件压缩,如: mysql-8.0.11-winx64-back.zip 通过u…

    2023-02-25
    146
  • Python CGI示例:从Web服务器获取表单数据

    Python CGI示例:从Web服务器获取表单数据CGI(Common Gateway Interface)是一种让web服务器能够执行程序和脚本的标准协议,它允许web浏览器或客户端向服务器发送请求,然后服务器返回与请求相关的信息或数据。对于Python程序员来说,CGI是一个非常重要的工具,可以使他们轻松地开发以Python为基础的web应用程序。本文将介绍如何在Python中使用CGI从web服务器获取表单数据。

    2024-03-28
    79
  • Python工程师的Opencv安装指南

    Python工程师的Opencv安装指南Opencv(Open Source Computer Vision)是一个广泛使用的计算机视觉开源库,适用于工业图像处理、机器人视觉等领域。由于其功能强大,Opencv被广泛应用于图像处理、人脸检测、目标跟踪、运动分析、手势识别等领域中。

    2024-06-05
    66
  • sql语句为null或空值_sql查询结果为null默认0

    sql语句为null或空值_sql查询结果为null默认0第一种方法: 判断字段是否为空,如果为空转成你要的字符 1.oracle : nvl(“字段名”,’转换后的值’);//字段名是双引号,转换后的值是单引号 2.sql Server: isnull(“

    2023-02-22
    149
  • 如何退出conda

    如何退出condaConda是一个包管理系统和环境管理系统。它可以让你在不同的项目之间快速切换环境,并管理不同的依赖包。Conda也提供了一些命令行工具,包括conda、conda-env和conda-build等工具,用于在conda环境下进行不同的操作。

    2024-09-01
    19
  • MySQL 窗口函数「建议收藏」

    MySQL 窗口函数「建议收藏」1. 窗口函数概念和语法 窗口函数对一组查询行执行类似聚合的操作。然而,聚合操作将查询行分组到单个结果行,而窗口函数为每个查询行产生一个结果: 函数求值发生的行称为当前行 与发生函数求值的当前行相关的

    2023-06-09
    147

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注