存档

作者存档

PHP进程信号处理

2013年6月6日 1 条评论

PHP的pcntl扩展提供了信号处理的功能,利用它可以让PHP来接管信号的处理,在开发服务器端守护进程方面,信号处理至关重要。pcntl这个扩展仅在cli/cgi模式下可用。mod_php和php-fpm中不可以使用。PHP在编译的过程中,并没有把pcntl连接到php-cli可执行文件中。

函数原型:

bool pcntl_signal(int $signo ,callback $handler [,bool $restart_syscalls=true])

第一个参数是信号ID,具体可以参见这里http://swoole.sinaapp.com/archives/124

第二个参数是信号发生时回调的PHP函数。

第三个参数是是否restart,是否重新注册此信号。这个参数如果为false,那此信号只注册处理一次。


<?php
//信号处理需要注册ticks才能生效,这里务必注意
//PHP5.4以上版本就不再依赖ticks了
declare(ticks = 1);

function sig_handler($signo)
{
switch ($signo) {
case SIGUSR1:
echo "SIGUSR1\n";
break;
case SIGUSR2:
echo "SIGUSR2\n";
break;
default:
echo "unknow";
break;
}

}

pcntl_signal(SIGUSR1, "sig_handler");
pcntl_signal(SIGUSR2, "sig_handler");

posix_kill(posix_getpid(), SIGUSR1);
posix_kill(posix_getpid(), SIGUSR2);
?>

 

分类: PHP系统编程 标签:

Linux常见信号大全

2013年6月6日 没有评论

 

编号 信号名称 缺省动作 说明
1 SIGHUP 终止 终止控制终端或进程
2 SIGINT 终止 键盘产生的中断(Ctrl-C)
3 SIGQUIT dump 键盘产生的退出
4 SIGILL dump 非法指令
5 SIGTRAP dump debug中断
6 SIGABRT/SIGIOT dump 异常中止
7 SIGBUS/SIGEMT dump 总线异常/EMT指令
8 SIGFPE dump 浮点运算溢出
9 SIGKILL 终止 强制进程终止
10 SIGUSR1 终止 用户信号,进程可自定义用途
11 SIGSEGV dump 非法内存地址引用
12 SIGUSR2 终止 用户信号,进程可自定义用途
13 SIGPIPE 终止 向某个没有读取的管道中写入数据
14 SIGALRM 终止 时钟中断(闹钟)
15 SIGTERM 终止 进程终止
16 SIGSTKFLT 终止 协处理器栈错误
17 SIGCHLD 忽略 子进程退出或中断
18 SIGCONT 继续 如进程停止状态则开始运行
19 SIGSTOP 停止 停止进程运行
20 SIGSTP 停止 键盘产生的停止
21 SIGTTIN 停止 后台进程请求输入
22 SIGTTOU 停止 后台进程请求输出
23 SIGURG 忽略 socket发生紧急情况
24 SIGXCPU dump CPU时间限制被打破
25 SIGXFSZ dump 文件大小限制被打破
26 SIGVTALRM 终止 虚拟定时时钟
27 SIGPROF 终止 profile timer clock
28 SIGWINCH 忽略 窗口尺寸调整
29 SIGIO/SIGPOLL 终止 I/O可用
30 SIGPWR 终止 电源异常
31 SIGSYS/SYSUNUSED dump 系统调用异常

 

分类: Linux 标签:

gcc中的预编译宏

2013年5月10日 没有评论

