注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

fastcgi重启  

2013-03-16 13:29:26|  分类: apache分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、fastcgi
fastcgi是一些提供某项频繁功能的apache服务器的一项常用实现方式,它需要在apache侧加载fcgi模块,cgi侧包含和连接特定的头文件及库文件。但是现在的问题是fastcgi运行的cgi是一个常驻的进程,如果程序退出时,它会如何被重启?这个退出包括很多中不同情况:例如有些fastcgi觉得自己运行的时间够多了,然后希望重新启动一下,洗头革面,从新做人,所以就主动退出;还有些cgi本身就有问题,例如缺少了so文件,压根启动不了;或者有一些偶发问题,例如在某些情况下触发了coredump,或者被人通过kill命令暴力杀死了,这些都是有可能的,那么此时的mod_fastcgi如何来感知并重启这些任务呢?
二、一些通用的思路
fastcgi其实和之前的cgi一样,都是一种cgi模式,但是cgi的模式和fastcgi的模式并不相同,cgi是天生一次性的存在,当父进程创建了cgi之后,它不会通过waitpid或者其它的操作来执行等待这个cgi返回,因为即使知道它返回,父进程也无能为力,也没有责任来处理它返回的情况或者状态。但是对于fcgi来说,fcgi正常情况下应该是一个常驻的进程,如果它很快就退出的话,很可能和作者当时设计的原始目的不同。
和cgi实现一样,fcgi模块也有一个自己的独立进程来管理这些派生的fast实例(在apache的代码中这些叫做fastcgi server),cgi中这个独立的进程叫做cgid。只是cgid的主要功能是侦听和apache通过端口交互的协议(通过套接口listen,不同的请求到来之后accept创建子socket,并把这个socket传递给新创建的cgi,从而cgi只负责向自己的标准输出打印html文本即可),此时apache只是充当了一个中介的角色,至于连接建立之后它们如何交互或者子进程是死是活,apache是不管的。
对于fcgi来说,它其实也创建了自己的管理模块,并且同样为独立进程,子进程的入口为fcgi_pm.c:fcgi_pm_main函数

    /*
     * Loop until SIGTERM
     */
    for (;;) {
        int sleepSeconds = min(dynamicKillInterval, dynamicUpdateInterval);
#ifdef WIN32
        time_t expire;
#else
        pid_t childPid;
        int waitStatus;
#endif
        unsigned int numChildren;
unsigned int minServerLife;

        /*
         * If we came out of sigsuspend() for any reason other than
         * SIGALRM, pick up where we left off.
         */
        if (alarmLeft)
            sleepSeconds = alarmLeft;
……
        if((!caughtSigChld) && (!caughtSigAlarm)) {
            fd_set rfds;

            alarm(sleepSeconds);

            FD_ZERO(&rfds);
            FD_SET(fcgi_pm_pipe[0], &rfds);
            read_ready = ap_select(fcgi_pm_pipe[0] + 1, &rfds, NULL, NULL, NULL);这是和apache主进程通讯的接口

            alarmLeft = alarm(0);
        }
……
            if (s->directive == APP_CLASS_STANDARD) {
                /* Always restart static apps */
                s->procs[i].state = FCGI_START_STATE;
                if (! (WIFEXITED(waitStatus) && (WEXITSTATUS(waitStatus) == 0))) {
                    /* don't bump the failure count if the app exited with 0 */
                    s->numFailures++;
                }
            }
之间省略了一些有意思的逻辑,
1、fcgi启动失败
如果一个fcgi不能启动时apache如何应对:此时apache有一个判断,如果一个fcgi实例运行时间小于30s,则认为apache执行失败,连续三次启动失败,会对fcgi的重启进行惩罚,不再尝试马上拉起这个进程。在apache fastcgi配置中
        else if (strcasecmp(option, "-restart-delay") == 0) {
            if ((err = get_u_int(tp, &arg, &s->restartDelay, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-init-start-delay") == 0) {
            if ((err = get_int(tp, &arg, &s->initStartDelay, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
默认值为
u_int dynamicListenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
u_int dynamicInitStartDelay = DEFAULT_INIT_START_DELAY;
#define FCGI_DEFAULT_RESTART_DELAY 5       /* delay between restarts */
#define DEFAULT_INIT_START_DELAY 1         /* delay between starts */

/*
 * The number of failed starts that can occur before the application is
 * considered broken and start attempts fall back to FAILED_STARTS_DELAY.
 */
#define MAX_FAILED_STARTS 3

/*
 * The number of seconds between attempts to start an application that 
 * has been declared broken (see MAX_FAILED_STARTS).
 */
#define FAILED_STARTS_DELAY 600
2、何时认为fcgi实例失败
        else if (strcasecmp(option, "-min-server-life") == 0) {
            if ((err = get_u_int(tp, &arg, &s->minServerLife, 0)))
                return invalid_value(tp, name, NULL, option, err);
        }
如果fcgi实例存活时间小于指定的最小生存时间后推出,认为实例启动时出现了问题,如果连续出现3次运行时间小于最小时间,认为fcgi实例出现问题,开始接收启动时间延长的惩罚。
3、超时策略
        else if (strcasecmp(option, "-idle-timeout") == 0) {
            if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
                return invalid_value(tp, name, fs_path, option, err);
        }
如果在超过这段时间内server没有响应(通过select等待超时),则认为此处交互失败,直接返回错误。这里的问题一般是fcgi没有进程在侦听这个unix 套接字端口。因为所有的fcgi实例都启动失败了。
4、负载均衡策略
在fcgi模块没有找到负载均衡的代码。这一点是由系统的accept调用来自动完成的,所有的fcgi实例都在侦听同一个端口,当有请求到达之后,此时如果有一个进程在侦听,它就可以成功的接收到请求;如果多个,操作系统随机选择一个。如果所有请求都忙,此时在一段时间之后超时,此次交互失败。
三、server模型
1、manager+wokrer模型
一般都有一个统一的管理接口来关系所有的工作进程。
2、随时log
任何异常都会打印日志,对于服务器一般不能现场调试,否则服务就会被中断,服务进程也没有控制台输出,所以日志是尽量需要详细的。这也是为什么linux下有如此多的日志管理工具,rsyslog,syslogd,syslog-ng……。
  评论这张
 
阅读(1165)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017