Создаем высокопроизводительный сайт с использованием nginx и django

Базовая установка и настройка uWSGI

Установите uWSGI в свой virtualenv

pip install uwsgi

Конечно, есть и другие способы установки uWSGI, но этот так же хорош, как и любой другой. Помните, что вам нужно будет установить пакеты разработки Python. В случае Debian или систем, производных от Debian, таких как Ubuntu, вам нужно установить pythonX.Y-dev, где X.Y — ваша версия Python.

Базовый тест

Создайте файл с названием test.py:

# test.py
def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return  # python3
    #return  # python2

Примечание

Учтите, что Python 3 требует bytes().

Запуск uWSGI:

uwsgi --http :8000 --wsgi-file test.py

Эти опции означают:

  • : использовать протокол http и порт 8000
  • : загружаем файл test.py

При обращение через браузере к http://example.com:8000 вы должны сообщение «Hello World».

Теперь наш стек компонентов выглядит следующим образом:

the web client <-> uWSGI <-> Python

Протестируем проект Django

Теперь мы хотим, чтобы uWSGI делал то же самое, но вместо приложения test.py запускал сайт на Django.

Если вы еще этого не сделали, убедитесь, что ваш проект на Django действительно работает:

python manage.py runserver 0.0.0.0:8000

И далее запустите его с помощью uWSGI:

uwsgi --http :8000 --module mysite.wsgi

module mysite.wsgi: означает загрузку указанный модуля wsgi

Если теперь зайти через браузер на сервер должно отобразиться приложение а наш стек компонентом будет таким:

the web client <-> uWSGI <-> Django

Но как правило, браузер не должен напрямую обращаться к uWSGI. Это работа для веб-сервера, который будет действовать как посредник.

Serving Python WSGI applications with uWSGI

In this section, we will see how a Python WSGI application works with uWSGI web server. Working with uWSGI to serve Python WSGI applications is not dissimilar to other application containers. What uWSGI needs, just like other servers, is for your application to provide it with an entry point (a callable). During launch, this callable, alongside configuration variables, are passed to uWSGI and it starts to do its job. When a request arrives, it processes it and passes it to your application’s controller to handle.

Architecture:

WSGI

WSGI in a nutshell is an interface between a web server and the application itself. It exists to ensure a standardized way between various servers and applications (frameworks) to work with each other, allowing interchangeability when necessary (e.g. switching from development to production environment), which is a must-have need nowadays.

Note: If you are interested in learning more about WSGI and Python web servers, check out our article: A Comparison of Web Servers for Python Based Web Applications.

WSGI Application Object (Callable): “wsgi.py”

As mentioned above, web servers running on WSGI need an application object (i.e. your application’s).

With most frameworks and applications, this consists of a wsgi.py to contain and provide an application object (or callable) to be used by the server.

We will begin with creating an exemplary wsgi.py which then will be imported and used by uWSGI to run the application.

Let’s begin with creating a wsgi.py file to contain a basic WSGI application.

Run the following command to create a wsgi.py using the text editor nano:

And let’s continue with moving (copy/paste) the basic WSGI application code inside (which should be replaced with your own application’s callable for production):

After placing the application code in, press CTRL+X and then confirm with Y to save this file inside the “my_app” folder alongside the virtual environment and the app module containing your actual application.

Note: This WSGI application is the most basic example to its kind. You will need to replace this code block to include your own application object from the application module.

Once we are done, this is how your main application deployment directory should look like:

Running the server

uWSGI has a lot of options and configurations with many possible ways of using them thanks to its flexibility. Without complicating things from the start, we will begin with working with it as simply as possible and continuing thereon with more advanced methods.

Simple usage example:

To simply run uWSGI to start serving the application from wsgi.py, run the following:

To run the server in the background, run the following:

Important: When you run the server to work with Nginx using the configuration from the section Configuring Nginx, make sure to remove from the chain of arguments, otherwise Nginx and uWSGI will not be able to talk to each other.

Managing uWSGI server and processes with signals

