2011-04-29 36 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服務器的特定主題: