9. ASGI of Django3

Nine, Django3’s ASGI

9.1, Web applications and web servers

Web application (Web) is an application that can complete web business logic and allow users to access it based on a web browser. It can be a function or class that implements http request and response functions, or it can be Django, Flask, sanic Such a web framework can of course also be web programs or web frameworks in other languages.

Web Server (Web Server) is a software that runs on the background of the website (physical server). The web server is mainly used to provide web browsing or file download services. It can provide html web documents to web clients such as browsers, and can also provide other types of displayable documents for client users to browse; it can also provide data file downloads, etc. . Currently, the most mainstream web servers in the world include Nginx, Apache, IIS, and tomcat.

Q: What is the difference between Web server and Web application?
Answer: Web applications are mainly responsible for processing the business logic of web applications, while Web servers are mainly responsible for receiving, responding and forwarding external requests.
    A web server needs to be used to start and run the web application before it can be accessed by users.
    In the Django framework, the reason why we only have one web application running is because we executed a command in the terminal, python manage.py runserver. This command starts the test web server provided built into the Django framework. 

9.2, gateway interface

Gateway Interface (GI) is a communication interface that runs in web servers and web applications in order to load dynamic scripts. It can also be understood as a protocol/specification. Only after both the Web server and the Web application implement the gateway interface specification can the communication between the two parties be completed successfully. Common gateway interface protocols: CGI, FastCGI, WSGI, ASGI.

image-20210608222947398

(1)CGI

CGI (Common Gateway Inteface): literally means common gateway interface.

It is an interface standard between external applications and web servers

This means that it is used to specify how a program should communicate with the web server program so that the program can run on the web server. Of course, CGI is only a very basic protocol, and it has basically disappeared from modern common server structures. What is more, it is its expansion and update.

FastCGI: An extension of CGI that improves performance and abolishes the working method of CGI fork-and-execute (fork a new process to handle a request, and then kill the process after processing), and instead uses a long-lived This method reduces process consumption and improves performance.

Here FastCGI is used in the communication between the front-end server (nginx) and the back-end server (uWSGI), formulating specifications, etc., so that the front-end and back-end servers can smoothly understand what both parties are saying (of course uWSGI itself does not use FastCGI, it has other protocol)

(2)WSGI

WSGI (Python Web Server GateWay Interface): It is a specification used between applications written in the python web framework and back-end servers (in this case, between Django and uWSGI), allowing the applications you write to communicate with back-end servers. Smooth communication. Before the emergence of WSGI, you had to write a specific API for a certain back-end server, and you could not change the back-end server. WSGI is a unified specification. All servers using WSGI can run web frameworks that use the WSGI specification. vice versa.

WSGI and ASGI are both Gateway Interface (GI) designed based on Python.

image-20210608223815714

Web Server Gateway Interface (Python Web Server Gateway Interface, WSGI) is designed by Python to solve the communication between Web server and client based on CGI standard. Web servers that implement the WSGI protocol include: uWSGI, uvicorn, and gunicorn. Like the Django framework, runserver will not be used to run in general development, but the web server that implements the WSGI protocol will be used to run.

When running the runserver command in Django, the wsgiref module is actually started internally to run as a web server. wsgiref is a web server program built into python that simply follows the wsgi interface specification.

from wsgiref.simple_server import make_server
# application is called by the wsgi server, and the function encapsulates http requests and responses, making Python focus on HTML
# environ http request (dist)
# start_response response (function)
def application(environ, start_response):
    # ask
    if environ['REQUEST_METHOD'] == 'GET' and environ['PATH_INFO'] == '/':
        # response
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [b'<h1>hi, python!</h1>']

if __name__ == '__main__':
    # Start the server | This server is responsible for connecting data with the application function of the wsgi interface
    httpd = make_server('127.0.0.1', 8000, application)

    # Listen for requests
    httpd.serve_forever()
    
    
# 1. Listen to port 8000,
# 2. Convert the http request to the environ parameter in applcation according to the WSGI protocol, and then call the application function.
# 3. wsgiref will convert the response header settings provided by the application function into response headers of the http protocol.
# 4. Use the application's return as the response body, generate a response according to the http protocol, and return it to the browser.

During development, we generally use uWSGI or Gunicorn as the web server to run django.

(3)uWSGI

uWSGI is a fast, self-driven, developer- and system administrator-friendly application container server that is used to receive dynamic requests forwarded by front-end servers and process them before sending them to web applications. Completely written in C, it implements WSGI protocol, uwsgi, http and other protocols. Note: The uwsgi protocol is a uWSGI server’s own protocol, used to define the type of transmitted information, and is often used in data communication between the uWSGI server and other network servers.

uwsgi: It is a unique protocol implemented by the uWSGI server. There is no clear explanation on the Internet where this protocol is used. I personally think that it is a communication specification for the front-end server and uwsgi, which is equivalent to the role of FastCGI.

img

img

9.3, about ASGI

9.3.1, Historical Interesting Talk

In December 2019, Django 3.0 was released, which has an interesting new feature – support for ASGI servers.

In 2003, various Python web frameworks such as Zope, Quixote, etc. shipped with their own web servers or had their own native interfaces to communicate with popular web servers such as Apache.

Becoming a Python web developer means devoting yourself to a complete technology stack, but then having to relearn everything if you need another framework. As you can imagine, this can lead to fragmentation. PEP 333, Python Web Server Gateway Interface v1.0, attempts to solve this problem by defining a simple standard interface called WSGI (Web Server Gateway Interface). Its excellence lies in its simplicity.

WSGI is so popular that it is adopted not only by large web frameworks like Django and Pylons, but also by microframeworks like Bottle.

Why does ASGI appear?

If we are so happy with WSGI, why bring up ASGI? If you carefully examine the entire processing flow of a network request, the answer is very obvious. You can view an animation of how network requests work in Django. Notice how the framework waits after the database query but before the response is sent. This is the disadvantage of synchronous processing.

Frankly, this flaw didn’t become obvious or urgent until 2009, when Node.js emerged. Node.js creator Ryan Dahl was troubled by the C10K problem, which is why popular web servers like Apache cannot handle 10,000 or more concurrent connections (given typical web server hardware, memory will be exhausted). He thought, “What is the software doing when it queries the database?”.

Of course, the answer is that nothing happened. It is waiting for a response from the database. Ryan believes that network servers should not wait for I/O activity at all. In other words, it should switch to handling other requests and be notified when the slower activity completes.

It is becoming increasingly obvious that an asynchronous event-based architecture is the right approach to solve many concurrency problems. Perhaps that’s why Python’s creator, Guido, took it upon himself to provide language-level support for the Tulip project, which later became the asyncio module. Finally, Python 3.7 adds new keywords async and await to support asynchronous event loops. This has significant implications not only for how Python code is written but also for code execution.

Two worlds of Python

Although writing asynchronous code in Python is very simple by adding the async keyword before the function definition, you must be very careful not to break one important rule: do not mix synchronous and asynchronous code haphazardly.

This is because synchronous code can block the event loop in asynchronous code. This situation will bring your application to a standstill. As Andrew Goodwin writes: This splits your code into two worlds – “synchronous code” and “asynchronous code” with different libraries and calling styles.

Going back to WSGI, this means we can’t write an asynchronous callable and embed it. WSGI is written for a synchronous world. We will need a new mechanism to call asynchronous code. But if everyone writes their own set of mechanics, we’ll be back to the original hell of incompatibility. Therefore, we need a new standard similar to WSGI for asynchronous code. Thus, ASGI was born.

ASGI also has other purposes. But before that, let’s take a look at two similar web applications “Hello World”, in WSGI and ASGI style respectively.

Like WSGI, ASGI callable objects can be chained together one after another to handle web requests (as well as other protocol requests), that is, chained calls. In fact, ASGI is a superset of WSGI and can call WSGI callable objects. ASGI also supports long polling, slow streaming, and other response types without sideloading, allowing for faster responses.

As a result, ASGI introduces new ways of building asynchronous web interfaces and handling bidirectional protocols. Neither the client nor the server needs to wait for the other to communicate – this can happen asynchronously at any time. Existing WSGI-based web frameworks written in synchronous code will not support this event-driven way of working.

Django evolution

At the same time, trying to bring all these asynchronous benefits to Django faces a major problem – all Django code is written in a synchronous style. If we need to write any asynchronous code, then we need a copy of the entire Django framework written in an asynchronous style. In other words, create two Django worlds.

Well, don’t panic – we probably won’t have to write a complete copy, as there are clever ways to reuse some code between the two worlds. As Andrew Godwin, who leads the Django Async project, rightly points out, “This is one of the largest revisions in Django history”. An ambitious project to reimplement ORM, request handler, template renderer and other components in an asynchronous style. This will be done in phases and across multiple releases. Here’s what Andrew envisions (this is not considered a submitted schedule):

  • Django 3.0-ASGI server
  • Django 3.1 – Async views
  • Django 3.2/4.0 – Asynchronous ORM

You may be thinking about the remaining components such as template rendering, forms, caching, etc. They may remain synchronous or their asynchronous implementation may be included in future technology roadmaps. But the above are key milestones in Django’s evolution in the asynchronous world.

9.3.2, asgi usage

ASGI is an asynchronous server gateway interface built on the WSGI interface specification and is an extension and extension of WSGI.

A refers to Async, which means asynchronous. 
Protocols, specifications Supported request protocols (common, not all listed) Synchronous/asynchronous Supported frameworks
CGI HTTP CGI program
WSGI HTTP Synchronization Before django3.0, Flask1.0
ASGI HTTP, HTTP2, WebSocket, etc. Synchronous/asynchronous FastAPI, Quart, Sanic, Tornado, django3. After 0, flask2.0

After Python 3.5 added the async/await feature and simplified coroutine operations, asynchronous programming became extremely popular, and more and more developers embraced asynchronous programming.

Before version 3.0, all internal functions provided by Django were based on synchronous programming. Therefore, in the past Django development, blocking caused by IO operations such as network requests and database reads often led to a decrease in project running performance. Although it takes microseconds to wait for I/O operations, as the traffic increases and the frequency of operations increases, this little bit of blocking will cause the entire project to run slowly. If you switch to asynchronous, there will be no blocking, and other tasks can be processed at the same time, thereby processing more requests with lower latency. Therefore, in current python development, more and more frameworks have begun to support asynchronous programming. Therefore, after version 3.0, Django began to support asynchronous programming, allowing developers to use python third-party asynchronous modules in Django, and launched the asgi asynchronous web server. Version 3.1 introduced asynchronous views. Of course, the current asynchronous programming of Django is not perfect enough. Only very few functions in Django support asynchronous operations.

image-20210608235013829

Uvicorn is a fast ASGI server. Uvicorn is built based on uvloop and httptools and is an important member of the Python asynchronous ecosystem.

Uvicorn currently supports HTTP/1.1 and WebSockets, with plans to support HTTP/2 in the future.

Documentation: https://www.uvicorn.org/

Install uvicorn

pip install uvicorn

In the project root directory, run the django project

# uvicorn main application directory name.asgi:application --reload
uvicorn homework.asgi:application --reload

Gunicorn is generally used to manage uvicorn during development. So it can be installed together

pip install gunicorn

run

# gunicorn -w 4 main application directory name.asgi:application -k uvicorn.workers.UvicornWorker --reload
gunicorn -w 4 homework.asgi:application -k uvicorn.workers.UvicornWorker --reload