Managing uWSGI consists of actions taken during runtime. There are various commands set for this task to manipulate the process:

  • SIGHUP gracefully reloads the workers and the application

  • SIGTERM “brutally” reloads

  • SIGINT and SIGQUIT kills all the workers immediately

  • SIGUSR1 prints statistics (stdout)

  • SIGUSR2 prints worker status

  • SIGURG restores a snapshot

  • SIGTSTP pauses, suspends or resumes an instance

  • SIGWINCH wakes up a worker blocked in a syscall

Restarting the server with SIGHUP

This command gracefully restarts the server. What this means is, it waits for the current workers’ job to be done, and then it terminates them before spawning them again, inheriting its settings.

Usage:

Stopping the server with SIGINT

To stop the server and its processes, you need to use the signal. This will terminate everything in the background.

Example:

Definitions and Concepts

Clarifying Some Terms

Before we jump in, we should address some confusing terminology associated with the interrelated concepts we will be dealing with. These three separate terms that appear interchangeable, but actually have distinct meanings:

  • WSGI: A Python spec that defines a standard interface for communication between an application or framework and an application/web server. This was created in order to simplify and standardize communication between these components for consistency and interchangeability. This basically defines an API interface that can be used over other protocols.
  • uWSGI: An application server container that aims to provide a full stack for developing and deploying web applications and services. The main component is an application server that can handle apps of different languages. It communicates with the application using the methods defined by the WSGI spec, and with other web servers over a variety of other protocols. This is the piece that translates requests from a conventional web server into a format that the application can process.
  • uwsgi: A fast, binary protocol implemented by the uWSGI server to communicate with a more full-featured web server. This is a wire protocol, not a transport protocol. It is the preferred way to speak to web servers that are proxying requests to uWSGI.

WSGI Application Requirements

The WSGI spec defines the interface between the web server and application portions of the stack. In this context, “web server” refers to the uWSGI server, which is responsible for translating client requests to the application using the WSGI spec. This simplifies communication and creates loosely coupled components so that you can easily swap out either side without much trouble.

The web server (uWSGI) must have the ability to send requests to the application by triggering a defined “callable”. The callable is simply an entry point into the application where the web server can call a function with some parameters. The expected parameters are a dictionary of environmental variables and a callable provided by the web server (uWSGI) component.

In response, the application returns an iterable that will be used to generate the body of the client response. It will also call the web server component callable that it received as a parameter. The first parameter when triggering the web server callable will be the HTTP status code and the second will be a list of tuples, each of which define a response header and value to send back to the client.

With the “web server” component of this interaction provided by uWSGI in this instance, we will only need to make sure our applications have the qualities described above. We will also set up Nginx to handle actual client requests and proxy them to the uWSGI server.

Step 4 — Configuring uWSGI

Your application is now written with an entry point established. We can now move on to configuring uWSGI.

Testing uWSGI Serving

Let’s test to make sure that uWSGI can serve our application.

We can do this by simply passing it the name of our entry point. This is constructed by the name of the module (minus the extension) plus the name of the callable within the application. In our case, this is .

Let’s also specify the socket, so that it will be started on a publicly available interface, as well as the protocol, so that it will use HTTP instead of the binary protocol. We’ll use the same port number, , that we opened earlier:

Visit your server’s IP address with appended to the end in your web browser again:

You should see your application’s output again:

When you have confirmed that it’s functioning properly, press in your terminal window.

We’re now done with our virtual environment, so we can deactivate it:

Any Python commands will now use the system’s Python environment again.

Creating a uWSGI Configuration File

You have tested that uWSGI is able to serve your application, but ultimately you will want something more robust for long-term usage. You can create a uWSGI configuration file with the relevant options for this.

Let’s place that file in our project directory and call it :

Inside, we will start off with the header so that uWSGI knows to apply the settings. We’ll specify two things: the module itself, by referring to the file minus the extension, and the callable within the file, :

~/myproject/myproject.ini

Next, we’ll tell uWSGI to start up in master mode and spawn five worker processes to serve actual requests:

~/myproject/myproject.ini

When you were testing, you exposed uWSGI on a network port. However, you’re going to be using Nginx to handle actual client connections, which will then pass requests to uWSGI. Since these components are operating on the same computer, a Unix socket is preferable because it is faster and more secure. Let’s call the socket and place it in this directory.

Let’s also change the permissions on the socket. We’ll be giving the Nginx group ownership of the uWSGI process later on, so we need to make sure the group owner of the socket can read information from it and write to it. We will also clean up the socket when the process stops by adding the option:

~/myproject/myproject.ini

The last thing we’ll do is set the option. This can help ensure that the init system and uWSGI have the same assumptions about what each process signal means. Setting this aligns the two system components, implementing the expected behavior:

~/myproject/myproject.ini

You may have noticed that we did not specify a protocol like we did from the command line. That is because by default, uWSGI speaks using the protocol, a fast binary protocol designed to communicate with other servers. Nginx can speak this protocol natively, so it’s better to use this than to force communication by HTTP.

When you are finished, save and close the file.

Подготовка сервера к производству

Данный раздел посвящен подготовке виртуального сервера к производству (то есть, к развертыванию приложения).

Для начала нужно:

  • Обновить операционную систему по умолчанию;
  • Скачать и установить общие инструменты Python (pip и virtualenv);
  • Создать виртуальную среду, которая будет содержать приложение, а также его зависимости.

Примечание: здесь приведены краткие инструкции. Более подробную информацию можно получить, прочитав статью «Общие инструменты Python: использование virtualenv, установка пакетов с помощью pip и управление пакетами».

Обновление операционной системы

Примечание: в данном руководстве все дальнейшие действия выполнены на новом сервере с использованием последних версий операционных систем. Теоретически, данные инструкции сработают должным образом на любом другом VPS. Тем не менее, старую версию системы, которая используется долгое время, рекомендуется сменить на новую.

Итак, чтобы обеспечить использование последней доступной версии необходимых приложений, необходимо обновить систему.

Для обновления систем на основе Debian (Ubuntu, Debian):

Для обновления систем на основе RHEL (CentOS):

Установка Python, pip и virtualenv

Примечание для пользователей CentOS / RHEL

По умолчанию CentOS / RHEL поставляются почти чистыми. Инструментарий на данном сервере предоставляется не для запуска приложений пользователя, а для питания инструментов системы (например, yum).

Чтобы подготовить систему CentOS, нужно установить (то есть, скомпилировать из исходного кода) Python, а затем установить pip и virtualenv при помощи специального интерпретатора.

Чтобы получить подробную информацию по установке Python 2.7.6 и 3.3.3 на CentOS 6.4 и 5.8, прочтите данную статью.

На Ubuntu и Debian последняя версия интерпретатора Python (который можно использовать) поставляется по умолчанию. Потому все, что осталось установить:

  • python-dev — средства разработки
  • pip — для управления пакетами
  • virtualenv — для создания изолированной виртуальной среды

python-dev: общесистемный пакет, который содержит расширенные средства разработки для построения модулей Python

Для установки python-dev запустите:

pip: менеджер пакетов, который помогает устанавливать необходимые пакеты приложений.

Выполните следующие команды для установки pip:

На данном этапе могут понадобиться привилегии sudo

Virtualenv:

Приложение Python вместе со всеми его зависимостями рекомендуется хранить в отдельной среде. Проще говоря, среда — это изолированное место (каталог) для размещения пакетов веб-приложения. Для этого используется инструмент под названием virtualenv.

Чтобы установить virtualenv с помощью pip, используйте:

Создание автономный виртуальной среды Python

Подготовив все необходимые инструменты, можно перейти к созданию среды для развертывания приложения.

Запомните: если на (локальной) машине разработки нет virtualenv (или виртуальной среды), необходимо создать ее и переместить туда приложение и его зависимости.

Для начала нужно создать папку, которая будет содержать виртуальную среду и модуль приложения:

Конечно, папку можно назвать согласно требованиям разработчика или проекта.

Затем нужно войти в эту папку и создать в ней новую виртуальную среду:

Виртуальную среду также можно назвать как угодно.

Теперь создайте новую папку для модуля приложения Python:

Активируйте интерпретатор внутри виртуальной среды:

Пожалуйста, убедитесь в том, что заменили имя виртуальной среды «my_app_venv» именем своей venv (в случае, если она имеет другое имя).

Теперь главный каталог развертывания приложений должен выглядеть так:

Загрузка и установка Gunicorn

Все связанные с приложением компоненты настоятельно рекомендуется хранить внутри виртуальной среды. Потому Gunicorn также будет установлен здесь.

