Nginx+PHP-FPM 500 504错误简析

最近新配置的 Nginx + PHP-FPM 环境遇到了几次 Nginx 500(Internal Server Error) 和 504(gateway timeout) 错误。就索性把配置修改的过程记录下来,已备后查。

先说一下 500 错误,这个一般是 PHP 代码错了,看一下 PHP 的 error 日志就清楚了。但有时候是 Nginx 和 PHP-FPM 配置不当导致的,比如说上传文件的场景。我们都知道 php.ini 文件里面 post_max_size 和 upload_max_filesize 两个配置项决定了文件上传的大小。但上调配置后发现大文件上传还是会 500,原来是因为 Nginx 也会限制上传文件的大小,有 client_max_body_size 配置项决定。这里还有一个比较重要的参数:client_body_buffer_size。为了节省资源 Nginx 不会把 request body 里面的数据一口气读到内存中,而是分片处理,这个参数就是设置缓存区的大小(一般也不用改),大于缓冲区大小的数据会以一个个小文件(buffer_size)形式存储到 client_body_temp_path,为了避免高并发下缓存文件冲突和一些文件系统限制(比如 ext3 磁盘格式文件夹下一级文件个数限制为 3.2w 个)以及提高性能可根据业务需要设置多级子目录。还需特别注意的是路径要有被 Nginx 进程写的权限,不然又会 500 错误了。

然后是 504 错误,除了业务代码本身超时更多是配置问题。还是先说 PHP 的配置,很多人都知道 PHP 脚本有执行时间限制(php.ini 中的 max_execution_time),但在 PHP-FPM 却是 php-fpm.conf 中的 request_terminate_timeout 配置项控制的。还有就是 max_input_time 配置项,值比较小的话在接收大文件或大数据量 POST 请求的时候可能会超时,一般不用做改动,因为大部分场景都是上游 web server 接收好数据后传给 PHP-FPM 进程的,传输的非常快,几乎不会超时,但也不能一概而论,要看具体业务场景。然后就是 Nginx 的锅了,刚也说到是 Nginx 接收好(或者说是转发)数据后传给下游,在这个承上启下的环节很容易超时。几个比较重要的配置项:fastcgi_send_timeout 控制向下游(这里是 PHP-FPM)发送数据的超时时间,与之对应的一个配置项是 fastcgi_read_timeout,表示读取下游 response 的超时时间,这里需要注意的是要和前面说的 request_terminate_timeout 保持一致(或大于)。还有一个配置项 fastcgi_connect_timeout,表示和下游 FastCGI 建立连接的超时时间,不过这个值就不用设置的太长了,不然下游某个节点挂了就会夯住 Nginx 的处理线程,影响业务。

我所遇到的场景就是上面这些,可能还有其它一些情况,具体问题具体分析应该也很好解决。

参考资料:

http://nginx.org/en/docs/http/ngx_http_core_module.html

http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html

《PHP-CGI 进程 CPU 100% 与 file_get_contents 函数的关系》 http://zyan.cc/tags/request_terminate_timeout/1/

《PHP超时处理全面总结》 https://segmentfault.com/a/1190000000313184

《PHP file upload affected or not by max_input_time?》 http://stackoverflow.com/questions/11387113/php-file-upload-affected-or-not-by-max-input-time

一个 MySQL 用户名长度的坑

今天使用 PHP 连接一个 MySQL 数据库的时候连不上,提示无权限。

因为 MySQL 是在另外一个机房,首先想到的是防火墙的原因,但使用 MySQL-cli 却能正常连接,遂排除这种可能。

又怀疑是 PHP 框架的问题,写了一个简单的测试脚本,主要语句:mysqli_connect(),并打印出错误。运行一下还是不行,错误如下:

真是奇了怪了,这个用户创建时指定的是通配符 ‘%’,而且在别的机器都可以连接。又把测试脚本放在以前一直运行的环境(PHP 7)中,能运行通过。

看来是是环境问题(PHP 5.4)了,回过头来看那句报错,发现用户名好像被截断了(应该是xxx_user),是不是显示的问题,随便改一个用户名试试,同样报错,用户名却没有截断。这时又想了想是不是 MySQL 的版本太高(5.7.10)了。找了个 MySQL 5.5 的环境,创建相同的用户却发现报错了:String ‘xxx_user’ is too long for user name (should be no longer than 16)。查询 MySQL 文档发现:MySQL user names can be up to 32 characters long (16 characters before MySQL 5.7.8). http://dev.mysql.com/doc/refman/5.7/en/user-names.html

这样看来应该是老版 PHP 的 mysqli 扩展内部限定了用户名的长度,但新版的 MySQL 却可以创建更长的用户名了。知道原因了就很好办了,创建一个短用户名 OK 了。其实也是阴差阳错,因为新库是多应用共有,所以用户名创建的比较长。_(┐「ε:)_

Ubuntu 平滑升级 MySQL 到 5.7

最近 MySQL 发布了 5.7 正式版(https://dev.mysql.com/doc/refman/5.7/en/mysql-nutshell.html)。5.7 可以说是里程碑式的版本,提高了性能,并增加了很多新的特性。不管怎么样,先升级再说。

首先我的 Ubuntu 版本是 14.04,已经通过 ppa 的方式安装了 MySQL 5.6,所以首先得去掉这个源。

手工删除的话可以去 /etc/apt/sources.list.d 目录下干掉类似 xxx_mysql-5.6_xxx.list 的文件即可。

然后再安装上官方 apt 源,先在 http://dev.mysql.com/downloads/repo/apt/ 下载最新的 deb 文件,然后使用 dpkg 命令添加源,最后执行安装 MySQL 命令即可:

需要注意的是在添加源那一步的时候,会叫你选择安装 MySQL 哪个应用,这里选择 Server 即可,再选择 MySQL 5.7 后又会回到选择应用的那个界面,此时选择 Apply 即可。

安装完之后还需执行一下 sudo mysql_upgrade -u root -p 更新数据(重要)。

一般这样就完事了,数据什么的都完整无缺。

但一般就是会出现一点小插曲。我在 MySQL 自动启动的时候起不来了:

d96bb863e4ebd54d13a65ff5c

也没看见日志在哪儿,在 /etc/mysql 目录下找日志的时候发现多了个 my.cnf.dpkg-dist 文件,对比一下发现和原来的 my.cnf 不太一样呀,把原来的 my.cnf 备份后使用这个文件替换掉。再次启动 MySQL 果然 OK 了。

这篇文章写得还是没啥营养,权当做个记录吧。等以后水平高了,再来填 MySQL 5.7 新特征及其优化的坑。

update:

关于配置优化,介绍一个好网站:http://tools.percona.com/ (Free online productivity tools for MySQL DBAs, SysAdmins and Developers)。我 1 CPU,1 GB RAM 的配置如下: Continue Reading…

巧用七牛CDN的镜像功能使百度分享支持HTTPS

唉,好懒呀,好久没更新博客了。

最近搞了个 HTTPS 证书,像以前一样给博客添加了个百度分享(http://share.baidu.com/)的组件,但发现百度分享不支持 HTTPS(百度分享图标出不来,console 会提示页面有不安全的脚本元素)。看了其它几家也都不支持,搜索了下发现有人建议把百度分享所需的 js 都保存到自己本地就行了。这也是个办法,分享功能大多是抓取这个页面的 title、摘要、图片等然后起调一个页面完成分享,这些都是本地 js 文件能完成的。

看了下从百度分享获取的代码,里面主要加载了这个:http://bdimg.share.baidu.com/static/api/js/share.js,访问了一下果然还是不支持 HTTPS。然后我就天真的把 share.js 上传到了七牛 CDN(七牛是支持 HTTPS的,在空间设置-域名配置里面设置下就行),然而百度分享的图标还是没出来。看了下控制台,卧槽,又加载了一堆 js,作为一个全栈工程师,我非常灵性的瞅了眼代码里面有一段:domain:{staticUrl:”http://bdimg.share.baidu.com/”},原来是模块化加载,把链接替换成七牛 CDN  的链接后有些请求 404 了,我又天真的以为把这几个 js 文件补全就行,但是补完几个,又有几个文件 404 了,我可没耐心一个个文件补齐呀。

作为一个灵性码农,我马上想到七牛不是有个镜像存储功能嘛,设置一发:

20150817003746

故事就这么结束了吗?怎么可能。百度“幺蛾子”还是比较多。百度分享不光是分享功能,还有分享的数据分析。数据哪里来呢?前端埋点统计的呀,原理简单说就是监控分享时的点击事件,发送数据到后台。这其中的核心就是 http://nsclick.baidu.com/v.gif,需要统计的参数和值都以 GET 参数的形式附在链接后面。然后后端再清洗请求日志或者获取请求的时候就直接把数据入库了。但这个统计小图片也不支持 HTTPS。没办法,只能去掉了,方法也很简单,static/api/js/trans/logger.js 文件为空就行(上传个空文件、占个位)。到此才算大功告成。

上面是授之以渔,不想自己弄的,可以直接抓鱼,当然希望你也能明白其中的风险,文件是我这边的(可能有后门,当然我没有),而且哪天我流量没了可能会把文件删了。

update:2016-05-24,七牛账单已经超支,上面的代码地址已经失效,还请见谅。其实了解原理之后自己设置一个即可,或者自己 Nginx 反代一下。

一点后话:一直感觉百度分享没人维护了,在群里打听了下。应该是有人(部门)维护着(至于不支持 HTTPS 那是百度 CDN 的锅),但是现在不流行打社交牌了,公司也不重视这块了,还是 200 亿糯米 O2O 更实在,而且百度首页貌似也不显示搜索结果页面的分享次数了。

IIS和Serv-U端口冲突造成网站无法访问

今天收到报警公司的网站突然无法访问了,我用电脑访问了下没问题(当时可能是缓存原因)。看到报警信息上面也只有一个监控节点报警,就没管了。后来收到同事反馈后台进不去了,悲剧了果然进不去,提示一个很奇怪的错误:

serv-u报错

访问静态页面也报错:

用IE访问看到的是一个登录验证页面。

我明明访问的是web服务怎么会到ftp了呢?

远程登录到服务器发现iis已经跪掉了,重启一下,又报错了:

iis端口冲突报错

因为没怎么用过iis,就在群里问了下,得到的回复就是端口冲突。

难道80端口被serv-u占用了?不应该呀,ftp用的是21端口,怎么会冲突呢?打开监听器一看,这尼玛,真的占用了80端口,去掉监听,重启iis,网站立马就能访问了。

80端口被占用

前人挖坑,后人填坑。当我接手这个服务器时看见右下角360安全卫士、360杀毒的时候我就已经有了觉悟。

梳理一下整个过程:一开始不知道什么原因iis跪掉了,然后serv-u争夺到了80端口的使用权,我再重启iis的时候就会提示文件被占用,关掉serv-u的80端口监听器(让出端口),再重启iis就恢复正常了。

php中GET/POST方法+号等特殊字符处理

自己在项目开发中写了个自用接口,用GET方法传参(用户名和密码)。最近收到用户反馈:密码为特殊字符时会出错。我一开始想是不是php的mysql_real_escape_string函数将特殊字符转义了,但用户说自己密码只有“+”号这个特殊字符,而“+”号不属于该函数转义的范围之内。

为了弄明白这个问题我就在本地测试了一下,果然发现有bug。

测试代码:

测试的url为http://localhost/test/?a=123!@#&b=123结果报错了:

#号后面的参数被屏蔽了

可以看出“#”号后面的参数被屏蔽了,这很正常,因为“#”号后面的数据不会发送到HTTP请求中。 Continue Reading…

外网免费下载学校图书馆各类论文资源(非原创)

后记:更详细的教程请参考资讯民大的推文【小贴士】置身校外如何安全访问校内资源。同时推荐学弟、学妹们关注资讯民大,了解更多校园资讯以及各种实用功能(查成绩、课表等)。

寒假期间想写论文?该怎么样通过校外网来免费下载学校图书馆的各类资源呢?下面为大家简单的介绍下,学校的系统改进了,现在通过外网(非校园网)同样可以免费下载图书馆的全部资源了。主要使用vpn校外访问系统。

第一步:

使用IE浏览器打开https://vpn.scuec.edu.cn/进入中南民族大学vpn系统。提示访问时可能会看到如下提示,点击“继续浏览此网站”即可,至于为什么会有这个警告请参考http://www.williamlong.info/archives/3461.html

证书警告

第二步登录:

进去后的界面:

vpn登陆界面

右边的其它登陆方式想研究的同学可以看一下,我们直接在左边输入用户名和密码登陆(用户名、密码同教务系统/学生门户的用户名、密码)。 Continue Reading…

win8安装校园网客户端(Edu Supplicant)

是前言的后记(2015-10):下面说的教程Windows 8.1同样适用,Windows 10也可以类似的方法解决。不过这些都已经成为历史了,现在学校早已经是VPN拨号(自带全平台兼容属性)了,插上网线就能自动获得ip,然后使用学号和密码拨号就行。使用路由器就更简单了,现在的“智能”路由器基本都支持VPN拨号,而且和网络中心的老师聊过,学校也没有明面上禁止,因为学校根本就不靠这点网费赚钱(学校钱多就是任性,现在都支持免费申请虚拟机了)。不过风险也有,若是别人用你网做一些“和谐”的事情,因为拨号的学号是你的,到时候“查水表第一个找的就是你(校园网一抓一个准,学校这么好的条件,还是多做点更有意义的事情吧)。

最近有人找我重装系统(好男人,重装系统从不收费),问其原因,她说是win8无法安装校园网客户端。自己装了用不了,网络中心也贴出告示说校园网客户端不兼容win8。她拿到售后去装系统却被告知要收费300(售后真是黑啊,我要是收费30早就发家致富了)。本着不到黄河心不死的精神我决定尝试一下在win8上安装校园网的客户端。在失败N次后得出了正确的安装方法:

在桌面下,右键点击右下角网络图标,打开网络和共享中心。

打开网络和共享中心

点击左侧的更改适配器设置,在弹出的窗口中右键打开以太网(若是外接网卡可能不叫以太网)的属性。

以太网属性

更改ipv4属性。按照学校分配的ip地址进行设置(备用DNS服务器地址填写谷歌的DNS服务地址8.8.8.8能有效解决校园网有时无法打开微博等网页的情况)。

ip地址设置

修改保存后,就会弹出网络中心的一个上网须知,下载64位的操作系统。如未弹出下载页面请自行下载,下载地址:http://172.16.0.2/ATclient64.exe (校园网)备用下载地址:http://yunpan.cn/QpP92ujFyrI68

上网须知

然后需要重启到【禁用驱动程序强制签名】模式下安装校园网客户端。

按win+i键,选择更改电脑设置。

更改电脑设置

点击左侧的常规面板,在右侧最下部选择【立即重启】。 Continue Reading…

解决gem install无反应

有时候使用ruby时gem install后半天无反应,这是什么原因呢?其实是由于国内的防火墙阻断了和ruby服务器的链接,ruby的资源文件存放在Amazon的服务器上,好像好多国外的云空间都存放在Amazon的服务器上,在中国都不能正常访问。

难道我们要挂上代理翻墙吗?其实不用那么麻烦,淘宝网提供了一个国内的Rubygems 镜像(为什么是淘宝网,很奇怪)。淘宝网提供的Rubygems 镜像是完整的rubygems.org 镜像,可以用此代替官方版本,同步频率目前为15分钟一次。(参考:http://ruby.taobao.org/

说到这里应该就明白了,将默认的下载源改成淘宝提供的Rubygems 镜像就可以了。具体操作步骤:

是否发现连接稳定多了,下载速度明显加快了呢?

如何将代码插入到word中

在一般的时候word和代码没什么关系,word也不可以用来编辑代码(貌似也没哪个人用word写代码)。但在有的时候需要在word中插入代码。比如说你写实验报告的时候,老师要求将代码插入进去。一般也就是直接复制进去就好了,然而作为一个完美主义者是不能忍受这种粗暴的方式的。

那样怎么保证代码的高亮和缩进风格呢?就要用到一个神奇notepad++。 Continue Reading…