目录
Keep-Alive
PHP怎么做
MySQL的wait_timeout和interactive_timeout
总结
首页 后端开发 php教程 PHP数据库长连接mysql_pconnect的细节_PHP教程

PHP数据库长连接mysql_pconnect的细节_PHP教程

Jul 13, 2016 am 10:33 AM
php 长连接

PHP的MySQL持久化连接,美好的目标,却拥有糟糕的口碑,往往令人敬而远之。这到底是为啥么。近距离观察后发现,这家伙也不容易啊,要看Apache的脸色,还得听MySQL指挥。

对于作为Apache模块运行的PHP来说,要实现MySQL持久化连接,首先得取决于Apache这个web服务器是否支持Keep-Alive。

Keep-Alive

Keep-Alive是什么东西?它是http协议的一部分,让我们复习一下没有Keep-Alive的http请求,从客户在浏览器输入一个有效url地址开始,浏览器就会利用socket向url对应的web服务器发送一条TCP请求,这个请求成功一次就得需要来回握三次手才能确定,成功以后,浏览器利用socket TCP连接资源向web服务器请求http协议,发送以后就等着web服务器把http返回头和body发送回来,发回来后浏览器关闭socket连接,然后做http返回头和body的解析工作,最后呈现在浏览器上的就是漂亮的页面了。这里面有什么问题呢?TCP连接需要三次握手,也就是来回请求三次方能确定一个TCP请求是否成功,然后TCP关闭呢?来回需要4次请求才能完成!每次http请求就3次握手,4次拜拜,这来来回回的不嫌累啊,多少时间和资源都被浪费在socket连接关闭上了,能不能一次socket TCP连接发送多次http请求呢?于是Keep-Alive就应运而生,http/1.0里需要客户端自己在请求头加入Connection:Keep-alive方能实现,在这里我们只考虑http1.1了,只需要设置一下Apache,让它默认就是Keep-Alive持久连接模式(Apache必须1.2+才能支持Keep-Alive)。在httpd.conf里找到KeepAive配置项,果断设置为On,MaxKeepAliveRequests果断为0(一个持久TCP最多允许的请求数,如果过小,很容易在TCP未过期的情况下,达到最大连接,那下次连接就又是新的TCP连接了,这里设置0表示不限制),然后对于mysql_pconnect最重要的选项KeepAliveTimeout设置为15(表示15秒)。

好了,重启Apache,测试一下,赶紧写行东西:

<?php
    echo "Apache进程号:". getmypid();
?>
登录后复制

很简单,获取当前PHP执行者(Apache)的进程号,用浏览器浏览这个页面,看到什么?对,有看到一串进程号数字,15秒内,连续刷新页面,看看进程号有无变化?木有吧?现在把手拿开,交叉在胸前,度好时间,1秒,2秒,3,...15,16。好,过了15秒了,再去刷新页面,进程号有没有变化?变了!又是一个新的Apache进程了,为什么15秒后就变成新的进程了?记得我们在Apache里设置的KeepAliveTimeout吗?它的值就是15秒。现在我们应该大致清楚了,在web服务器默认打开KeepAlive的情况下,客户端第一次http成功请求后,Apache不会立刻断开socket,而是一直监听来自这一客户端的请求,监听多久?根据KeepAliveTimeout选项配置的时间决定,一旦超过这一时间,Apache就会断开socket了,那么下次同一客户端再次请求,Apache就会新开一个进程来相应。所以我们之前15内不停的刷新页面,看到的进程号都是一致的,表明是浏览器请求给了同一个Apache进程。

浏览器是怎么知道不需要重新进行TCP连接就可以直接发送http请求呢?因为http返回头里就会带上Connection:keep-alive,Keep-alive:15两行,意思就是让客户端浏览器明白,这次socket连接我这边还没关闭呢,你可以在15内继续使用这个连接,并发送http请求,于是乎浏览器就知道应该怎么做了。

PHP怎么做

那么,PHP的MySQL连接资源是怎么被hold住的呢,这需要查看PHP的mysql_pconnect的函数代码,我看了下,大概的做法就是mysql_pconnect根据当前Apache进程号,生成hash key,找hash表内有无对应的连接资源,没有则推入hash表,有则直接使用。有些代码片段可以说明(具体可查看PHP5.3.8源码ext/mysql/PHP_mysql.c文件690行PHP_mysql_do_connect函数)

	#1.生成hash key
	user=php_get_current_user();//获取当前PHP执行者(Apache)的进程唯一标识号
	//hashed_details就是hash key
	hashed_details_length = spprintf(&hashed_details, 0, "MySQL__%s_", user);
    #2.如果未找到已有资源,就推入hash表,名字叫persistent_list,如果找到就直接使用
	/* try to find if we already have this link in our persistent list */
	if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) {  
		/* we don't */
		...
		...
		/* hash it up(推入hash表) */
		Z_TYPE(new_le) = le_plink;
		new_le.ptr = mysql;
		if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
			...
     		...      
			}
   		}
		else
		{/* The link is in our list of persistent connections(连接已在hash表里)*/
            ...
            ...
            mysql = (PHP_mysql_conn *) le->ptr;//直接使用对应的sql连接资源
            ...
            ...
		}
登录后复制

zend_hash_find比较容易看明白,原型是zend_hash_find(hash表,key名,key长,value);如果找到,value就有值了。

MySQL的wait_timeout和interactive_timeout

说完Keep-Alive,该到MySQL家串串门了,说的是mysql_pconnect,怎么能绕开MySQL的设置。影响mysql_pconnect最重要的两个参数就是wait_timeout和interactive_timeout,它们是什么东西?先撇一边,首先让我们把上面的代码改动一下PHP代码

<?php
    $conn = mysql_pconnect("localhost","root","123456") or die("Can not connect to MySQL");
    echo "MySQL线程号:". MySQL_thread_id($conn). "<br />";
    echo "Apache进程号". getmypid();
?>
登录后复制

以上的代码没啥好解释的,让我们用浏览器浏览这个页面,看到什么?看到两个显眼的数字。一个是MySQL线程号,一个是Apache进程号,好了,15秒后再刷新这个页面,发现这两个id都变了,因为已经是新的Apache进程了,进程id是新的,hash key就变了,PHP只好重新连接MySQL,连接资源推入persistent list。如果15内刷新呢?Apache进程肯定不变,MySQL线程号会变吗?答案得问MySQL了。首先这个MySQL_thread_id是什么东西?shell方式登录MySQL后执行命令'show processlist;',看到了什么?

mysql> show processlist;
+-----+------+-----------+------+--------+-----+------+-----------------+
| Id  | User | Host      | db   | Command| Time| State| Info            |
+-----+------+-----------+------+--------+-----+------+-----------------+
| 348 | root | localhost | NULL | Query  |    0| NULL | show processlist|
| 349 | root | localhost | NULL | Sleep  |    2|      | NULL            |
+-----+------+-----------+------+--------+-----+------+-----------------+
登录后复制

发现了很重要的信息,这个processlist列表就是记录了正在跑的线程,忽略Info列为show processlist那行,那行是你当前shell登录MySQL的线程。PHP连接MySQL的线程就是Id为349那行,如果读者自己做测试,应该知道这个Id=349在你的测试环境里是另外一个值,我们把这个值和网页里输出的MySQL_thread_id($conn)做做比较,对!他们是一样的。接下来最重要的是观察Command列和Time列,Command = Sleep,表明什么?表明我们mysql_pconnect连接后就一直在sleep,Time字段就告诉我们,这个线程Sleep了多久,那么Sleep了多久这个线程才能作废呢?那就是wait_timeout或者interactive_timeout要做的工作了,他们默认的值都是8小时,天啊,太久了,所以如果说web服务器关掉KeepAlive支持,那个这个processlist很容易就被撑爆,就爆出那个Too many connections的错误了,max_connectiosns配置得再多也没用。为了观察这两个参数,我们可以在MySQL配置文件my.cnf里设置这两个值,找到[MySQLd]节点,在里面设置多两行

interactive_timeout = 60
wait_timeout        = 30
登录后复制

