Don’t let the server run naked

As anyone who has studied PHP knows, the formal PHP environment deployment is very simple, and it takes only a few files to change. Using FastCgi is also a matter of minutes. In contrast, Python deployment in web applications is much more complicated, mainly due to the variety of tools, mainstream server support is not enough, before understanding Python deployment in production environment, first clear some concepts! Is important!

CGI:

The Common Gateway Interface (CGI) is an Interface standard between external applications (CGI programs) and Web servers. It is a procedure for transferring information between CGI programs and Web servers. The CGI specification allows Web servers to execute external programs and send their output to Web browsers. CGI turns a simple set of static hypermedia documents on the Web into a complete new interactive medium. In layman’s terms, CGI is like a bridge between the WEB page and the WEB server’s executable. It passes the instructions received by THE HTML to the server’s executable, and returns the results of the server’s execution to the HTML page. CGI is cross-platform and can be implemented on almost any operating system.

CGI creates a CGI child process, activates a CGI process, processes the request, and terminates the child process. This is the fork-and-execute mode. So there are as many CGI child processes as there are connection requests on a CGI server, and repeated loading of child processes is a major cause of poor CGI performance. A large number of user requests occupy system resources, such as memory and CPU time, resulting in low performance.

CGI script workflow:

  1. The browser requests a URL to a CGI application through an HTML form or hyperlink.
  2. The server sends and receives the request. The CGI application specified.
  3. The CGI application does what it needs to do, usually based on what the viewer enters.
  4. CGI applications format the results into a document (usually an HTML web page) that the web server and browser can understand.
  5. The web server returns the results to the browser.

Python has CGI modules that support native CGI programs

FastCGI:

FastCGI is a scalable, high-speed interface for communicating between HTTP Server and dynamic scripting languages. Most popular HTTP servers support FastCGI, including Apache, Nginx, and Lighttpd. FastCGI is also supported by many scripting languages, including Python. FastCGI is an evolution of CGI. The main disadvantage of the traditional CGI interface approach is poor performance, because every time the HTTP server encounters a dynamic program, the script parser needs to be restarted to perform the parsing, and the results are then returned to the HTTP server. This is almost unavailable when dealing with high concurrent access. FastCGI is like a long-live CGI that can be executed as long as it is activated and doesn’t have to fork every time (the most notorious fork-and-execute mode for CGI). CGI is what is called a short-life application, and FastCGI is what is called a long-life application. Because FastCGI programs do not need to constantly generate new processes, they can greatly reduce the strain on the server and lead to higher application efficiency. It is at least five times faster than CGI. It also supports distributed computing, meaning that FastCGI programs can be executed on a host other than the web server and accept requests from other web servers.

FastCGI is a language-independent, scalable architecture CGI open extension whose primary behavior is to keep the CGI interpreter process in memory for high performance. It is well known that repeated loading of CGI interpreters is a major cause of poor CGI performance, and if the CGI interpreter is kept in memory and scheduled by the FastCGI process manager, it can provide good performance, scalability, fail-over features, and so on. The FastCGI interface uses C/S structure to separate the HTTP server from the script parsing server and start one or more script parsing daemons on the script parsing server. Each time the HTTP server encounters a dynamic program, it can deliver it directly to the FastCGI process for execution, and then return the results to the browser. This approach allows the HTTP server to exclusively handle static requests or return the results of the dynamic script server to the client, greatly improving the overall performance of the application system.

FastCGI workflow:

  1. Load the FastCGI process manager (php-cgi or php-fpm or spawn- CGI) at Web Server startup
  2. The FastCGI process manager initializes itself, starts multiple CGI interpreter processes (multiple phP-CGI visible) and waits for a connection from the Web Server.
  3. When a client request arrives at the Web Server, the FastCGI process manager selects and connects to a CGI interpreter. Web Server sends CGI environment variables and standard input to the FastCGI child process php-cgi.
  4. The FastCGI child process returns the standard output and error message from the same connection to the Web Server. The request is processed when the FastCGI child closes the connection. The FastCGI child process then waits for and processes the next connection from the FastCGI process manager running in the Web Server. In CGI mode, php-cgi exits at this point.

FastCGI features:

  1. Break with traditional page handling techniques. In traditional page processing techniques, the Application must reside on the same server as the Web server or Application server. This history was broken years ago by FastCGI technology, FastCGI applications can be installed on any server in a server farm and communicate with Web servers through TCP/IP protocol, which is suitable for both the development of large distributed Web farms and efficient database control.
  2. Explicit request patterns. CGI technology does not have an explicit role. In FastCGI programs, programs are assigned explicit roles (responder role, authenticator role, filter role).

WSGI:

The Python Web Server Gateway Interface (WSGI for short) is a simple and generic Interface between a Web Server and a Web application or framework defined for the Python language. Since WSGI was developed, similar interfaces have appeared in many other languages. WSGI serves as a low-level interface between a Web server and a Web application or application framework to enhance the commonality of portable Web application development. WSGI is designed based on the existing CGI standard.

WSGI is divided into two parts: a “server” or “gateway” and an “application” or “application framework.” When processing a WSGI request, the server provides the environment context and a Callback Function to the application. When the application completes processing the request, it sends the result back to the server through the previous callback function. So-called WSGI middleware implements both sides of the API and therefore acts as a mediator between WSGI services and WSGI applications: from the PERSPECTIVE of the WSGI server, the middleware acts as the application, and from the perspective of the application, the middleware acts as the server. The middleware component can perform the following functions:

  1. After overriding the environment variables, the request message is routed to different application objects based on the destination URL.
  2. Allows multiple applications or application frameworks to run simultaneously in one process.
  3. Load balancing and remote processing by forwarding request and response messages over the network.
  4. Post-processing of content, such as applying XSLT stylesheets.

In the past, choosing the right Web application framework was a problem that plagued Python beginners because, in general, the choice of Web application framework limited the choice of available Web servers and vice versa. Python applications at the time were often designed for one of CGI, FastCGI, mod_python, or even a custom API for a particular Web server. There is no official implementation of WSGI because WSGI is more like a protocol. WSGI applications can run on any Server as long as they follow these protocols, and vice versa. WSGI is a CGI wrapper for Python, as opposed to Fastcgi for PHP.

WSGI divides Web components into three categories: Web Server, Web Middleware, and Web applications. The basic processing mode for WSGI is WSGI Server -> (WSGI Middleware)* -> WSGI Application.

  

Uwsgi:

Uwsgi is a protocol of the UWSGI server, which defines the type of information to be transmitted. The first 4 bytes of each UWSGI packet are the description of the type of information to be transmitted, which is different from WSGI. It is claimed to be 10 times more efficient than FCGI. For details, see The UWSGi Protocol

The above four can be understood as an agreement! Deal! Deal! By implementing such a protocol, you can implement Web services associated with Web servers and Web applications!

UWSGI:

The uWSGI project aims to develop a complete solution for networking applications that deploy distributed clusters. UWSGI is geared towards the Web and its standard services and has been successfully used in many different languages. Due to uWSGI’s extensible architecture, it can be extended indefinitely to support more platforms and languages. Currently, you can write plug-ins in C, C++, and Objective-C. “WSGI” in the project name is a nod to the Python Web standard of the same name, as WSGI developed the first plug-in for the project. UWSGI is a Web server that implements WSGI, uWSGI, HTTP, and other protocols. UWSGI, which uses neither WSGI nor FastCGI, has created its own uWSGI protocol.

The main features of uWSGI are as follows:

  1. Super fast performance.
  2. Low memory footprint (measured at about half of MOD_WSGI for Apache2).
  3. Multi-app management.
  4. Detailed logging capabilities (for analyzing app performance and bottlenecks).
  5. Highly customizable (memory size limit, restart after a certain number of services, etc.).

Gunicorn:

A tool similar to uWSGi was ported from the Rails deployment tool (Unicorn). But it uses the protocol WSGI, which is the official standard defined by python2.5 (PEP 333), and is fairly straightforward to deploy. A full tutorial is available here. Gunicorn adopts prefork mode, Gunicorn server is compatible with various Web frameworks, requires very simple execution, lightweight resource consumption, and is quite fast. It features strong Django integration and is easy to deploy. There are also a lot of disadvantages, not support HTTP 1.1, concurrent access performance is not high, with uWSGI, Gevent and other performance gap.

1. The Gunicorn design

Gunicorn is a master process that spawns several worker processes on the Web server. The master process controls the birth and death of worker processes, which only need to accept requests and process them. This separation makes the Reload code very convenient, and it’s easy to add or subtract worker processes. The worker process section has been extended to support different IO methods such as Gevent,Sync, Asyc, Eventlet, etc. Master and worker processes are completely separated, making Gunicorn essentially a process control service.

Gunicorn source code structure

Starting with application.run (), we first initialize the configuration, read it from a file, read it from a terminal, and so on. Then start Arbiter, Arbiter is essentially the core of the master process, it first reads and sets from the configuration class, and then initializes the signal processing function, establish socket. It is then time to start the Spawn worker process based on the number of configured worker processes. And then you go to the polling state, you get the signal, you process the signal and you continue. The way to wake up the process here is to create a PIPE, write to the PIPE using a signal handler, and then wake up the master from selt.select ().

After spawn, the worker process starts initialization, processes the signal as well, and starts polling, processing HTTP requests, calling the WSGI application, and getting resOPNSE returns. And then continue.

The advantage of Sync is that each request is isolated and each request failure does not affect other requests, but this can lead to performance bottlenecks.

Tornado:

Tornado, even a Python development framework, is also an asynchronous non-blocking HTTP server. Its data output implementation does not comply with some general protocols mentioned above. Because it is a Web server itself, dynamic requests are directly output into the dynamic content requested by users through internal mechanisms. If put it as a single server, want to use it to cooperate with other frameworks such as Flask to deploy, you need to use WSGI agreement, Tornado built in the agreement, Tornado. WSGI. WSGIContainer.

Wsgiref:

Python comes with WSGI Server that implements the WSGI protocol. Wsgi Server can be understood as a WSGI compliant Web server that receives request requests, encapsulates a series of environment variables, invokes the registered WSGI app according to THE WSGI specification, and finally returns the response to the client. This is the server that comes with Django.

All of the above can be understood as implementation! To achieve! To achieve! Implements protocol tools!

Note: mod_WSgi is actually a module that implements the WSGI protocol. It is almost not deprecated now, so don’t say more about it. If you are interested, check it out.

So if you want to deploy your Django application to a production environment, you can use uWSGI server, Or Gunicorn or Tornado, which implements WSGI. Also can use FastCGI, CGI mode Nginx, Lighttpd, Apache server. The same goes for other frameworks! Knowing these concepts will allow you to know when you deploy them, and you’ll “know what’s going on and why” between the various tools.

Django and Tornado are two frameworks in our group’s project, and two deployments are used in production environments. UWSGI and Gunicorn:

Django was deployed using Nginx+uWSGI, and Tornado was deployed using Nginx+Gunicorn:

Nginx both acts as load balancing as well as static content forwarding. The Tornado Program is overseeing Gunicorn, and the Tornado program is overseeing Gunicorn. As we all know, Python’s concurrency is in multi-process mode due to the existence of Python’s GIL, so we deploy two processes at a core.