В случае если виртуальная среда дезактивирована, Gunicorn будет установлен общесистемно (глобально), чего делать не рекомендуется.

Чтобы установить Gunicorn с помощью pip, запустите:

Загрузка и установка Nginx

Нижеприведенные инструкции недействительны для системы CentOS. При необходимости, пожалуйста, обратитесь к руководству «Как установить nginx на CentOS 6 с помощью yum».

Запустите следующую команду, чтобы установить Nginx с помощью aptitude, менеджера пакетов по умолчанию:

Для запуска Nginx используйте:

Чтобы выключить Nginx, используйте:

Чтобы перезапустить Nginx:

Примечание: Nginx нужно перезапускать после внесения любых изменений в конфигурации, чтобы новые настройки вступили в силу.

Чтобы получить дополнительные инструкции по установке Nginx на Ubuntu, читайте статью «Установка Nginx на Ubuntu 12.04 LTS (Precise Pangolin)».

Some notes about this tutorial¶

Note

This is a tutorial. It is not intended to provide a reference guide,
never mind an exhaustive reference, to the subject of deployment.

nginx and uWSGI are good choices for Django deployment, but they are not the
only ones, or the ‘official’ ones. There are excellent alternatives to both, and
you are encouraged to investigate them.

The way we deploy Django here is a good way, but it is not the only way;
for some purposes it is probably not even the best way.

It is however a reliable and easy way, and the material covered here will
introduce you to concepts and procedures you will need to be familiar with
whatever software you use for deploying Django. By providing you with a working
setup, and rehearsing the steps you must take to get there, it will offer you a
basis for exploring other ways to achieve this.

Note

This tutorial makes some assumptions about the system you are using.

It is assumed that you are using a Unix-like system, and that it features
an aptitude-like package manager. However if you need to ask questions like
“What’s the equivalent of aptitude on Mac OS X?”, you’ll be able to find that
kind of help fairly easily.

Dockerfile

Его мы создали для контейнера python. Именно здесь больше работы приходится производить, так как нам нужно установить приложения, пакеты и примонтировать директории. Ниже содержимое файла.

FROM python:3.6

COPY ./<project> /srv/www/<project>
WORKDIR /srv/www/<project>

RUN pip install -r requirements.txt

Построчно:

Указываем имя контейнера, на основе кторого будем это все собирать. Я использую официальный контейнер под python 3.6. Ты можешь выбрать свою версию.
Указываем что и куда мотировать. Я использую директорию /srv/www/имя_проекта для лаконичности

Важно понимать, что лучше указывать путь до проекта так, как он будет выглядеть на твоем сервере. Приближаем окружение к боевой системе.
Указываем эту же директорию как точку входя при выполнении следующих команд.
Запускаем установку пакетов из requirements.txt

После этого твой образ сохранится уже с этими пакетами и тебе не придется каждый раз пересобирать их. главное заранее подготовить файл со всеми нужными пакетами. Каждый раз, меняя requirements.txt, придется перезапускать сборку образа и, соответственно, с нуля устанавливать эти пакеты.

Set up an App Directory and a Virtualenv

We will start by creating a folder for our app. This can hold a nested folder containing the actual application code in a more complete application. For our purposes, this directory will simply hold our virtual environment and our WSGI entry point:

Next, move into the directory so that we can set up the environment for our application:

Create a virtual environment with the command. We will call this for simplicity:

A new Python environment will be set up under a directory called . We can activate this environment by typing:

Your prompt should change to indicate that you are now operating within the virtual environment. It will look something like this:

If you wish to leave this environment at any time, you can simply type:

If you have deactivated your environment, re-activate it again to continue with the guide.

With this environment active, any Python packages installed will be contained within this directory hierarchy. They will not interfere with the system’s Python environment. With this in mind, we can now install the uWSGI server into our environment using . The package for this is called (this is still the uWSGI server and not the protocol):

You can verify that it is now available by typing:

If it returns a version number, the uWSGI server is available for use.

Testing Your Application Without a Web Server

With an understanding of this simple interface, we can easily create scripts to test our applications without actually needing to start up a server.

Take this small script, for example:

