{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Дима пишет | Дмитрий Смотров: заметки с тегом ОтказоустойчивоеПО",
    "_rss_description": "backend python fastapi django rabbitmq kafka postgresql sqlalchemy",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/dimasmotrov.ru\/tags\/otkazoustoychivoepo\/",
    "feed_url": "https:\/\/dimasmotrov.ru\/tags\/otkazoustoychivoepo\/json\/",
    "icon": "https:\/\/dimasmotrov.ru\/pictures\/userpic\/userpic@2x.jpg?1718470292",
    "authors": [
        {
            "name": "Дима Смотров",
            "url": "https:\/\/dimasmotrov.ru\/",
            "avatar": "https:\/\/dimasmotrov.ru\/pictures\/userpic\/userpic@2x.jpg?1718470292"
        }
    ],
    "items": [
        {
            "id": "36",
            "url": "https:\/\/dimasmotrov.ru\/all\/12-faktorov-chast-4\/",
            "title": "12 факторов. Часть 4",
            "content_html": "<p>10) <b>Паритет разработки\/работы приложения. Держим среду разработки идентичной среде развертывания. <\/b>Если на проде используется Postgres, то локально мы тоже используем Postgres, никаких SQLite\/Oracle\/MySQL, иначе вы очень рискуете стать тем самым «а у меня локально все работает» парнем. На моей практике различие версии одной зависимости между стейджем и продом привели к двухнедельному кранчу. Фактор обеспечивает способность непрерывного развертывания приложения за счет минимизации различий между средами разработки и исполнения.<br \/>\n11) <b>Журналирование. Логи как поток событий.<\/b> Приложение отдает контроль за своими логами на аутсорс стороннему инструментарию(привет <i>ELK<\/i>, а если точнее, то <i>logstash<\/i>). Каждый процесс пишет логи в стандартный вывод, а там оно уже как-нибудь «само». Почему? Опять же: для простоты масштабирования. Еще важно подчеркнуть — логи рассматриваются как <i>поток событий<\/i>(одна строка логов — одно событие системы), из которых формируется журнал. <i>Журнал<\/i> — это поток агрегированных, упорядоченных по времени событий, собранных из потоков вывода всех запущенных процессов и вспомогательных сервисов. По сути это такой же текстовый файл, но его можно визуализировать для удобства(привет <i>Kibana<\/i>).<br \/>\n12) <b>Администрирование<\/b>. Выполняем администрирование в разовых процессах, причем среда выполнения таких процессов идентична среде выполнения всего приложения. К администрированию относится выполнение миграций, запуск разовых скриптов(например пользака с админскими правами создать), и тому подобное. Очень сильно перекликается с 10 пунктом и нужно по тем же причинам: если мы будем запускать приложение в одной среде, а администрировать приложение в другой, мы точно в конечном итоге нарвемся на рассогласование конфигураций. Хранить разовые скрипты рекомендуется рядом с основным кодом приложения.<\/p>\n",
            "date_published": "2025-09-14T22:57:25+03:00",
            "date_modified": "2025-09-14T22:57:23+03:00",
            "tags": [
                "АрхитектураПО",
                "ОтказоустойчивоеПО",
                "Разработка"
            ],
            "_date_published_rfc2822": "Sun, 14 Sep 2025 22:57:25 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "36",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "35",
            "url": "https:\/\/dimasmotrov.ru\/all\/12-faktorov-chast-3\/",
            "title": "12 факторов. Часть 3",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"https:\/\/dimasmotrov.ru\/pictures\/image_2025-08-16_23-52-57.png\" width=\"405\" height=\"389\" alt=\"\" \/>\n<\/div>\n<p>7) <b>Привязки портов.<\/b> Сервисы экспортируются через бинд порта — то есть сервис тусит на порту и слушает запросы. Тут камень в огород способа развертывания приложения как дополнительного модуля к веб серверу, существовавшему ранее. Сейчас же будьте добры делать приложение самодостаточным, идущем в комплекте с собственным веб-сервером(который вы объявите в зависимостях), а не подсовывайте сервер извне.<br \/>\n8) <b>Параллельное выполнение команд.<\/b> И для параллельного выполнения используются процессы. За основу взяли все хорошее из модели Unix процессов + разделение на типы процессов: если сервис будет обрабатывать HTTP-запросы и выполнять задачи в фоне, то сервис должен быть разделен на веб-процесс и процесс фоновых задач. Таким образом, если увеличивается нагрузка на веб-процесс, то мы докидываем дополнительный веб процесс. Аналогично для процесса фоновых задач. На картинке можно наглядно посмотреть. Вот тут <a href=\"https:\/\/adam.herokuapp.com\/past\/2011\/5\/9\/applying_the_unix_process_model_to_web_apps\/\">пост<\/a> сооснователя heroku с предложением данной концепции.<br \/>\n9) <b>Утилизируемость<\/b>. Приложение должно запускаться и останавливать свою работу в любой момент, когда это потребуется. В идеале мы минимизируем время запуска, а процесс завершения делаем безопасным — завершаем текущую сессию с БД, чтобы соединения не текли, завершаем все фоновые задачи, только после этого процесс умирает. Хорошо бы еще добавить <i>устойчивость к внезапной смерти оборудования<\/i>, но подобное событие считается менее вероятным, чем простое завершение работы по SIGTERM. Весь этот фактор направлен на то, чтобы автомасштабирование работало по принципу «включил\/выключил», как свет на кухне: нужно — добавили подов, ненужно — убрали.<\/p>\n",
            "date_published": "2025-09-04T16:42:49+03:00",
            "date_modified": "2025-09-04T16:42:43+03:00",
            "tags": [
                "АрхитектураПО",
                "ОтказоустойчивоеПО",
                "Разработка"
            ],
            "image": "https:\/\/dimasmotrov.ru\/pictures\/image_2025-08-16_23-52-57.png",
            "_date_published_rfc2822": "Thu, 04 Sep 2025 16:42:49 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "35",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/dimasmotrov.ru\/pictures\/image_2025-08-16_23-52-57.png"
                ]
            }
        },
        {
            "id": "34",
            "url": "https:\/\/dimasmotrov.ru\/all\/12-faktorov-chast-2\/",
            "title": "12 факторов. Часть 2",
            "content_html": "<p>Прошлый <a href=\"https:\/\/dimasmotrov.ru\/all\/12-faktorov-chast-1\/\">пост<\/a><\/p>\n<p>4) <b>Сторонние службы<\/b>. Это службы, доступные приложению по сети. База данных, очереди сообщений, кеши — все это сторонние службы и они должны быть *подключаемыми ресурсами*, доступными по URL-адресу, который в свою очередь заносится через параметры конфигурации. В случае, если сервер сторонней службы начинает барахлить, служба переносится на другой сервер и приложению дают URL с новым сервером.<br \/>\n5) <b>Сборка, релиз и выполнение<\/b>. Жесткое разделение этапов развертывания приложения на сборку(берем код и «компилируем» его: ставим зависимости в окружение; реально компилируем, если ЯП проекта компилируемый), релиз(к «собранной» программе докидываются конфиги) и выполнение(непосредственно запуск программы) позволяет контролировать то, какой код был развернут на сервере с помощью систем контроля релиза(например Jenkins), которые в случае чего позволят откатить релиз и проанализировать проблемный релиз на предмет ошибок.<br \/>\n6) <b>Процессы<\/b>. Приложение запускается как один, либо как несколько процессов, без сохранения внутреннего состояния(сервис без состояния — *stateless*). Так же между процессами не должно быть разделяемых данных. Это нужно для упрощения горизонтального масштабирования — просто добавь ~~воды~~ еще один процесс. В случае, если у сервиса есть состояние(допустим, он кеш хранит в глобальном словаре), то нужно это состояние распространить и держать согласованным между всеми инстансами приложения. Состояние, если оно у вас есть, должно быть вынесено во внешнюю службу(для нашего примера для кеша использовать Redis\/Memcached).<\/p>\n",
            "date_published": "2025-08-06T09:49:43+03:00",
            "date_modified": "2025-08-06T09:49:38+03:00",
            "tags": [
                "АрхитектураПО",
                "ОтказоустойчивоеПО",
                "Разработка"
            ],
            "_date_published_rfc2822": "Wed, 06 Aug 2025 09:49:43 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "34",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "33",
            "url": "https:\/\/dimasmotrov.ru\/all\/12-faktorov-chast-1\/",
            "title": "12 факторов. Часть 1",
            "content_html": "<p>Был период, когда стандартов развертывания веб приложениях особых не было, каждый разворачивался как хотел, масштабировался как мог.  Появились докер, кубер и стали корпоративным стандартом:  заворачивай приложение в контейнер, настраивай деплой и автоматическое масштабирование и поехали.<\/p>\n<p>Так как появились стандартизированные инструменты, появились и рекомендации для разработки приложений с той целью, чтобы минимизировать проблемы с деплоем с помощью этих инструментов. Рекомендации эти обозвали «12 факторные приложения» или же «12 шагов к куберу».<\/p>\n<p>Кратко концепцию можно сформулировать так: если приложение не может запуститься одной командой на вашей рабочей тачке — вы не заскейлитесь в нужный момент, либо скейл будет сопровождаться танцем с бубном и шаманским горловым пением.<\/p>\n<p>Предлагаю рассмотреть часть пунктов и разберемся чем они полезны.<\/p>\n<p>1) <b>Кодовая база.<\/b> Одна кодовая база — одно приложение. Кодовая база ведется с помощью системы контроля версий, любой, на ваш вкус. Каждый разработчик в команде работает с одним и тем же кодом(изменения, внесенные разработчиком во время работы не противоречат этому пункту), на серверах запускается этот же код. Представьте, что у вас есть N друзей близняшек, одевающихся почти одинаково. Отличать их друг от друга смогут разве что родители(а смогут ли?).<br \/>\n2) <b>Зависимости.<\/b> Приложения явно указывает пакеты, которые нужны ему для работы через манифесты декларации зависимостей и  менеджер зависимостей. Таким образом мы избегаем ситуаций, когда в одной среде приложение работает корректно, а при запуске на другом компьютере приложение падает из-за отсутствия нужной библиотеки.<br \/>\n3) <b>Конфигурация<\/b>. Должна подкидываться приложению из переменных окружения. Если вы прибьете гвоздями креды для подключения к БД в коде, а потом поменяете пароль на сервере базы или же переместите базу на другой хост, то без патча в исходном коде приложения вы банально не заведетесь.<\/p>\n<p>В последующих постах пройдемся и по остальным 9 пунктам :)<\/p>\n",
            "date_published": "2025-08-03T21:25:44+03:00",
            "date_modified": "2025-08-03T21:25:38+03:00",
            "tags": [
                "АрхитектураПО",
                "ОтказоустойчивоеПО",
                "Разработка"
            ],
            "_date_published_rfc2822": "Sun, 03 Aug 2025 21:25:44 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "33",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        }
    ],
    "_e2_version": 4134,
    "_e2_ua_string": "Aegea 11.3 (v4134)"
}