* __NASE_FILE__ 源文件的完整路径名,和 __FILE__ 不同,被引用的文件仍然是原来文件名
* __CHAR_UNSIGNED__ 用于指定该机器上 char 是无符号类型
* __cplusplus 使用 C++ 编译器编译
* __DATE__ 编译时的日期
* __FILE__ 编译文件名
* __func__ 同 __FUNCTION__
* __GNUC__ GCC 的主版本号
* __GNUC_MINOR__ GCC 的次版本号
* __GNUC_PATCHLEVEL__ GCC 的修订号
* __GNUG__ 由 C++ 编译程序定义
* __INCLUDE_LEVEL__ 指 #include 的层次
* __LINE__ 当前行号
* __NO_INLINE__ 不允许 inline
* __OPTIMIZE__ 打开了优化选项
* __OPTIMIZE_SIZE__ 打开了对编译出文件尺寸的优化
* __STDC__ 表示该程序符合 ansi C 标准
* __STDC_HOSTED__ 表示宿主具有标准 C 的环境
* __STDC_VERSION__ 标准 C 制定时间
* __TIME__ 编译时系统时间
* __VERSION__ GCC 版本号

分类: C/C++ 标签:

Linux的errno定义

2013年4月28日 没有评论

从网上搜到的,这个东东用处很大,随时备查。
  124 EMEDIUMTYPE Wrong medium type
  123 ENOMEDIUM No medium found
  122 EDQUOT Disk quota exceeded
  121 EREMOTEIO Remote I/O error
  120 EISNAM Is a named type file
  119 ENAVAIL No XENIX semaphores available
  118 ENOTNAM Not a XENIX named type file
  117 EUCLEAN Structure needs cleaning
  116 ESTALE Stale NFS file handle
  115 EINPROGRESS +Operation now in progress
  114 EALREADY Operation already in progress
  113 EHOSTUNREACH No route to host
  112 EHOSTDOWN Host is down
  111 ECONNREFUSED Connection refused
  110 ETIMEDOUT +Connection timed out
  109 ETOOMANYREFS Too many references: cannot splice
  108 ESHUTDOWN Cannot send after transport endpoint shutdown
  107 ENOTCONN Transport endpoint is not connected
  106 EISCONN Transport endpoint is already connected
  105 ENOBUFS No buffer space available
  104 ECONNRESET Connection reset by peer
  103 ECONNABORTED Software caused connection abort
  102 ENETRESET Network dropped connection on reset
  101 ENETUNREACH Network is unreachable
  100 ENETDOWN Network is down
  99 EADDRNOTAVAIL Cannot assign requested address
  98 EADDRINUSE Address already in use
  97 EAFNOSUPPORT Address family not supported by protocol
  96 EPFNOSUPPORT Protocol family not supported
  95 EOPNOTSUPP Operation not supported
  94 ESOCKTNOSUPPORT Socket type not supported
  93 EPROTONOSUPPORT Protocol not supported
  92 ENOPROTOOPT Protocol not available
  91 EPROTOTYPE Protocol wrong type for socket
  90 EMSGSIZE +Message too long
  89 EDESTADDRREQ Destination address required
  88 ENOTSOCK Socket operation on non-socket
  87 EUSERS Too many users
  86 ESTRPIPE Streams pipe error
  85 ERESTART Interrupted system call should be restarted
  84 EILSEQ Invalid or incomplete multibyte or wide character
  83 ELIBEXEC Cannot exec a shared library directly
  82 ELIBMAX Attempting to link in too many shared libraries
  81 ELIBSCN .lib section in a.out corrupted
  80 ELIBBAD Accessing a corrupted shared library
  79 ELIBACC Can not access a needed shared library
  78 EREMCHG Remote address changed
  77 EBADFD File descriptor in bad state
  76 ENOTUNIQ Name not unique on network
  75 EOVERFLOW Value too large for defined data type
  74 EBADMSG +Bad message
  73 EDOTDOT RFS specific error
  72 EMULTIHOP Multihop attempted
  71 EPROTO Protocol error
  70 ECOMM Communication error on send
  69 ESRMNT Srmount error
  68 EADV Advertise error
  67 ENOLINK Link has been severed
  66 EREMOTE Object is remote
  65 ENOPKG Package not installed
  64 ENONET Machine is not on the network
  63 ENOSR Out of streams resources
  62 ETIME Timer expired
  61 ENODATA No data available
  60 ENOSTR Device not a stream
  59 EBFONT Bad font file format
  57 EBADSLT Invalid slot
  56 EBADRQC Invalid request code
  55 ENOANO No anode
  54 EXFULL Exchange full
  53 EBADR Invalid request descriptor
  52 EBADE Invalid exchange
  51 EL2HLT Level 2 halted
  50 ENOCSI No CSI structure available
  49 EUNATCH Protocol driver not attached
  48 ELNRNG Link number out of range
  47 EL3RST Level 3 reset
  46 EL3HLT Level 3 halted
  45 EL2NSYNC Level 2 not synchronized
  44 ECHRNG Channel number out of range
  43 EIDRM Identifier removed
  42 ENOMSG No message of desired type
  40 ELOOP Too many levels of symbolic links
  39 ENOTEMPTY +Directory not empty
  38 ENOSYS +Function not implemented
  37 ENOLCK +No locks available
  36 ENAMETOOLONG +File name too long
  35 EDEADLK +Resource deadlock avoided
  34 ERANGE +Numerical result out of range
  33 EDOM +Numerical argument out of domain
  32 EPIPE +Broken pipe
  31 EMLINK +Too many links
  30 EROFS +Read-only file system
  29 ESPIPE +Illegal seek
  28 ENOSPC +No space left on device
  27 EFBIG +File too large
  26 ETXTBSY Text file busy
  25 ENOTTY +Inappropriate ioctl for device
  24 EMFILE +Too many open files
  23 ENFILE +Too many open files in system
  22 EINVAL +Invalid argument
  21 EISDIR +Is a directory
  20 ENOTDIR +Not a directory
  19 ENODEV +No such device
  18 EXDEV +Invalid cross-device link
  17 EEXIST +File exists
  16 EBUSY +Device or resource busy
  15 ENOTBLK Block device required
  14 EFAULT +Bad address
  13 EACCES +Permission denied
  12 ENOMEM +Cannot allocate memory
  11 EAGAIN +Resource temporarily unavailable
  10 ECHILD +No child processes
  9 EBADF +Bad file descriptor
  8 ENOEXEC +Exec format error
  7 E2BIG +Argument list too long
  6 ENXIO +No such device or address
  5 EIO +Input/output error
  4 EINTR +Interrupted system call
  3 ESRCH +No such process
  2 ENOENT +No such file or directory
  1 EPERM +Operation not permitted
  0 Success

