Category Archives: PHP
理解PHP中Mysql的永久连接
参考自这里 PHP程序员应该都知道连接MySQL数据库可以使用mysql_pconnect(永久连接)函数,使用数据库永久连接可以提高效率,但是实际应用中数据库永久连接往往会导致出现一些问题,通常的表现就是在大访问量的网站上时常发生断断续续的无法连接数据库的情况,出现类似"Too many connections in ..."的错误提示信息,重新启动服务器又正常了,但过不了一会儿又出现同样的故障。对于这些问题的成因,恐怕就不是每个人都能说清楚的了,虽然PHP文档里有一些相关资料,但是解释的并不浅显易懂,这里我厚着脸皮试图做一个简单的讨论,所述观点不见得全都正确,欢迎大家反馈意见。 首先看看数据库永久连接的定义: 永久的数据库连接是指在脚本结束运行时不关闭的连接。当收到一个永久连接的请求时。PHP 将检查是否已经存在一个(前面已经开启的)相同的永久连接。如果存在,将直接使用这个连接;如果不存在,则建立一个新的连接。所谓“相同”的连接是指用相同的用户名和密码到相同主机的连接。 PHP使用永久连接方式操作MySQL是有前提的:就是PHP必须安装为多线程或多进程Web服务器的插件或模块。最常见的形式是把PHP用作多进程Apache服务器的一个模块。对于一个多进程的服务器,其典型特征是有一个父进程和一组子进程协调运行,其中实际生成Web页面的是子进程。每当客户端向父进程提出请求时,该请求会被传递给还没有被其它的客户端请求占用的子进程。这也就是说当相同的客户端第二次向服务端提出请求时,它将有可能被一个不同的子进程来处理。在开启了一个永久连接后,所有不同子进程请求SQL服务的后继页面都能够重新使用这个已经建立的 SQL服务器连接。它使得每个子进程在其生命周期中只做一次连接操作,而非每次在处理一个页面时都要向 SQL 服务器提出连接请求。每个子进程将对服务器建立各自独立的永久连接。PHP本身并没有数据库连接池的概念,但是Apache有进程池的概念, 一个Apache子进程结束后会被放回进程池, 这也就使得用mysql_pconnect打开的的那个mysql连接资源可以不被释放,而是依附在相应的Apache子进程上保存到了进程池中。于是在下一个连接请求时它就可以被复用。一切看起来似乎都很正常,但是在Apache并发访问量大的时候,如果使用mysql_pconnect,会由于之前的Apache子进程占用的MySQL连接没有close, 很快使MySQL达到最大连接数,使得之后的请求可能得不到响应。 上面的部分文字是摘抄自PHP文档,看起来可能还是有些文绉绉的不好理解,那么我就用大白话再举一个例子来说明问题: 假设Apache配置最大连接数为1000,MySQL配置最大连接数为100,当Apache服务器接到200个并发访问的时候,其中100个涉及到数据库访问,剩下的100个不涉及数据库访问,因为这个时候还不存在可用的数据库连接,所以这里面涉及到数据库访问的100个并发会同时产生100个数据库永久连接,达到了数据库最大连接数,当这些操作没有结束的时候,任何其他的连接都无法再获得数据库连接,当这些操作结束了,相应的连接会被放入进程池,此时Apache的进程池里就有了200个空闲的子进程,其中100个是带有数据库连接的,由于Apache会为访问请求随机的挑选空闲子进程,所以你得到的子进程很可能是不包含数据库连接的那100个中的一个,而数据库连接已经达到了最大值,你也不可能成功的建立新的数据库连接,唉,你便只好不停的刷新页面,哪个时候运气好,碰巧分配到了带有数据库连接的子进程,才能正常浏览页面。如果是大访问量的网站来说,任何时候都可能存在大量的并发,所以浏览者可能就会不停的发现无法连接数据库的现象了。 或许你会说,我们把Apache和MySQL的最大连接数调成一样大不就可以了么?是的,合理的调整这个最大连接数某种程度上会避免这个问题的发生,但是Apache和MySQL的负载能力是不同的,如果按照Apache的负载能力来设置,对于MySQL来说,这个最大连接数就偏大,会产生大量的MySQL数据库永久连接,打个比方,就好像和平时代还要养活一个几百万的军队一样,其开销得不偿失;而如果按照Mysql的负载能力设置,对于Apache来说,这个最大连接数就偏小,有点杀鸡牛刀的感觉,无法发挥Apache的最大效率。 所以按照PHP手册上的介绍,只适合在并发访问不大的网站上使用数据库永久连接,但对于一个并发访问不大的网站来说,使用数据库永久连接带来的效率提高似乎没有太大的意义,从这个角度上来看,我觉得PHP中的数据库永久连接基本上是一个鸡肋的角色,如果你一定要使用数据库连接池的概念,可以尝试一下sqlrelay或者Apache本身提供的mod_dbd,说不定会有惊喜。
Web-Server 中 PHP 的两种工作方式
部分内容参考自这里, 这里 在项目生产环境的 Web-Server 中 PHP.exe 通常以两种工作方式工作, 一种是 Apache 中的模块化方式, 另一种是在 Nginx 中的 FastCGI 方式. 除此之外, PHP.exe 还有一种古老的运行方式: CGI 方式, 这种方式基本上已经被淘汰, 我们可以通过 CGI 方式来很好的理解前两种方式. CGI 方式是: #当 Web-Server 启动时: 1, Web-Server 只初始化自身. #web 请求处理过程是: 1, 用户(浏览器)发起一个 *.php 文件的请求给 Web-Server 2, Web-Server 调用 php.exe 3, php.exe 完成一系列的初始化动作(如: 解析 php.ini , 载入全部扩展, ...) 4, php.exe 初始化完成, 解释 [...]
Zend Studio 使用 Xdebug 断点调试
部分内容参考自 这里 1, 下载 Xdebug # 下载地址 # http://xdebug.org/download.php # 寻找和自己所安装的 php 版本对应的 Xdebug 下载 # 对于 Windows 版本的 php 可以查看 phpinfo() 函数的打印信息, 查找"PHP Extension Build", 看你的 PHP 版本是 VC 几的, 2, 安装 # 安装说明页 # http://xdebug.org/docs/install # 对于 Windows 版本, 下载完成后将下载的 dll 文件重命名为 php_xdebug.dll # 将其复制到 PHP 的扩展目录中去 (例如: D:\Program Files\EasyPHP-5.3.2i\php\ext\ ) 3, 修改 [...]
Zend Studio 中 PHP Language Library 的用处
如果你在用 Zend Studio 编写 PHP 项目时发现调用系统函数时调试正常, 但是在编写代码时却提示函数未定义"Call to undefined function 'xxx'", 在左侧语法检测状态区域栏总是显示个小黄色的三角形的感叹号, 实在是看着扎眼. 解决办法: 1, 修改项目 .buildpath 文件 # .buildpath 文件内容类似下面的 <?xml version="1.0" encoding="UTF-8"?> <buildpath> <buildpathentry kind="src" path=""/> </buildpath> # 新增一句 kind="con" <?xml version="1.0" encoding="UTF-8"?> <buildpath> <buildpathentry kind="src" path=""/> <buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/> </buildpath> 2, 重置项目编译状态 Project -> Clean -> Clean all projects 3, 重新编译项目 Project [...]
Memcache 内存空间划分方法
参考自 这里, 这里, 这里, 这里 假如我们要存放的数据为 200 Bytes , 当向 memcache 存放数据时: 1, memcache 先检查数据的大小, 得到数据尺寸(200 Bytes); 2, 再检查 memcache 已划分过的并且可用的并且自身大小大于数据尺寸的最小容量的 chunk , 如果有存在这样的 chunk , 跳到第 4 步, 如果没有跳到第 3 步; 3, memcache 向内存申请 1MB 的空间并将这 1MB 的空间划分为 4096 个大小为 256 Bytes 的 chunk; 为什么是 4096 个? 1M = 1024K = 1048576B 1048576 / [...]
PHPDocumentor安装与使用
PHPDocumentor 是一个用PHP写的工具, 对于有规范注释的php程序, 它能够快速生成具有相互参照,索引等功能的API文档. 安装环境: 本机安装的是 EasyPHP-5.3.2i 套件, 安装目录是 D:\Program Files\EasyPHP-5.3.2i\ php.exe 所在路径是 D:\Program Files\EasyPHP-5.3.2i\php\php.exe 首先安装 PEAR: 1, 修改 D:\Program Files\EasyPHP-5.3.2i\php\go-pear.bat 内容如下: @ECHO OFF set PHP_BIN=%CD%\php.exe "%PHP_BIN%" -d output_buffering=0 -d phar.require_hash=0 PEAR\go-pear.phar pause 2, 开始->运行->cmd, 执行 go-pear.bat 开始安装 Pear, 一路回车 Microsoft Windows XP [版本 5.1.2600] (C) 版权所有 1985-2001 Microsoft Corp. C:\Documents and Settings\kuco>D: D:\>cd D:\Program [...]
PHP错误信息显示不完全
昨天在调试程序的时候发现 PHP 错误信息显示有点怪怪的, 但又说不出是哪个地方怪. 于是写了两行错误的代码测试一下: <?php phpinfo() //这行末故意少写了个括号 exit; //知道为什么要加上这一句话吗? 请看P.S. ?> 一运行, 报错: Parse error: s in E:\www\test\004.php on line 3 正确的报错应该是: Parse error: syntax error, unexpected T_EXIT in E:\www\test\004.php on line 3 怎么错误信息显示不全呢? 奇怪了. 上网搜索也未果. 于是打开 php.ini 一项一项的修改测试终于发现了元凶: ; Set maximum length of log_errors. In error_log information about the source is ; added. [...]
腾讯截取字符串面试题
传说中的腾讯面试题, 写着好玩, 更多解法看这里 <?php /* 题目是: 假设有"123<em>abc</em>456<em>def</em>789"这么一个字符串,写一个函数,可以传入一个字符串,和一个要截取的长度。返回截取后的结果。 要求: 1 <em>和</em>标记不得计算在长度之内。 2 截取后的字符串,要保留原有<em>标签,不过如果最后有一个标签没有闭合,则去掉其开始标签。 示例: 题中的字符串,要截取长度5,则返回的字符串应该为:123ab,要截取长度8,应返回123<em>abc</em>45。 */ function tencent_substr($str, $len) { $splitArr = preg_split("~(<[/]*em>)~is", $str, -1, PREG_SPLIT_DELIM_CAPTURE); $resultLen = 0; for($i=0, $n=count($splitArr); $i<$n; $i++) { if($resultLen >= $len) { unset($splitArr[$i]); continue; } $str = $splitArr[$i]; if($str!="<em>" && $str!="</em>") { $resultLen += strlen($str); if($resultLen <= $len) { continue; [...]
PHP的Session存储优化与存取过程
Session 在 Server 端默认是以文本文件形式保存的保存位置是: # Linux /tmp/sess_* # Windows C:\Windows\temp\sess_* # 或 C:\Documents and Settings\kuco\Local Settings\Temp\sess_* 对于高并发同时在线用户大的网站来说会在同一目录下产生大量的 Session 文件(sess_*), 在同一个目录下文件数过多会导致IO性能下降, 影响 Server 性能. 这时我们可以通过配置 php.ini 中的 session.save_path 项来将 Session 文件分目录保存. # http://php.net/session.save-path # 其中 # N 是指将 Session 文件要存放的目录深度(N级目录) # 例如: 设置 '5;/tmp' Session 文件保存的目录将会看起来像 # /tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If # 注意: 如果存放目录不存在 php 不会自动生成, # 所以要提前手动建好目录: # [...]
理解 Memcache 的服务器端与客户端