FCGi principle and asynchronous model

1. Introduction

Because the repeated loading of the CGI interpreter will lower the performance of CGI, FastCGI can keep the CGI interpreter in memory to improve performance
Related address: https: //fastcgi-archives.github.io

2. Fastcgi features:

  • Performance
  • Simple and easy to transplant
  • Language-independent
  • Process isolation
  • Universal, supported by mainstream WebServer, supported by nginx and apache
  • Support distributed computing, FastCGI provides remote running applications Function, this is very useful for distributing load and managing external Web sites (this point is to be verified whether it is easy to use, I hope it can support asynchronous processing)

3. Principle

  1. To put it simply, use the spawn-fcgi (management program of fastcgi) mentioned later to start fastcgi, support multi-instance start, and data binding through socket
  2. WebServer (such as: nginx) After receiving the request, send it to a fixed address according to the fastcgi address to be forwarded configured in the configuration, for example: fastcgi is bound to 127.0.0.1:8088
  3. After fastcgi Accept and process the data, it will respond to the data Return to the WebServer via Socket and disconnect, then it means that one processing is complete

Management program– spawn-fcgi

Download address: http://redmine .lighttpd.net/projects/spawn-fcgi/wiki
-f specifies the location of the execution program of the process calling FastCGI
-a is bound to the address addr.
-p binds to port port.
-s bind to unix domain socket
-C specifies the number of FastCGI processes generated, the default is 5. (For PHP only)
-P specifies the PID file path of the spawned process.
-F specifies the number of generated FastCGI processes (C CGI uses this)
Example: ./spawn-fcgi -a 127.0.0.1 -p 8088 -F 500 -f cgi (start 500 cgi programs, The listening port is 8088, and the binding address is 127.0.0.1)

4. How to configure nginx

  1. fastcgi_pass
    fastcgi_pass address;
    address is the backend The address of fastcgi server
    Available location: location,if in location
  2. fastcgi_index
    fastcgi_index name;
    fastcgi default homepage resource
    Example: fastcgi_index index.php;
  3. fastcgi_param
    fastcgi_param parameter value [if_not_empty];
    Set the parameter value passed to the FastCGI server, which can be text, variable or combination

5. Blocking and non-empty Blocking mode

fastcgi example-blocking mode

#include "fcgi_stdio.h"
#include 

void main(void)
{
    int count = 0;
    while(FCGI_Accept() >= 0)
        printf("Content-type: text/html
"
               "
"
               "FastCGI Hello!"
               "

FastCGI Hello!

" "Request number %d running on host %s ", ++count, getenv("SERVER_NAME")); }

fastcgi example-producer, consumer mode (non-blocking can be realized)

The realization of non-blocking, the session state and requests can be bound< /p>

ZEN_Message_Queue_Deque t_que(100000);

// This step is very critical, because the data flow binding in FCGX_Accept_r is directly bound to the request ptr
// So on the premise that the data has not been processed, the life cycle of requests must be consistent with the life cycle of the session
FCGX_Request requests[1000];
uint32_t use_idx[1000];

void *do_session(void *arg)
{
    int ret = 0;

    while (1)
    {
        uint32_t idx = 0;
        ret = t_que.try_dequeue(idx);

        if (ret != 0)
        {
            // no data sleep 1ms
            usleep(1000);
            continue;
        }

        FCGX_Request &request = requests[idx];
        std::string out = "Content-type:application/json

";
        Json::Value root;
        root["ret"] = 1000;
        root["t_id"] = (int)gettid();
        out.append(root.toStyledString());
        FCGX_FPrintF(request.out, out.c_str());
        FCGX_Finish_r(&request);
        use_idx[idx] = 0;
    }

    return NULL;
}

int get_free()
{
    static uint32_t idx = 0;

    for (; idx <1000; idx ++)
    {
        if (use_idx[idx] == 0)
        {
            use_idx[idx] = 1;
            return idx;
        }
    }

    return -1;
}

int main(int argc, char **argv)
{
    pthread_t pthread_id;
    int iThreadNum = 10;

    for (int index = 0; index != iThreadNum; ++ index)
    {
       pthread_create(&pthread_id, NULL, do_session, NULL);
    }

    memset(use_idx, 0, sizeof(use_idx));
    int ret = FCGX_Init();

    if (ret != 0)
    {
        printf("init fail
");
        return -1;
    }

    while (1)
    {
        int idx = get_free();

        if (idx <0)
        {
            continue;
        }

        FCGX_Request &request = requests[idx];
        ret = FCGX_InitRequest(&request, 0, 0);

        if (ret != 0)
        {
            printf("init fail
");
            return -1;
        }

        ret = FCGX_Accept_r(&request);

        if (ret <0)
        {
            continue;
        }

        t_que.enqueue(idx);
    }

    return 0;
}

#include "fcgi_stdio.h"
#include 

void main(void)
{
    int count = 0;
    while(FCGI_Accept() >= 0)
        printf("Content-type: text/html
"
               "
"
               "FastCGI Hello!"
               "

FastCGI Hello!

" "Request number %d running on host %s ", ++count, getenv("SERVER_NAME")); }

ZEN_Message_Queue_Deque t_que(100000);

// This step is very critical, because the data flow binding in FCGX_Accept_r is directly bound to the request ptr
// So on the premise that the data has not been processed, the life cycle of requests must be consistent with the life cycle of the session
FCGX_Request requests[1000];
uint32_t use_idx[1000];

void *do_session(void *arg)
{
    int ret = 0;

    while (1)
    {
        uint32_t idx = 0;
        ret = t_que.try_dequeue(idx);

        if (ret != 0)
        {
            // no data sleep 1ms
            usleep(1000);
            continue;
        }

        FCGX_Request &request = requests[idx];
        std::string out = "Content-type:application/json

";
        Json::Value root;
        root["ret"] = 1000;
        root["t_id"] = (int)gettid();
        out.append(root.toStyledString());
        FCGX_FPrintF(request.out, out.c_str());
        FCGX_Finish_r(&request);
        use_idx[idx] = 0;
    }

    return NULL;
}

int get_free()
{
    static uint32_t idx = 0;

    for (; idx <1000; idx ++)
    {
        if (use_idx[idx] == 0)
        {
            use_idx[idx] = 1;
            return idx;
        }
    }

    return -1;
}

int main(int argc, char **argv)
{
    pthread_t pthread_id;
    int iThreadNum = 10;

    for (int index = 0; index != iThreadNum; ++ index)
    {
       pthread_create(&pthread_id, NULL, do_session, NULL);
    }

    memset(use_idx, 0, sizeof(use_idx));
    int ret = FCGX_Init();

    if (ret != 0)
    {
        printf("init fail
");
        return -1;
    }

    while (1)
    {
        int idx = get_free();

        if (idx <0)
        {
            continue;
        }

        FCGX_Request &request = requests[idx];
        ret = FCGX_InitRequest(&request, 0, 0);

        if (ret != 0)
        {
            printf("init fail
");
            return -1;
        }

        ret = FCGX_Accept_r(&request);

        if (ret <0)
        {
            continue;
        }

        t_que.enqueue(idx);
    }

    return 0;
}

Leave a Comment

Your email address will not be published.