数据库“长连接”与“短连接”

什么是长连接?

其实长连接是相对于通常的短连接而说的,也就是长时间保持客户端与服务端的连接状态。

通常的短连接操作步骤是:

连接-》数据传输-》关闭连接

而长连接通常就是:

连接-》数据传输-》保持连接-》数据传输-》保持连接-》…………-》关闭连接

这就要求长连接在没有数据通信时,定时发送数据包,以维持连接状态,短连接在没有数据传输时直接关闭就行了

什么时候用长连接,短连接?

长连接主要用于在少数客户端与服务端的频繁通信,因为这时候如果用短连接频繁通信常会发生Socket出错,并且频繁创建Socket连接也是对资源的浪费。

但是对于服务端来说,长连接也会耗费一定的资源,需要专门的线程(unix下可以用进程管理)来负责维护连接状态。

总之,长连接和短连接的选择要视情况而定。

 

首先,如果使用了长连接而长期没有对数据库进行任何操作,那么在timeout值后,mysql server就会关闭此连接,而客户端在执行查询的时候就会得到一个类似于“MySQL server has gone away“这样的错误。

在使用mysql_real_connect连接数据库之后,再使用mysql_options( &mysql, MYSQL_OPT_RECONNECT, … ) 来设置为自动重连。这样当mysql连接丢失的时候,使用mysql_ping能够自动重连数据库。如果是在mysql 5.1.6之前,那么则应在每次执行完real_connect 之后执行mysql_options( &mysql, MYSQL_OPT_RECONNECT, … ) ,如果是mysql 5.1.6+,则在connect之前执行一次就够了。

 

查看mysql连接数

mysqladmin -uroot -p  processlist

实际的测试中我发现,当设置了MYSQL_OPT_RECONNECT为1时,超时后再查看processlist,则自动建立的连接不在列表中,但事实上连接确实建立并被使用了。

 

在MYSQL的默认设置中,如果一个数据库连接超过8小时没有使用(闲置8小时),服务器将断开这条连接,后续在该连接上进行的查询操作都将失败。网络上对该问题的描述非常多。也提供了相应的解决办法。我在这里提一些我自己的看法。

解决办法一:修改MYSQL服务器的配置参数

道理非常简单,MYSQL的默认设置是在数据库连接超过8小时没有使用后将其断开,如果我们将这个时间改成更大的数值,那么连接超时所需的时间就会更长,也就意味着更不容易超时。网络上提供的修改方法一般是修改/etc/my.cnf,在这个文件中添加一行wait_timeout=你需要设置的超时时间。实际上有一种比较简单的方法来修改这个参数:

首先作为超级用户登录到MYSQL,注意必须是超级用户,否则后面会提示没有修改权限。然后输入

show global variables like 'wait_timeout';

回车执行后显示目前的超时时间:

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| wait_timeout | 28800 |

+---------------+-------+

1 row in set (0.00 sec)

上面显示的是默认的超时时间,即8个小时(单位是秒)。现在重新设置该参数,例如我们要将超时时间设置成10个小时,可以输入:

set global wait_timeout=36000;

回车执行,显示:

Query OK, 0 rows affected (0.00 sec)

表示设置成功,可以重新使用show global variables like 'wait_timeout'来验证。

这种方法比较直观,而且设置的参数立即生效。但如果/etc/my.cnf中没有配置,则重启服务后,global变量会从/etc/my.cnf中读取新的变量值。

 

下边是一段示例代码:

if(!mysql_real_connect(&logdb, my_hostname, my_user, my_password, my_dbname, my_port, my_sock, 0)){ 
        ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", my_dbname, my_hostname); 
        use_mysql = 0; 
} else { 
       char value = 1; 
       mysql_options(&logdb, MYSQL_OPT_RECONNECT, (char*)&value); 
        use_mysql = 1; 
}


 

 


 

 

譬如 HTTP 的 Connection-alive 如果为 close,则 server 收到一个 request 并发送完一个 response 之后就会主动关闭连接,这就是短连接;如果 Connection-alive keep-alive 的话可以在一个 tcp 连接中交换多次对话。是这个定义?那就只是个程序结构设计问题了。

 


长连接短连接只是一个概念性的问题,只要知道其概念,不是一个特殊的东西:
长连接:系统通讯连接建立后就一直保持。
短连接:只有系统需要相互发消息连接才建立(客户端发起),请求消息得到响应后连接关闭;
通讯实体间使用长连接,一般还需要定义心跳消息,定期发送来检测系统间链路是否异常,每隔一定时间发送一次心跳,如果一定次数没有收到心跳消息,这认为此连接出现问题,需要断开连接重新建立。
具体心跳消息的格式,以及发送间隔,以及多少次没有收到心跳就认为链路异常,以及数据部是否算作心跳消息(有的系统如果接收到数据包则会清除心跳计时器也就相当于系统中的数据包也算作心跳消息);这个需要两端进行协商。比如GSM常用的短消息中心和其他网络实体互连的SMPP协议,要求建立的就是长连接.

所以长短连接只是一个概念问题长短连接的socket,就是使用普通的socket函数,没有什么特殊的。


PHP在連結MYSQL時有兩個FUNCTION
CONNECT與PCONNECT
這兩個函式的差別在哪裡?
一般的標準答案都是:
PCONNECT是持續性的連接,PHP會重複使用已經存在的資料庫連線

 

但是再追問下去,能說得出來的人就少了許多
常見的疑問有:
什麼時候要用CONNECT什麼時候用PCONNECT?
mysql_close何時使用?
為什麼DATABASE上有一堆SLEEP的PROCESS?
明明用PCONNECT為何每次RESOURCE ID都不同?

先回歸到最簡單的解釋,pconnect會去檢查是否有已經存在的資料庫連線。
若有,就使用舊的連線;若無,就新開啟一個連線
但是這裡所說得檢查連線,是指這一個APACHE行程所開啟的資料庫連線
而不是這一台WEB SERVER所開啟的資料庫連線。
一台WEB SERVER上可能有上百個APAHE行程(2.0預設最大150個)
也就是說 在最大情況下可能會有上百個PCONNECT造成的資料庫連線
(實際上會遠少於此)
所以同樣使用PCONNECT是會出現不同RESOURCE ID的
因為他可能是在不同行程上面執行

而PCONNECT是不會在查詢完成後就關閉,而是會等待一定時間
這個時間可以由MYSQL上的wait_timeout設定
而且mysql_close並無法關閉pconnect所開啟的連線,只能關閉connect所開啟的資料庫連線。當然如果沒有CLOSE在經過TIMEOUT時間之後也是會被DB DROP掉。

PCONNECT必須要小心使用,在寫的不好的CODE中,會殘留一大批的DATABASE CONNECTION。最大值可以這樣計算
每台SERVER的APACHE行程數 * 所有WEB SERVEWR數量
當然不需要我來提醒,每個連線都會消耗DB的CPU TIME與MEMORY

寫WEB CODE時,不論使用何種語言,有兩點一定要再動手寫之前先有答案
一是,要從DATABASE抓取什麼資料
二是,要傳送什麼資料到USER端
(其實這也不只用於WEB)
DATABASE的連線是很慢的,能夠一次抓取完所需的資料,就不要分兩次


数据库连接池由数据库管理器提供。与连接语言无关。
php 提供了 pconnect 的機制, 可以實現連接池的功能 .
對於   mysql , mysql_pconnect 函數就可以實現 :
 數據庫連接使用完畢後, 並不釋放, 而是留在系統中, 下一次調用 mysql_pconnect 連接數據庫時, 首先檢查是否有空閒的連接未被使用, 如果有, 則使用這個連接, 而不是進行連接數據庫的操作, 從而節省系統開銷 .
 


1.数据库连接池的工作机制是什么?它怎么提高数据的访问速度呢?  
--------------------------------------------------------------- 
连接池的作用主要是节省打开数据库的时间。  
由于打开数据库连接比较耗时,所以连接池机制预先打开N个数据库连接,把它们缓存起来,当需要使用数据库的时候就直接使用这些已经打开的连接,从而节省了 时间。

创建新的对象并初始化的操作,可能会消耗 很多的时间。在这种对象的初始化工作包含了一些费时的操作(例如,从一台位于20,000千米以外的主机上读出一些数据)的时候,尤其是这样。在需要大量 生成这样的对象的时候,就可能会对性能造成一些不可忽略的影响。要缓解这个问题,除了选用更好的硬件和更棒的虚拟机以外,适当地采用一些能够减少对象创建 次数的编码技巧,也是一种有效的对策。对象池化技术(Object  Pooling)就是这方面的著名技巧.  

对象池化的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当 保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。  

数据库连接pool是专门保存和管理数据库连接的pool.  

恰当地使用对象池化技术,可以有效地减少对象生成和初始化时的消耗,提高系统的运行效率。  

采用对象池化的本意,是要通过减少对象生成的次数,减少花在对象初始化上面的开销,从而提高整体的性能。然而池化处理本身也要付出代价,因此,并非任何情 况下都适合采用对象池化。    

基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合进行对象池化。如果进行池化所能带来的性能提高并不重要的话,还是不采用对象池 化技术,以保持代码的简明,而使用更好的硬件和更棒的虚拟机来提高性能为佳。    

恰当地使用对象池化,可以有效地降低频繁生成某些对象所造成的开销,从而提高整体的性能。而借助Jakarta Commons  Pool组件,可以有效地减少花在处理对象池化上的工作量,进而,向其它重要的工作里,投入更多的时间和精力。

数据库连接池的原理:

J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。
客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。
如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。
当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。


 

1.长连接 
Client方与Server方先建立通讯连接,连接建立后不断开,然后再进行报文发送和接收。

2.短连接 
Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点通讯,比如多个Client连接一个Server.

 

 

 

短连接常见于大客户情况 如WEB服务器如果每个连接都使用长连接 那么每个客户都保留一个socket 系统资源耗费很大 。

长连接则是多用于操作频繁情况每个TCP连接都需要三步握手 这需要时间 如果每个操作都是先连接 再操作的话那么处理速度会降低很多 所以每个操作完后都不断开 下次处理时直接发送数据包就OK了 不用建立TCP连接。

另外还有同步操作和异步操作,同步操作指上一个操作返回结果后才能发下一个操作的数据包;异步操作指先把所有的操作数据包发完后 再等待它们的返回结果。相比较看, 异步操作速度快 特别是在每个包处理方法独立的情况下 。

上面只是一个参考 最后要使用哪种类型还是决定于你。如联通的短信协议就是 连接后可以发送多个短信包 但如果一段时间(如60s)没有操作 那么连接就会被关闭。

 


 

 

 

数据库永久连接

永久的数据库连接是指在脚本结束运行时不关闭的连接。当收到一个永久连接的请求时。PHP 将检查是否已经存在一个(前面已经开启的)相同的永久连接。如果存在,将直接使用这个连接;如果不存在,则建立一个新的连接。所谓“相同”的连接是指用相同的用户名和密码到相同主机的连接。 

对 web 服务器的工作和分布负载没有完全理解的读者可能会错误地理解永久连接的作用。特别的,永久连接不会在相同的连接上提供建立“用户会话”的能力,也不提供有效建立事务的能力。实际上,从严格意义上来讲,永久连接不会提供任何非永久连接无法提供的特殊功能。 

为什么? 

这和 web 服务器工作的方式有关。web 服务器可以用三种方法来利用 PHP 生成 web 页面。 

第一种方法是将 PHP 用作一个“外壳”。以这种方法运行,PHP 会为向 web 服务器提出的每个 PHP 页面请求生成并结束一个 PHP 解释器线程。由于该线程会随每个请求的结束而结束,因此任何在这个线程中利用的任何资源(例如指向 SQL 数据库服务器的连接)都会随线程的结束而关闭。在这种情况下,使用永久连接不会获得任何地改变――因为它们根本不是永久的。 

第二,也是最常用的方法,是把 PHP 用作多进程 web 服务器的一个模块,这种方法目前只适用于 Apache。对于一个多进程的服务器,其典型特征是有一个父进程和一组子进程协调运行,其中实际生成 web 页面的是子进程。每当客户端向父进程提出请求时,该请求会被传递给还没有被其它的客户端请求占用的子进程。这也就是说当相同的客户端第二次向服务端提出请求时,它将有可能被一个不同的子进程来处理。在开启了一个永久连接后,所有请求 SQL 服务的后继页面都能够重新使用这个已经建立的 SQL Server 连接。 

最后一种方法是将 PHP 用作多线程 web 服务器的一个插件。目前 PHP 4 已经支持 ISAPI、WSAPI 和 NSAPI(在 Windows 环境下),这些使得 PHP 可以被用作诸如 Netscape FastTrack (iPlanet)、Microsoft's Internet Information Server (IIS) 和 O'Reilly's WebSite Pro 等多线程 web 服务器的插件。永久连接的行为和前面所描述的多过程模型在本质上是相同的。注意 PHP 3 不支持 SAPI。 

如果永久连接并没有任何附加的功能,那么使用它有什么好处? 

答案非常简单――效率。当客户端对 SQL 服务器的连接请求非常频繁时,永久连接将更加高效。连接请求频繁的标准取决于很多因素。例如,数据库的种类,数据库服务和 web 服务是否在同一台服务器上,SQL 服务器如何加载负载等。但我们至少知道,当连接请求很频繁时,永久连接将显著的提高效率。它使得每个子进程在其生命周期中只做一次连接操作,而非每次在处理一个页面时都要向 SQL 服务器提出连接请求。这也就是说,每个子进程将对服务器建立各自独立的永久连接。例如,如果有 20 个不同的子进程运行某脚本建立了永久的 SQL 服务器永久连接,那么实际上向该 SQL 服务器建立了 20 个不同的永久连接,每个进程占有一个。 

注意,如果永久连接的子进程数目超过了设定的数据库连接数限制,系统将会产生一些缺陷。如果数据库的同时连接数限制为 16,而在繁忙会话的情况下,有 17 个线程试图连接,那么有一个线程将无法连接。如果这个时候,在脚本中出现了使得连接无法关闭的错误(例如无限循环),则该数据库的 16 个连接将迅速地受到影响。请查阅使用的数据库的文档,以获取关于如何处理已放弃的及闲置的连接的方法。

 

 

 


 

 


 


应用程序和数据库建立连接,如果超过 wait_timeout (默认28000秒8小时) 应用程序不去访问数据库,连接一直处于空闲状态,那么MySQL就会自动关闭该连接 ,如果再在该连接上执行查询操作,就会发生MySQL server has gone away错误。

wait_timeout 

服务器在关闭连接之前在一个连接上等待行动的秒数,默认数值是28800,即如果没有事情发生,服务器在 8个小时后关闭连接。
  

尝试解决办法:

<1>.这是由于超时时间 wait_timeout 过短导致,所以修改它的值即可。打开MySQL安装目录下的 mysql.ini,在文件中添加一行配置项 wait_timeout=1000000 即可。(默认没有此选项,需要手动的添加)
该方法可行。

 

<2>.在代码中设置自动重连选项,

m_connection.set_option( new mysqlpp::ReconnectOption(true) );

 

然后在发生 MySQL server has gone away错误 的时候 调用 Connection::ping()方法,该函数会检查对服务器的连接是否正在工作,必要时重新连接,但经过测试后发现,这种方法不起作用。

posted on 2017-03-22 10:03  wajika  阅读(2019)  评论(0编辑  收藏  举报

导航