nginx、php-fpm默认配置与性能–TCP socket还是unix domain socket 前几天看到一篇博客,提到php所在服务器在大并发情况下,频繁创建TCP短连接,而其所在服务器的2MSL时间过长,导致没有端口可用,系统无法创建TCP socket,而大量报错。博主在后面给的解决方案是减少2MSL的时间,尽快清除TIME_WAIT状态的TCP连接,回收端口。同时,文章结尾写了不用长连接的理由,但这真的是最好的解决办法吗?有其他办法可以更好的做法吗? 类似经历 之所以多这篇文章兴趣这么高,是因为在前段时间,末学也经历了一件类似的优化历程,先简短的描述下我们的服务器架构。如图 想必看到这幅架构图的同学,都比较熟悉吧,也比较简单。“最前面”的nginx 反代负责与玩家的http请求通讯,这里是长连接。在其与后端游戏大区通讯时,使用了短连接,也就是意味着,每处理用户的一个http请求,都要重新与后端的nginx建立一次TCP(http)请求,后端nginx处理完之后就关闭。后端的nginx与php在同一台服务器上,通讯配置如下: 在这个架构图中,反代承担这承上启下的作用,前面是用户,后面是web app服务器,长连接用户,短连接后端。若用户数在1W人,1W人与反代的连接,在反代服务器上都用80端口。但这1W人的每一个请求,反代都要重新使用服务器的端口与后端nginx的80创建tcp socket,来处理请求。若2MSL时间为1分钟以上,同时,玩家两次请求间隔很短,想我们游戏的服务器,两次请求间隔大约5秒(甚至2-3秒)。那么反代的端口,5秒用1W个,10秒2W,15秒3W,20秒4W,25秒5W,30秒6W!!!,前面已经用掉的端口还没被回收掉。那么将会有很多的用户请求被nginx反代接收之后,因没有端口资源而无法与后端nginx创建tcp连接。。。以游戏的其中一个大区为例: 关于这个问题,末学在新浪微博上请教过其他大牛,其中tengine负责人淘叔度前辈以及@120斤的大青蛙前辈告诉我,nginx将在1.1.4版本开始支持ngx_http_upstream_keepalive,3月1号左右,是1.1.16 dev版本,我们的运维团队稍微由于几天,之后在部分小区的服务器上适用了1.1.16,效果不错,Nginx反代上与目标服务器的80端口的TCP连接中处于ESTABLISHED状态的非常多,TIME_WAIT的几乎没有,很稳定。我们几乎计划为了这个性能的提升,决定用dev版了。接着nginx1.2Stable version也出来了,那么也就用这个版本了。至于反代上nginx与后端app server建立TCP连接个数,也就是端口数(满载情况下,维持ESTABLISHED状态)的为nginx worker_processes * ((upstream1 server * keepalive参数数量) + (upstream2 server * keepalive参数数量) + ...),并不多。 如上,端口占用数少了,那么还有其他有点吗?先看一副 socket创建,监听、数据接收发送、关闭与客户端连接的socket流程图: 如上图,nginx反代跟后端nginx的形式跟php-fpm与mysqld socket的模型一样的。 nginx反代跟php-fpm 相对来说,就是客户端,这种做法,他们的每个新socket 请求的发起,都会跟着左边的流程走一遍,一遍又一遍。。。。每次的socket创建,端口等资源申请,与服务端的三次握手,关闭时的四次握手,端口的回收。。。。 改用长连接之后,如下图: 只有php-fpm(或者nginx反代)的子进程分别与mysqld创建1次TCP连接,之后都是send、recv数据的事情了,端口占用也是为数不多的几个(每个fpm子进程将与mysqld维持一个TCP长连接)。 同样,后端服务器的nginx与php-fpm的通讯也是如此,只是请求两没有反代那么大。区别就是IP地址是回环地址127.0.0.1。 既然是回环地址,那么两个服务都是在同一台机器上跑的,既然是同一台机器,为何不用进程间通讯的socket--unix domain socket呢? socket是神马?摘抄一段描述: Socket 可以被定义描述为两个应用通信通道的端点。一个 Socket 端点可以用 Socket 地址来描述, Socket 地址结构由 IP 地址,端口和使用协议组成( TCP or UDP )。http协议可以通过socket实现,socket在传输层上实现。从这个角度来说,socket介于应用层和传输层之间。但是socket作为一种进程通信机制,操作系统分配唯一一个socket号,是依赖于通信协议的,但是这个通信协议不仅仅是 tcp或udp,也可以是其它协议。 在同一台服务器上,用tcp socket与unix domain socket有什么区别? 如图所示,对于进程间通讯的两个程序,unix domain socket的流程不会走到TCP 那层,直接以文件形式,以stream socket通讯。如果是TCP socket,则需要走到IP层。 对于非同一台服务器上,TCP socket走的就更多了。 至于localhost\127.0.0.1以及网络IP他们之间的区别,无意中找到一篇博客写的是以mysql作为验证,来说明localhost不走TCP/IP层,跟127.0.0.1不一样。末学认为他理解错了。他的理由如下 (以下截图均在linux上,windows的没有unix domain socket) mysql连接本机时,不加-h参数: mysql连接本机时,加-h参数且值是localhost: mysql连接本机时,加-h参数且值是127.0.0.1: 那位同学从mysql工具的使用方法、与结果的区别,来理解推导localhost与127.0.0.1的区别,这从方向上就存在问题,我更相信,这是mysql这个程序自己的行为,遇到-h参数没加,或者-h参数的值不是IP形式,且my.cnf里指定mysql的socket路径时,则直接使用unix domain socket来连接服务器,当然,这也是我的猜测,没有去验证,大家听听就好,别相信。 鉴于末学对以上的理解,将服务器的架构配置变更如下 至此,优化还为完毕,若php-fpm与mysql使用mysql_pconnect的话,那么php-fpm的子进程生成模式最好用static模式,若为dynamic模式,可能会出现mysql连接数被占满的情况,这也跟mysql服务的连接超时时间有关,适当调整也容易避免。 不过,我们目前还没用mysql_pconnect,主要原因是我们的代码中,有些事务处理开启之后,对于代码的失败处理,忘记写回滚语句,在短连接的情况下,这个连接的销毁,哪怕客户端没提交ROLLBACK或者COMMIT指令,mysql会自动回滚之前的事务。但使用长连接之后,不同请求会使用同一个MYSQL连接句柄,每个事务开启都会禁用MYSQL的自动提交,即SET AUTOCOMMIT=0语句,这语句会提交之前的事务。对于我们代码忘记写回滚,而直接返回结果的情况下,这是会出大问题的,也是我们目前唯一没有使用MYSQL_pconnect的原因。(计划近期找到没有写回滚语句的代码,修复,继续使用mysql_pconnect) 其实还有,我们php-fpm使用了APC来缓存php file,以及 变量数据等,这些也是有优化的地方(如果有时间的话,则待续)。 回过头来再理解下文章开头那位同学给的解决办法,我仍不能从他给的理由中,理解长连接的缺点,哪怕是解决了TIME_WAIT的问题,但每次创建TCP socket ,连接到服务器时三次握手,关闭TCP socket时的四次握手 这些也是开销。当然,缩短2MSL的时间,也是更好利用服务器资源的一个好方法。 最后,我们调整优化的服务器架构图如下: 好像有点偏离这篇文章的标题了,其实我更想说我不能理解为啥nginx跟php-fpm给的默认配置中,都是TCP socket通讯的,为啥不默认给unix domain socket的默认配置呢?如果说为了方便非同一台服务器时的情况,但给的默认IP也是回环地址呀。 而且,nginx给默认配置中,对于uri请求中的php文件的处理,匹配规则还是老的,之前发生因为NGINX与PHP的配置而导致的安全问题,虽然不是nginx的错,但nginx也可给出更严谨的范例,但仍没有。 值得欣慰的是,在UBUNTU 12.4中,nginx的默认配置有了很大的改进,不管是匹配uri的规则,还是nginx与php-fpm的交互方式: PS:末学只是个web程序员,这些只是末学学习研究如上知识的总结,理解上难免有错,各位请海涵。 2012-05-31 +18 22 0
CodeIgniter框架中关于DB事务处理的设计缺陷 起因: 在我们线上的某个业务中,使用较老版本的CodeIgniter框架,其中的DB类中,对DB事物处理部分存在着一个设计上的缺陷,或许也算不上缺陷吧。但他却影响了我们生产环境,导致连锁反应。对业务产生较大影响,且不容易排查。这个问题,我在今年的3月中旬,曾向http://codeigniter.org.cn/的站长Hex 报告过,之后,我也忘记这件事情了。直到今天,我们线上业务又一次以为这个问题,害的我又排查一次。具体原因,各位且先听我慢慢说完。(这个问题同样存在于最新版本Version 2.1.0中) 分析: 以CodeIgniter框架Version 2.1.0为例,在system\database\DB_driver.php的CI_DB_driver类中第58行有个$_trans_status属性。 同时,这个类的query方法中,有赋值此属性的代码,见文件306、307行 这里也给了注释,告诉我们,如果使用了事物处理,那么这属性将成为一个回滚的决定条件。 在520行的事物提交方法trans_complete中,如下代码 在535行中,如果_trans_status属性如果是false,那么将发生回滚,并且返回false。 在我们的业务代码中,由于程序员疏忽,没有判断trans_complete()方法是否正确执行,直接告诉用户操作成功,但实际上,程序已经向DB下达回滚指令,并未成功更新DB记录。当用户执行下一步操作时,程序又发现相应记录并未更新,又提醒用户上个操作没有完成,通知用户重新执行。如此反复... 排查的过程,也是挺有意思的,起初从PHP代码中,总是不能确定问题所在,并没有把焦点放到trans_complete()方法的返回上。直到后来strace抓包分析,才知道是因为此属性而导致了回滚。 可以看到,在22:54:08.380085时间点处,发送更新SQL语句指令,在22:54:08.380089时间读取返回结果,得到SQL执行错误,不存在字段"cfc4n_user_lock";22:54:08.381791和22:54:08.382703两个时间点,PHP发送停止“自动提交”与“开始事务处理”指令,在 22:54:08.433954 发送“事务回滚”指令。 配合如上的代码分析,可以清楚的知道,因为“UPDATE `cfc4n_user_info` SET `cfc4n_user_lock` = 1 WHERE `cfc4n_user_id` = '6154' AND `cfc4n_user_lock` = 0”这句SQL执行错误,导致$_trans_status属性被设置为FALSE,当代码提交事务时,被trans_complete()方法判断,认为“上一个事务处理”(下面将仔细分析)中存在SQL语句执行失败,决定回滚事务,不提交。 刚刚提到“上一个事务处理”,可能有些朋友不能理解,我们先继续回到代码中来,继续看该属性,同样在trans_complete方法中,542-545行: 也可以很容易的从注释中看明白,设置CI的设计者,为了更严谨的处理 同一个脚本中,存在多个事务时,事务间彼此关系重要,一荣俱荣,一损俱损。这里的trans_strict属性,是个开关,当 trans_strict为false,便是非严格模式,意味着多个事务之间,彼此关系不重要,不影响。当前一个事务中有SQL语句执行失败,影响不到自己。便将_trans_status 设置为TRUE。 毫无疑问,这是个非常周全的考虑。考虑了多个事务之间的关系,保证业务跑在更严谨的代码上。 可是,我们的代码中,错误的SQL语句是执行在事务处理以外的,并不是事务之内。按照我们对事务的认识,可以很清晰的知道,事务之外的SQL相比事务之内的SQL来说,事务之内的SQL更重要,之外的可以允许出错,但事务之内的,务必要正确,不受外界干扰。但CI的框架中,因为一个事务以外的语句执行失败,却导致整个事务回滚...当然,我们的程序员没有对事务提交方法的返回做判断,这也是个问题。 问题已经很清晰了,那么解决方法想必对你来说,是多么的简单。 比如在trans_start方法中,对_trans_status 属性赋值,设置为TRUE,不理会事务外的问题。 结束: 在不明白对方设计意图的情况下,不能盲目的定义对方的代码评价,不管程序作者的水平如何。比自己强,也不能盲目崇拜;比自己弱,更不能乱加指责;理解读懂设计意图,学习他人优秀的设计思路、代码风格、算法效率,这才是一个好习惯。当然codeigniter框架是优秀的。 2012-04-30 +3 7 0
心如止水-近来琐事总结 起 之前母亲、妻、子走亲戚,独留下我一个在家,倒也比较清静,也是难得的清静。从工作起,很少有这么清静的日子,独自一个人在夜里,躺在床上,熄灯,也不开电脑,什么事情都不做,就静静的坐在那里想、回忆、思考、思索。童年、中学大学,还有工作。每每想到这些,无不怀念感慨时光流逝,没有把握青春,虚度年华,也每每暗自鼓起定下目标,憧憬未来。但每次都被之后的忙碌冲淡、遗忘在某个角落。身为程序员的我,代码逻辑计算多了,理性占据大脑的绝大部分,各种来龙去脉都要理顺,一切都要有原因,有依据。有时感性却占了上峰,或许是物极必反吧。尤其是在安静的夜晚,一个人的时候,尤其想读几篇散文小说,净化心灵。虽然偶尔也会触景生情,但不至于想林黛玉那样。胡思乱想,无意中选了《朝花夕拾》、《季羡林谈人生》。 乘兴而至兴尽而归 我有一时,曾经屡次忆起儿时在故乡所吃的蔬果:菱角,罗汉豆,茭白,香瓜。凡这些,都是极其鲜美可口的;都曾是使我思乡的蛊惑。后来,我在久别之后尝到了,也不过如此;惟独在记忆上,还有旧来的意味留存。他们也许要哄骗我一生,使我也时时反顾。 这是鲁迅在《朝花夕拾》里写的一段小引,我也颇有共鸣,之前想读鲁迅的文章,买来之后,也发现并不是那么的喜欢。或许我怀念的是中学时,学鲁迅文章的那篇时光吧。 同样是朝花夕拾里的小引中写道“我常想在纷扰中寻出一点闲静来,然而委实不容易。目前是这么离奇,心里是这么芜杂。”这对我来说,又何尝不是呢?大学有段时间,舍友们常有各种活动或者私人事情,经常出门在外。高我一届的舍友也早已出去实习了,留我一个人在宿舍,夜里安静的时候,思绪自然比较洒脱飘逸,也曾洋洋洒洒得写过一段时间的日志,不管文笔如何,都是我曾经内心最真实的写照,如今早已封存在QQ空间。到现在为止,再也没动过笔。我常想在纷扰中寻出一点闲静来”鲁迅在《朝花夕拾》的小引中说道。而我,生活在物欲横流的花花世界中的我,面对无数诱惑的我,则想能在这繁杂中寻找心中的净土,品味着咖啡或是清茶,阅读一本好书。我一直向往这样安静祥和的生活。鲁迅在他“心中是这么芜杂”之际,能做的“只剩了回忆的时候”,我只能追随着他的《朝花夕拾》,随着他的思绪,一起漂移了。 人生的意义与价值 人生一无意义, 二无价值。他们也从来不考虑这样的哲学问题。走运时, 手里攥满了钞票, 白天两顿美食城, 晚上一趟卡拉0K, 玩一点小权术, 耍一点小聪明, 甚至恣睢骄横, 飞扬跋扈, 昏昏沉沉, 浑浑 噩噩, 等到钻入了骨灰盒, 也不明白自己为什么活过一生。 这些是季羡林大师在《谈人生》的书里写到一些观点,显然,这不是大家的目标,相信每个读者都不是这种人,不屑跟这种人打交道。季老归纳出,人生的意义与价值是“承上启下”。大到人类,对人类发展的承上启下;大到国家,对国家昌盛的承上启下;小到家庭,对家庭和睦的承上启下。这都少不了一份责任感,强烈的使命感,也与张横渠的话“为天地立心,为生民立命,为往圣继绝学,为万事开太平”产生共鸣,时代在变,历史伟人的价值观没变。难道我们能无动于衷吗?不说为了国家,为了家庭呢? 安身立命 季老总结了做人处世的三个关系: 第一, 人与大自然的关系; 第二, 人与人的关系, 包括家庭关系在内; 第三, 个人心中思想与感情矛盾与平衡的关系。第一条对我来说,并不感兴趣,我也做不了什么。人与人的关系,他的想法是对于好人,要“忍”、“真”,不管是家人还是朋友,这也是家庭间和睦生活、工作间合作愉快的金玉良言。真者, 以真情实意相待,不允许弄虚作假。对待坏人,则另当别论。忍者,相互容忍也。日子久了,难免有点磕磕碰碰。在这时候,头脑清醒的一方应该能够容忍。如果双方都不冷静,必致因小失大,后果不堪设想。至于个人心中思想感情的矛盾,则多半起于私心杂念。解之之方,唯有消灭私心,学习诸葛亮的“淡泊以明志,宁静以致远”, 庶几近之。大师很容易做到,我等普通人,说这容易,做着难。 自相矛盾 老与贫皆非人之所愿,然而谁也回天无力,在万般无奈的情况下,只能叹而且嗟,聊以抒发郁闷而已,其次是故作豪言壮语,表面强硬,内实虚弱。最有名的最为人所称誉的是曹操的名作: 老骥伏枥,志在千里。烈士暮年,壮心不已。 初看起来气粗如牛;仔细品味,实极空洞。这有点像在深夜里一个人独行深山野林中故意高声歌唱那样,流露出来的正是内心的胆怯。 这或许也符合读者对我这篇日志的看法,标题是“心如止水”,但稍稍搅动,就是波涛汹涌。感性时,难免有点胡思乱想。感性之后,也就是黎明到来之时,仍会回归理性,开始一天的编程coding... 末 日子不能太舒服,太舒服会出问题。在忙碌的工作生活节奏中,抽出一会儿时间,思考一下自己,以免出发的太久,忘记出发的目的;也避免污浊的想法占据你的大脑,清理净化下你的灵魂,树立真正的人生观,价值观,找找自己真正的目标是什么。“三十而立,四十而不惑”说的就是这个道理。好比买了新PC,开始收集各种技术手册、代码案例、视频等等,时间久了,硬盘满了,你也会发现,很多资料并不是你想要的,也不适合你...人生也是如此... 2012-03-07 2 0
php5.3.8中编译pdo_mysql的艰难历程 我们的一个项目,用了PDO_MYSQL拓展,准备迁移服务器,新环境需要编译安装环境。昨天,运维同事抽空编译了一下,一直编译不上pdo_mysql,同时,公司的一款新webgame临近上线,他们实在太忙,我这个三流运维技术的程序员来试试吧。 运维同事描述: 服务器系统版本:Linux version 2.6.32-71.el6.x86_64 (mockbuild@c6b6.centos.org) (gcc version 4.4.4 20100726 (Red Hat 4.4.4-13) (GCC) ) #1 SMP Fri May 20 03:51:51 BST 2011 编译PHP的参数 之后再次编译 pdo_mysql 拓展 之后, shell里执行 php -i 和 php -m都没有看到 pdo_mysql拓展。搜pdo_mysql,在将路径添加到php.ini中,仍找不到这个扩展,判断为编译失败。 这里是将pdo_mysql作为一个拓展引入使用的。在php5.3中,PHP开发组把mysqlnd作为默认的连接MYSQL的数据库驱动来使用,据官方描述,节省内存40%,速度更快,当然或许是为了解决许可协议的问题。之前PHP连接MYSQL,是调用MYSQL官方提供的C/C++编写的lib_mysql的dll/so,来实现。这个类库同样可以给PYTHON等脚本语言调用,只要按照API规范来。我们改用mysqlnd之后,就不用再为了lib_mysql去安装mysql client了。详情见:mysqlnd插件mysqlnd_ms的介绍。 两种方法都可以,运维同事都尝试了,由于时间关系,他们没做过多的尝试研究,就转向更紧急的项目了。 运维同事下载使用的PDO_MYSQL拓展的地址是 http://pecl.php.net/package/PDO_MYSQL ,里面用很耀眼的颜色,标注如下几行字 This package is not maintained anymore and has been superseded. Package has moved to channel http://svn.php.net/viewvc/php/php-src/trunk/ext/pdo_mysql/, package ext/pdo_mysql. 也就是说,早在2006年5月1(我是根据最后一个打包文件日期猜的,或许不准)之后,PHP已经将这个pdo拓展放到PHP源码的 ext/pdo_mysql下内置了。这里的这个包,将不会在更新维护了。 在PHP官方文档上对pdo_mysql使用mysqlnd的时候,是这么描述的 在php5.3中,已经支持mysqlnd作为数据库连接驱动了,无需再使用libmysql。而在将来的php5.4中,将变为默认的连接驱动。如图: 开启这个类库的 之后,我的编译参数如下 区别是使用php内置的pdo_mysql类库,使用mysqlnd作为连接驱动,不在使用之前的MYSQL官方提供的libmysql.so。 make之后,提示如下错误 这种错误,让我手足无措,GOOGLE搜了下,也没找到相关案例,而且,一直被墙,打不开国外网页。百度搜的结果,还是算了。(中文还行,E文的话,百度确实不行,尤其是程序相关) 之后,尝试make clean,清除之前的编译结果缓存之类。 再次make,有个小意外 再次搜索,这倒是很多网友遇到过,大部分的建议就是无视这个错误,不影响编译。照做。make install ,一路挺顺畅。 接着,php -i / php -m 也没发现pdo_mysql模块。 郁闷无比,决定看下web下的phpinfo结果,发现居然有了。问题终于解决了。。。万岁。。 可是!!! 1,为啥php -i 、php -m 的结果里看不到呢? 思考,为什么呢? 结合刚刚的报错,联想到CLI 模式下的php 脚本(以及相关的php.ini)跟刚刚从web下访问的php程序不是同一个。检查环境变量,以及切换到编译好的目录下执行php -i,发现pdo_mysql、mysqlnd等相关添加的模块了。 2,php.ini里没启用pdo_mysql拓展,为什么还能看的到呢? 这次使用的是PHP内置的类库,不是以新拓展方式加载运行的,所以,不用更改php.ini,再添加相关so路径。 综上所述,文章没有高深的东西,只是有几个需要细心的点。 1,以官方文档为准,一切跟着官方文档来,不轻易采信网络上网友提供的编译参数,包括这边博文。不论对方是老手、大牛,还是其他什么什么有威望的人。他们提供的方法或许跟你当前的环境不一致,时间也相差很大,或许相隔好几年了。 2,确认得到的结果是准确的,怎么说呢,文中的例子中php-i的路径不是我们新编译的,而是之前编译,或者yum安装的,一定要到自己编译的程序目录下,用自己新编译的脚本去执行测试,获得测试结果,下结论,不为了偷懒,不敲路径,直接写程序名进行测试。 3,遇到诡异的错误,我总会想要一个全新的系统,进行安装,以确保不被各种冗余、缓存等垃圾文件干扰。例子中用了make clean进行清除相关缓存,来解决文件缓存问题。(感谢@ivon_lee 的帮助) 4,自动安装脚本要及时更新,当然,不是意味着追求最新版本。例子中的pdo_mysql的拓展,官方提供了更好的方式,不论是效率,资源占用,都有更好的提升,为啥不使用呢。 备注:mysqlnd 的相关有点对比见http://developer.51cto.com/art/200903/115995.htm PS:文中出现的我搜索无果两次错误,如果有人知道,请告诉我,谢谢。 2011-11-25 4 0
WEB开发安全与运维安全浅见 前段时间,同事LeeQueen为公司同事做了个《安全意识防护》的PPT,效果很好,各位新同事也知道日常公工作中,不太注意到的隐私保护问题。PPT中也提到了一些社会工程学的案例,提到了某团购网站前台人员被声称是新开礼品公司的工作人员,以填写信息就送礼品为由,获取到此团购网站的所有员工联系方式。后此团购网站的高层打电话回访,得知对方是猎头公司[详情见乌云网的链接]。此案例非常典型,讨论也尤为激烈,可谓是非常成功的培训。 此次培训之后,职业欠钱[sina微博][腾讯微博]让我给我们开发部门的PHP程序员同事们做一次PHP开发、运维时候一些安全注意事项。由于我在安全这块资历较浅,没有经验,我了解的大家都懂,这个话题太高深,我的水平完全不够,没法写这个PPT。而且,同事里有好几位安全界的前辈,我怎可关公面前耍大刀呢。上次写过一次关于正则表达式PPT,也就是一个月之前,深刻的体会到写PPT的痛苦,尤其是排版。实在不想写了。 后来,经常看到网上的安全工程师提到程序员安全意识较差,以至于同样的危险代码,危险程序,却屡次不改。当然,不是程序员不想改,而是程序员不太理解代码形成安全漏洞的原因。为此,我也觉得有必要提高一下我们程序员的安全意识了。 PPT中写了网络上常见的漏洞,形成原因,漏洞原理,防护建议等;也列举了近年来跟WEB相关的安全漏洞,以程序员的视角理解漏洞原理,并给出修复建议。这些建议仅供参考,不是正确答案。 由于本人水平原因,PPT中难免有错误,请见谅。也请安全界工程师指正。 借用网友的一句话,作为程序员,尽量要做到“知其然,知其所以然”,多多关注web安全,不要给安全工程师添麻烦,不能丢了程序员的脸。 同时,公司招聘PHP程序员,地点上海,公司规模为150人+,做网络游戏研发、运营。招聘条件以及待遇之类的,可以通过以下方式联系我,我们私聊。 http://weibo.com/cfc4nx http://t.qq.com/cfc4nx 邮箱:cfc4n@博客域名点COM 最后,PPT是周末两天写的,这两天老婆挺着6个月的大肚子,为我做饭,老婆实在是太辛苦了,感谢我老婆。 PS:讨厌写PPT[流泪]。 在线阅读: Web开发与运维安全浅见View more presentations from cfc4n. 下载到本地: PPT下载:web开发与运维安全浅见PPT下载,猛点这里 更多亮点在PPT的备注里,各位一定要看备注。转载的朋友麻烦保留PPT完整,包括招人信息。尤其是备注要保留。 ------- PPT在2011/09/19 更新了,更换匹配NGINX 对URI中PHP脚本的正则,考虑到了拓展名为 .phpa .phpb .phpc之类的情况。主要是更换了正则匹配的图,更改了正则内容。 2015/06/09 备注, nginx匹配URI时,对于PHP的解析,更改为 location ~ ^(?:(? 2011-09-19 +13 17 0
YSLOW法则中,为什么yahoo推荐用GET代替POST? 背景: 上上周五,公司前端工程师培训,提到前端优化的一些技巧,当然不能少了yahoo yslow的优化法则。其中有这么一条“Use GET for AJAX Requests”,这些法则从最开始的14条,到现在的35条,一直都时刻关注的。可这么一条的原因我却一点都不清楚。在提问的环节里,我对yahoo WEB前端优化法则推荐AJAX中,使用GET代替POST的原因有疑问,便请教前端工程师。我们的工程师说GET的话,浏览器发送一个包,POST会发两个等等。我对这个解释仍带有疑问,甚至怀疑。培训结束后,我随便搜索了一下,并没有得到理想的结果,可能很少人对Yahoo这么有权威的组织提出的优化法则产生怀疑,也很少人想知道为什么建议这么做,更多的人会唯命是从,墨守成规。之后,我又看了遍优化法则,看到一条是推荐开发者使用AJAX缓存的,这时,一个“伟大”的想法在我脑袋中一闪,莫非是GET请求可以缓存,而POST不可以?接着,我把我这个“伟大”的猜测告诉我的同事们,当初已经是下班时间,好多同事都离开公司,我也匆忙收拾东西下班了,没有仔细查找答案。 周末期间,脑袋中频繁的闪现这个问题,仍对我的想法有怀疑,Yahoo前端这么牛X的团队的想法,岂是我这样的菜鸟能这么容易的猜测推断到的?我对我当初的推测的怀疑就像“小时候就怀疑小JJ绝对不是只用来撒尿那么简单”一样坚定。但向我这么懒惰的同学,实在找不出一点时间来验证我这个想法,空闲的时间宁愿多打几盘CS。一直拖到现在,台风来了,在家宅两天,头都睡扁了,也找不出不写这篇文章的理由。 验证Yahoo推荐的理由: 验证XHR请求中yahoo推荐用GET代替POST做法的理由 POST is implemented in the browsers as a two-step process: sending the headers first, then sending data. So it's best to use GET POST请求分两步:发送http headers,再发送http data HTML+JS代码: 抓包工具:wireshark 提示:wireshark(1.2.5版)在抓http包的时候,会默认合并packet reassembly选项,记得全部去掉。如下图(edit-->Preferences) 我分别发了一个GET、一个POST的XHR(XMLHttpRequest)请求,其数据包如下: 如上图,GET请求发送的数据包为第一个红框内的结果;POST请求发送的数据包为第二个红框内结果,但多了一个第12条数据包(粉红色框内),从10.0.0.108(我的PC)发往98.126.129.106(www.cnxct.com的服务器IP,也就是表单提交的目标服务器IP),wireshark给出的信息是“Continuation or non-HTTP traffic”,这个提示就是说,本次数据包是接着上一次的HTTP请求发的,没有HTTP header,只有http data。 详情如下图 XHR HTTP POST请求的header部分数据: XHR HTTP POST 请求的DATA部分: 结论?: 果然,如伟大的YAhoo前端团队所说,XHR HTTP的POST请求会分为两步,先发HTTP HEADER,再发HTTP DATA部分。 然而,新的疑问又来了。为什么要分为两部?谁(例如W3C这种机构)规定的?每个浏览器都是这样的么?分两次比一次的的效率更高吗? 继续: 带这我新的疑问,又进行了如下尝试:先分浏览器,IE8、Firefox5.0、Chrome13分别发送XHR GET 、XHR POST请求,抓包对比结果。 我惊奇的发现(细心的同学会注意到第三张图中,有椭圆形的框标出那些结果的浏览器是Chrome13),Firefox5发送POST的数据包确是没有像yahoo前端优化法则中提到的那样,分为两次,两个包发送,而是一次完成http headers和 http data的发送。如下图: 大家可以从图中看到line-based text data:application/x-www-from-urlcoded下面就是POST的数据。 这时,又有很多疑问产生了,其他浏览器呢?IE的所有版本都会分两次发么?Firefox的其他版本呢? 当我想一个一个尝试抓包对比的同时,幸运的搜到了关于我这个疑问的PDF(Analysis_of_browser_specific_characteristics.pdf) 其中,提到firefox大部分版本在XP、WIN7、UBUNTU、MAC OS等系统上都是以1个包来实现的,其他常见浏览器都是分为两个包。 相比大家很清楚的知道,HTTP(TCP)完成一次事务,通讯次数越多,越有可能出现故障(网络延迟等因素),开销越大,浏览器(客户端)、服务端都要再进行一次TCP通讯,而且,需要一定的时间。对于我们追求更高的用户体验,需要HTTP通讯都避免到这些缺点,而各大浏览器开发商为何仍这么做呢?firefox的做法是最好的吗? 上面的PDF里,模拟了各种网络环境,比如网络延迟、网络丢包等情况,分别来对比POST请求的1次包和2次包的优缺点。得出的结论是:当网络环境好的情况下,1次包跟2次包的在时间上差别基本可以无视。而在网络环境差的情况下,(2次包)TCP的验证数据包完整性上,有非常大的优点,客户端先告诉服务端即将发送的数据包大小,MD5等标识,当服务端告诉客户端收到(ACK包)的时候,客户端再次向服务端发送POST 的DATA。假如网络环境不好,网络延迟、丢包的时候,服务端会等待(延迟时),客户端重发POST的DATA数据到服务单,来确保本次请求的完整性。 撰写这个PDF的作者在他的博客里详细的描述了写这个博客的起因,以及结果,还有一些关于与yahoo yslow前端团队的一些沟通过程,大家可以在这里阅读下(yahoo 的前端团队好像不太友好,哈)。 结论: 通过参考这个PDF,以及我自己做的抓包测试,让我了解Yahoo YSLOW前端团队的这个推荐(他们没详细的说为啥这么推荐,只是简单的提了下GET请求产生TCP一个包;POST请求,产生2个TCP包。甚至都没告诉我们Firefox的多数版本[可能是所有版本]都是发一个TCP包的。更详细、更深层原因也没说,这里还得感谢下http://loadimpact.com的作者)。 备注: 这里提供下我抓包测试时候的数据包(截图用到的数据包中包含我的一些cookie,没上传。这里的是我新抓的,各位见谅),各位可以参考下,如果我的文字、方向有错,欢迎指出。 IE8、FF5、Chrome13发起XHR请求数据包 当你读到这里时,我承认,我骗了你,文章的内容不光是标题中所写的,为何推荐使用POST代替GET,更多的是抓去TCP、HTTP通讯包来验证各个浏览器是否如YSLOW所述的那样分2次包的过程,以及2次包与1次包的优缺点(PDF中)。希望你看到最后的时候,忘记标题讲的是什么。 更新日期:2014年10月27日 在网上看到一篇文章也是介绍GET跟POST区别的,见:XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST? 2011-08-07 +14 18 0
《正则表达式》PPT共享(公司内部培训) 近来我越发懒惰,博客很少更新,最近在公司内部做了一个培训,关于正则表达式的,发到博客里来凑数吧,也算分享给其他朋友了。至于正则表达式的重要性,想必不用我说了吧。 发明BSD、TCP/IP、csh、vi和NFS的SUN首席科学家Bill Joy说过,在计算机体系结构领域里,缓存是唯一称得上伟大的思想的。其他的一切发明和技术不过是在不同场景下应用这一思想而已。在计算机软件领域里,情形也大体相似。如果罗列这个领域的伟大发明,绝对不超过二十项。这些包括分组交换网络、WEB、lisp、哈希算法、UNIX、编译技术、关系模型、面向对象、XML这些大名鼎鼎的家伙,而正则表达式绝对不应该被漏掉。 你还记得大学时候的课程编译原理中提到的 NFA\DFA 吗?还有印象吗?你知道PHP编译器扫描你写的PHP代码字符串的时候,是如何区分哪个是变量,哪个是常量的吗?你知道SQL语法分析器是如何判断你的WHERE条件中出现的SELECT\FROM\ WHERE等关键字是字符串,而不是子查询等关键字的? 你知道.ini配置文件跟xml配置文件对程序来说,是如何扫描解析的吗?他们一样吗?如果你想知道,那你务必的熟悉正则表达式,精通正则表达式。不光能写出正则实现功能,还得能写出高效的正则表达式。(编译原理的课程里,有关于NFA\DNA的大篇幅描述,想写出自己的编程语言,正则是躲不掉的。) 不扯淡了,附PPT吧。 (PPT模版是网上网友的,我是借用他的,其中有几张PPT是直接用他的。很好区分,动画效果很炫的(主要是文字层下的颜色,大约10页吧,简单描述那几页)就是原作者的,其他都是我自己写的。作者信息在PPT最后一页有) PDF也放出来,效果没PPTX好,很多层都被遮住了。 猛击这里下载《正则表达式》PPTX 或者您也可以在线阅读: 正则表达式匹配原理 View more presentations from cfc4n 2011-07-18 +9 13 0
编译xhprof时的一个小意外 新项目基本开发完毕,剩余收尾工作。趁美工调整新UI的时间,赶紧在测试机上安装PHP的性能检测利器xhprof。 下载地址http://pecl.php.net/package/xhprof,这里有tar包,我下了http://pecl.php.net/get/xhprof-0.9.2.tgz, 之后,遍完成了。一路很“顺利”。 php.ini如下设置 代码中,程序头部如下设置: 程序最下面: 之后遍看到统计数据结果了。 可是,当我查看[View Full Callgraph]的时候,却提示如下:Error: either we can not find profile data for run_id 4d7f0bd99a12f or the threshold 0.01 is too small or you do not have 'dot' image generation utility installed.,这TMD神马玩意?是什么错呢? 关于dot的介绍,xhprof在这里写出来了: http://mirror.facebook.net/facebook/xhprof/doc.html dot (image generation utility): The callgraph image visualization ([View Callgraph]) feature relies on the presence of Graphviz "dot" utility in your path. "dot" is a utility to draw/generate an image for a directed graph. GOOGLE了半天,也没找到可用的信息。问了下群里的同学,大牛老王告诉俺,xhprof绘制的是png图,系统(graphviz-2.24.0)不支持。才知道绘图的dot拓展没装成功。我的操作系统是UBUNTU 10.10 SERVER版的,也就是dot 不支持PNG。赶紧再次编译下graphviz,看看提示信息有什么缺少的。果然: png: No (missing png.h)果然。。。。 赶紧到libpng官网down分源码,再次编译一下。 SF.NET上地址是 http://sourceforge.net/projects/libpng/files/libpng15/1.5.1/,我下的是http://sourceforge.net/projects/libpng/files/libpng15/1.5.1/libpng-1.5.1.tar.gz/download ,一气呵成,很顺利。 再次编译graphviz的时候,提示如下: 好了,内牛满面。之后就是 make&make install了。 当打开[View Full Callgraph]的时候,果然是性感的资源占用统计图了。 展示下效果图: 优化前: 找到问题所在,稍微调试: 最终代码优化结果: 2011-03-15 +2 6 0
程序员的谦逊编程 译注:开发人员如何从无休止的需求、项目进度中摆脱烦躁的心态,这是每个人都值得思考的话题。无意间看见了这篇文章,恐于太长遂将其精简翻译,错误之处难免欢迎指正。 同时如果你有有关程序员修身养性的观点和心得,欢迎说说你的看法。 -- Split -- 其实每个程序员或多或少都会有个毛病,就是具有某种有强烈的“优越感”。而这种“优越感” 有可能成为激励自身不断发展的动力,同时也有可能成为其职场中的绊脚石。 程序员的这种心态,源自自身掌握的技术、以及多年积累的经验。正如上面所言,这种心态 能使其一切都力求完美、同时准确按照自己的思路行事,能使其技术不断的提升。而另一方 面,如果将这种态度套用给身边其他的人(包括陌生人、同事、朋友甚至家庭),则会发现 他的生活将会如履薄冰 -- 他们只会看见完美的一面而忽略了更多更需要关注的事物。 总而言之,越早发现并解决这一问题,越对自身有利。套用 GeraldWeinberg 在《计算机编程心理学》中的一段话 这种想法是程序员必须解决的,他们对待自己的代码犹如对待自己身体的 一部分,因此他们拒绝所有的负面评价。相反,它们(指代这种心态)应 该及时的引导到正途,使其发挥真正的效用。人非圣贤,这不仅仅是心态 更是精神上的境界,并非所有人都能达到,但仍旧值得去尝试。 症状 那么,你如何得知这种“优越感”正在伤害到自己?除了应付那些没完没了的催促项目进度的 电话,以及给同事擦屁股的优化工程,其它的现象并非显而易见。 其实就我个人而言,时常也会自我责备,这就能窥出事态的严重。例如一方面你对项目疲于 奔命,而同时却忽略身边的人对你表达的看法(该死,这个时候我应该放下手头的工作听他 们说完的)。或者你“假装”静下心来听取他们的意见,但不就繁杂的工作却让你左耳进右耳 出。 其他的些症状 如上面所说的,不会妥善处理批评 不放心同伴的代码,经常性地对他们进行代码审查(Review) 报复性的编写大量充斥着错误的代码 个人的消极心态,对自身和团队造成不利的影响 必须要求进行测试,但出发点却是炫耀 对事物的看法仅仅局限于个人或者本职位的角度 这不仅仅是你个人的事情,编程以及项目开发实际上是团队活动。了解到这些,你将会意识到 你的心态将会直接影响到你的同事。 事实就是这样,当我对您的代码提出写意见甚至批评时,你应该听、并且认 真的听,这样你才能理解我的看法。 有可能最糟糕的情况就是,即便早已经收到其他同事的提醒,当事人已经陷入此泥潭无法自拔。 准则 让我们回到文章的题目本身,正如上面的例子中看到,“谦逊编程”不是编程技术本身,而是 种态度,但它的确会比你掌握的某种技术要有用的得多。 行为准则的确能改变人的心态,下面是些不成文的建议,或许你可以尝试下 不要草率的宣布你的决定,在大多数情况下,你应该和你们的同事们讨论 不要使用这些论调,这非常让人感到不适:“这是见过的最糟糕的代码了”,换之你可以这样说,“我有个更好的解决方案,要不看看?” 不要轻易认为他们没有考虑到你想的方式,即便很不幸是这样,应该善意的提醒。例如“你觉得我这个看法怎么样...” 不要无理由的批评你认为很弱智的现象,例如“我觉得 DBA 脑门子被夹了,这个字段竟然使用 INT 型” 更多的,可以参考 Tech Republic 中的“谦逊编程”十条诫律: 理解和接受你将犯下的“错误”。 重点是及早的发现你已经犯下的错误,当代码投入使用以后,改动起来就会非常的困难。 你的代码不能代表你的人。 记住始终要 Review 你的代码,即便你已经认为无懈可击,经验证明总能发现些错误。 不管怎么样,有些“奇技淫巧”总能派上用场,而可能这些技巧别人知道的比你更多。 如果你坚持不耻下问,你的同伴总能分享你更多。 不要在完全没有沟通的情况下,自作多情的进行代码重构。 当你确定要更改别人的代码时,必须加上良好的修改记录,这也是出于对他人的种尊重。 对待那些新手要保持充分的尊重、细心以及耐心。 记住当他们成长起来后,能帮你解决的问题会比你想象中的还要多。 唯一不变的是变化。 怀着开放的心态对待变化,对于各种需求、平台甚至开发工具的变更,应该是迅速适应而不是牢骚满腹 -- 这样解决不了问题。 真正的权威来自学识,而不是立场。 权威源自学识、尊重源自权威。 优雅的接受失败。 最终你的一些观点将会被推翻,即便你有能力证明你的观点是正确的,请不要重复的争辩。帮助其他人意识到这点的最好工具,就是你的理解以及时间。 不要成为“办公室男”。 不要在昏暗的办公室里独自喝着可乐敲着代码。当与外界隔绝,离开同伴的视线,也就说明你离开了一个开放、合作的环境。 批判代码而不是编写它的人。 要知道你的意见可以影响到代码也可以影响到其人,如果你想尝试下如何打击别人的自信并造成冲突,那么尝试下吧。 此文转载自:http://www.gracecode.com/archives/2971/ ,自勉自勉。 2011-01-21 1 0
为什么使用ubuntu server的会被鄙视? 由于个人经历原因,我在06年经Dancefire推荐,才认识ubuntu的。时至今日,已有5、6年了。对着ubuntu有着莫名的喜爱。ubuntu桌面版的易用性,友好性,使得我这个菜鸟很容易的入门了。 如今,在公司的svn服务器系统选择上,我也选了ubuntu。 近期,重写了passport系统,出于好奇心,好奇自己的登录程序的并发处理能力、占用资源情况等,想压力测试一下,并不是项目真正完成的时候进行的测试。测试环境一切都是ubuntu的apt之后默认安装的配置。测试中发现瓶颈在DB,顺便让DBA帮看下哪里需要优化的。不想却被一位同事鄙视(善意的鄙视)一番,嘲笑我选择了ubuntu server。我很纳闷,我对linux不熟悉,找不到强有力的理由来反驳。不过,我觉得,不选择ubuntu的理由不能是向他所说的“哪有公司用ubuntu server?”。容我直白的说,如果真的这么想的话,我觉得这可能有些“井底之蛙”了。可能是ubuntu pc版本的界面,比较漂亮,安装软件更傻瓜化,点点鼠标的事情。软件的源很多,基本不用编译等等这些原因,认为使用ubuntu的人都是菜鸟级的。认为全是命令行的界面,所有软件都亲自编译那才叫高手。。。如果要是从内核上找优点,论证这些强项,我会更容易接受你的看法。 比起快速部署,我想,ubuntu server应该比centos之类redhat系的要快的多吧。至于觉得安装的没有编译的效率高,这些可以通过配置文件来设置吧。ubuntu更新比较频繁,可能在升级生,不会很平滑。 对于比较那种linux的server比较好的这种比较,就跟比较 asp.net、PHP、jSP、python等脚本语言比较牛B一样没有意义。更多的在于使用者,而不在于语言本身。如何选择,就看哪种自己更熟悉,更习惯。当然,我也是瞎扯了。我对linux基本不熟悉的。 顺便附上2011年-01-19的linux市场份额图: 其中,centos占了29%,ubuntu占了12.3%,也算不少了吧。 原文地址:http://w3techs.com/technologies/details/os-linux/all/all 2011-01-19 +10 14 0