In this way, we might, for example, initialize some test data and mock modules into our app, and make calls in order to test if it responds accordingly. We can see that it isn’t an actual web server, but interfaces with our app in a comparable way by providing the application with a callback and a dictionary with our environment variables. At the end of the request, it consumes the response body iterator and returns a string with all of its content. Similar methods (or a general one) can be created for different types of HTTP requests.

Further configuration¶

It is important to understand that this has been a tutorial, to get you
started. You do need to read the nginx and uWSGI documentation, and study
the options available before deployment in a production environment.

Both nginx and uWSGI benefit from friendly communities, who are able to offer
invaluable advice about configuration and usage.

nginx

General configuration of nginx is not within the scope of this tutorial though
you’ll probably want it to listen on port 80, not 8000, for a production
website.

You should also configure a separate nginx location block for serving non-Django
files. For example, it’s inefficient to serve static files via uWSGI. Instead,
serve them directly from Nginx and completely bypass uWSGI.

uWSGI

uWSGI supports multiple ways to configure it. See uWSGI’s documentation and
examples.

Some uWSGI options have been mentioned in this tutorial; others you ought to
look at for a deployment in production include (listed here with example
settings):

env = DJANGO_SETTINGS_MODULE=mysite.settings # set an environment variable
safe-pidfile = /tmp/project-master.pid # create a pidfile
harakiri = 20 # respawn processes taking more than 20 seconds
limit-as = 128 # limit the project to 128 MB
max-requests = 5000 # respawn processes after serving 5000 requests
daemonize = /var/log/uwsgi/yourproject.log # background the process & log

Placeholders¶

Placeholders are custom magic variables defined during configuration time by
setting a new configuration variable of your own devising.

; These are placeholders...
my_funny_domain = uwsgi.it
set-ph = max_customer_address_space=64
set-placeholder = customers_base_dir=/var/www
; And these aren't.
socket = /tmp/sockets/%(my_funny_domain).sock
chdir = %(customers_base_dir)/%(my_funny_domain)
limit-as = %(max_customer_address_space)

Placeholders can be assigned directly, or using the
/ option. These latter options can be useful to:

  • Make it more explicit that you’re setting placeholders instead of
    regular options.
  • Set options on the commandline, since unknown options like
    are rejected but is ok.
  • Set placeholders when strict mode is enabled.

Placeholders are accessible, like any uWSGI option, in your application code
via .

import uwsgi
print uwsgi.opt'customers_base_dir'

This feature can be (ab)used to reduce the number of configuration files
required by your application.

WSGI servers learning checklist

  1. Understand that WSGI is a standard Python specification for applications
    and servers to implement.

  2. Pick a WSGI server based on available documentation and tutorials. Green
    Unicorn is a good one to start with since it’s been around for awhile.

  3. Add the WSGI server to your server deployment.

  4. Configure the web server to pass requests to the WSGI server for
    appropriate URL patterns.

  5. Test that the WSGI server responds to local requests but not direct
    requests outside your infrastructure. The web server should be the pass
    through for requests to and responses from the WSGI server.

What’s next after your Python app is running?

Tell me about standard relational databases.

What is Docker and how does it fit with Python deployments?

How can I cache repeated requests for better performance?

Introduction – How NGINX is Used with Python

Python is famous for being easy and fun to use, for making software development easier, and for runtime performance that is said to exceed other scripted languages. (Though the latest version of PHP, PHP 7, may give Python a run for its money.)

Everyone wants their website and application to run faster. Also, every website with growing traffic or sharp traffic spikes is vulnerable to performance problems and downtime, often occurring at the worst – that is, busiest – times. Also, nearly all websites suffer performance problems and downtime, whether traffic volume is growing steadily or they experience sharp spikes in usage.

That’s where NGINX and NGINX Plus come in. They improve website performance in three different ways:

  1. As a web server – NGINX was originally developed to solve the C10K problem – that is, to easily support 10,000 or more simultaneous connections. Using NGINX as the web server for your Python app makes your website faster, even at low levels of traffic. When you have many thousands of users, it’s virtually certain to deliver much higher performance, fewer crashes, and less downtime. You can also do static file caching or microcaching on your NGINX web server, though both work better when run on a separate NGINX reverse proxy server (see the next paragraph).
  2. As a reverse proxy server – You can “drop NGINX in” as a reverse proxy server in front of your current application server setup. NGINX faces the Web and passes requests to your application server. This “one weird trick” makes your website run faster, reduces downtime, consumes less server resources, and improves security. You can also cache static files on the reverse proxy server (very efficient), add microcaching of dynamic content to reduce load on the application itself, and more.
  3. As a load balancer for multiple application servers – Start by deploying a reverse proxy server. Then scale out by running multiple application servers in parallel and using NGINX or NGINX Plus to load balance traffic across them. With this kind of deployment, you can easily scale your website’s performance in line with traffic requirements, increasing reliability and uptime. If you need a given user session to stay on the same server, configure the load balancer to support .

NGINX and NGINX Plus bring advantages whether you use them as a web server for your Python app, as a reverse proxy server, as a load balancer, or for all three purposes.

In this first article of a two‑part series, we describe five tips for improving the performance of your Python apps, including the use of NGINX and NGINX Plus as a web server, how to implement caching of static files, and microcaching of application‑generated files. In Part 2, we’ll describe how to use NGINX and NGINX Plus as a reverse proxy server and as a load balancer for multiple application servers.

Настройка кеш-бэк-энда

Теперь всё вроде бы настроено и работает, и мы переходим к самой интересной и важной части статьи. Кеширование критически важно для быстродействия любого динамического сайта, вне зависимости от технологий, на которых он построен

Мы должны упростить процесс переваривания и отдачи сервером динамической составляющей. Есть несколько способов решения этой задачи, но здесь всё зависит от специфики веб-сайта.

Во-первых, можно тупо кешировать все страницы сайта. Это самый простой и очень легко реализуемый с помощью Django способ. Однако он является и самым неэффективным: любое изменение страницы приведет к промаху мимо кеша и повторной загрузке страницы в него. Изменение может быть каким угодно: срабатывание счетчика на сайте, появление нового комментария, обновление списка популярных статей и разделов. Поэтому полное кеширование имеет смысл включать только для более-менее статичных сайтов вроде блогов, словарей, энциклопедий и т. п.

Во-вторых, можно кешировать данные, загружаемые из БД. Также легко реализуемый, но очень спорный вид оптимизации. Он результативен только для тех сайтов, где осуществляется много операций чтения из БД и мало операций записи, да и то лишь в том случае, если само хранилище кеша работает быстрее механизма кеширования базы данных. Другими словами, кеширование результатов выборки из БД подойдет, опять же, для более-менее статичных сайтов, размещенных на сервере, который имеет достаточный объем памяти для нормальной работы memcached.

В-третьих, кешировать можно нечасто изменяемые фрагменты шаблонов. Этот метод подойдет практически для любого сайта, он достаточно дешев и, на мой взгляд, наиболее эффективен. Однако, в отличие от первых двух, он требует работы напильником и не имеет прямого отношения к администрированию как таковому. Логикой и архитектурой занимаются программисты.

Также большое значение имеет выбор хранилища для кешированных данных. Django предлагает нам четыре варианта:

  • memcached — дорого в плане памяти, но очень эффективно;
  • оперативная память — менее затратно, но и менее эффективно;
  • жесткий диск — очень неэффективно и очень дешево;
  • база данных — более эффективно, чуть дороже.

Первые два подойдут для владельцев выделенных серверов, последние два можно применять на хостинге и недорогих VPS’ках. Хотя, конечно, лучше протестировать производительность в реальных условиях и выбрать наиболее подходящий вариант.

Теперь о том, как включить кеш-хранилище. Здесь всё просто — открываем settings.py проекта и пишем следующее:

Во втором случае необходимо предварительно создать таблицу в базе данных. Делается это с помощью стандартного manage.py:

Любой тип бэк-энда поддерживает следующие аргументы:

  • timeout — время жизни кешированных данных в секундах (по умолчанию 300);
  • max_entries — максимальное количество записей в кеше (по умолчанию 300);
  • cull_frequency — процент старых записей, которые удаляются по достижении max_entries (по умолчанию 3, то есть треть всех записей).

Для передачи аргументов используется синтаксис CGI, например:

Ненагрузочное тестирование uWSGI 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector