6月 282016
 

参考资料:

http://php.net/manual/zh/features.dtrace.php

通过mark的方式,了解php都提供了哪些探针:

php探针完全版: all_probes.stp

 

 Posted by at 下午 5:31
6月 062016
 

参考资料:http://blog.aboutc.net/profiling/17/php-profiler-xhprof

这里不说别的,只记录一个小有意思的事情:

由于所谓的PHP内存泄漏,在程序跑上几分钟后就耗尽内存而退出,据说xhprof很是厉害,可以分析是哪个函数占用了太多内存;由于xhprof没有现成的环境,配置起来花费了一些功夫,最后发现,是pdo_mysql的execute占用了90%+的内存,天哪,用了N多年的东西突然有问题了?冥思苦想,夜不能寐。

突然间,想到一个其他的办法,就是在每段代码前后添加memory_get_usage()来检查是否内存使用有发生变化,如果没有变化,则这部分代码没有问题;如果有变化,则这部分代码有问题;(注意:如果这部分代码有函数调用,则函数调用不应该有大的返回值,如果有自己看着处理);就这样,通过二分法一步一步排查,终于发现,小朋友为了提高性能,使用类的静态变量数组cache了sql查询的结果,这个cache没有大小限制。

然后回到xhprof分析的结果,可以想象,之所以xhprof认为pdo_mysql的execute有问题,是因为这些内存都是该函数申请的,你说pdo_mysql 冤不冤?

 Posted by at 下午 3:40
4月 292016
 

场景:

PHP通过phpredis(https://github.com/phpredis/phpredis)循环执行如下操作:

 

 

发现connect会出现大量超过1s的情况,甚至超过3s;但是,如下图抓包所示:两次请求之间间隔了3s才发送syn请求,并且没有失败,也就是说,并非syn丢包所致,而是因为某种原因导致根本没有发送syn包;但是外部表现却是connect花费了很多时间(3s);

所以,从此推断,连接超时未必就一定是网络的问题,你们究竟会是什么原因导致client端3s后才发送syn的呢?

 

阅读源码发现: redis的connect用的是php提供的connect方法:php_stream_xport_create

其实,fsockopen用的也是该方法,如此的话,不放通过如下脚本直接测试connect:

结果如下:

  1. connect超过1s的还挺不少的
  2. 前面300多次的时候连续出了好几次超过1s的,你们怎么会从374到13489一直没出错呢?而且,运行程序的时候也能感觉到,从第374到第13489花费时间很短的,难道这个区间根本没有发生真正的连接? strace 跟踪统计发现,确实connect了,就是说,一般情况下,connect是很快的
  3. 该问题可能发生在PHP中,也可能发生在glibc中,也可能发生在系统层面,排查办法:
    1. 写一个C的,如果不出现问题,那么就是PHP的问题;如果依然如此,很可能是系统问题
 Posted by at 上午 11:50
3月 302016
 

PHP中默认的sessionid为PHPSESSID;

当然,也可以通过

string session_name ([ string $name ] )

来修改, 官方说明:

name

The session name references the name of the session, which is used in cookies and URLs (e.g. PHPSESSID). It should contain only alphanumeric characters; it should be short and descriptive (i.e. for users with enabled cookie warnings). If name is specified, the name of the current session is changed to its value.

 

疑问: 只能包含字母和数字?

参考源码:

  1. 不能全数字
  2. 当然,sessionid毕竟是个cookie name,也会遵循cookie name的检查(参看: http://phpor.net/blog/post/1122 )
  3. 没有发现哪里体现“只能包含字母和数字”,实测也发现,其实 dot、_ 都是可以的

 

 

 

 Posted by at 下午 5:23
3月 102016
 

如下:

a.php

 

b.php

 

php a.php

 

如果 a.php 中

则输出的是 Group in B;

否则: 输出Group in A;

至少不会冲突

 Posted by at 下午 7:41
2月 112016
 

长连接避免了每次请求都重新建立连接,理论上是好事儿,欣然用之;后发现nginx偶尔会报如下错误:

而且有同事A反应,调用同事B的接口时,收到了200响应码,但是没有收到响应的其他数据,而且确认不是因为超时所致;同事B反馈说,接口执行正常,应该有数据返回,而且确认接口执行速度很快,日志为证。

双方说的都对,事实却是如此,我试图模拟这种情况的出现,模拟办法:

让接口输出响应码后,直接杀死fpm进程,nginx果然报出了几乎一样的错误;但是实际场景中,没有发现fpm猝死的任何蛛丝马迹,也找不到fpm会在响应头输出之后就猝死的理由;

按照以前的风格,我将通过看源码、调试等方式查个水落石出,现在不想了,先把长连接关掉试试吧;(凭啥直接怀疑长连接?凭直觉)

现在,长连接关了有一周时间了,没有再出现类似错误;还有好多更重要的事情要做,先不纠结这个了;服务器端建立连接的代价也没有大到不可以接受,先这样吧!

 Posted by at 下午 1:59
12月 142015
 

或许你会问:刚开始学习PHP的时候都会做文件的上传下载,难道这还有什么要研究的吗?

呃….有

为了方便讨论,这里基于nginx+fpm来讨论。

默认情况下:

对于文件上传下载服务,请求从开始到结束,需要全程有一个fpm进程来伺候的,如果同时有1000个文件上传的请求,则需要有1000个fpm进程来伺候;一般来讲,上传或下载文件都需要持续较长的时间,用一个进程来伺候一个请求不是浪费,是非常浪费

 

 

参考资料:

http://www.jb51.net/article/51854.htm

http://www.ttlsa.com/nginx/nginx-modules-upload-module/

 Posted by at 下午 7:31
11月 112015
 

缘起:

曾经在nginx(1.7.4)两个地方配置过unix socket;一个是nginx日志,一个是fastcgi;但是,这两个地方有所不同。

关于日志的配置,通过unix socket (/dev/log) 写到本地的syslogd,如果syslogd重启了,则/dev/log 其实是被更新了的,但是nginx却不会自动重连,然后nginx就写log失败了。 如此,重启syslogd就得重启nginx,是多么“2”的一件事情啊!

关于fastcgi的配置,通过unix socket访问本地的php-fpm,如果php-fpm重启,则 unix socket不更新,自然影响不到nignx; 如果fpm stop then start,则unix socket会更新,但是,nginx却知道自动重连,也不会影响到nginx。(难道是因为该socket走的是stream的原因?)

注: 如果你不小心将socket文件配到了/tmp 下面,则socket文件可能是660的权限,nginx(用户如果和php-fpm不同)可能就没有权限连接该unix socket

 Posted by at 下午 12:08
11月 042015
 

题记: 学习要细心

曾经,在php中要创建一个权限为 0777的目录:

应该问题不大,写完就交差了,测也不测;后来发现,创建的目录是 0755的,再检查一遍代码,确认是0777,不可能错的!可能是谁给修改成0755了吧?然后就做别的去了…

终于有一天,同事遇到了同样的问题,叫我过去看看,猜测可能和umask有关系,修改umask=0000(零零零零)后,终于创建出了0777的目录了,果然和umask有关系,有点儿坑die吧?

难道是PHP中添加了这种奇怪的逻辑? (写C的同学不要笑我,俺没写过C)

查看PHP源代码,发现PHP的mkdir直接调用的是glibc中的mkdir,没有做任何特殊处理,那么?

man 2 mkdir

有如下描述:

问题真相大白了。

我们知道命令行的mkdir -m 0777 能创建出来777的目录,难道命令行的mkdir用的不是glibc的mkdir?不太可能,参看: mkdir –help

很有可能mkdir在创建目录之后,chmod修改了目录的权限

 Posted by at 上午 10:53