配置完后,重启MySQL,shell登录MySQL,这时候show processlist可以发现只有当前线程。然后运行那个带有mysql_pconnect的PHP页面,再回来MySQL端show processlist可发现,多了一个Commond为Sleep的线程,不停的show processlist(方向键上+enter键)观察Time列的变化2,5,10...14!,突然那个Sleep线程程被kill掉了,咋回事,还没到30秒呢,噢!忘了修改一下Apache keepalive的参数了,把KeepAliveTimeOut从15改成120(只为观察,才这么改),重启Apache。刷新那个页面,好,开始不停的show processlist,2..5..10..14,15,..20...26....28,29!线程被kill,这次是因为wait_timeout起了作用,浏览器那边停了30秒,30内如果浏览器刷新,那这个Time又会从0开始计时。这种连接不属于interactive connection(MySQL shell登录那种连接就属于interactive connection),所以采用了wait_timeout的值。如果mysql_pconnect的第4个参数改改呢

<?php
$conn = mysql_pconnect('localhost','root','123456',MySQL_CLIENT_INTERACTIVE);
echo "MySQL线程号:".MySQL_thread_id($conn)."<br />";
echo "Apache进程号:".getmypid();
?>
登录后复制

刷新下页面,MySQL那边开始刷show processlist,这回Time > 30也不会被kill,>60才被kill了,说明设置了MySQL_CLIENT_INTERACTIVE,就会被MySQL视为interactive connection,那么这次PHP的MySQL连接在120秒内未刷新的情况下,何时作废将取决于MySQL的interactive_timeout的配置值。

总结

PHP的mysql_pconnect要达到功效,首先必须保证Apache是支持keep alive的,其次KeepAliveTimeOut应该设置多久呢,要根据自身站点的访问情况做调整,时间太短,keep alive没啥意义,时间太长,就很可能为一个闲客户端连接牺牲很多服务器资源,毕竟hold住socket监听进程是要消耗cpu内存的。最后Apache的KeepAliveTimeOut配置得和MySQL的time out配置要有个平衡点,联系以上的观察,假设mysql_pconnect未带上第4个参数,如果Apache的KeepAliveTimeOut设置的秒数比wait_timeout小,那真正对mysql_pconnect起作用的是Apache而不是MySQL的配置。这时如果MySQL的wait_timeout偏大,并发量大的情况下,很可能就一堆废弃的connection了,MySQL这边如果不及时回收,那就很可能Too many connections了。可是如果KeepAliveTimeOut太大呢,又回到之前的问题,所以貌似Apache。KeepAliveTimeOu不要太大,但比MySQL。wait_timeout 稍大,或者相等是比较好的方案,这样可以保证keep alive过期后,废弃的MySQL连接可以及时被回收。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/752494.htmlTechArticlePHP的MySQL持久化连接,美好的目标,却拥有糟糕的口碑,往往令人敬而远之。这到底是为啥么。近距离观察后发现,这家伙也不容易啊,要...
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

CakePHP 项目配置 CakePHP 项目配置 Sep 10, 2024 pm 05:25 PM

在本章中,我们将了解CakePHP中的环境变量、常规配置、数据库配置和电子邮件配置。

适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 带来了多项新功能、安全性改进和性能改进,同时弃用和删除了大量功能。 本指南介绍了如何在 Ubuntu、Debian 或其衍生版本上安装 PHP 8.4 或升级到 PHP 8.4

CakePHP 日期和时间 CakePHP 日期和时间 Sep 10, 2024 pm 05:27 PM

为了在 cakephp4 中处理日期和时间,我们将使用可用的 FrozenTime 类。

CakePHP 文件上传 CakePHP 文件上传 Sep 10, 2024 pm 05:27 PM

为了进行文件上传,我们将使用表单助手。这是文件上传的示例。

CakePHP 路由 CakePHP 路由 Sep 10, 2024 pm 05:25 PM

在本章中,我们将学习以下与路由相关的主题?

讨论 CakePHP 讨论 CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP 是 PHP 的开源框架。它的目的是使应用程序的开发、部署和维护变得更加容易。 CakePHP 基于类似 MVC 的架构,功能强大且易于掌握。模型、视图和控制器 gu

如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也称为 VS Code,是一个免费的源代码编辑器 - 或集成开发环境 (IDE) - 可用于所有主要操作系统。 VS Code 拥有针对多种编程语言的大量扩展,可以轻松编写

CakePHP 创建验证器 CakePHP 创建验证器 Sep 10, 2024 pm 05:26 PM

可以通过在控制器中添加以下两行来创建验证器。

See all articles