分类: C/C++ 标签:

PHP进程间通信IPC-消息队列的使用

2013年4月25日 1 条评论

Linux IPC消息队列是一个全内存设计,内核保证读写顺序和数据同步,并且性能非常强悍的先进现先出数据结构。它的特性如下:

  1. 每秒可读写超过50万次(4核/4G内存的机器)
  2. 支持消息多类型,抢队列时可根据需要获取特定的消息类型
  3. 每个消息长度最大支持65535个字节
  4. 队列长度受内存大小限制,最大不超过机器内存的50%,可以修改内核参数来调整

消息队列可以用在很多场景下,如异步任务处理,抢占式的数据分发,顺序缓存区等。使用方法也非常简单,Linux提供了4个库函数,msgget,msgsnd,msgrcv,msgctl,分别用于创建/获取消息队列、发送数据、接收数据、设置/获取消息队列。PHP内核包含了这个扩展,需要在./configure时加入–enable-sysvmsg来开启。具体可参考PHP手册。Swoole框架内提供了一个sysvmsg的封装,代码在http://code.google.com/p/swoole/source/browse/trunk/libs/class/swoole/queue/SysvQueue.class.php.

下面写一个简单的例子,采用单Proxy主进程+多Worker进程的模式,功能是做异步任务的处理。本代码没有提供进程管理、信号处理、队列过载保护,如果要用在生产环境,请自行实现。


