2011-04-29 104 views
7

我想写一个FastCGI应用程序,它应该使用线程处理多个同时发生的请求。我有一个看看threaded.c样品附带的SDK:多线程FastCGI应用程序

#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_MPXS_CONNS返回1 FCGI_MAX_CONNS和FCGI_MAX_REQS和0。因此threaded.c示例永远不会收到多个连接。

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

+1

您是如何测试并发性的?关于FCGI支持并发的程度有很多不同的信息可用。虽然我没有声称已经找出所有答案,但我尝试了多线程测试来验证并发性:两个线程被配置为接受连接。第一个人在接受连接后会睡10秒,阻止该线程。第二个连接被接受并作出响应。最后,第一个线程完成并作出响应。你的问题差不多一岁了,但我在寻找关于FCGI的答案时遇到了麻烦,所以希望这会有所帮助。 – HikeOnPast 2012-04-06 21:19:25

回答

6

用http_load测试threaded.c程序。该程序运行在nginx后面。只有一个程序正在运行。如果这些请求是按顺序提供的,那么即使并行发送,也可能需要40秒才能完成20个请求。下面是结果(我使用相同的数字安德鲁布拉德福德 - 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应用程序中,当一个线程在任何时候都为第一个请求服务时,另一个线程不会等待第一个请求完成,它会接收第二个请求并开始处理它。等等。

因此,唯一会失去的是从队列中读取请求所花费的时间。与处理请求所用的时间相比,这个时间通常可以忽略不计。

+0

很好的回答。现在这一切都有道理。 – 2014-09-28 14:21:00

1

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

您不应该修改FCGI_MAX_CONNS,FCGI_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的应报告在插座上增加“负载”请求之前的先前进来请求完成。

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

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服务器的特定主题: