什么是 CGI/FastCGI/PHP-FPM?

什么是 CGI?

CGI 全称是“公共网关接口”(Common Gateway Interface),定义了一套协议。HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。 CGI 可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如 php,perl,tcl 等

Nginx 只是内容的分发者。比如,如果请求 index.html,那么 Nginx 会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。 如果现在请求的是 index.php,根据配置文件,nginx知道这个不是静态文件,则启动对应的CGI程序,找到PHP解析器来处理(PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程。Nginx 再把结果返回给浏览器)。

Nginx 会传哪些数据给PHP解析器呢?URL+QueryString+PostData+HttpHeader。

好的,CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的一套协议。

什么是 FastCGI

FastCGI 相当于定义了一套管理办法。FastCGI 是一套跟语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存中并因此获得较高的性能

1. CGI程序的性能问题在哪呢?

CGI解释器的反复加载是CGI性能低下的主要原因,如果CGI解释器保持在内存中并接受 FastCGI 进程管理器调度,则可以提供良好的性能、伸缩性、Fail- Over特性等等。即一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次 (这是CGI最为人诟病的fork-and-execute 模式)。它还支持分布式的运算,即 FastCGI 程序可以在网站服务器以外的主机上执行并且接受来自其它网站服务器来的请求。

2. FastCGI 如何优化性能?

FastCGI 会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。而且当worker不够用时,master可以根据配置预先启动几个worker等着;当然空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。master和children之间通过共享内存来共享配置文件

什么是 PHP-FPM?

FastCGI 是一个协议,PHP-FPM 实现了这个协议。 PHP-FPM 是一个 PHP FastCGI 管理器,可以有效控制内存和进程、平滑重载PHP配置,已被PHP官方收录。在 ./configure 的时候带 –enable-fpm 参数即可。

什么是 PHP-CGI?

PHP-CGI 与 PHP-FPM 一样,是 PHP 自带的FastCGI管理器,PHP-CGI 的问题在于:

  1. PHP-CGI 变更 php.ini 配置后需重启 PHP-CGI 才能生效,不可以平滑重启。
  2. 直接杀死 PHP-CGI 进程,php 就不能运行了。(PHP-FPM 和 Spawn-FCGI 就没有这个问题,守护进程会平滑从新生成新的子进程。)

针对 PHP-CGI 的不足,PHP-FPM 应运而生。

什么是 Spawn-FCGI?

Spawn-FCGI 也是一个FastCGI管理器,它是 lighttpd 中的一部份。 PHP-FPM 控制的进程CPU回收的速度比较慢,内存分配的很均匀。 Spawn-FCGI 控制的进程CPU下降的很快,而内存分配的比较不均匀。有很多进程似乎未分配到,而另外一些却占用很高。导致了总体响应速度的下降。

参考文章

搭建 ued.morecruit.cn 笔记(Nginx Basic Auth)

1、先按照上篇文章利用 GitWebHook 自动部署代码

2、设置允许目录浏览

vi /usr/local/nginx/conf/vhost/ued.morecruit.cn.conf 在 server {} 段中增加:

autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
charset utf-8, gbk;

3、给站点增加 Nginx Basic Auth

vi /usr/local/nginx/conf/vhost/ued.morecruit.cn.conf 在 server {} 段中增加:

auth_basic "plz input password:";
auth_basic_user_file vhost/ued.morecruit.cn.htpasswd;

注意 auth_basic_user_file 的相对目录是 /usr/local/nginx/conf

新增一对用户和密码

printf "用户名:$(openssl passwd -crypt 密码)\n" >> /usr/local/nginx/conf/vhost/ued.morecruit.cn.htpasswd

重启 Nginx 即可

/etc/init.d/nginx reload

参考文章:

使用 Coding.net 的 WebHook 来自动更新、部署

需求:

开发人员提交 git push 后,在目标机器上可以自动触发执行 git pull 获取最新代码

特别要注意是操作权限问题,假设目标机器为我们的 BigIns 测试机。

1、在『目标机器』上执行生成公钥:

mkdir /home/www/.ssh
chown www.www /home/www/.ssh

sudo -u www ssh-keygen
cat /home/www/.ssh/id_rsa.pub

2、把公钥文本粘贴到 Coding.net 中指定项目的『设置-项目设置-部署公钥』里

3、在『目标机器』找一个 Web 可访问到的目录,新建 PHP 文件:

sudo -u www vi git_hook.php

<?php

const WIKI_DIR = '/home/wwwroot/pai.bigins.wiki';

// 假设 wiki 文档放在 coding-pages 分支上
echo shell_exec('cd ' . WIKI_DIR . ' && git pull origin coding-pages 2>&1');

?>

4、设置 Coding.net 的 WebHook,填入以下 URL:

http://pai.bigins.wiki/git_hooks.php

5、在『目标机器』初始化检出代码(必须用 www 用户)

# 新建
cd /home/wwwroot/
mkdir pai.bigins.wiki
chown www.www pai.bigins.wiki

# 检出代码
# 注意:git remote 仓库地址必须用 SSH 地址:git@git.coding.net,不能用 https://git.coding.net
# 因为经测试 https 检出的库,每次 pull 还是要输入密码,ssh 方式则无需重复认证
sudo -u www git clone -b coding-pages git@git.coding.net:grampus/hmb_oa_wiki.git pai.bigins.wiki

6、如果需要手动 pull,则必须以 www 身份执行:

cd /home/wwwroot/pai.bigins.wiki
sudo -u www git pull origin coding-pages

参考文章:

Nginx 在 StayLife 的一些应用

需求:将 m.69night.cn/mapi 所有请求转发到 api.staylife.cn

修改 /usr/local/nginx/conf/vhost/69night.conf

location /mapi/
{
    # 尾部的斜杠不能少,目的是不用把 /mapi 这个路径转发出去
    proxy_pass https://qa.api.staylife.cn/;
    proxy_redirect  off;
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    access_log /home/wwwlogs/69night_mapi.log access;
}

值得一提的是,原来我们用的 rewrite 来转发。当 POST 请求时,对于内部的 URL(斜杠开头)转发时,POST 数据不会丢失。对于外部跳转,实际上是一次 GET 302,所以会丢失第一次的 POST 数据。

location /mapi/ {
    rewrite ^ https://qa.api.staylife.cn/;
}

参考文章:

Nginx 访问日志记录 POST/COOKIE/HEADER 等数据

初始日志格式中的变量:

$remote_addr        The remote host
$remote_user        The authenticated user (if any)
$time_local         The time of the access
$request            The first line of the request
$status             The status of the request
$body_bytes_sent    The size of the server's response, in bytes
$http_referer       The referrer URL, taken from the request's headers
$http_user_agent    The user agent, taken from the request's headers

我们要用到的几个变量:

$request_body   请求体(含POST数据)
$http_XXX       指定某个请求头(XXX为字段名,全小写)
$cookie_XXX     指定某个cookie值(XXX为字段名,全小写)

修改 /usr/local/nginx/conf/nginx.conf,增加新的日志格式 big_api

log_format  big_api  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$request_body" "$http_referer" '
    '"$http_user_agent" $http_x_forwarded_for "appid=$http_appid,appver=$http_appver,vuser=$http_vuser" '
    '"phpsessid=$cookie_phpsessid,vuser_cookie=$cookie___vuser" ';

修改 /usr/local/nginx/conf/vhost/hicrew.conf,底部对应的日志格式也改为 big_api

access_log  /home/wwwlogs/hicrew.log big_api;

参考文章:

Mac 通过 brew 安装 Apache2.4

执行安装

brew install homebrew/apache/httpd24

删除原有自带的 apache

sudo rm -rf /usr/sbin/httpd
sudo rm -rf /etc/apache2

修改配置 /usr/local/etc/apache2/2.4/httpd.conf

# 修改监听端口(初始为8080)
Listen 80

找 `Require all denied` 替换成 `Require all granted`

# 开启 mod_rewrite 模块
LoadModule rewrite_module libexec/apache2/mod_rewrite.so

# 开启 PHP7 模块
LoadModule php7_module /usr/local/Cellar/php70/7.0.6/libexec/apache2/libphp7.so

# 开启引入虚拟主机
Include /usr/local/etc/apache2/2.4/extra/httpd-vhosts.conf

# 底部增加一行
Include /usr/local/etc/apache2/2.4/other/*.conf

修改文件 /usr/local/etc/apache2/2.4/extra/httpd-vhosts.conf

<VirtualHost *:80>
    ServerName localhost
    DocumentRoot "/Users/silverd/home/wwwroot"
    <Directory "/Users/silverd/home/wwwroot">
        Include /usr/local/etc/apache2/2.4/extra/php-yaf.conf
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    ServerName local.api.hicrew.cn
    ServerAlias local.m.hicrew.cn
    DocumentRoot "/Users/silverd/home/wwwroot/hicrew/app/web"
    <Directory "/Users/silverd/home/wwwroot/hicrew/app/web">
        Include /usr/local/etc/apache2/2.4/extra/php-yaf.conf
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    ServerName local.admincp.hicrew.cn
    DocumentRoot "/Users/silverd/home/wwwroot/hicrew/admin/web"
    <Directory "/Users/silverd/home/wwwroot/hicrew/admin/web">
        Include /usr/local/etc/apache2/2.4/extra/php-yaf.conf
    </Directory>
</VirtualHost>

新增文件 /usr/local/etc/apache2/2.4/other/php7.conf

<IfModule php7_module>
    AddType application/x-httpd-php .php
    AddType application/x-httpd-php-source .phps
    <IfModule dir_module>
        DirectoryIndex index.html index.php
    </IfModule>
</IfModule>

新增文件 /usr/local/etc/apache2/2.4/extra/php-yaf.conf

Options Indexes FollowSymLinks
Require all granted
AllowOverride All
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>

设置开机启动

ln -sfv /usr/local/opt/httpd24/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

设置启动、停止命令别名

vi ~/.bash_profile
alias httpd24.start="launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist"
alias httpd24.stop="launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist"
alias httpd24.restart='httpd24.stop && httpd24.start'
source ~/.bash_profile

其实仍然可以通过以下命令来管理

sudo apachectl start
sudo apachectl stop
sudo apachectl restart

因为 apachectl 命令此时指向的是:

/usr/local/bin/apachectl -> /usr/local/Cellar/httpd24/2.4.23_2/bin/apachectl

对了,记得把原先系统自带的 Apache 停止掉:

sudo /usr/sbin/apachectl stop

# 或粗鲁点直接杀进程
ps -ef | grep /usr/sbin/httpd | grep -v grep | cut -c 6-12 | xargs sudo kill -9