<?php
$msg_key = 0x3000111; //系统消息队列的key
$worker_num = 2;   //启动的Worker进程数量
$worker_pid = array();

$queue = msg_get_queue($msg_key, 0666);
if($queue === false)
{
    die("create queue fail\n");
}
for($i = 0; $i < $worker_num; $i++)
{
    $pid = pcntl_fork();
    //主进程
    if($pid > 0)
    {
        $worker_pid[] = $pid;
        echo "create worker $i.pid = $pid\n";
        continue;
    }
    //子进程
    elseif($pid == 0)
    {
        proc_worker($i);
        exit;
    }
    else
    {
        echo "fork fail\n";
    }
}

proc_main();

function proc_main()
{
    global $queue;
    $bind = "udp://0.0.0.0:9999";
    //建立一个UDP服务器接收请求
    $socket = stream_socket_server($bind, $errno, $errstr, STREAM_SERVER_BIND);
    if (!$socket)
    {
        die("$errstr ($errno)");
    }
    stream_set_blocking($socket, 1);
    echo "stream_socket_server bind=$bind\n";
    while (1)
    {
        $errCode = 0;
        $peer = '';
        $pkt = stream_socket_recvfrom($socket, 8192, 0, $peer);

        if($pkt == false)
        {
            echo "udp error\n";
        }
        $ret = msg_send($queue, 1, $pkt, false, true, $errCode); //如果队列满了,这里会阻塞
        if($ret)
        {
            stream_socket_sendto($socket, "OK\n", 0, $peer);
        }
        else
        {
            stream_socket_sendto($socket, "ER\n", 0, $peer);
        }
    }
}

function proc_worker($id)
{
    global $queue;
    $msg_type = 0;
    $msg_pkt = '';
    $errCode = 0;
    while(1)
    {
        $ret = msg_receive($queue, 0, $msg_type, 8192, $msg_pkt, false, $errCode);
        if($ret)
        {
            //TODO 这里处理接收到的数据
            //.... Code ....//
            echo "[Worker $id] ".$msg_pkt;
        }
        else
        {
            echo "ERROR: queue errno={$errCode}\n";
        }
    }
}

运行结果:

create worker 0.pid = 18885
create worker 1.pid = 18886
stream_socket_server bind=udp://0.0.0.0:9999
[Worker 0] hello
[Worker 1] hello2
[Worker 0] hello1

客户端使用netcat来测试,netcat -u 127.0.0.1 9999。

使用ipcs -q来查看系统消息队列:

tianfenghan@VM_194_118_sles10_64:/data/nginx_log> ipcs -q

------ Message Queues --------
key msqid owner perms used-bytes messages
0x4000270f 0 tianfengha 666 0 0
0x03000111 32769 tianfengha 666 0 0

0×03000111就是刚才我们创建的消息队列。

分类: PHP 标签:

大型网站运营的技术经验分享

2013年3月28日 没有评论

一、日志系统

对于一个大型网站来说,代码库非常庞大,模块众多。部门协作的人数规模在百人以上,如何跟踪定位问题不像小网站那样容易。而且我们的服务器都是集群化的,动辄几千台。有一套可查询方便使用的日志系统至关重要。

对于日志的使用也有了一定的经验。我们的日志通常会非常详细的记录各种参数,环境变量,HOST等信息,在出现异常的情况下,必须要记录日志。我们使用了MySQL按时间分片的方式来记录日志,所有集群内节点均通过网络方式来写入到中心日志系统。

在管理端我们提供了很方便友好的工具,来查询定位日志,可按用户ID、类型、时间等几种索引方式查询。日志系统帮助我们定位到了很多问题。

二、PHP错误日志收集系统

PHP错误日志是所有PHP程序问题最直接的反馈渠道。通过分析PHP日志可以发现和分析出系统现有的Bug和潜在的问题。我们通过在节点部署监控工具,实时收集PHP错误日志,Fatal Error告警。解决了很多问题

三、数据统计中心

我们有一整套数据上报的系统,系统内各种接口调用、请求响应、错误返回,都会上报到数据统计中心。我们以报表的形式展现出来,可以很方便的看到每个模块,每个接口的可用性,成功率,数据规模。根据数据,我们还做了成功率告警,当接口成功率低于某个数值,比如99.99%时就会发送短信报警。还有历史数据对比报警,当发现今日数据与往期数据差距较大时,可能是系统出现了问题,会及时进行报警。

四、硬件系统报警

我们有一套工具,来监控每个服务器节点的CPU、硬盘、内存、网卡流量信息,以及其他系统关键参数的信息。并以图表方式提供展示,方便了解服务器运行情况。每次新版本,或新功能上线,都通过这些信息来感知访问量变化,以及机器的负载情况。

五、容灾工具

当一组Server中其中一台出现问题时,会及时发现,并踢掉。这个也可以做成自动容灾,不过控制不好会发生雪崩。

分类: PHP 标签:

说说产品驱动型的管理模式

2013年3月28日 1 条评论

很多IT公司都采用产品驱动技术的管理模式,我们腾讯也是如此。身为一个程序员不得不对这种模式做点评价。

不可否认这种模式会比较快得作出产品来,虽然开发出的产品不一定会是最好,最起码不会是最差。另外产品开发的成功率也得到了保证,不至于做了一半不搞了。

但是也顺便讲讲他的坏处吧。产品驱动的开发模式最致命的问题是:会让所有程序员彻底失去积极性。无论多么棒的Idea,多么有意思的Idea,只要用了这种模式,程序员的那种积极性,创新性都将不存在了。逐渐会产生另外一个问题,反正不是我主导的,我不用再思考了,你们怎么说我就怎么做吧。效率越来越差劲。如果军队是参谋指挥将军,打起仗来会怎么样?

谈论下Facebook的管理模式吧。他们也有产品经理,但主要产品的是技术人员而不是产品经理,产品经理负责给技术出谋划策,提供信息帮助技术人员。他们的效率很高。

腾讯也是产品驱动型的管理模式,不过广州研发部是个例外,也正是因为例外,所以他们搞出了QQ邮箱,微信这样的重量级产品来。

分类: 互联网 标签:

腾讯朋友网tp_netclient.php介绍

2013年3月28日 没有评论

一、为什么要开发tp_netclient.php

大家都知道PHP有2套socket的封装:stream扩展和socket扩展。stream系列函数可以直接用fread/fwrite来读写,PHP做了一些封装,使用起来更方便。但从一下几点因素我们基于socket扩展开发了tp_netclient.php

1、超时设置的问题。调用fread读取socket时,如果没有显式设置超时那么将会取默认的socket超时值75秒。另外即使显式设置了超时,代码中如果调用了stream_socket_recvfrom,还会取默认的75秒超时(这是PHP stream_socket_recvfrom函数的bug)。一旦server端无响应,75秒的超时会使当前进程长时间阻塞。PWS,PSF,SAPS都将无法相应新的请求,造成严重的后果。tp_netclient.php默认设置了100ms,就算没接收到数据,也只会阻塞100ms,之后进程会继续处理新的请求。

2、fread有8192长度限制,一旦读到8192字节,此函数就会返回。TCP可以循环读取, UDP包就会被丢弃。这样如果用UDP协议,就不能处理超过8192字节的包。tp_netclient.php使用了socket扩展,可以支持到UDP包的最大长度65535,不存在此问题。

3、stream的socket不能设置socket option。很多有用的socket option,如SO_REUSEADDR、TCP_NODELAY都不能支持。tp_netclient.php基于socket扩展,可以很方便设置各种socket option。

4、tp_netclient.php支持waitall,在知道包长度的情况下可以一次取完,不必循环取。

5、tp_netclient.php支持UDP connect,解决了UDP串包问题

6、stream扩展是2层封装的,而socket扩展是原生socket函数的封装,性能更好。

二、tp_netclient.php如何使用

目前在朋友网系统消息模块中已广泛使用,在生产环境安全可靠无问题。

示例代码:


$client = new TP_NetClient_TCP;

if($client->connect('10.6.207.204', 19003 ,0.5))
{
   $data = 'GET /default.php HTTP/1.1\r\nHost: www.pengyou.com\r\n\r\n';
   $client->send($data);
   $cnt = $client->recv(65535);
   echo 'succ:',$cnt,'\n';
}
else
{
   echo 'faile:';
   echo $client->code;
   echo $client->msg;
}

注:此代码是私有的,大家可以直接使用swoole扩展提供的client封装。使用方法基本相同。
https://github.com/matyhtf/php_swoole/blob/master/examples/client.php

分类: PHP 标签:

PHP-AOP扩展介绍

2013年3月8日 1 条评论

项目地址:http://pecl.php.net/package/AOP

首先介绍下AOP编程,也叫做面向切面编程,是一种非倾入式编程的方法,采用外部注入的方式来取代嵌入代码。可以实现非常好的模块低耦合。

假设你的框架有一个 Frameworkd::init方法,功能是初始化框架资源。现在有db,template的初始化也需要在这个阶段执行,传统的做法就是只能修改 Frameworkd::init在里面加入 db,template的方法调用。未来如果增加了新的模块,比如cache。那就需要修改Frameworkd::init的代码。这种做法显然是侵入性的。

当然也可以用hook list的方式来实现。在需要外部注入的地方加入一个hook list,遍历执行外部注入的接口。但远没有AOP强大,而且还需要不断加入hook list的遍历点。

如果AOP编程的话,只需要外部注入一个函数,执行 Frameworkd::init时,就会执行指定的代码。


<?php
class MyServices
{
        public function doAdminStuff1 ()
        {
                //some stuff only the admin should do
                echo "Calling doAdminStuff1\n";
        }

        public function doAdminStuff2 ()
        {
                //some stuff only the admin should do
                echo "Calling doAdminStuff2\n";
        }
}

function adviceForDoAdmin ()
{
        echo "AOP[1] Run\n";
}

function adviceForDoAdmin2 ()
{
        echo "AOP[2] Run\n";
}
aop_add_after('MyServices->doAdmin*()', 'adviceForDoAdmin');
aop_add_after('MyServices->doAdmin*()', 'adviceForDoAdmin2');
$o = new MyServices;
$o->doAdminStuff1();
$o->doAdminStuff2();

执行结果:

Calling doAdminStuff1
AOP[2] Run
AOP[1] Run
Calling doAdminStuff2
AOP[2] Run
AOP[1] Run
分类: PHP 标签:

腾讯PSF框架介绍

2013年1月28日 没有评论

PSF是腾讯开发的一套完全使用PHP开发的逻辑Server框架,基于epoll异步事件通知模型。支持TCP长连接、TCP短连接、UDP,3种模式。TCP使用了经典的Multi-Reactor模型,UDP使用类似LVS的半同步/半异步模型,运行效率很高。在高并发高负载的环境可快速稳定地运行。

PSF拥有完善的多配置多插件管理体系,健壮的Worker进程管理系统,全自动柔性重启策略。PSF框架支撑着很多逻辑层Server,有数百台线上服务器运行着PSF的插件。在公司内的四层架构建设中发挥了很大的作用。

PSF使用简单方便,开发人员无需关注底层实现,只需专注于业务逻辑开发。PSF采用了单一配置文件,开发人员只需要修改配置文件即可调整监听IP、端口、资源分配、协议类型、业务组件的上线/下线以及服务器扩容。配置文件中提供了很多选项,可以针对业务的特征,对Server的运行参数进行微调。

PSF框架性能非常好,并发2000压测,一个简单的EchoServer,TCP每秒可处理4万个请求,UDP可处理6万请求。

分类: PHP 标签: