多线程FastCGI应用程序

时间:2011-04-29 08:37:31

标签: multithreading cgi fastcgi

我想编写一个FastCGI应用程序,它应该使用线程处理多个同时请求。我查看了SDK附带的threaded.c示例:

#define THREAD_COUNT 20
static int counts[THREAD_COUNT];

static void *doit(void *a)
{
    int rc, i, thread_id = (int)a;
    pid_t pid = getpid();
    FCGX_Request request;
    char *server_name;

    FCGX_InitRequest(&request, 0, 0);

    for (;;)
    {
        static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
        static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER;

        /* Some platforms require accept() serialization, some don't.. */
        pthread_mutex_lock(&accept_mutex);
        rc = FCGX_Accept_r(&request);
        pthread_mutex_unlock(&accept_mutex);

        if (rc < 0)
            break;

        server_name = FCGX_GetParam("SERVER_NAME", request.envp);

        FCGX_FPrintF(request.out,…
        …     

        FCGX_Finish_r(&request);
    }

    return NULL;
}

int main(void)
{
    int i;
    pthread_t id[THREAD_COUNT];

    FCGX_Init();

    for (i = 1; i < THREAD_COUNT; i++)
        pthread_create(&id[i], NULL, doit, (void*)i);

    doit(0);

    return 0;
}

FastCGI specification中有一个解释,Web服务器将如何确定FastCGI应用程序支持的连接数:

  

Web服务器可以查询特定的   应用程序中的变量。该   服务器通常会执行查询   在应用程序启动时为了   自动化系统的某些方面   配置。

     

...

     

•FCGI_MAX_CONNS:最大数量   并发传输连接   此应用程序将接受,例如, “1”   或“10”。

     

•FCGI_MAX_REQS:最大数量   并发请求   申请将接受,例如“1”或   “50”。

     

•FCGI_MPXS_CONNS:如果是这样,则为“0”   应用程序不复用   连接(即处理并发   请求通过每个连接),“1”   否则。

但此查询的返回值被硬编码到FastCGI SDK中,并为FCGI_MAX_CONNS和FCGI_MAX_REQS返回1,为FCGI_MPXS_CONNS返回0。所以threaded.c样本永远不会收到多个连接。

我使用lighttpd和nginx测试了样本,应用程序一次只处理了一个请求。如何让我的应用程序处理多个请求?或者这是错误的做法?

3 个答案:

答案 0 :(得分:6)

使用http_load测试threaded.c程序。该程序在nginx后面运行。程序只有一个实例在运行。如果请求是按顺序提供的,我预计即使并行发送,20个请求也需要40秒。以下是结果(我使用相同的数字作为Andrew Bradford - 20,21和40) -

20个请求,20个并行,需要2秒 -

$ http_load -parallel 20 -fetches 20 request.txt
20 fetches, 20 max parallel, 6830 bytes, in 2.0026 seconds
341.5 mean bytes/connection
9.98701 fetches/sec, 3410.56 bytes/sec
msecs/connect: 0.158 mean, 0.256 max, 0.093 min
msecs/first-response: 2001.5 mean, 2002.12 max, 2000.98 min
HTTP response codes:
  code 200 -- 20

21个请求,20个并行,需要4秒 -

$ http_load -parallel 20 -fetches 21 request.txt
21 fetches, 20 max parallel, 7171 bytes, in 4.00267 seconds
341.476 mean bytes/connection
5.2465 fetches/sec, 1791.55 bytes/sec
msecs/connect: 0.253714 mean, 0.366 max, 0.145 min
msecs/first-response: 2001.51 mean, 2002.26 max, 2000.86 min
HTTP response codes:
  code 200 -- 21

40个请求,20个并行,需要4秒 -

$ http_load -parallel 20 -fetches 40 request.txt
40 fetches, 20 max parallel, 13660 bytes, in 4.00508 seconds
341.5 mean bytes/connection
9.98732 fetches/sec, 3410.67 bytes/sec
msecs/connect: 0.159975 mean, 0.28 max, 0.079 min
msecs/first-response: 2001.86 mean, 2002.62 max, 2000.95 min
HTTP response codes:
  code 200 -- 40

因此,它证明即使FCGI_MAX_CONNS,FCGI_MAX_REQS和FCGI_MPXS_CONNS值是硬编码的,也会并行提供请求。

当Nginx收到多个请求时,它会将它们全部放回FCGI应用程序的队列中。在发送第二个请求之前,它不会等待第一个请求的响应。在FCGI应用程序中,当一个线程在任何时间为第一个请求提供服务时,另一个线程不等待第一个请求完成,它将接收第二个请求并开始处理它。等等。

因此,您将失去的唯一时间是从队列中读取请求所需的时间。与处理请求所需的时间相比,此时间通常可以忽略不计。

答案 1 :(得分:2)

这个问题没有一个答案,因为这不仅取决于FastCGI协议,而且最重要的是取决于正在使用的FastCGI流程管理器。对于Apache2 Web服务器,FastCGI流程管理器通常可以是mod_fastcgimod_fcgid。这两种行为都不同。 mod_fastcgi似乎是多线程感知的,并且会将并发请求发送到FastCGI服务器,该服务器声明它自己支持它。 mod_fcgid到目前为止(可能在将来发生变化?)不是多线程感知的,并且将始终在并发请求上生成新的FastCGI服务器进程,并且永远不会将并发请求发送到FastCGI服务器。

所有这些都说:是的,FastCGI已经提供了多线程FastCGI服务器,但运行FastCGI服务器的环境也必须使这个功能成为现实......在实践中,它可能会,或者它可能不会,不幸的是,mod_fcgid至少到目前为止没有。

如果您的FastCGI SDK来自mod_fcgid,则可能是对FCGI_MAX_CONNS管理请求的响应始终返回固定硬编码值1的原因。

您可能对我最近的问题和其他两个网络链接感兴趣,这三个链接都提到了多线程FastCGI服务器的特定主题:

答案 2 :(得分:1)

我认为您可能会以限制单线程的方式进行测试。我遇到了类似的情况,使用libfcgi和lighttpd,但确定如果我使用Firefox进行测试,那么Firefox会人为地限制向服务器提交HTTP请求,直到前一个服务器完成为止。您用来测试的工具可能会做类似的事情。

您无需修改​​FCGI_MAX_CONNSFCGI_MAX_REQSFGCI_MPXS_CONNS。对于像nginx或lighttpd这样的现代Web服务器,硬编码值无关紧要。

使用像curl这样的命令行工具,一次生成20个curl进程,对所有命中服务器导致所有20个线程激活,所有20个curl进程同时完成,2秒后,当针对SDK提供的示例threaded.c(具有明确的sleep(2)调用)运行时。

我的lighttpd配置设置如下:

fastcgi.server = (
    "/test" => (
        "test.fastcgi.handler" => (
            "socket" => "/tmp/test.fastscgi.socket",
            "check-local" => "disable",
            "bin-path" => "/tmp/a.fastcgi",
            "max-procs" => 1,
        )
    )
)

max-procs设置为1只会生成fcgi程序的一个副本,而lighttpd会在请求进入前一个请求完成之前报告套接字增加“load”。

如果你产生21个卷曲过程,前20个应该在2秒内完成,然后最后一个应该在另外2秒内完成。产卵40个卷曲过程应该与21个持续时间几乎相同(总共超过4秒)。