https://github.com/yongboy/bindp
Binding specific IP and Port fro Linux Running Application
DevOps
https://github.com/yongboy/bindp
Binding specific IP and Port fro Linux Running Application
system/exec 函数:
这两个函数会利用/bin/sh 指定的shell来执行指定的命令,所以,指定的命令实际上不仅可以包含可以执行的命令和参数,还可以是对应shell的内置命令以及shell支持的控制结构。
缺点: 无法区分标准输出与标准错误
注意: 这两个函数执行的外部命令默认继承了php进程的标准输入、标准输出和标准错误,你可以通过返回值得到进程的标准输出,但是标准错误却悄悄地流进了php进程定义的标准错误输出里面去了;更加隐晦的是,对于php-fpm进程来讲,该外部进程也默认listen(继承来的)了php-fpm监听的端口,但是肯定不会去处理php-fpm请求,一般情况下不会有问题,特殊情况下回让你莫名其妙
pcntl_exec 函数:
该函数会取代当前执行的进程空间,而且是不会再回到当前进程空间,可能你很少会用到该函数,但是,当你确实需要该函数的时候,却又是没有其他函数可以替代的,如:
1 |
# php -d error_log="" -r 'pcntl_exec("/bin/sleep", array(1));echo 2;' |
echo 2 是不可能被执行到的
注意: pcntl_exec不同于其他函数,并不会使用shell来执行指定的命令,而且指定的命令需要是要执行的可执行文件的全路径
proc_open 函数:
这个是我最喜欢的函数:
proc_open 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?php $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a file to write to ); $cwd = '/tmp'; $env = array('some_option' => 'aeiou'); $process = proc_open('ssh -i /home/phpor/.ssh/id_rsa phpor@localhost ', $descriptorspec, $pipes, $cwd, $env); if (is_resource($process)) { // $pipes now looks like this: // 0 => writeable handle connected to child stdin // 1 => readable handle connected to child stdout // Any error output will be appended to /tmp/error-output.txt fwrite($pipes[0], $argv[1]); fclose($pipes[0]); echo stream_get_contents($pipes[1]); fclose($pipes[1]); echo stream_get_contents($pipes[2]); fclose($pipes[2]); // It is important that you close any pipes before calling // proc_close in order to avoid a deadlock $return_value = proc_close($process); echo "command returned $return_value\n"; } |
什么是进程会计?
进程会计记录了什么时间启动了什么进程,进程的属主是什么,进程的结束时间等信息。
linux默认并没有开启进程会计,那么如何开启进程会计呢?
centos中提供了一个叫做psacct的软件包,其中包含accton 、lastcomm、ac、sa、dump-acct、dump-utmp几个命令,可以帮助我们开启、关闭、查看进程会计信息,简要介绍如下:
accton on|off|file
打开、关闭进程会计,也可以直接accton file来指定进程会计信息的记录位置,同时开启进程会计;注意:
实现原理:
linux提供了一个acct系统调用,用来通知内核信息进程会计:
accton on 等同于: acct(“/var/account/pacct”)
accton off等同于: acct(NULL)
(注意:有的版本可能不能accton off,而是不带任何参数就意味着off)
lastcomm: 查看进程会计信息
1 2 3 4 5 6 7 8 |
# lastcomm -f acct accton root pts/0 0.00 secs Tue Apr 4 13:13 sh zabbix __ 0.00 secs Tue Apr 4 13:13 wc zabbix __ 0.00 secs Tue Apr 4 13:13 grep zabbix __ 0.00 secs Tue Apr 4 13:13 netstat zabbix __ 0.01 secs Tue Apr 4 13:13 accton root pts/0 0.00 secs Tue Apr 4 13:13 ... |
sa:统计进程会计信息
1 2 3 4 5 6 7 8 9 10 |
# sa -a acct 227 0.02re 0.00cp 0avio 28444k 2 0.00re 0.00cp 0avio 29776k netstat 88 0.00re 0.00cp 0avio 31031k ls 84 0.01re 0.00cp 0avio 26976k sleep 10 0.00re 0.00cp 0avio 28816k sh 10 0.00re 0.00cp 0avio 28160k grep 8 0.00re 0.00cp 0avio 28368k awk 8 0.00re 0.00cp 0avio 26976k head 8 0.00re 0.00cp 0avio 26976k cat |
dump-utmp
1 2 3 4 5 |
dump-utmp /var/log/wtmp|head reboot |~ |2|~~ | 0|3.10.0-327.el7.x86_64 |Tue Mar 7 00:42:20 2017 |tty1 |5|tty1| 1806| |Mon Mar 6 16:42:36 2017 LOGIN |tty1 |6|tty1| 1806| |Mon Mar 6 16:42:36 2017 runlevel |~ |1|~~ | 51|3.10.0-327.el7.x86_64 |
问题:
如何让php-fpm能优雅地重启?
办法:
问题:
kill -SIGQUIT 可以解除子进程对9000端口的listen,却不能解除master进程对9000端口的listen
子进程的listen是继承父进程的
子进程接到SIGQUIT 信号后,close掉listen的文件描述符,然后创建了一个新的socket,如下:
(为什么要创建一个新的socket?)
同一个文件描述符被fork到多个子进程后,每个进程的关闭只会在本进程内关闭(让该资源和本进程脱离关系),然后减少该资源的引用计数,直到最后一个引用被解除,该资源才真正销毁
关于上述的问题7:
1 2 3 4 5 6 7 8 9 |
<?php $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to ); $process = proc_open('sleep 10000',$descriptorspec, $pipe); print_r($pipe); sleep(10000); |
这样就对了; 而且,proc_close() 可以获取外部进程的退出码
1 2 3 |
#!/bin/bash exec 0<&- $@ |
注意: 这个shell会存在一些问题,如下:
改进如下:
1 2 3 4 5 |
#!/bin/bash exec 0<&- cmd=$1 shift $cmd "$@" |
到现在为止,我们有能力不让外部的子进程来影响fpm请求的处理了;但是,还有一个listen 9000 但是不能处理请求的进程,那就是: php-fpm master进程
我们的处理方法可以如下:
最后:
我们还没有解决如何让旧进程消费完旧进程的backlog中剩余的连接的问题,稍后研究。
分析:
socket中有一个shutdown的方法,可以关闭socket的读或(和)写,会触发关闭已建立的连接的方法,(对于listen的socket没有对端,想必不能用shutdown方法),测试发现:
1 2 3 4 5 |
<?php $s = socket_create_listen (8882, 1); fgets(STDIN); socket_shutdown($s); fgets(STDIN); |
一种其它的实现方式:
在so_reuseport出现之前(包括现在)有一些程序是可以实现优雅重启的,原理就是,新旧进程时间继承lisen的文件描述符; 其实,继承文件描述符需要不小的工作量的。
如果能有一种标准的接口来处理继承文件描述符的事情,那么完全可以开发一个和应用无关的小程序,用来创建socket端口,然后遗传给真正要干活的应用程序,只需要遗传给应用程序的master进程就算OK了,如果需要重启程序,则只需要fork新的应用程序的master进程,然后发信号让旧的空闲的应用进程退出就可以了,这样就不会丢弃已创建的连接。
参考:
https://my.oschina.net/miffa/blog/390931