mirror of https://github.com/tiangolo/fastapi.git
🌐 Add Russian translation for `docs/ru/docs/deployment/concepts.md` (#9577)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
72c72774c5
commit
061e912ccf
|
|
@ -0,0 +1,311 @@
|
|||
# Концепции развёртывания
|
||||
|
||||
Существует несколько концепций, применяемых для развёртывания приложений **FastAPI**, равно как и для любых других типов веб-приложений, среди которых Вы можете выбрать **наиболее подходящий** способ.
|
||||
|
||||
Самые важные из них:
|
||||
|
||||
* Использование более безопасного протокола HTTPS
|
||||
* Настройки запуска приложения
|
||||
* Перезагрузка приложения
|
||||
* Запуск нескольких экземпляров приложения
|
||||
* Управление памятью
|
||||
* Использование перечисленных функций перед запуском приложения.
|
||||
|
||||
Рассмотрим ниже влияние каждого из них на процесс **развёртывания**.
|
||||
|
||||
Наша конечная цель - **обслуживать клиентов Вашего API безопасно** и **бесперебойно**, с максимально эффективным использованием **вычислительных ресурсов** (например, удалённых серверов/виртуальных машин). 🚀
|
||||
|
||||
Здесь я немного расскажу Вам об этих **концепциях** и надеюсь, что у Вас сложится **интуитивное понимание**, какой способ выбрать при развертывании Вашего API в различных окружениях, возможно, даже **ещё не существующих**.
|
||||
|
||||
Ознакомившись с этими концепциями, Вы сможете **оценить и выбрать** лучший способ развёртывании **Вашего API**.
|
||||
|
||||
В последующих главах я предоставлю Вам **конкретные рецепты** развёртывания приложения FastAPI.
|
||||
|
||||
А сейчас давайте остановимся на важных **идеях этих концепций**. Эти идеи можно также применить и к другим типам веб-приложений. 💡
|
||||
|
||||
## Использование более безопасного протокола HTTPS
|
||||
|
||||
В [предыдущей главе об HTTPS](./https.md){.internal-link target=_blank} мы рассмотрели, как HTTPS обеспечивает шифрование для Вашего API.
|
||||
|
||||
Также мы заметили, что обычно для работы с HTTPS Вашему приложению нужен **дополнительный** компонент - **прокси-сервер завершения работы TLS**.
|
||||
|
||||
И если прокси-сервер не умеет сам **обновлять сертификаты HTTPS**, то нужен ещё один компонент для этого действия.
|
||||
|
||||
### Примеры инструментов для работы с HTTPS
|
||||
|
||||
Вот некоторые инструменты, которые Вы можете применять как прокси-серверы:
|
||||
|
||||
* Traefik
|
||||
* С автоматическим обновлением сертификатов ✨
|
||||
* Caddy
|
||||
* С автоматическим обновлением сертификатов ✨
|
||||
* Nginx
|
||||
* С дополнительным компонентом типа Certbot для обновления сертификатов
|
||||
* HAProxy
|
||||
* С дополнительным компонентом типа Certbot для обновления сертификатов
|
||||
* Kubernetes с Ingress Controller похожим на Nginx
|
||||
* С дополнительным компонентом типа cert-manager для обновления сертификатов
|
||||
* Использование услуг облачного провайдера (читайте ниже 👇)
|
||||
|
||||
В последнем варианте Вы можете воспользоваться услугами **облачного сервиса**, который сделает большую часть работы, включая настройку HTTPS. Это может наложить дополнительные ограничения или потребовать дополнительную плату и т.п. Зато Вам не понадобится самостоятельно заниматься настройками прокси-сервера.
|
||||
|
||||
В дальнейшем я покажу Вам некоторые конкретные примеры их применения.
|
||||
|
||||
---
|
||||
|
||||
Следующие концепции рассматривают применение программы, запускающей Ваш API (такой как Uvicorn).
|
||||
|
||||
## Программа и процесс
|
||||
|
||||
Мы часто будем встречать слова **процесс** и **программа**, потому следует уяснить отличия между ними.
|
||||
|
||||
### Что такое программа
|
||||
|
||||
Термином **программа** обычно описывают множество вещей:
|
||||
|
||||
* **Код**, который Вы написали, в нашем случае **Python-файлы**.
|
||||
* **Файл**, который может быть **исполнен** операционной системой, например `python`, `python.exe` или `uvicorn`.
|
||||
* Конкретная программа, **запущенная** операционной системой и использующая центральный процессор и память. В таком случае это также называется **процесс**.
|
||||
|
||||
### Что такое процесс
|
||||
|
||||
Термин **процесс** имеет более узкое толкование, подразумевая что-то, запущенное операционной системой (как в последнем пункте из вышестоящего абзаца):
|
||||
|
||||
* Конкретная программа, **запущенная** операционной системой.
|
||||
* Это не имеет отношения к какому-либо файлу или коду, но нечто **определённое**, управляемое и **выполняемое** операционной системой.
|
||||
* Любая программа, любой код, **могут делать что-то** только когда они **выполняются**. То есть, когда являются **работающим процессом**.
|
||||
* Процесс может быть **прерван** (или "убит") Вами или Вашей операционной системой. В результате чего он перестанет исполняться и **не будет продолжать делать что-либо**.
|
||||
* Каждое приложение, которое Вы запустили на своём компьютере, каждая программа, каждое "окно" запускает какой-то процесс. И обычно на включенном компьютере **одновременно** запущено множество процессов.
|
||||
* И **одна программа** может запустить **несколько параллельных процессов**.
|
||||
|
||||
Если Вы заглянете в "диспетчер задач" или "системный монитор" (или аналогичные инструменты) Вашей операционной системы, то увидите множество работающих процессов.
|
||||
|
||||
Вполне вероятно, что Вы увидите несколько процессов с одним и тем же названием браузерной программы (Firefox, Chrome, Edge и т. Д.). Обычно браузеры запускают один процесс на вкладку и вдобавок некоторые дополнительные процессы.
|
||||
|
||||
<img class="shadow" src="/img/deployment/concepts/image01.png">
|
||||
|
||||
---
|
||||
|
||||
Теперь, когда нам известна разница между **процессом** и **программой**, давайте продолжим обсуждение развёртывания.
|
||||
|
||||
## Настройки запуска приложения
|
||||
|
||||
В большинстве случаев когда Вы создаёте веб-приложение, то желаете, чтоб оно **работало постоянно** и непрерывно, предоставляя клиентам доступ в любое время. Хотя иногда у Вас могут быть причины, чтоб оно запускалось только при определённых условиях.
|
||||
|
||||
### Удалённый сервер
|
||||
|
||||
Когда Вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самое простое, что можно сделать, запустить Uvicorn (или его аналог) вручную, как Вы делаете при локальной разработке.
|
||||
|
||||
Это рабочий способ и он полезен **во время разработки**.
|
||||
|
||||
Но если Вы потеряете соединение с сервером, то не сможете отслеживать - работает ли всё ещё **запущенный Вами процесс**.
|
||||
|
||||
И если сервер перезагрузится (например, после обновления или каких-то действий облачного провайдера), Вы скорее всего **этого не заметите**, чтобы снова запустить процесс вручную. Вследствие этого Ваш API останется мёртвым. 😱
|
||||
|
||||
### Автоматический запуск программ
|
||||
|
||||
Вероятно Вы пожелаете, чтоб Ваша серверная программа (такая как Uvicorn) стартовала автоматически при включении сервера, без **человеческого вмешательства** и всегда могла управлять Вашим API (так как Uvicorn запускает приложение FastAPI).
|
||||
|
||||
### Отдельная программа
|
||||
|
||||
Для этого у обычно используют отдельную программу, которая следит за тем, чтобы Ваши приложения запускались при включении сервера. Такой подход гарантирует, что другие компоненты или приложения также будут запущены, например, база данных
|
||||
|
||||
### Примеры инструментов, управляющих запуском программ
|
||||
|
||||
Вот несколько примеров, которые могут справиться с такой задачей:
|
||||
|
||||
* Docker
|
||||
* Kubernetes
|
||||
* Docker Compose
|
||||
* Docker в режиме Swarm
|
||||
* Systemd
|
||||
* Supervisor
|
||||
* Использование услуг облачного провайдера
|
||||
* Прочие...
|
||||
|
||||
Я покажу Вам некоторые примеры их использования в следующих главах.
|
||||
|
||||
## Перезапуск
|
||||
|
||||
Вы, вероятно, также пожелаете, чтоб Ваше приложение **перезапускалось**, если в нём произошёл сбой.
|
||||
|
||||
### Мы ошибаемся
|
||||
|
||||
Все люди совершают **ошибки**. Программное обеспечение почти *всегда* содержит **баги** спрятавшиеся в разных местах. 🐛
|
||||
|
||||
И мы, будучи разработчиками, продолжаем улучшать код, когда обнаруживаем в нём баги или добавляем новый функционал (возможно, добавляя при этом баги 😅).
|
||||
|
||||
### Небольшие ошибки обрабатываются автоматически
|
||||
|
||||
Когда Вы создаёте свои API на основе FastAPI и допускаете в коде ошибку, то FastAPI обычно остановит её распространение внутри одного запроса, при обработке которого она возникла. 🛡
|
||||
|
||||
Клиент получит ошибку **500 Internal Server Error** в ответ на свой запрос, но приложение не сломается и будет продолжать работать с последующими запросами.
|
||||
|
||||
### Большие ошибки - Падение приложений
|
||||
|
||||
Тем не менее, может случиться так, что ошибка вызовет **сбой всего приложения** или даже сбой в Uvicorn, а то и в самом Python. 💥
|
||||
|
||||
Но мы всё ещё хотим, чтобы приложение **продолжало работать** несмотря на эту единственную ошибку, обрабатывая, как минимум, запросы к *операциям пути* не имеющим ошибок.
|
||||
|
||||
### Перезапуск после падения
|
||||
|
||||
Для случаев, когда ошибки приводят к сбою в запущенном **процессе**, Вам понадобится добавить компонент, который **перезапустит** процесс хотя бы пару раз...
|
||||
|
||||
!!! tip "Заметка"
|
||||
... Если приложение падает сразу же после запуска, вероятно бесполезно его бесконечно перезапускать. Но полагаю, Вы заметите такое поведение во время разработки или, по крайней мере, сразу после развёртывания.
|
||||
|
||||
Так что давайте сосредоточимся на конкретных случаях, когда приложение может полностью выйти из строя, но всё ещё есть смысл его запустить заново.
|
||||
|
||||
Возможно Вы захотите, чтоб был некий **внешний компонент**, ответственный за перезапуск Вашего приложения даже если уже не работает Uvicorn или Python. То есть ничего из того, что написано в Вашем коде внутри приложения, не может быть выполнено в принципе.
|
||||
|
||||
### Примеры инструментов для автоматического перезапуска
|
||||
|
||||
В большинстве случаев инструменты **запускающие программы при старте сервера** умеют **перезапускать** эти программы.
|
||||
|
||||
В качестве примера можно взять те же:
|
||||
|
||||
* Docker
|
||||
* Kubernetes
|
||||
* Docker Compose
|
||||
* Docker в режиме Swarm
|
||||
* Systemd
|
||||
* Supervisor
|
||||
* Использование услуг облачного провайдера
|
||||
* Прочие...
|
||||
|
||||
## Запуск нескольких экземпляров приложения (Репликация) - Процессы и память
|
||||
|
||||
Приложение FastAPI, управляемое серверной программой (такой как Uvicorn), запускается как **один процесс** и может обслуживать множество клиентов одновременно.
|
||||
|
||||
Но часто Вам может понадобиться несколько одновременно работающих одинаковых процессов.
|
||||
|
||||
### Множество процессов - Воркеры (Workers)
|
||||
|
||||
Если количество Ваших клиентов больше, чем может обслужить один процесс (допустим, что виртуальная машина не слишком мощная), но при этом Вам доступно **несколько ядер процессора**, то Вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределить запросы между этими процессами.
|
||||
|
||||
**Несколько запущенных процессов** одной и той же API-программы часто называют **воркерами**.
|
||||
|
||||
### Процессы и порты́
|
||||
|
||||
Помните ли Вы, как на странице [Об HTTPS](./https.md){.internal-link target=_blank} мы обсуждали, что на сервере только один процесс может слушать одну комбинацию IP-адреса и порта?
|
||||
|
||||
С тех пор ничего не изменилось.
|
||||
|
||||
Соответственно, чтобы иметь возможность работать с **несколькими процессами** одновременно, должен быть **один процесс, прослушивающий порт** и затем каким-либо образом передающий данные каждому рабочему процессу.
|
||||
|
||||
### У каждого процесса своя память
|
||||
|
||||
Работающая программа загружает в память данные, необходимые для её работы, например, переменные содержащие модели машинного обучения или большие файлы. Каждая переменная **потребляет некоторое количество оперативной памяти (RAM)** сервера.
|
||||
|
||||
Обычно процессы **не делятся памятью друг с другом**. Сие означает, что каждый работающий процесс имеет свои данные, переменные и свой кусок памяти. И если для выполнения Вашего кода процессу нужно много памяти, то **каждый такой же процесс** запущенный дополнительно, потребует такого же количества памяти.
|
||||
|
||||
### Память сервера
|
||||
|
||||
Допустим, что Ваш код загружает модель машинного обучения **размером 1 ГБ**. Когда Вы запустите своё API как один процесс, он займёт в оперативной памяти не менее 1 ГБ. А если Вы запустите **4 таких же процесса** (4 воркера), то каждый из них займёт 1 ГБ оперативной памяти. В результате Вашему API потребуется **4 ГБ оперативной памяти (RAM)**.
|
||||
|
||||
И если Ваш удалённый сервер или виртуальная машина располагает только 3 ГБ памяти, то попытка загрузить в неё 4 ГБ данных вызовет проблемы. 🚨
|
||||
|
||||
### Множество процессов - Пример
|
||||
|
||||
В этом примере **менеджер процессов** запустит и будет управлять двумя **воркерами**.
|
||||
|
||||
Менеджер процессов будет слушать определённый **сокет** (IP:порт) и передавать данные работающим процессам.
|
||||
|
||||
Каждый из этих процессов будет запускать Ваше приложение для обработки полученного **запроса** и возвращения вычисленного **ответа** и они будут использовать оперативную память.
|
||||
|
||||
<img src="/img/deployment/concepts/process-ram.svg">
|
||||
|
||||
Безусловно, на этом же сервере будут работать и **другие процессы**, которые не относятся к Вашему приложению.
|
||||
|
||||
Интересная деталь - обычно в течение времени процент **использования центрального процессора (CPU)** каждым процессом может очень сильно **изменяться**, но объём занимаемой **оперативной памяти (RAM)** остаётся относительно **стабильным**.
|
||||
|
||||
Если у Вас есть API, который каждый раз выполняет сопоставимый объем вычислений, и у Вас много клиентов, то **загрузка процессора**, вероятно, *также будет стабильной* (вместо того, чтобы постоянно быстро увеличиваться и уменьшаться).
|
||||
|
||||
### Примеры стратегий и инструментов для запуска нескольких экземпляров приложения
|
||||
|
||||
Существует несколько подходов для достижения целей репликации и я расскажу Вам больше о конкретных стратегиях в следующих главах, например, когда речь пойдет о Docker и контейнерах.
|
||||
|
||||
Основное ограничение при этом - только **один** компонент может работать с определённым **портом публичного IP**. И должен быть способ **передачи** данных между этим компонентом и копиями **процессов/воркеров**.
|
||||
|
||||
Вот некоторые возможные комбинации и стратегии:
|
||||
|
||||
* **Gunicorn** управляющий **воркерами Uvicorn**
|
||||
* Gunicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **множества работающих процессов Uvicorn**.
|
||||
* **Uvicorn** управляющий **воркерами Uvicorn**
|
||||
* Один процесс Uvicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Он будет запускать **множество работающих процессов Uvicorn**.
|
||||
* **Kubernetes** и аналогичные **контейнерные системы**
|
||||
* Какой-то компонент в **Kubernetes** будет слушать **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**.
|
||||
* **Облачные сервисы**, которые позаботятся обо всём за Вас
|
||||
* Возможно, что облачный сервис умеет **управлять запуском дополнительных экземпляров приложения**. Вероятно, он потребует, чтоб Вы указали - какой **процесс** или **образ** следует клонировать. Скорее всего, Вы укажете **один процесс Uvicorn** и облачный сервис будет запускать его копии при необходимости.
|
||||
|
||||
!!! tip "Заметка"
|
||||
Если Вы не знаете, что такое **контейнеры**, Docker или Kubernetes, не переживайте.
|
||||
|
||||
Я поведаю Вам о контейнерах, образах, Docker, Kubernetes и т.п. в главе: [FastAPI внутри контейнеров - Docker](./docker.md){.internal-link target=_blank}.
|
||||
|
||||
## Шаги, предшествующие запуску
|
||||
|
||||
Часто бывает, что Вам необходимо произвести какие-то подготовительные шаги **перед запуском** своего приложения.
|
||||
|
||||
Например, запустить **миграции базы данных**.
|
||||
|
||||
Но в большинстве случаев такие действия достаточно произвести **однократно**.
|
||||
|
||||
Поэтому Вам нужен будет **один процесс**, выполняющий эти **подготовительные шаги** до запуска приложения.
|
||||
|
||||
Также Вам нужно будет убедиться, что этот процесс выполнил подготовительные шаги *даже* если впоследствии Вы запустите **несколько процессов** (несколько воркеров) самого приложения. Если бы эти шаги выполнялись в каждом **клонированном процессе**, они бы **дублировали** работу, пытаясь выполнить её **параллельно**. И если бы эта работа была бы чем-то деликатным, вроде миграции базы данных, то это может вызвать конфликты между ними.
|
||||
|
||||
Безусловно, возможны случаи, когда нет проблем при выполнении предварительной подготовки параллельно или несколько раз. Тогда Вам повезло, работать с ними намного проще.
|
||||
|
||||
!!! tip "Заметка"
|
||||
Имейте в виду, что в некоторых случаях запуск Вашего приложения **может не требовать каких-либо предварительных шагов вовсе**.
|
||||
|
||||
Что ж, тогда Вам не нужно беспокоиться об этом. 🤷
|
||||
|
||||
### Примеры стратегий запуска предварительных шагов
|
||||
|
||||
Существует **сильная зависимость** от того, как Вы **развёртываете свою систему**, запускаете программы, обрабатываете перезапуски и т.д.
|
||||
|
||||
Вот некоторые возможные идеи:
|
||||
|
||||
* При использовании Kubernetes нужно предусмотреть "инициализирующий контейнер", запускаемый до контейнера с приложением.
|
||||
* Bash-скрипт, выполняющий предварительные шаги, а затем запускающий приложение.
|
||||
* При этом Вам всё ещё нужно найти способ - как запускать/перезапускать *такой* bash-скрипт, обнаруживать ошибки и т.п.
|
||||
|
||||
!!! tip "Заметка"
|
||||
Я приведу Вам больше конкретных примеров работы с контейнерами в главе: [FastAPI внутри контейнеров - Docker](./docker.md){.internal-link target=_blank}.
|
||||
|
||||
## Утилизация ресурсов
|
||||
|
||||
Ваш сервер располагает ресурсами, которые Ваши программы могут потреблять или **утилизировать**, а именно - время работы центрального процессора и объём оперативной памяти.
|
||||
|
||||
Как много системных ресурсов Вы предполагаете потребить/утилизировать? Если не задумываться, то можно ответить - "немного", но на самом деле Вы, вероятно, пожелаете использовать **максимально возможное количество**.
|
||||
|
||||
Если Вы платите за содержание трёх серверов, но используете лишь малую часть системных ресурсов каждого из них, то Вы **выбрасываете деньги на ветер**, а также **впустую тратите электроэнергию** и т.п.
|
||||
|
||||
В таком случае было бы лучше обойтись двумя серверами, но более полно утилизировать их ресурсы (центральный процессор, оперативную память, жёсткий диск, сети передачи данных и т.д).
|
||||
|
||||
С другой стороны, если Вы располагаете только двумя серверами и используете **на 100% их процессоры и память**, но какой-либо процесс запросит дополнительную память, то операционная система сервера будет использовать жёсткий диск для расширения оперативной памяти (а диск работает в тысячи раз медленнее), а то вовсе **упадёт**. Или если какому-то процессу понадобится произвести вычисления, то ему придётся подождать, пока процессор освободится.
|
||||
|
||||
В такой ситуации лучше подключить **ещё один сервер** и перераспределить процессы между серверами, чтоб всем **хватало памяти и процессорного времени**.
|
||||
|
||||
Также есть вероятность, что по какой-то причине возник **всплеск** запросов к Вашему API. Возможно, это был вирус, боты или другие сервисы начали пользоваться им. И для таких происшествий Вы можете захотеть иметь дополнительные ресурсы.
|
||||
|
||||
При настройке логики развёртываний, Вы можете указать **целевое значение** утилизации ресурсов, допустим, **от 50% до 90%**. Обычно эти метрики и используют.
|
||||
|
||||
Вы можете использовать простые инструменты, такие как `htop`, для отслеживания загрузки центрального процессора и оперативной памяти сервера, в том числе каждым процессом. Или более сложные системы мониторинга нескольких серверов.
|
||||
|
||||
## Резюме
|
||||
|
||||
Вы прочитали некоторые из основных концепций, которые необходимо иметь в виду при принятии решения о развертывании приложений:
|
||||
|
||||
* Использование более безопасного протокола HTTPS
|
||||
* Настройки запуска приложения
|
||||
* Перезагрузка приложения
|
||||
* Запуск нескольких экземпляров приложения
|
||||
* Управление памятью
|
||||
* Использование перечисленных функций перед запуском приложения.
|
||||
|
||||
Осознание этих идей и того, как их применять, должно дать Вам интуитивное понимание, необходимое для принятия решений при настройке развертываний. 🤓
|
||||
|
||||
В следующих разделах я приведу более конкретные примеры возможных стратегий, которым Вы можете следовать. 🚀
|
||||
|
|
@ -79,6 +79,7 @@ nav:
|
|||
- Развёртывание:
|
||||
- deployment/index.md
|
||||
- deployment/versions.md
|
||||
- deployment/concepts.md
|
||||
- deployment/https.md
|
||||
- deployment/manually.md
|
||||
- project-generation.md
|
||||
|
|
|
|||
Loading…
Reference in New Issue