curl与file_get_contents访问远程接口慢的解决

  这几天在协调处理短信接口调用失败的问题,处理完后发现发送短信很耗时,要5秒左右,是PHP调用 file_get_contents访问远程接口的的,而我前面处理调用失败问题时最后测试短信接口时是直接用的Linux命令curl调用,速度是非常快的。

  先从代码入手,刚开始以为是file_get_contents比curl慢,虽然觉得也不至于慢到这种程度,但是总得试试看,于是换成curl,依旧很慢。

  难道是域名解析问题?于是在hosts文件里写好本地解析,再试,果真正常了,秒发。看来真是域名解析问题,但又不知为何Shell里没问题,独独PHP里有问题。虽然把域名写死在hosts里能解决问题,但是总不是办法。

  上网查,有人说是PHP缓存了域名解析,重启PHP即可。我马上去重启PHP,还真好了。但是有一点我不明白,既然是缓存,那应该是速度更快才对。在一个技术群里讨论时我突然想起来昨天测试接口时发现服务器设置的首选DNS是不能用的,然后我改了。难道PHP缓存的不是域名解析,而是域名解析服务器(DNS)?看来只有这个解释了,有空可以做个测试验证一下。

PHP中Notice: iconv(): Unknown error (84) 的解决办法

   今天在写一个导出数据到csv的功能,为了防止中文乱码,需要将utf8转码,我使用了这样的语句:

#这里先是把csv文件的内容生成,然后下面转码
$csv=iconv('utf-8','gb2312',$csv);

结果报Notice: iconv(): Unknown error (22)的错误,想起来$csv里带有换行,所以没办法转换,于是在各个数据项串成csv文件内容前转换,这时报了两个iconv(): Unknown error (84)的错误,输出内容,发现报错时有一个是处理汉字“密菓”,第二个字不认得,生僻,我突然想到,难道是字符集不支持,于是换成gbk:

$csv .= iconv('utf-8','gbk',$val)

再运行,没报错了。

使用socket方式连接Nginx优化php-fpm性能

Nginx连接fastcgi的方式有2种:TCP和unix domain socket

什么是Unix domain socket?—— 维基百科
Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。与管道相比,Unix domain sockets 既可以使用字节流和数据队列,而管道通信则只能通过字节流。Unix domain sockets的接口和Internet socket很像,但它不使用网络底层协议来通信。Unix domain socket 的功能是POSIX操作系统里的一种组件。

Unix domain sockets 使用系统文件的地址来作为自己的身份。它可以被系统进程引用。所以两个进程可以同时打开一个Unix domain sockets来进行通信。不过这种通信方式是发生在系统内核里而不会在网络里传播。

TCP和unix domain socket方式对比
TCP是使用TCP端口连接127.0.0.1:9000
Socket是使用unix domain socket连接套接字/dev/shm/php-cgi.sock(很多教程使用路径/tmp,而路径/dev/shm是个tmpfs,速度比磁盘快得多

测试机是个1核的centos5.4,2用户并发时系统资源消耗50%左右,10用户资源就跑得很满了。

 
    2users 10users
nginx/1.2.9 + PHP 5.2.5 tcp 1060 1294
nginx/1.2.9 + PHP 5.2.5 socket 997 1487
nginx/1.2.9 + PHP 5.3.10 tcp 906 1082
nginx/1.2.9 + PHP 5.3.10 socket 880 1247

结论是在服务器压力不大的情况下,tcp和socket差别不大,但在压力比较满的时候,用套接字方式,效果确实比较好。

下面是php 5.3以上版本将TCP改成socket方式的配置方法:

修改php-fpm.conf(/usr/local/php/etc/php-fpm.conf)

XML/HTML代码
  1. ;listen = 127.0.0.1:9000  
  2. listen = /dev/shm/php-cgi.sock  

修改nginx配置文件server段的配置,将http的方式改为socket方式

XML/HTML代码
  1. location ~ .php$ {  
  2.     #fastcgi_pass   127.0.0.1:9000;  
  3.     fastcgi_pass unix:/dev/shm/php-cgi.sock;  
  4.     fastcgi_index  index.php;  
  5.     fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;  
  6.     include        fastcgi_params;  
  7. }  

重启php-fpm与nginx

service nginx restart
service php-fpm restart

然后
ls -al /dev/shm
可以看到php-cgi.sock文件unix套接字类型

参考:http://zh.wikipedia.org/wiki/Unix_domain_socket

 

转载后记:我根据上文配置完后,访问PHP页面出现502,查看Nginx日志,有错误信息:nginx error connect to php-cgi.sock failed (13: Permission denied)

编辑配置文件/usr/local/php/etc/php-fpm.conf

;listen.owner = nobody
;listen.group = nobody
;listen.mode = 0660
改为
listen.owner = nobody
listen.group = nobody
listen.mode = 0666

保存,重启PHP-FPM即可

 

xhprof与Xdebug的奇怪问题

  为了查找项目中比较耗性能的PHP代码,这两天在装xhprof用来跟踪代码,结果遇到了一个很奇怪的问题。安装配置好xhprof后,用来跟踪简单的代码没一点问题,但是在项目中一跟踪,PHP-FPM进程直接就挂了,查看各种日志,并且开了内核转储,折腾了半天也没找到挂了的原因。

  没办法,只好换Xdebug。安装,配置,很快就搞定了。

  在使用Xdebug前我突发奇想,不知道Xdebug能不能跟踪到xhprof导致PHP-FPM挂了的的问题,于是同时启用两者,结果意外地发现xhprof也能用了。为了证明是不是Xdebug导致xhprof可以用了,我禁用了Xdebug,xhprof又导致PHP-FPM挂了,重新启用又好了。

  真是好奇怪的问题,不知道是什么原因造成的,暂时也没时间深究了。

附Xhprof的安装与使用方法:

XML/HTML代码
  1. [root@localhost ~]# tar -zxvf xhprof-0.9.4.tgz     
  2. [root@localhost ~]# cd xhprof-0.9.4/extension/    
  3. [root@localhost extension]# phpize    
  4. [root@localhost extension]# ./configure –with-php-config=/usr/local/php/bin/php-config    
  5. [root@localhost extension]# make    
  6. [root@localhost extension]# make install  

如果phpize执行不了,请先安装或者做链接:ln -s /usr/local/php/bin/phpize /usr/bin/phpize

在php.ini文件中,添加如下配置:

XML/HTML代码
  1. [xhprof]    
  2. extension=xhprof.so;    
  3. ; directory used by default implementation of the iXHProfRuns    
  4. ; interface (namely, the XHProfRuns_Default class) for storing    
  5. ; XHProf runs.    
  6. ;    
  7. ;xhprof.output_dir=<directory_for_storing_xhprof_runs>    
  8. xhprof.output_dir=/tmp/xhprof    

把xhprof-0.9.4目录下的目录xhprof_html 和 xhprof_lib 下的所有文件拷贝到你网站的主目录下

PHP代码
  1. <?php    
  2. //cpu: XHPROF_FLAGS_CPU    
  3. //内存: XHPROF_FLAGS_MEMORY    
  4. //如果都监控用XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY    
  5. xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);    
  6.     
  7. //这中间是需要性能分析的php代码  
  8.     
  9. //停止性能分析    
  10. $data = xhprof_disable();     
  11.   
  12. //显示性能分析数据    
  13. include_once "xhprof_lib/utils/xhprof_lib.php";     
  14. include_once "xhprof_lib/utils/xhprof_runs.php";     
  15. $objXhprofRun = new XHProfRuns_Default();     
  16.   
  17. //第一个参数 是xhprof_disable()的返回值    
  18. //第二个参数 是自定义命名空间字符串     
  19. //返回运行id,用这个id查看相关运行结果    
  20. $run_id = $objXhprofRun->save_run($data"xhprof");    
  21.   
  22. //查看运行结果的url    
  23. //run的值来源于save_run的返回值    
  24. //source值来源于save_run的第二个参数                                     
  25. //www.abc.com 需要用自己的域名替换    
  26. echo "<a href='http://www.abc.com/xhprof_html/index.php?run=".$run_id."&source=xhprof'>查看结果</a>";  

 

Ajax返回结果中文乱码的解决办法

情景:用JQuery的Ajax调用他站接口查询数据。

代码:

Javascript代码
  1. $.getJSON(  
  2.     $strurl + "/fwqueryjson.asp?callback=?",  
  3.     { FwCode: $FwCode.val() },  
  4.     function(data) {$CheckResult.html(data.QueryResult);}  
  5. );  

现象:返回的结果里的中文是乱码,英文与数字正常。

原因:本地是UTF-8编码,他站是GB2312编码,请求时默认以本地编码发起请求,与远端不一致,导致乱码。

解决:先指定Ajax请求的编码,代码如下

Javascript代码
  1. $.ajaxSetup({ scriptCharset: "gb2312" , contentType: "application/json; charset=gb2312"});  

 

PHP5.5编译安装之后设定PHP-FPM自启动及服务控制

   PHP-5.3.3版本以后PHP已经包含了PHP-FPM,编译时加上参数–enable-fpm就会安装PHP-fpm。

  php-fpm装完后默认没有自动启动,需要设置自动启动。PHP-5.3.3版本以后源代码包中已经自带启动脚本,复制到/etc/init.d目录下,并更改权限,命令如下:

cp <php-source-dir>/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
chmod 755 /etc/init.d/php-fpm

然后使用chkconfig设定开机启动:

chkconfig php-fpm on

修改php-fpm配置文件,如果PID文件配置被注释了,就删除pid = run/php-fpm.pid前面的分号。

这样设置完后同时也能用/etc/init.d/php-fpm来控制php-fpm了,参数有:start|stop|force-quit|restart|reload|status,如重启就用命令:/etc/init.d/php-fpm restart

如果启动时报路径错误,就检查下/etc/init.d/php-fpm里的相关路径。

nginx与php-fpm打开PHP页面报错File not found

   最近在虚拟机上装了个CentOS6.5,由于是以最小化的方式装的,装LNMP环境时缺少好多东西,特别是安装PHP时缺少很多东西,过程是非常的曲折。

  我装的版本分别是:Nginx 1.6.0,Mysql 5.6.19,PHP 5.5.14。前两个用Yumj装起来还比较顺利,装PHP的时候我采用自己编译的方式安装,以php-fpm的方式与Nginx配合,装完后写了个php文件,一访问提示File not found,查看Nginx日志,有错误信息:

[error] "1842#0" *7 connect() failed (111: Connection refused)

用命令netstat -ano | grep 9000查了一下,发现9000端口没开,应该是php-fpm没有启动。马上去启动:

#/usr/local/sbin/php-fpm

启动php-fpm后还是提示File not found。再查看Nginx的错误日志,这回的错误信息是:

FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream

折腾了半天,发现Nginx默认的配置文件是站点的root写在了各个location配置块里了,之前只改了根目录的配置,没注意php配置这块里也有一个,将root这个参数移到server块下,将配置PHP的那块location改成:

XML/HTML代码
  1. location ~ .php$ {  
  2.     try_files $uri =404;  
  3.     fastcgi_pass   127.0.0.1:9000;  
  4.     fastcgi_index  index.php;  
  5.     fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;  
  6.     include        fastcgi_params;  
  7. }  

其中try_files $uri =404;这个配置项是为了让Nginx判断文件不存在就直接返回404,而不用再发给php-fpm去处理。

重启Nginx:

#service nginx restart

CentOS下yum安装Nginx

 CentOS里直接用yum安装Nginx是不会成功的,要先做一些处理。

先到http://nginx.org/en/linux_packages.html找到适合你的CentOS版本的rpm包,记下路径

执行:

rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm

系统就会开始自动下载这个rpm包,然后安装。你也可以先用wget下载这个包,然后再运行rpm命令来安装。

然后就可以直接用yum install nginx来安装Nginx了。

安装完后在浏览器里打开127.0.0.1,如果看到Welcome to nginx!这样的内容,说明安装成功了。

Centos 6的单网卡多IP设置

cd /etc/sysconfig/network-scripts #进入网卡配置目录
cp ifcfg-eth0 ifcfg-eth0:0 #拷贝一个网卡配置文件
vi ifcfg-eth0:0 #用vi编辑器编辑
内容如下:
DEVICE=eth0:0 #此处添加:0,保持和文件名一致,添加多个IP依次递增
ONBOOT=yes #是否开机激活
BOOTPROTO=static #静态IP,如果需要DHCP获取请输入dhcp
IPADDR=192.168.1.2 #此处修改为要添加的IP
NETMASK=255.255.255.0 #子网掩码根据你的实际情况作修改

保存完之后重启网卡让设置生效,也可以重启服务器。

重启网卡命令:service network restart
重启服务器命令:reboot

只要设置没有问题,重启之后新添加的ip就生效了。用ifconfig查看IP

加IP段:
vi ifcfg-eth0-range0 #用Vi编辑配置文件
内容如下:
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR_START=192.168.2.2 #起始IP
IPADDR_END=192.168.2.254 #结束IP
CLONENUM_START=1 #表示这段IP网卡号从eth0:1开始
NETMASK=255.255.255.0

Centos 6 最小化安装后的网络设置

 在centos最小化安装刚安装完毕的时候。如果不经过设置是无法联网的,

不能联网的原因基本就是以下的3个。

1.没有网卡驱动。
如果ifconfig中只有lo,并且sudo ifconfig eth0 up都找不到网卡,那基本就是网卡没有驱动起来了。

2.网卡没有开机启动
这种情况挺多的,貌似在安装系统后才添加的网卡都不是默认启动的。这时候可以试试sudo ifconfig eth0 up (具体是eth几要看你是第几块网卡)。如果up成功了,ifconfig看看有没有对应的网卡的信息。如果有信息,那就说明网卡没有开机自动加载,只要在对应网卡的配置文件中加入 ONBOOT=yes 就ok了。如果up不成功,驱动又已经装好了,那这个问题就不在本文的讨论范围内了。

3.DHCP
如果centos的dhclient没有开机启动。这时候就要根据你的网络情况开启dhclient或手动设置ip。试着输入sudo dhclient eth1 (同上,网卡编号看情况),如果启动后获得了ip,那么就是这个问题了。解决的方法也很简单,一种是在开机脚本中写入dhclient,另一种则是在网卡的配置文件中加入BOOTPROTO=dhcp。个人推荐第二种。