<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Высокие нагрузки</title>
    <description/>
    <link>https://tproger.ru/tag/highload</link>
    <atom:link href="https://tproger.ru/tag/highload/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 26 Sep 2026 13:31:23 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Высокие нагрузки</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Инференс под нагрузкой: как обслуживать модель и честно считать её стоимость</title>
      <link>https://tproger.ru/articles/inferens-pod-nagruzkoj-kak-obsluzhivat-model-i-chestno-schitat</link>
      <comments>https://tproger.ru/articles/inferens-pod-nagruzkoj-kak-obsluzhivat-model-i-chestno-schitat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/inferens-pod-nagruzkoj-kak-obsluzhivat-model-i-chestno-schitat</guid>
      <description><![CDATA[<p>Куда уходит память видеокарты при инференсе, что дают PagedAttention и непрерывное пакетирование и как посчитать стоимость задачи до запуска. Разбираем с цифрами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/inferens-pod-nagruzkoj-kak-obsluzhivat-model-i-chestno-schitat">Инференс под нагрузкой: как обслуживать модель и честно считать её стоимость</a>»</p>]]></description>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[GPU]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Sep 2026 13:00:15 GMT</pubDate>
      <content:encoded><![CDATA[<p>Прототип агента на одном пользователе работает прекрасно. На пятидесяти одновременных он упирается в память видеокарты, короткие запросы начинают ждать длинных, а счёт за токены растёт быстрее, чем польза от них.</p><p>Обе проблемы решаются на слое, о котором в прототипе не думают вовсе: на слое обслуживания модели. Разбираем, куда уходит память при генерации, какие механизмы возвращают пропускную способность и как посчитать стоимость пакетной задачи до того, как сделан первый запрос.</p><p>Инференс — это применение уже обученной модели: веса зафиксированы, и модель предсказывает вывод по одному токену за раз. Учиться она перестала, но дешёвой от этого не стала: длинные запросы дороже в обработке, длинные ответы дороже в генерации, а множество одновременных запросов давит и на планировщик, и на память.</p><p>Генерация делится на две фазы с разной природой: разбор запроса грузит вычисления и хорошо распараллеливается, а генерация ответа последовательна и упирается в число шагов.</p><p>Главный потребитель памяти видеокарты — это кеш ключей и значений: для типовой конфигурации выходит около 128 КБ на каждый токен, и именно он ограничивает число одновременных запросов.</p><p>Один запрос пользователя к агенту превращается в десять, двадцать и больше обращений к модели, поэтому нагрузка получается неравномерной по памяти и по длительности.</p><p>Непрерывное пакетирование не даёт коротким запросам ждать длинных, а кеширование общего префикса убирает повторную обработку одного и того же системного промпта.</p><p>Расход токенов не является метрикой продуктивности: у неё тот же изъян, что у подсчёта строк кода, потому что она вознаграждает объём, а не результат.</p><h2>Две фазы инференса, которые дорожают по-разному</h2><p>Обслуживающая система делает две вещи: координирует запросы на стороне процессора и исполняет модель на ускорителе. Само исполнение <a href="https://www.freecodecamp.org/news/how-to-scale-llm-inference-for-ai-agents-using-vllm/">распадается на две фазы</a>, и путать их не стоит, потому что дорожают они от разных причин.</p><p><b>Разбор запроса</b> (в англоязычной документации prefill). Модель обрабатывает все токены входного промпта. Их можно считать параллельно, поэтому фаза упирается в вычислительную мощность. Длинный промпт с историей диалога, найденными документами и описаниями инструментов увеличивает задержку до первого символа ответа.</p><p><b>Генерация</b> (decode). Модель выдаёт по одному токену за раз, и каждый следующий зависит от предыдущих, поэтому распараллелить эту фазу нельзя. Длинный ответ означает много отдельных шагов исполнения модели.</p><p>Отсюда три коротких правила: длинные входы удорожают разбор, длинные ответы удорожают генерацию, а рост числа одновременных запросов давит одновременно на планирование и на память.</p><h2>KV-кеш: где на самом деле кончается память</h2><p>Внутри трансформера механизм внимания строит для каждого обработанного токена представления ключей и значений. Чтобы не пересчитывать их заново на каждом шаге генерации, модель хранит их в памяти. Это и есть кеш ключей и значений, без которого авторегрессивная генерация была бы непрактичной.</p><p>Платить за него приходится памятью видеокарты, и объём считается напрямую:</p><p>Для модели с 32 слоями, 8 KV-головами, размерностью головы 128 и половинной точностью получается примерно 128 КБ на один токен. У других моделей цифра будет своя, но зависимость одна: чем длиннее контекст, тем больше памяти занято. Именно поэтому длинные промпты, долгие диалоги и подтянутые из поиска документы делают инференс заметно дороже, а свободный объём этого кеша прямо определяет, сколько запросов сервер потянет одновременно.</p><h3>Почему агентская нагрузка тяжелее обычной</h3><p>Агент усиливает все перечисленные проблемы, потому что один запрос пользователя порождает множество обращений к модели: спланировать следующее действие, выбрать инструмент, разобрать его результат, свернуть найденное, восстановиться после ошибки, решить, нужна ли ещё работа, и наконец собрать ответ.</p><p>Одно взаимодействие легко превращается в десять или двадцать вызовов, а при сотне активных пользователей счёт идёт на тысячи. Вдобавок запросы неравноценны: в одном короткий вопрос, в другом длинный системный промпт с историей, документами и результатами инструментов. Получается динамическая нагрузка, где запросы приходят в разное время, занимают разный объём памяти и завершаются вразнобой.</p><h2>Четыре механизма, которые возвращают пропускную способность</h2><p>Именно на такую нагрузку рассчитаны специализированные движки обслуживания вроде <a href="https://docs.vllm.ai/">vLLM</a>. Вместо загрузки модели прямо в приложение и вызова метода генерации приложение обращается к серверу по HTTP, и логика агента отделяется от инфраструктуры под ней.</p><h3>Страничное внимание, оно же PagedAttention</h3><p>В наивной системе кеш каждой последовательности занимает один непрерывный участок памяти. Поскольку длины непредсказуемы, участки резервируются с запасом, и память утекает во фрагментацию. Страничная организация хранит кеш блоками фиксированного размера, которые выделяются по мере надобности и не обязаны лежать рядом. Завершился запрос — его блоки вернулись в общий пул и достались другому.</p><h3>Непрерывное пакетирование</h3><p>Обычное пакетирование работает раундами: сервер собирает группу запросов и держит её состав неизменным, пока цикл не отработает. Для генерации текста это плохо, потому что запросы заканчиваются в разное время.</p><p>Представьте: запросу A нужно сто токенов ответа, запросу B двадцать, а запрос C приходит, пока A ещё считается. При фиксированном пакетировании B освободится рано, но его место будет простаивать, а C дождётся конца всего цикла. Непрерывное пакетирование добавляет C в ближайший же шаг генерации, как только освободилось место. Ускоритель остаётся занят полезной работой.</p><h3>Кеширование общего префикса</h3><p>Агенты раз за разом отправляют один и тот же системный промпт, те же описания инструментов и ту же преамбулу рабочего процесса. Без кеширования этот префикс обрабатывается заново при каждом запросе:</p><p>С кешированием общая часть считается один раз и переиспользуется. Важное ограничение: выигрыш приходится только на фазу разбора запроса, генерацию новых токенов приём не ускоряет. Поэтому эффект тем заметнее, чем длиннее общий префикс.</p><p><b>Что здесь на самом деле новое:</b><br />Обычное кеширование ключей и значений есть в любой современной реализации авторегрессивной генерации, это не отличительная черта конкретного движка. Преимущество специализированных серверов в другом: в том, как они планируют запросы и как выделяют, переиспользуют и освобождают память кеша между конкурирующими нагрузками.</p><h3>Совместимый интерфейс</h3><p>Четвёртый пункт скучный, но на практике решающий: сервер выставляет интерфейс, совместимый с OpenAI. Существующие приложения и агентские фреймворки переключаются на него правкой конфигурации, а не переписыванием кода.</p><h2>Когда всё это действительно нужно</h2><p>Специализированный сервер инференса оправдан, когда вы держите модели с открытыми весами у себя и обслуживаете конкурентную нагрузку. Для одиночного прототипа на одного пользователя он избыточен: там хватит <a href="https://tproger.ru/articles/zapuskaem-llm-lokalno-cherez-ollama-gajd-ot-ustanovki-do-claude">локального запуска модели</a>, и вся описанная механика памяти просто не проявится.</p><p>Переломный момент наступает, когда прототип начинает принимать параллельный трафик, а агент проводит большую часть времени в ожидании модели. Тогда дешевле улучшить слой обслуживания под ним, чем переписывать логику самого агента.</p><h2>Вторая половина задачи: считать деньги до запуска</h2><p>Инфраструктура решает вопрос скорости. Вопрос стоимости она не решает, а иногда и обостряет, потому что удобная система располагает к длинным контекстам.</p><p>Дальше речь пойдёт и о тех, кто ходит в модель по чужому тарифу. Своя инфраструктура переводит счёт из токенов в часы работы видеокарт, но сама задача остаётся той же: понять цену задачи до запуска, а не после. Разница только в единице, в которой её считают.</p><h3>Реестр токенов вместо пробного запуска</h3><p>Пакетные задачи ломаются неприятным образом: счётчик прыгает по завершении, а не до старта; повтор удваивает расход без всякой обратной связи; системные промпты, длинные ответы и служебная разметка тоже считаются. <a href="https://dev.to/magickong/learn-to-budget-a-free-model-tier-by-building-a-tiny-token-ledger-3dde">Крошечный офлайновый реестр</a> превращает всё это в проверку до первого обращения к модели.</p><p>Оценка строится на грубой эвристике: для английского текста один токен занимает примерно четыре символа. Точность здесь и не нужна, задача — понять порядок величины:</p><p>Проверим на задаче из 6000 сводок, где промпт занимает около 21 000 символов, а ответ ограничен 500. Выходит 5250 токенов на промпт плюс 125 на ответ, то есть 5375 на вызов, а на всю задачу 32 250 000 токенов при лимите в 30 000 000. Задача не помещается с запасом минус 7,5%, и узнать это удалось, не потратив ни одного токена.</p><p>Соседняя задача с промптом в 4000 символов, тем же ограничением ответа в 500 символов и 10 000 вызовов даёт 1125 токенов на вызов и 11 250 000 на всё, помещаясь с запасом в 62,5%. Живая пробная отправка ни того, ни другого не покажет: она расскажет о поведении конкретной ручки прямо сейчас, но не о сумме по всей пачке, и вдобавок сама потратит токены.</p><h3>Почему расход токенов нельзя делать метрикой продуктивности</h3><p>Тут стоит остановиться отдельно, потому что соблазн велик. Расход токенов удобно считается и потому легко попадает в отчёты, но <a href="https://devops.com/why-tokenmaxxing-was-always-the-wrong-way-for-developers-to-measure-ai-productivity/">как метрика продуктивности он повторяет ошибку подсчёта строк кода</a>.</p><p>Возьмите двух разработчиков с одинаковой задачей и одним инструментом. Первый пишет размытые промпты, позволяет контексту разрастаться в длинной переписке и заставляет модель раз за разом восстанавливать одну и ту же вводную. Второй решает ту же задачу коротким настроенным сценарием. По расходу токенов первый выглядит продуктивнее, хотя на деле он просто шумнее.</p><p>Само по себе потребление токенов отвечает на вопрос, пользуется ли человек инструментом вообще. На раннем этапе внедрения этот сигнал полезен. Но он ничего не говорит о том, получилось ли в итоге что-то осмысленное, а «много ИИ» и «хорошо с ИИ» — разные вещи.</p><h3>Стоимость на результат</h3><p>Правильная постановка вопроса одна: что мы получили за то, что потратили. Оплата по токенам — совершенно разумная коммерческая модель со стороны поставщика вычислений. Ошибка возникает на стороне покупателя, когда единица биллинга поставщика переезжает во внутреннюю систему оценки работы.</p><p>Связь между расходом и результатом реальна, но не универсальна. Более способные модели действительно тратят больше токенов и на сложных задачах дают заметно лучший результат: расширенные рассуждения и многошаговые попытки стоят токенов и окупаются. При этом один и тот же расход при разных конфигурациях и стратегиях промптинга даёт совершенно разные результаты, а неудачная обвязка и небрежная работа с контекстом жгут токены без всякой отдачи.</p><p>Практический вывод: считайте отношение результата к затратам, а не сам объём. Для команды безопасности это стоимость одной подтверждённой находки, для продуктовой команды — доля задач, доведённых до готовой и проверенной функциональности.</p><h3>Слишком жёсткая квота выталкивает работу за периметр</h3><p>Обратная крайность встречается не реже. Когда организация выставляет квоты слишком консервативно, инженеры, которые видят реальную пользу от инструмента, упираются в искусственный потолок и начинают пользоваться личными аккаунтами и бесплатными тарифами.</p><p>Это рациональное поведение человека, которому нужно сдать работу. Но результат предсказуем: использование уходит из контролируемого контура, а вместе с ним пропадают наблюдаемость, возможность аудита и любая уверенность в том, что результат соответствует требованиям к качеству и безопасности. Осмысленная квота с измерением отдачи здесь работает лучше, чем экономная квота без измерений.</p><h2>Что забрать с собой</h2><p>Слой обслуживания модели, то есть инференса, становится узким местом раньше, чем логика приложения, и лечится он не переписыванием агента, а работой с памятью и планированием запросов. Кеш ключей и значений задаёт потолок конкурентности, страничная организация возвращает потерянную на фрагментации память, непрерывное пакетирование убирает простой, а кеширование префикса снимает повторную обработку одинаковых преамбул.</p><p>Со стоимостью работает та же логика: считать нужно до запуска и в единицах результата, а не расхода. Офлайновый расчёт пакета занимает двадцать строк и ловит ошибку формы задачи раньше, чем она превратится в исчерпанный лимит посреди ночного прогона.</p><p>Материалы разбора: <a href="https://www.freecodecamp.org/news/how-to-scale-llm-inference-for-ai-agents-using-vllm/">устройство обслуживания моделей под агентские нагрузки</a>, <a href="https://devops.com/why-tokenmaxxing-was-always-the-wrong-way-for-developers-to-measure-ai-productivity/">почему расход токенов не метрика продуктивности</a> и <a href="https://dev.to/magickong/learn-to-budget-a-free-model-tier-by-building-a-tiny-token-ledger-3dde">офлайновый расчёт бюджета пакетной задачи</a>.</p><p>Посчитайте свой самый крупный пакетный прогон по эвристике четырёх символов на токен и сравните с остатком лимита. Если не сходится, вы только что сэкономили ночь и деньги.</p>]]></content:encoded>
    </item>
    <item>
      <title>Пагинация и лимиты API: как отдавать данные постранично и не дать выгрести базу</title>
      <link>https://tproger.ru/articles/paginaciya-i-limity-api-kak-otdavat-dannye-postranichno-i-ne-dat</link>
      <comments>https://tproger.ru/articles/paginaciya-i-limity-api-kak-otdavat-dannye-postranichno-i-ne-dat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/paginaciya-i-limity-api-kak-otdavat-dannye-postranichno-i-ne-dat</guid>
      <description><![CDATA[<p>Пагинация через OFFSET тормозит на глубоких страницах и теряет строки. Смотрите, как перейти на курсор и настроить лимиты запросов — с кодом и замерами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/paginaciya-i-limity-api-kak-otdavat-dannye-postranichno-i-ne-dat">Пагинация и лимиты API: как отдавать данные постранично и не дать выгрести базу</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Sep 2026 05:00:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ваш API отдаёт страницы по двадцать записей и работает прекрасно ровно до того дня, когда у первого крупного клиента накопится полмиллиона строк. Тогда выяснится сразу две вещи: страницы стали открываться секундами, а синхронизация на стороне клиента дважды затянула одни и те же заказы.</p><p>Оба симптома дают один и тот же виновник — постраничная выдача через OFFSET. И оба чинятся одним переходом, причём переписывать приходится только слой выдачи.</p><p>Пагинация — это способ отдать большую коллекцию по частям. Вариантов ровно два. Offset-пагинация просит базу пропустить N строк и вернуть следующие двадцать. Курсорная (её же называют keyset) запоминает последнюю отданную запись и просит всё, что идёт после неё.</p><p>Стоимость OFFSET растёт линейно: на таблице в 1,2 млн строк выборка со смещением в миллион занимает 2,4 с против 3 мс у курсора.</p><p>Под параллельными вставками и удалениями OFFSET выдаёт дубликаты и пропуски, потому что нумерация строк сдвигается между запросами.</p><p>Курсор не поддерживает переход на произвольную страницу, поэтому для админок и таблиц с кнопкой «страница 47» offset остаётся правильным выбором.</p><p>Лимиты запросов на счётчике в памяти инстанса не работают: при десяти инстансах настроенные 100 запросов в минуту превращаются в 1000.</p><p>Скользящее окно на сортированном множестве Redis и атомарном Lua-скрипте занимает пятнадцать строк и снимает гонку без распределённых блокировок.</p><p>Результат на спокойной базе одинаковый. Поведение под ростом данных и параллельными записями — принципиально разное.</p><h2>Offset ломается двумя разными способами</h2><p>Про первый знают почти все, про второй вспоминают уже после инцидента.</p><h3>Он линейно замедляется</h3><p>PostgreSQL, MySQL и SQLite не умеют «перепрыгнуть» через строки. При OFFSET 100000 база честно читает сто тысяч строк и выбрасывает их, чтобы отдать следующие двадцать. Стоимость запроса растёт вместе со смещением.</p><p>Автор разбора <a href="https://dev.to/sirmax/why-i-switched-my-api-from-offset-to-cursor-pagination-and-when-you-shouldnt-1464">замерил это на таблице в 1,2 млн строк</a> в PostgreSQL 15 с холодным кешем и обычным btree-индексом по id:</p><p>Курсорный вариант на той же таблице держал 3 мс на любой глубине. Разница объясняется сложностью: поиск по индексу это O(log n), а большое смещение — O(offset). На пятидесятитысячной странице пользователь ждёт больше двух секунд вместо миллисекунд.</p><h3>Он врёт, когда в таблицу пишут</h3><p>Этот сценарий коварнее. Пользователь загрузил первую страницу с двадцатью записями, отсортированными от новых к старым. Пока он читал, в таблицу добавились три новые записи. Запрос второй страницы с OFFSET 20 вернёт часть того, что уже было на первой: всё сдвинулось на три позиции.</p><p>Клиент получает дубликаты. При удалении записей картина обратная — часть строк он не увидит никогда, потому что они проскочили мимо границы страницы. У автора статьи на этом сломалась синхронизация у клиента: задание дважды загрузило одни и те же двадцать заказов, и три письма в поддержку ушло на то, чтобы понять, что виновата пагинация, а не код клиента.</p><p>Курсор от этого защищён по построению. Курсор — это последняя фактически полученная запись, поэтому «всё, что после неё» остаётся верным независимо от того, сколько строк вставили или удалили между запросами.</p><h2>Как выглядит курсор в коде</h2><p>Простейшая версия работает по первичному ключу и умещается в один обработчик:</p><p>Обратите внимание на per_page + 1. Запрашивая на одну запись больше, чем собираетесь отдать, вы узнаёте о существовании следующей страницы без отдельного запроса COUNT. Лишняя запись отбрасывается, а её наличие становится флагом has_more.</p><h3>Составной курсор: место, где ломается наивная версия</h3><p>Курсор по одному id корректен, только пока вы сортируете по id. Как только сортировка идёт по created_at, простое условие created_at &gt; X начинает терять записи: два заказа, созданные в одну миллисекунду, дают ничью, и одна из строк молча исчезает из выдачи.</p><p>Лечится это составным курсором — ключ сортировки плюс первичный ключ, сравниваемые как кортеж:</p><p>Сравнение кортежей разрешает ничьи детерминированно, поэтому ни одна строка не дублируется и не пропадает. Под это нужен составной индекс (created_at DESC, id DESC), иначе выигрыш в скорости пропадёт вместе с планом запроса.</p><p><b>Про формат курсора:</b><br />Не отдавайте наружу голый идентификатор, если планируете менять схему. Заверните значения в маленький JSON с полем версии и закодируйте в base64: тогда через год вы поменяете состав курсора, не сломав клиентов, которые прямо сейчас держат страницу открытой.</p><h2>Когда офсетную пагинацию нужно оставить</h2><p>Курсор не бесплатный, и подменять им всё подряд не стоит. Есть четыре ситуации, где offset честно лучше:</p><ul><li>Интерфейсу нужен переход на конкретную страницу. У курсора нет номеров страниц, поэтому админки, таблицы и всё с кнопкой «перейти к странице 47» остаются на offset.</li><li>Данных мало и они не меняются. Справочник на пять тысяч строк не выиграет ничего, зато offset проще объяснить и отладить.</li><li>Пагинация идёт по памяти или по кешу, где смещение и так стоит O(1).</li><li>Сортировка задаётся пользователем по произвольной колонке. Курсор тут превращается в кодирование кортежей в непрозрачные строки, и это уже заметная сложность.</li></ul><p>Разумное правило: курсор по умолчанию для всего, что может перерасти десять тысяч строк или читается во время записи. Offset — для небольших, статичных и внутренних данных.</p><p>И отдельно стоит помнить, что пагинация обычно не единственная нагрузка на базу. Кто ещё и насколько сильно её грузит, разбирали в переводе про <a href="https://tproger.ru/translations/patterny-upravleniya-trafikom-k-postgresql-v-production">паттерны управления трафиком к PostgreSQL</a>.</p><h2>Вторая половина задачи: кто и сколько может забрать</h2><p>Правильная пагинация решает, как отдавать данные. Она не решает, сколько их заберут за минуту. Ограничение частоты запросов выглядит тривиально («считай запросы, блокируй сверх N») и превращается в задачу распределённых систем ровно в тот момент, когда серверов становится два.</p><h3>Сначала ответьте, от чего защищаетесь</h3><p>От выбранной цели зависит вся конструкция, и целей <a href="https://dev.to/weston_carnes_d580b505e0c/api-rate-limiting-patterns-algorithms-and-how-to-do-it-right-4l35">обычно выделяют четыре</a>:</p><ul><li>Защита от перегрузки — не дать всплеску положить сервис.</li><li>Честное распределение — не дать одному шумному клиенту вытеснить остальных.</li><li>Защита от злоупотреблений — притупить перебор паролей, скрейпинг и подстановку учётных данных.</li><li>Контроль расходов — ограничить дорогие ручки вроде вызова модели или построения отчёта. Тот же принцип со стороны поставщика разбирали на примере <a href="https://tproger.ru/articles/kak-ogranichit-rashody-na-openai-api-chtoby-ii-agenty-ne-sozhgli">лимитов трат в OpenAI API</a>.</li></ul><h3>Три алгоритма и один, который выбирают почти всегда</h3><p><b>Фиксированное окно</b> считает запросы в календарном интервале: сто в минуту со сбросом на начале минуты. Просто и дыряво: клиент отправляет сотню в 12:00:59 и ещё сотню в 12:01:00, то есть двести за одну секунду. Граница окна и есть дыра.</p><p><b>Скользящее окно</b> считает в непрерывно сдвигающемся интервале, часто взвешивая счётчик предыдущего окна по мере хода времени. Точнее, но требует больше состояния.</p><p><b>Ведро токенов</b> обычно и оказывается верным выбором по умолчанию. В ведре лежит до N токенов, оно пополняется с постоянной скоростью, каждый запрос тратит один токен. Такая схема разрешает контролируемые всплески (молчавший клиент накопил токены и может потратить их разом), но держит среднюю нагрузку в рамках. Родственное «дырявое ведро» выдаёт идеально ровный поток и нужно там, где принимающая сторона всплесков не переносит.</p><blockquote>Фиксированное окно пишут первым и потом жалеют. На ведро токенов мигрируют.</blockquote><h3>Ловушка, из-за которой лимит не работает вообще</h3><p>Счётчик в памяти процесса живёт до появления второго сервера. После этого «сто запросов в минуту» тихо означает «сто запросов в минуту на инстанс», и при десяти инстансах клиент законно получает тысячу. Ошибку не видно ни в логах, ни в мониторинге: лимит вроде бы работает, просто не тот.</p><p>Лечится это переносом счётчика в общее хранилище, обычно в Redis, причём проверка и инкремент обязаны быть атомарными. Последовательность «прочитать, сравнить, увеличить» из кода приложения гоняется между инстансами и недосчитывает запросы ровно под той нагрузкой, ради которой лимит и ставили.</p><h2>Скользящее окно на Redis: пятнадцать строк Lua</h2><p>Команда сервиса jo4.io столкнулась с частным случаем этой задачи: ручка подсказки категорий ходит в модель через Groq, каждый вызов стоит денег, а пользователь может дёрнуть её полсотни раз за минуту. Нужны были лимиты на конкретную ручку и на конкретного пользователя, причём в тот же день.</p><p>Скользящее окно они <a href="https://dev.to/anand_rathnas_d5b608cc3de/redis-sliding-window-rate-limiting-with-lua-the-15-line-script-that-saved-our-ai-budget-p0i">собрали на сортированном множестве Redis</a>. Скор записи — временная метка в миллисекундах, а весь алгоритм умещается в один Lua-скрипт, который Redis выполняет атомарно:</p><p>Первая команда чистит записи старше окна относительно текущего момента — именно поэтому окно скользящее, а не фиксированное: границ, к которым можно приурочить всплеск, здесь просто нет. PEXPIRE с запасом в секунду доубивает ключ, если новых запросов не приходит, так что чистить хранилище отдельно не нужно.</p><h3>Две детали, на которых легко ошибиться</h3><p><b>Уникальность члена множества.</b> ZADD не добавляет запись, а перезаписывает существующую, если член совпал. Два запроса в одну миллисекунду с одинаковым значением дадут счётчик, который занижен. Авторы склеивают метку времени с восемью символами UUID: метка обеспечивает уникальность почти всегда, а восемь шестнадцатеричных символов дают около четырёх миллиардов вариантов внутри одной миллисекунды.</p><p><b>Куда падать при отказе Redis.</b> Решение здесь принимается осознанно и по-разному для двух случаев. Если вызов не получил внятного ответа вовремя (таймаут клиента, сетевая икота), запрос пропускают: лимит здесь страхует бюджет, а не безопасность, и блокировать живого пользователя из-за сбоя инфраструктуры хуже, чем оплатить лишний вызов модели. А вот жёсткое исключение (Redis недоступен, соединение отвергнуто) пробрасывают наверх: если хранилище легло целиком, лучше шумно упасть, чем молча жечь бюджет вообще без ограничений.</p><p>Обошлось это в два часа работы вместе с тестами. Одна запись в сортированном множестве занимает около 50 байт, на пользователя их пять, и даже при десяти тысячах активных пользователей всё хранилище лимитов весит порядка 2,5 МБ. Настроенный лимит составил пять запросов за шестьдесят секунд на пользователя. Первым же уловом стал автоматизированный скрипт, бивший в ручку больше двухсот раз в час.</p><h2>Честный контракт с клиентом</h2><p>Ограничение без внятного ответа превращает вежливого клиента в невежливого: не понимая, что происходит, он начинает долбить чаще. Минимальный набор обязательств выглядит так:</p><ul><li>Отдавать 429 Too Many Requests, а не общий 400 или 503. По коду клиент понимает, что делать.</li><li>Присылать заголовок Retry-After, чтобы клиент знал момент следующей попытки, а не подбирал его перебором.</li><li>Показывать остаток бюджета в заголовках вида X-RateLimit-Remaining и X-RateLimit-Reset.</li></ul><p>Последний пункт стоит дешевле всего и работает лучше всего: клиент, который видит свой остаток, обычно распределяет запросы сам и до стены не доходит.</p><h2>Что забрать с собой</h2><p>Обе половины задачи решаются до того, как появится нагрузка, и обе стоят один вечер. Курсорная пагинация убирает и деградацию на глубоких страницах, и молчаливую порчу выдачи при параллельных записях. Атомарный счётчик в общем хранилище превращает лимит из декоративного в настоящий.</p><p>Отложить их дешевле всего прямо сейчас и дороже всего в момент, когда в поддержку придёт клиент с задвоенными заказами: тогда чинить придётся не только API, но и данные на его стороне.</p><p>Разборы, на которых основан материал: <a href="https://dev.to/sirmax/why-i-switched-my-api-from-offset-to-cursor-pagination-and-when-you-shouldnt-1464">переход с offset на курсор с замерами</a>, <a href="https://dev.to/weston_carnes_d580b505e0c/api-rate-limiting-patterns-algorithms-and-how-to-do-it-right-4l35">паттерны и алгоритмы ограничения частоты</a> и <a href="https://dev.to/anand_rathnas_d5b608cc3de/redis-sliding-window-rate-limiting-with-lua-the-15-line-script-that-saved-our-ai-budget-p0i">скользящее окно на Redis и Lua</a>.</p><p>Откройте свой самый нагруженный список и выполните запрос с большим смещением. Если ответ идёт дольше сотни миллисекунд, вы уже нашли, с чего начать.</p>]]></content:encoded>
    </item>
    <item>
      <title>Rust, Go или Zig: как выбрать язык для высоконагруженного бэкенда в 2026 году</title>
      <link>https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend</link>
      <comments>https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend</guid>
      <description><![CDATA[<p>Сравниваем Rust, Go и Zig для высоконагруженных сервисов: производительность, сложность, экосистема и реальные кейсы миграции.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend">Rust, Go или Zig: как выбрать язык для высоконагруженного бэкенда в 2026 году</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 09 Jul 2026 06:41:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы строите высоконагруженный бэкенд, выбор языка сегодня сводится к тройке: Rust, Go и Zig. У каждого — своя цена, своя скорость разработки и свои сценарии, в которых он выигрывает. Разбираем, как не ошибиться и когда смешивать их в одном проекте.</p><p>Речь пойдёт не о сравнении синтаксиса в вакууме, а о бэкенд-сервисах: API, шлюзах, обработке событий, парсинге данных и всём, что работает под нагрузкой. В статье — авторский взгляд на материал блога инженера Pooya Golchian, дополненный российским контекстом и поправками на реальное состояние экосистем.</p><p><b>Go</b> остаётся стандартным выбором для большинства микросервисов: быстрая компиляция, простота найма, огромная экосистема.</p><p><b>Rust</b> выигрывает там, где важны предельная задержка и контроль над памятью, но требует опытной команды и времени на обучение.</p><p><b>Zig</b> подходит для узких, критичных к производительности участков и для интеграции с существующим C-кодом, но экосистема пока незрелая.</p><p>В больших системах работает гибридный подход: Go для скорости разработки, Rust/Zig для горячих путей.</p><p>Мигрировать стоит только после профилирования: оптимизация без замеров обычно дороже, чем выгода.</p><h2>Почему именно эти три языка</h2><p>В 2026 году для нового backend-проекта по-прежнему можно взять Java, C#, Python или Node.js. Но если речь заходит о высоких нагрузках, низкой задержке и контроле над ресурсами, внимание смещается к трём игрокам.</p><ul><li><b>Rust</b> — язык с владением и заимствованием, дающий безопасность памяти без сборщика мусора.</li><li><b>Go</b> — язык с простой моделью конкурентности, статической линковкой и минималистичной философией.</li><li><b>Zig</b> — язык в духе C, но с современной системой сборки, comptime и явным управлением памятью.</li></ul><p>Все трое компилируются в нативный код, дают один бинарник на выходе и не требуют виртуальной машины. Именно это отличает их от Java, C# и Python на старте.</p><h2>Rust: максимум производительности, максимум сложности</h2><h3>Сильные стороны</h3><ul><li>Безопасность памяти на этапе компиляции — нет use-after-free, data races и большинства утечек.</li><li>Нулевая стоимость абстракций: высокоуровневый код часто компилируется так же эффективно, как ручной C.</li><li>Мощная модель конкурентности поверх tokio или async-std.</li><li>Зрелая экосистема: axum, actix-web, serde, sqlx.</li></ul><h3>Слабые стороны</h3><ul><li>Крутая кривая обучения: borrow checker требует перестройки мышления.</li><li>Долгая компиляция: полная пересборка крупного проекта занимает десятки секунд и минуты.</li><li>Меньше кадров на рынке, чем у Go или Java.</li><li>Итерации медленнее: каждая ошибка компилятора — это время на переделку.</li></ul><h3>Когда выбирать Rust</h3><p>Rust логичен, если вы строите инфраструктуру — прокси, базы данных, очереди, edge-сервисы — или если профилирование показывает, что горячий путь съедает CPU и память. Примеры из продакшена: Cloudflare использует Rust на edge, Discord переписал на Rust часть read-path сервисов.</p><h2>Go: скорость разработки в масштабе</h2><h3>Сильные стороны</h3><ul><li>Компиляция за секунды и один статический бинарник для деплоя.</li><li>Встроенные горутины и каналы — простая, но мощная конкурентность.</li><li>Отличная стандартная библиотека и быстрое тестирование через go test.</li><li>Большая база инженеров и проверенные практики в крупных компаниях.</li></ul><h3>Слабые стороны</h3><ul><li>Сборщик мусора может давать всплески задержек, хотя в последних версиях паузы сокращаются.</li><li>Меньше контроля над расположением памяти и размером структур.</li><li>Пиковая пропускная способность ниже, чем у Rust и Zig, на CPU-bound задачах.</li><li>Система типов и обработка ошибок минималистичны — кому-то этого достаточно, кому-то не хватает.</li></ul><h3>Когда выбирать Go</h3><p>Go — выбор по умолчанию для команд из 5–50 человек, которым нужно быстро запускать CRUD-сервисы, API-шлюзы и data pipeline. Uber, Google и Яндекс активно используют Go в микросервисах. Если главная метрика — time to market, а не последний процент производительности, Go обычно выигрывает.</p><h2>Zig: новый игрок с C-душой</h2><h3>Сильные стороны</h3><ul><li>Производительность уровня C с более современным синтаксисом и системой сборки.</li><li>comptime — выполнение кода на этапе компиляции для генерации оптимизированных структур.</li><li>Прямое взаимодействие с C без FFI-слоёв.</li><li>Маленькие быстрые бинарники и явное управление памятью.</li></ul><h3>Слабые стороны</h3><ul><li>Экосистема backend-фреймворков и библиотек пока существенно меньше, чем у Rust и Go.</li><li>Сообщество и количество инженеров на рынке ограничены.</li><li>Ручное управление памятью перекладывает ответственность на разработчика.</li><li>Некоторые части языка и стандартной библиотеки всё ещё эволюционируют.</li></ul><h3>Когда выбирать Zig</h3><p>Zig хорош, когда нужна C-производительность, но с более удобным инструментарием, или когда приходится интегрироваться с существующим C-кодом. Пример из продакшена: финансовая база данных TigerBeetle написана на Zig. Для универсального backend в 2026 году Zig ещё рано называть mainstream-выбором.</p><h2>Сравнение в цифрах</h2><p>Ниже — иллюстративные цифры из оригинального материала, полученные на AWS c7g.2xlarge (Graviton3). Относитесь к ним как к точке отсчёта, а не как к гарантии для вашего сервиса: в реальности большее значение имеют I/O, запросы к базе данных и сетевая задержка.</p><p><b>Бенчмарки:</b><br />HTTP throughput — Rust 892K req/s, Go 734K req/s, Zig 812K req/s.<br />JSON-сериализация — Rust 1,2M/s, Go 890K/s, Zig 1,1M/s.<br />Память на 10K соединений — Rust 45MB, Go 78MB, Zig 38MB.<br />Размер бинарника — Rust 8,2MB, Go 12,4MB, Zig 6,1MB.<br />Время компиляции с нуля — Rust 42s, Go 3,2s, Zig 18s.<br />P99 latency — Rust 2,1ms, Go 3,8ms, Zig 2,4ms.</p><h2>Реальные истории миграции</h2><h3>Discord: Go → Rust</h3><p>Discord переводил read-path сервисы с Go на Rust из-за пауз сборщика мусора, которые проявлялись в хвостовых задержках. По данным компании, throughput вырос в несколько раз, а tail latency снизилась. Ключевой вывод: мигрировать стоит только горячие пути, а не весь сервис целиком.</p><h3>Uber: Python → Go</h3><p>Uber мигрировал часть микросервисов с Python на Go, чтобы обойти ограничения GIL и упростить масштабирование. Переход занял годы, но зато проходил постепенно: Go-совместимость и простота языка позволяли быстро обучать команду.</p><h3>TigerBeetle: C++ → Zig</h3><p>TigerBeetle — финансовая база данных, ориентированная на корректность и производительность. Команда выбрала Zig, отказавшись от сложности C++ и сборщика мусора. comptime позволил генерировать специализированные структуры данных под задачу.</p><h2>Гибридная архитектура</h2><p>На практике редко выбирают один язык на весь проект. Гораздо чаще используют гибрид:</p><ul><li><b>API Gateway и CRUD</b> — Go: быстро писать, просто деплоить, легко искать людей.</li><li><b>Горячие пути</b> — Rust: низкая задержка и контроль над памятью.</li><li><b>Специализированные компоненты</b> — Zig: парсинг бинарных форматов, криптография, интеграция с C.</li></ul><p>Такая схема позволяет получить скорость разработки в большинстве сервисов и производительность там, где она действительно нужна. Главное — разделять систему по чётким границам и не превращать проект в зоопарк ради самого зоопарка.</p><h2>Что выбрать в 2026 году</h2><p>Выбор зависит от приоритетов команды и задачи:</p><ul><li><b>Нужна скорость разработки и лёгкий найм</b> — Go.</li><li><b>Нужна максимальная производительность и безопасность памяти</b> — Rust.</li><li><b>Нужна C-производительность с современной сборкой и интеграцией с legacy на C</b> — Zig.</li><li><b>Команда маленькая и сроки горят</b> — начинайте с Go, профилируйте, мигрируйте горячие пути при необходимости.</li><li><b>Строите базу данных, прокси или edge</b> — Rust становится очень сильным кандидатом.</li></ul><h2>FAQ</h2><h2>Выводы</h2><p>Rust, Go и Zig — не конкуренты в прямом смысле, а инструменты для разных условий. Go задаёт темп разработки, Rust отвечает за надёжность и производительность, Zig покрывает специализированные ниши. Лучшая стратегия для 2026 года — начать с Go, измерять, а затем точечно внедрять Rust или Zig там, где данные это оправдывают.</p><blockquote>Нет универсального лучшего языка — есть лучший язык для конкретной команды, задачи и бюджета на обучение.</blockquote><p><b>Источник:</b> <a href="https://pooya.blog/blog/rust-go-zig-high-performance-backend-2026/">Pooya Golchian — Rust vs Go vs Zig: High-Performance Backend Services in 2026</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Страница статусов снизила нагрузку на поддержку в три раза. Как мы к этому пришли</title>
      <link>https://tproger.ru/articles/stranica-statusov-snizila-nagruzku-na-podderzhku-v-tri-raza-kak</link>
      <comments>https://tproger.ru/articles/stranica-statusov-snizila-nagruzku-na-podderzhku-v-tri-raza-kak?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Симоненков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/stranica-statusov-snizila-nagruzku-na-podderzhku-v-tri-raza-kak</guid>
      <description><![CDATA[<p>Разбор кейса: как страница статусов сократила количество тикетов во время инцидентов на 67%. Что пробовали до этого, как устроен нормальный incident workflow и что важно при выборе инструмента для российского рынка.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/stranica-statusov-snizila-nagruzku-na-podderzhku-v-tri-raza-kak">Страница статусов снизила нагрузку на поддержку в три раза. Как мы к этому пришли</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Новости]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Системное администрирование]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Техподдержка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 28 Apr 2026 06:40:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Несколько лет назад я работал в компании, которая делала платёжный процессинг. Не скажу название - NDA жив до сих пор. Но расскажу про один конкретный вечер в пятницу, который изменил то, как я думаю об инцидентах.</p><p>Около семи вечера начали падать транзакции. Не все - примерно 15%. Команда сразу занялась разбором: логи, метрики, трейсы. Стандартный процесс. Проблему нашли и починили за 40 минут. По меркам платёжки - нормально.</p><p>Но пока мы разбирались, в поддержку пришло 300 тикетов. Три сотни «что происходит», «у нас не проходят платежи», «когда заработает». Саппорт ничего не знал - он ждал, пока инженеры выплывут из логов. Клиенты ждали саппорт. Всё это время тишина с нашей стороны читалась как безразличие.</p><p>Проблему починили за 40 минут. Разгребали тикеты три дня.</p><h2>Почему молчание хуже, чем «мы знаем о проблеме»</h2><p>Есть простая психология: человек переносит неопределённость хуже, чем плохие новости. Если транзакция не прошла и нет никакой информации - клиент начинает строить сценарии. Деньги потерялись. Сервис умер. Нас кинули. Он пишет в поддержку. Потом пишет ещё раз. Потом оставляет отзыв.</p><p>Если транзакция не прошла, но есть страница</p><p>с записью «Повышенное время отклика платёжного шлюза. Investigating. 19:12» - большинство людей закрывают вкладку и ждут. Не все. Но большинство.</p><p>Мы это проверили. После того как поставили нормальную страницу статусов, количество тикетов во время инцидентов упало примерно в три раза. Точнее - на 67% по среднему за квартал. Это не магия, это просто информация в нужный момент.</p><h2>Что мы пробовали до этого</h2><p>Расскажу честно, через что прошли, потому что это типичный путь.</p><p>Шаг первый: Telegram-канал. Завели канал «Статус сервиса». Писали туда когда что-то падало. Работало ровно до тех пор, пока кто-то не забыл написать. А потом написал через два часа когда уже всё починилось. Клиенты не понимали что происходило. Доверие к каналу упало быстро.</p><p>Шаг второй: статус в шапке сайта. Зелёный кружок когда всё хорошо. Ручной - кто-то должен был его менять. Понятно куда это ведёт: кружок всегда зелёный, потому что некогда, потому что забыли, потому что «сейчас разбираемся, потом обновим».</p><p>Шаг третий: Atlassian Statuspage. Это уже нормальный инструмент. Он решил проблему. Но у него есть два неудобства для русскоязычного рынка: оплата в долларах (что в 2022 стало практической проблемой) и серверы за пределами России (что для ряда клиентов принципиально с точки зрения регулирования).</p><h2>Как устроен нормальный incident workflow со страницей статусов</h2><p>Я говорю «нормальный» - имею в виду тот, который не требует героизма от дежурного инженера в 2 ночи.</p><p>Всё начинается с мониторинга. HTTP/TCP-проверки каждую минуту на все критичные эндпоинты: API, веб, база, очереди. Когда что-то падает - автоматическое создание инцидента и уведомление команды. Это не новость, большинство так и делают.</p><p>Новость в том, что параллельно с уведомлением команды - автоматическое обновление публичной страницы статусов. Не «кто-то должен написать туда», а именно автоматически. Клиент видит «Degraded performance» раньше, чем успевает написать в поддержку.</p><p>Дальше инженер работает по стандартному процессу: Investigating - Identified - Monitoring - Resolved. Каждый статус обновляется на странице. Клиенты, подписавшиеся на уведомления, получают апдейты в Telegram или email. Поддержка может в один клик скопировать ссылку на инцидент и отправить клиенту вместо объяснений.</p><p>После разрешения - postmortem прямо на странице. Клиенты видят что случилось, почему и что сделано чтобы не повторилось. Это, как ни странно, повышает доверие сильнее, чем если бы инцидента не было совсем.</p><h2>Что важно при выборе инструмента</h2><p>Несколько технических вещей, на которые стоит обратить внимание.</p><p>Uptime самой страницы статусов. Она должна быть на отдельной инфраструктуре. Если ваш основной сервис упал и страница статусов на той же инфраструктуре - вы получили идеальный шторм: сервис не работает и статус показать невозможно.</p><p>Собственный домен.</p><p>вместо</p><p>. Это доверие и брендинг.</p><p>Telegram-уведомления. Для российской аудитории это важнее email. Люди читают Telegram, а не почту, когда ищут статус сервиса в панике.</p><p>Локализация данных. Если работаете с персональными данными российских пользователей - вопрос где физически хранятся данные о ваших инцидентах становится юридическим, а не техническим.</p><p>Мы в Flaree делаем страницу статусов именно для таких случаев - серверы в России, Telegram из коробки, оплата в рублях. Сейчас открыт ранний доступ, первые 50 команд получают 3 месяца Pro бесплатно: <a href="https://flaree.ru/">flaree.ru</a></p><h2>Что в итоге</h2><p>Страница статусов - это не инструмент для больших команд. Это инструмент для любого сервиса, у которого есть клиенты и бывают инциденты. То есть для всех.</p><p>Настройка занимает 15 минут. Первый же инцидент, который клиенты узнают из статусной страницы раньше, чем напишут в поддержку - окупает это время с запасом.</p><p>P.S. Если у вас уже есть страница статусов - напишите в комментариях какой инструмент используете. Интересно что прижилось у разных команд.</p>]]></content:encoded>
    </item>
    <item>
      <title>Большой гайд по DevOps от Tproger: инструменты, практики, автоматизация</title>
      <link>https://tproger.ru/articles/bolwoj-gajd-po-devops-ot-tproger--instrumenty--praktiki--avtomatizaciya</link>
      <comments>https://tproger.ru/articles/bolwoj-gajd-po-devops-ot-tproger--instrumenty--praktiki--avtomatizaciya?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/bolwoj-gajd-po-devops-ot-tproger--instrumenty--praktiki--avtomatizaciya</guid>
      <description><![CDATA[<p>Собрали всё, что нужно DevOps-инженеру: CI/CD, Kubernetes, серверлесс, безопасность, мониторинг и альтернативы Docker — практично и по делу.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/bolwoj-gajd-po-devops-ot-tproger--instrumenty--praktiki--avtomatizaciya">Большой гайд по DevOps от Tproger: инструменты, практики, автоматизация</a>»</p>]]></description>
      <category><![CDATA[Мобильная разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[DevSecOps]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 10 May 2025 10:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Собрали подборку наших лучших материалов для тех, кто строит пайплайны, следит за стабильностью и разворачивает сервисы в прод. Здесь — про Docker и Podman, Kubernetes, CI/CD, DevSecOps, serverless и всё, что нужно знать DevOps-инженеру в 2025 году. Сохраняйте, пригодится не раз.</p><h2>Инструменты и окружение</h2><p>Современные DevOps-инженеры без инструментов — как админ без терминала. Вот что стоит добавить в стек:</p><p><a href="https://tproger.ru/articles/top-10-instrumentov-devops--kotorye-uprostyat-vawu-zhizn-i-izbavyat-ot-nochnyh-relizov">Топ-10 инструментов DevOps, которые упростят вашу жизнь и избавят от ночных релизов </a>— Список лучших инструментов для DevOps-инженеров, которые упрощают релизы, мониторинг и CI/CD-процессы.  От логгирования до автоматизации тестов.</p><p><a href="https://tproger.ru/articles/podman-alternativa-docker">Podman: Альтернатива Docker без daemon</a> — Знакомим с Podman, инструментом, который не требует daemon, но дает весь функционал Docker.</p><p><a href="https://tproger.ru/articles/docker-hub-v-rossii---vse--gajd--kak-obojti-blokirovku">Docker Hub в России — всё? Гайд, как обойти блокировку</a> —Объясняем, как работать с Docker Hub после блокировки: альтернативы, зеркала и решения.</p><h2>CI/CD, Kubernetes и деплой</h2><p>Когда каждое изменение должно доходить до продакшена быстро и без боли — нужна хорошая сборка:</p><p><a href="https://tproger.ru/articles/razvorachivaem-instrumenty-ci-cd--praktiki-ot-devops-inzhenerov">Разворачиваем инструменты CI/CD: практики от DevOps-инженеров</a> — Практическое руководство по внедрению и настройке CI/CD: инструменты, примеры, лайфхаки.</p><p><a href="https://tproger.ru/articles/kubernetes-node-js-werf">Собираем и деплоим в Kubernetes приложение на Node.js с помощью werf </a>— Пошагово показываем, как собрать и развернуть приложение на Node.js в Kubernetes с помощью инструмента werf.</p><p><a href="https://tproger.ru/articles/avtomatizaciya-deploya-s-ispolzovaniem-kubernetes---tproger">Как автоматизировать деплой с использованием Kubernetes</a> — Рассказываем, как автоматизировать процесс деплоя приложений в Kubernetes: подходы, инструменты и советы.</p><p><a href="https://tproger.ru/articles/vybiraem-optimalnuyu-arhitekturu-monitoringa--ot-legkovesnogo-servisa-do-vysokonagruzhennyh-klasterov">Выбираем оптимальную архитектуру мониторинга: от легковесного сервиса до высоконагруженных кластеров </a>—Рассматриваем варианты мониторинга от минимальных решений до сложных систем, подходящих под высокие нагрузки.</p><h2>Практики и подходы</h2><p>Не только инструменты, но и культура разработки — основа DevOps:</p><p><a href="https://tproger.ru/articles/kak-stat-devops-v-2024-godu">Как стать DevOps в 2024 году</a> — Что нужно знать, какие навыки прокачивать, с чего начать.</p><p><a href="https://tproger.ru/articles/kak-avtomatizirovat-bezopasnost-s-pomoshhyu-devsecops-i-iskusstvennogo-intellekta">Как автоматизировать безопасность с помощью DevSecOps и искусственного интеллекта</a> — Объясняем, как применить DevSecOps-подход и AI для защиты приложений на всех этапах разработки.</p><p><a href="https://tproger.ru/articles/kak-serverless-tehnologii-pomogajut-snizit-nagruzku-na-razrabotchikov">Как serverless-технологии помогают снизить нагрузку на разработчиков</a> — Разбираемся, как serverless помогает ускорить разработку, упростить масштабирование и снизить поддержку инфраструктуры.</p><p>Не забывайте читать предыдущие гайды. <a href="https://tproger.ru/articles/bolwoj-gajd-po-python-ot-tproger--topovye-instrumenty-dlya-raznyh-napravlenij">Python</a>, <a href="https://tproger.ru/articles/bolwoj-gajd-po-react-ot-tproger--topovye-stati-i-instrumenty">React</a>, <a href="https://tproger.ru/articles/bolwoj-gajd-po-mobilnoj-razrabotke-ot-tproger--poleznye-stati--praktiki-i-sovety">мобильная разработка</a>, <a href="https://tproger.ru/articles/s----vse-samye-vazhnye-materialy-ot-tproger">С++</a>, <a href="https://tproger.ru/articles/bolwoj-gajd-po-instrumentam-dlya-razrabotchikov-ot-tproger--frejmvorki--bazy--ai-i-devops-v-odnoj-podborke">инструменты</a>, <a href="https://tproger.ru/articles/veb-razrabotka-i-frontend--gajd-ot-tproger">фронтенд</a>.</p><p>Кстати! Забрать все самые топовые нейронки для айтишников можно в нашем <a href="https://tprg.ru/LN8a">большом гайде с 70+ ИИ-инструментами </a></p>]]></content:encoded>
    </item>
    <item>
      <title>Highload-приложения: технологии для обработки больших объемов данных и запросов</title>
      <link>https://tproger.ru/articles/highload-prilozheniya-tehnologii-dlya-obrabotki-bolwih-obemov-dannyh-i-zaprosov</link>
      <comments>https://tproger.ru/articles/highload-prilozheniya-tehnologii-dlya-obrabotki-bolwih-obemov-dannyh-i-zaprosov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Synergy Academy]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/highload-prilozheniya-tehnologii-dlya-obrabotki-bolwih-obemov-dannyh-i-zaprosov</guid>
      <description><![CDATA[<p>Рассказали, что такое highload-система, как она справляется с большими нагрузками на сервер и о других важных аспектах данной области.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/highload-prilozheniya-tehnologii-dlya-obrabotki-bolwih-obemov-dannyh-i-zaprosov">Highload-приложения: технологии для обработки больших объемов данных и запросов</a>»</p>]]></description>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 14 Jul 2023 11:04:59 GMT</pubDate>
      <content:encoded><![CDATA[<p>Highload-системы являются сложной и интересной областью развития для программистов.</p><p>Представьте, вы заходите в крупный интернет-магазин, просматриваете рекомендации, выбираете товары, кладете их в корзину и оплачиваете. Для вас все это происходит как одно непрерывное действие, но для магазина это серия запросов: «загрузить контент», «добавить продукт в корзину», «обработать оплату» и так далее.</p><p>Если вы единственный пользователь магазина, то проблем не возникнет. Однако если тысячи клиентов решат одновременно что-то купить, то сервер получит в тысячи раз больше запросов. Для решения большого объема задач как раз используют highload-системы.</p><p>О том, что такое highload-система, как она справляется с большими нагрузками на сервер и о других важных аспектах данной области рассказал <i>Виктор Евдокимов, преподаватель Synergy Academy, Team Lead «Альфа-банка». </i></p><h2>Что такое highload-системы</h2><p>Четкого определения термина highload-систем не существует, но если говорить «простыми словами» — это системы, которые справляются с большой нагрузкой на сервер. В их архитектуру заложена работоспособность даже при резком увеличении нагрузки на сервер. Например, во время проведения «черной пятницы», когда тысячи пользователей посещают различные сайты и покупают большое количество товаров.</p><p>Highload-системы по сравнению с «обычными» приложениями требуют более сложной реализации и поддержки. «Обычные» приложения — когда не нужно сильно заморачиваться с масштабируемостью. И, понятное дело, такие системы намного понятнее и их быстрее разработать. Масштабируемость нужно закладывать только тогда, когда это действительно нужно.</p><h2>Виды нагрузок на систему и как с ними справляться</h2><p>Нагрузка на сайт или приложение — это количество запросов и операций, которые требуется обработать серверу. Они могут быть вызваны активностью пользователей, такой как просмотр страниц, отправка форм, загрузка контента, оформление заказа.</p><p>Нагрузка может включать в себя различные факторы, такие как:</p><ul><li>Количество пользователей.</li><li>Объем данных.</li><li>Время ответа от «нижележащих» систем.<br />Например, чтобы вернуть ответ пользователю, нам нужно сходить в сторонний сервис геолокации.</li><li>Безопасность.<br />Проверка и аутентификация пользователей, обработка запросов на безопасность, шифрование данных и другие меры защиты могут создавать дополнительную работу на сервера.</li></ul><h2>Способы решения задач с большими нагрузками</h2><p>Универсального решения не существует. Можно выделить несколько распространенных методов.</p><h3>Реплицирование</h3><p>Это увеличение количества экземпляров программы, создание дополнительных  «копий» серверов или баз данных. Это позволяет сбалансировать нагрузку между ними, а также увеличивает отказоустойчивость и обеспечивает высокую доступность системы.</p><h3>Шардинг</h3><p>Это распределение нагрузки между экземплярами программы по ключу.</p><p>Например, по ID пользователя: в адресе http-запроса указывать айди пользователя — GET users/100500, далее по этому ID распределять нагрузку, например, все четные айдишники на первый сервер, нечетные — на второй.</p><h3>Кэширование</h3><p>Кэширование информации в оперативной памяти. К оперативной памяти доступ быстрее, чем к базе данных или куда-то на жестком диске. Это позволяет снять нагрузку с базы данных.</p><h3>Оптимизация базы данных</h3><p>Работа с базой данных является ключевым аспектом производительности сайта или приложения. Использование индексов, кэширование запросов, разделение информации, горизонтальное или вертикальное масштабирование помогают улучшить производительность базы данных.</p><h2>Заключение</h2><p>Highload-системы — это естественный путь развития программиста, которому интересно узнать, как это работает. Данные системы позволяют задуматься о том, как происходит обработка запросов, какие ресурсы необходимы для этого и почему. При возникновении конкретных задач придется углубляться в эту тему. Например, инженер по сопровождению может спросить, какое количество оперативной памяти потребуется для вашего приложения в продакшене. Все это требует хорошего понимания вашей системы и умения работать с ней.</p>]]></content:encoded>
    </item>
    <item>
      <title>Курс молодого бойца: ускоряем проекты на Битрикс, повышаем их отказоустойчивость</title>
      <link>https://tproger.ru/articles/kurs-molodogo-bojca-uskorjaem-proekty-na-bitriks-povyshaem-ih-otkazoustojchivost</link>
      <comments>https://tproger.ru/articles/kurs-molodogo-bojca-uskorjaem-proekty-na-bitriks-povyshaem-ih-otkazoustojchivost?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[AGIMA]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kurs-molodogo-bojca-uskorjaem-proekty-na-bitriks-povyshaem-ih-otkazoustojchivost</guid>
      <description><![CDATA[<p>Для проджектов и джуниор-разработчиков подготовили гайд по тому, как ускорить работу проектов на Битрикс и повысить их отказоустойчивость.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kurs-molodogo-bojca-uskorjaem-proekty-na-bitriks-povyshaem-ih-otkazoustojchivost">Курс молодого бойца: ускоряем проекты на Битрикс, повышаем их отказоустойчивость</a>»</p>]]></description>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[1C-Bitrix]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Гостевая публикация]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 13 Sep 2022 07:42:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет! На связи Данила Соловьев, руководитель направления PHP в AGIMA. Для проджект-менеджеров и джуниор-разработчиков я подготовил небольшой гайд по тому, как ускорять работу крупных проектов на Битрикс и повышать их отказоустойчивость. Здесь вы не найдете сложных кейсов или сногсшибательных решений. Но зато найдете простые и применимые советы.</p><h2>Как читать эту статью</h2><p>Речь пойдет о проектах на Битриксе уровня Enterprise. Некоторые рекомендации будут справедливы и для других PHP-фреймворков и стеков веб-разработки.</p><p>Но самое главное: все мы понимаем, что проект в первую очередь нужно реализовать. Уже на этом этапе разработчики продумывают, насколько быстро будет работать система и что ей в этом поможет. Но предусмотреть абсолютно всё невозможно. Эта статья поможет разобраться, как ускорить уже запущенный проект.</p><p>Каждый раздел этого текста — это архитектурный блок. Чтобы приложение летало, поработать можно со всеми сразу или с одним из них. Я выделил 5 блоков:</p><ol><li>Сам Битрикс и всё, что написано на PHP/HTML/CSS/JS поверх.</li><li>Базы данных: из коробки в Битриксе это MySQL.</li><li>Кэш.</li><li>Интеграция с другими системами.</li><li>Файловая система.</li></ol><p>Внутри каждого блока чек-лист с комментариями или просто список советов. Прочитаете — будете лучше понимать своего тимлида. А может, при случае и подскажете ему что-нибудь.</p><h2>Как ускорить проект на уровне Битрикс и PHP/HTML/CSS/JS</h2><h3>1. PHP</h3><h4>а. Использовать готовые библиотеки</h4><p>Все библиотеки под решение конкретных задач отлаживаются и версионируются разработчиками не за час и не за неделю. Это большой труд, и все решения прорабатываются годами. У них есть команда поддержки. Поэтому их нужно использовать — это повысит отказоустойчивость проекта.</p><p>Для работы с библиотеками и зависимостями используйте <a href="https://getcomposer.org/">composer</a>.</p><h4>b. Профилировать код в серьезных проектах</h4><p>Профилировщик собирает данные о том, с какой скоростью и какая функциональность на странице выполняется. Эти данные помогают разработчику и тимлиду на конкретной странице находить узкие места — те, что замедляют общее время загрузки.</p><h4>c. Пропускать самописный код через статические анализаторы</h4><p>Какой бы крутой ни была команда разработчиков, ошибки бывают у всех. Анализаторы страхуют всю команду от опечаток или мелких ошибок, которые бы серьезно сказывались на работе всего проекта.</p><h3>2. HTML/CSS/JS</h3><h4>a. Верстку и фронтовую часть делать на сборщике</h4><p>Если верстка изначально оптимизирована и сжата, изъяны искать будет проще. Скорее всего, они будут на стороне Backend-разработчиков. <a href="https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&amp;LESSON_ID=12435">Полезная ссылка</a>.</p><h3>3. Тестирование</h3><h4>a. Не забывать о тестировании</h4><p>Если проект реально большой, то без тестировщиков никуда. Важно, чтобы они внедряли смоки, регрессы и отлаживали процесс тестирования. Благодаря этому в прод уйдет меньше багов. И значит, у разработчиков будет больше времени, чтобы заниматься ускорением проекта и повышением отказоустойчивости.</p><h3>4. Bitrix</h3><h4>a. Помнить про ресайз картинок</h4><p>Представим сайт с инфоблоком «Новости». В одну из них загрузили картинку на 15 Мб. Без ресайза сеть будет подтягивать ее полностью, страница будет грузиться долго. Это скажется на индексации. Конечный пользователь получит очень долгий рендер.</p><h4>b. Использовать d7 и ORM</h4><p>Менеджерам сложно это проконтролировать, но знать полезно. Эти две технологии ускоряют проект примерно в 5 раз — моя личная статистика.</p><h4>c. Переносить как можно больше с инфоблоков на HLB</h4><p>Переносить на HighLoad-блоки нужно всё, что возможно. Особенно, если вам не нужен какой-то очень удобный контент-менеджмент из админки. А лучше вообще проектировать свои таблицы и решения. Особенно это касается автоматизированных интеграций.</p><h4>d. Кэшировать одинаковые данные на одном хите</h4><p>Объясню на примере. Допустим, на страницу выводятся баллы из системы лояльности. Выводятся они как в начале страницы, так и в конце. Чтобы не делать два запроса в процессе загрузки, можно сделать только первый. Дальше баллы нужно закэшировать на уровне PHP, а потом из кэша в оперативной памяти достать и отобразить в нижней части страницы. Так мы урезаем запрос и уменьшаем время рендера страницы.</p><h4>e. Архивировать устаревшие данные</h4><p>Если у вас хранятся данные 2015 года, а вы живете в 2022, то возможно, эти данные устарели. Желательно унести их куда-то в другое место и доставать только при необходимости.</p><h4>f. Учитывать агенты и их ограничение по времени</h4><p>Агенты — фоновые задачи. У них есть ограничение по времени — 10 минут. Поэтому, если тимлид говорит: «Мы будем вот эту выгрузку выполнять на агенте, которая содержит миллионы строк данных», — это плохая идея. Как сделать, чтобы выгрузка постоянно не падала, расскажу дальше.</p><h2>Как ускорить на уровне баз данных</h2><h3>1. Разносить базы данных и приложение на разные «машины»</h3><p>В идеальном мире работа Битрикс и PHP не связана с ресурсами, которые используют базы данных. Так вы распределите нагрузку на эти части системы.</p><h3>2. Использовать в базах индексы</h3><p>Индексы — это данные из таблиц, отсортированные по конкретным столбцам, по которым построен индекс. Благодаря им в базе работает бинарный поиск. Проще говоря, поиск идет не по каждой строчке. Вместо этого система делит таблицу на две равные части. Смотрит влево, смотрит вправо. Если влево не найдено — то вправо. Правая часть тоже делится пополам и т. д.</p><p>Если данные в таблице обновляются/создаются/удаляются намного чаще, чем выполняется их чтение, то использовать индексы не стоит. Этот вариант подходит в случае, если на сайте есть новости с фильтрацией. Фильтрация с помощью индексов будет работать быстрее.</p><h3>3. Использовать репликации</h3><p>Репликация — это механизм создания копий базы данных, которые синхронизируются с оригиналом. Копии бывают двух типов: Master и Slave. Если копия Master, то мы в ней можем и писать, и читать. А если Slave — только читать. Изменения с Master тиражируются на все копии. Реализуется этот механизм на стороне СУБД, ничего программировать не надо.</p><p>Полезно применять в случаях, когда у вас на стороне заказчика есть аналитики или системы, которые хотят читать данные в вашей базе. Вы можете сделать отдельную Slave-реплику только для аналитиков. Они будут делать сложные запросы, которые могут уронить всю базу. Но упадет она только для них.</p><h3>4. Использовать партиции</h3><p>Партиции помогут, если у вас одна большая таблица на проекте. Партиция — это принцип деления таблицы на основании какого-то фильтра. Например, по дате. Когда таблица очень большая, это поможет разделить нагрузку и повысить отказоустойчивость. Этот механизм тоже реализуется на стороне СУБД.</p><figure><img src="https://media.tproger.ru/uploads/2022/09/unnamed.png" alt="" /></figure><h3>5. Применять шардирование</h3><p>В этом случае нужна работа программиста. Шардирование — это вариант распределения нагрузки. Он похож на партиции: тоже деление таблиц по какой-то логике.</p><p>Например, можно шардировать фотографии пользователей. Все фотографии нечетных пользователей уходят в одну шарду, четных — в другую.</p><h2>Как ускорить проект на уровне кэша</h2><p>Кэш нужен, чтобы снять нагрузку с баз данных. В Битриксе «из коробки» разные типы кэша. Я перечислю плюсы и минусы самых популярных. Но отдельно подчеркну: все эти решения разгружают базу данных. Это их основная функция.</p><h3>1. Файловый кэш</h3><h4>Плюсы</h4><ul><li>Объем не ограничен: если ваш жесткий диск на терабайт, он будет наполняться кэшем, пока вы полностью его не забьете.</li><li>Персистентный: если у вас падает какая-то «машина», закэшированные данные не теряются — как лежали на диске, так и продолжают лежать.</li></ul><h4>Минусы</h4><ul><li>Самый медленный из всех типов.</li><li>Генерирует нагрузку на ту же файловую систему, потому что лежит на жестком диске.</li></ul><h3>2. Memcached</h3><h4>Плюсы</h4><ul><li>Очень быстрый.</li></ul><h4>Минусы</h4><ul><li>Не персистентный: работает в оперативной памяти — если «машина» упала, то кэш потерян.</li><li>Ограничен объемом выделенной под него оперативной памяти.</li></ul><h3>3. Redis</h3><h4>Плюсы</h4><ul><li>Быстрый.</li><li>Может быть персистентным: его можно сконфигурировать как персистеным, так и не персистентным. Но если персистентный, то работает медленнее.</li></ul><h4>Минусы</h4><ul><li>Небольшой объем.</li></ul><h3>Еще один способ — прогрев кэша</h3><p>Он подходит в случаях, когда на проекте могут собираться большие объемы кэша. Допустим, он собирается по городам — на каждый город свой кэш. Это увеличивает его объем. Когда вы задеплоили что-то, для чего потребуется его сброс, можно внедрить ручной или автоматизированный прогрев кэша.</p><p>Ручной: после сброса кэша запускаете тестировщика, и он меняет города; можно менять только основные, потому что с них будет больше всего потока и нагрузки.</p><p>Автоматизированный: это можно повесить на CI/CD и просто написать какие-то функциональные тесты, которые будут после деплоя ходить и медленно переключать города и собирать кэш.</p><h2>Как ускорить на уровне интеграций с другими системами</h2><p>В первую очередь я говорю о интеграциях типа «точка — точка»: REST, SOAP. Они работают просто и понятно: одна система отправила запрос, ждет. Вторая система приняла запрос, обработала, отдала ответ. Отправляющая система ждать перестала, обработала ответ, пошла дальше.</p><p>Более важная тема — брокеры сообщений и менеджеры очередей. Их мы можем применить вместо REST и SOAP. Примеры брокеров сообщений — Kafka, RabbitMQ. Вот чего они позволяют добиться:</p><h3>1. Асинхронность</h3><p>Система отправляет запрос в брокер и дальше занимается своими делами — ответ она заберет в фоновом режиме. Система не забивает память этим запросом: на ее стороне есть обработчик, он же консьюмер, который читает и обрабатывает ответы по одному.</p><h3>2. Гарантия доставки</h3><p>В случае с REST, когда ваша система отправляет запрос, а вторая система лежит, пользователь получает 500 ошибку. В случае с брокерами вы всегда дождетесь ответа от другой системы. Кроме тех случаев, когда ваш брокер лежит. Но это критическая проблема — сейчас речь не об этом.</p><h3>3. Уменьшение нагрузки на отправляющей и на принимающей стороне</h3><p>Когда у вас «точка — точка», системе тяжелее. Например, 5 млн пользователей одновременно зашли на сайт и вызвали одно и то же интеграционное действие. Ваша система ждет 5 млн ответов. Другая система обрабатывает 5 млн запросов. Брокер же принимает запросы и отдает ответы быстро. Он записывает запрос, отдает в другую систему. Там консьюмер читает и обрабатывает по одному сообщению в фоне. Всё это не занимая ресурсов на 5 млн запросов.</p><h3>4. Ускорение постоянных и многочисленных однотипных фоновых действий</h3><p>Если у вас на проекте много логирования, количество посетителей и файлов записей растет, всё это можно перевести на брокер. Система такая: ваш лог сначала пишется в брокер, а дальше в вашей же системе имеется консюмер, который читает из брокера и записывает в хранилище с логами, но не генерирует такого количества нагрузки.</p><h3>5. Решение продолжительных фоновых задач</h3><p>Например, если на проекте генерируется больше событий, чем агент успевает обработать за 1 раз, агент падает. В лучшем случае просто не успевает обрабатывать очередь поступающих заявок. С брокерами проще: заявки передаются им, а потом обрабатываются в другом месте без ограничения по времени.</p><h2>Как ускорить на уровне файловой системы</h2><p>Файловая система работает как база знаний: в ней есть операции чтения и записи. За этим показателем важно следить и уменьшать его на каждой конкретной «машине». Вот два параметра, на которые стоит обращать внимание:</p><h3>1. Статика минимизирована и оптимизирована</h3><p>Статический контент — то, что запрашивается при каждом запросе, если он не был закэширован в браузере. К такому контенту относится CSS, JS, дефолтные картинки типа логотипов компаний. В идеале они должны быть минимизированы, оптимизированы и куда-нибудь убраны — например, в CDN.</p><h3>2. Динамический контент и медиа в S3-хранилище</h3><p>S3-хранилище — это облачное хранилище, которое гарантирует, что ваши данные будут отдаваться, храниться, не пропадать и т. д. С помощью него вы разгрузите файловую систему: файлы при рендере страницы в браузере будут подтягиваться из хранилища, а не с вашего сервера.</p><p>Эти рекомендации сделают вашу систему более быстрой и отказоустойчивой. Разработчики применяют их в работе — но знать о них полезно всей команде. В следующий раз, когда покажется, что ваш проект на Битриксе работает медленно, спросите у тимлида, все ли способы ускорения он использовал.</p><p>Если есть вопросы, задавайте в комментариях. Я по-прежнему на связи!</p>]]></content:encoded>
    </item>
    <item>
      <title>Нагрузочное тестирование: особенности профессии</title>
      <link>https://tproger.ru/articles/nagruzochnoe-testirovanie-osobennosti-professii</link>
      <comments>https://tproger.ru/articles/nagruzochnoe-testirovanie-osobennosti-professii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/nagruzochnoe-testirovanie-osobennosti-professii</guid>
      <description><![CDATA[<p>Что стоит за нагрузочным тестированием в России и почему это направление требует более широкого технического кругозора, чем принято думать о тестировании.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/nagruzochnoe-testirovanie-osobennosti-professii">Нагрузочное тестирование: особенности профессии</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 28 Jan 2021 10:22:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>В этой статье я расскажу про нагрузочное тестирование. Сейчас в России эта специальность стала уже не столь экзотической, как лет 15-20 назад. Но все равно, даже когда доводится собеседовать выпускников ведущих вузов страны (МГУ, МГТУ, МАИ, МИРЭА), редко можно услышать внятный ответ на вопрос «Что такое нагрузочное тестирование?». Студенты знают, что есть программисты, аналитики, в лучшем случае – слышали про существование тестировщиков. И к роли последних отношение весьма скептическое: дескать, низкоквалифицированная работа для неудачников. А о том, что есть вид тестирования, более требовательный к техническому кругозору специалиста, чем в разработке, почти никто не догадывается. Попробуем исправить эту несправедливость.</p><h2>Что такое тестирование и его место в процессе разработки ПО</h2><p>Сначала несколько слов о тестировании вообще.</p><p>Сегодня вряд ли найдется столь смелый руководитель проекта или заказчик, который не озаботится организацией тестирования разрабатываемого продукта. И чем более зрелый процесс разработки, тем больше внимания уделяется тестированию. И ведь это лишь один из инструментов обеспечения качества! А в него входят и аудиты, и выстраивание процессов разработки… Но это уже отдельная тема, на которую написана не одна книга.</p><p>Если кратко сказать, что же такое тестирование, то это проверка продукта на соответствие требованиям. В идеальном упрощенном случае заказчик с помощью бизнес-аналитиков формулирует требования, системные аналитики вместе с архитекторами переформулируют их в технические задания, разработчики пишут код, а тестировщики проверяют, соответствует ли то, что написано, требованиям.</p><p>Интуитивно понятно, что требования могут быть совершенно различными, а значит, будут отличаться важность и трудоемкость их проверки. Например, одно дело проверить требование «В правом верхнем углу экрана должна быть кнопка с крестиком, при нажатии на которую приложение закрывается» или «Фон главного экрана программы должен быть розового цвета», и совсем другое дело проверить требование «Система должна обслуживать 10 000 одновременно работающих пользователей и время реакции системы на их действия не должно превышать 3 секунды».</p><h2>Отличие нагрузочного от других видов тестирования</h2><p>Как требования отличаются друг от друга, так и виды тестирования, необходимые для их проверки, будут отличаться по приоритету, объему работ и квалификации выполняющего их персонала.</p><p>Для примера рассмотрим три наиболее распространенных вида тестирования: функциональное (ФТ), автоматизированное функциональное (АФТ) и нагрузочное (НТ).</p><p>Ручное функциональное тестирование (ФТ) – бесспорно, основной вид, и без него не обходится практически ни один проект разработки программного обеспечения. С него, как правило, начинается проверка новой системы, и уже потом наступает время АФТ и НТ. Основные навыки специалистов по ФТ – умение разобраться в документации и функциональности тестируемого продукта, составление и выполнение тестовых сценариев. Порог вхождения в такую специальность достаточно низкий: не требуется навыков программирования или опыта работы в ИT, достаточно уверенного пользования компьютером, пытливого ума и аккуратности. Среди людей, пришедших в ручное тестирование, я лично встречал не только выпускников технических вузов, но и бывших операционистов банка, учителей начальных классов и даже фельдшеров. Именно поэтому появился миф, что ФТ – это низкоквалифицированная работа для неудачников. А ведь опытный тестировщик совмещает в себе навыки и аналитика, и менеджера, и разработчика. И работать ему приходится со множеством инструментов разработки, тестирования, администрирования, багтреккинга и даже писать код на SQL или Python.</p><p>Автотестирование (АФТ) – работа на стыке разработки и тестирования. Специалисты АФТ автоматизируют рутинные или объемные проверки функционального тестирования. Они не только обладают основными навыками ФТ, но и пишут много кода на различных языках (Java, C#, Python, Scala…). Этим тестировщикам не требуется настолько широко охватывать функциональность продукта, как в ФТ, но зато каждый из них достаточно глубоко погружается в логику работы и реализацию того фрагмента, тестирование которого он автоматизирует. В каком-то смысле работников АФТ можно назвать «программистами в тестировании», и порог вхождения в профессию достаточно высок. К базовым навыкам можно отнести опыт объектно-ориентированного программирования (ООП) и уверенное владение SQL. А через несколько лет работы специалист АФТ осваивает несколько языков программирования, специальные инструменты автоматизации, фреймворки и уверенно интегрирует свой код в процесс разработки, обладая навыками CI/CD и DevOps.</p><p>Нагрузочное тестирование (НТ) стоит особняком. Оно позволяет проверить такие нефункциональные требования к системе, как производительность, стабильность, масштабируемость, стрессо- и отказоустойчивость. На первый взгляд, в нем немного меньше глубина погружения в функционал и реализацию тестируемой системы, и в этом смысле НТ находится между ФТ и АФТ. Но при более детальном рассмотрении оказывается, что специалист по НТ совмещает в себе навыки нескольких профессий. Во-первых, он должен быть немного архитектором, чтобы разобраться в устройстве продукта, понять его связи с другими системами и определить источники нагрузки. Во-вторых, ему часто приходится выполнять роль аналитика, чтобы разобраться со специфическими нефункциональными требованиями к системе и составить модель тестирования. В-третьих, от него требуются навыки администрирования: серверов и баз данных до операционных систем и инструментов мониторинга. В-четвертых, специалист НТ должен уметь программировать. Причем набор языков может быть самым разным: от С и Python до Java и Scala. Это обуславливается используемыми инструментами НТ и стеком технологий тестируемой системы. Приходится писать как собственно скрипты, моделирующие нагрузку, так и эмуляторы смежных систем («заглушки»), разного рода генераторы тестовых данных и парсеры. Но, в первую очередь, специалист по НТ должен быть тестировщиком, то есть мыслить категориями проверки системы на соответствие требованиям. Явно указанным или соответствующим здравому смыслу. По объему задачи НТ условно можно поделить на три равные части:</p><ol><li>Аналитика и архитектура с написанием документации (методика и отчеты НТ).</li><li>Администрирование с настройкой мониторинга и системы на стенде НТ.</li><li>Программирование (скрипты, «заглушки», парсеры…).</li></ol><p>Таким образом, от специалиста по НТ требуются довольно противоречивые навыки: он должен быть аккуратен и внимателен, чтобы разбираться с технической документацией; усидчив, чтобы разбирать по логам и графикам причины проблем производительности; уметь неплохо программировать и при этом иметь широкий кругозор по ИT-технологиям. В области НТ, в отличие от ФТ и АФТ, очень большой разброс по квалификации специалистов, а значит и много возможностей для профессионального роста. При среднем пороге вхождения (требуются опыт программирования на любом языке, знание SQL и общее понимание сетевых технологий, которые даются в технических ВУЗах) за 2-3 года работы с различными системами специалист по НТ осваивает несколько языков программирования на уровне написания скриптов и «заглушек», погружается в устройство БД и особенности различных архитектурных решений от монолитов до микросервисов, осваивает различные инструменты НТ и мониторинга, повышает уровень владение SQL. Все это дает множество направлений для развития технических навыков.</p><p>При всех перечисленных различиях между типами тестирования у этих видов деятельности есть общие особенности: все они проверяют тестируемую систему на соответствие требованиям. Отличаются только цели и процесс.</p><h2>Цели и процессы нагрузочного тестирования</h2><p>Как и в любом тестировании, цели и процесс НТ вытекают из требований к тестируемой системе и зависят от организации разработки.</p><p>Примеры целей НТ:</p><ul><li>определение максимальной производительности на имеющемся оборудовании (в частности, позволяет понять, сколько пользователей сможет обслуживать разрабатываемая система);</li><li>проверка стабильности (например, отсутствие утечек памяти на сервере и его стабильная работа в течение длительного времени, что особенно важно для систем 24/7);</li><li>проверка масштабируемости (к примеру, после добавления еще одного сервера или оперативной памяти система сможет обслуживать большее число пользователей, когда вырастет количество клиентов);</li><li>проверка стрессоустойчивости (если система сама восстанавливает свою работоспособность даже после сверхвысокой нагрузки, например, при наплыве клиентов в «черную пятницу»).</li></ul><p>Для достижения каждой цели НТ нужно провести один или несколько тестов, при этом каждый из них может выполняться от нескольких минут до нескольких суток (например, тест проверки стабильности). Перед каждым тестом производится подготовка тестового стенда к нагрузке, а после выполняется анализ собранной информации (графики, таблицы, логи), делается заключение о том, успешно ли прошел тест, удовлетворяет ли система заявленным требованиям. Все это – «вершина айсберга» работ по НТ, а сам процесс может занимать от нескольких недель, до нескольких месяцев.</p><p>Различные варианты процессов НТ можно условно свести к двум:</p><ol><li>Нагрузочное тестирование внедрено в общий жизненный цикл продукта и выполняется на постоянной основе с каждым релизом системы. Команда НТ является частью общей команды разработки.</li><li>Нагрузочное тестирование выполняется разово по заказу владельца продукта и часто представляет из себя отдельный проект со своим бюджетом, планом работ и командой.</li></ol><p>В зависимости от варианта процесса меняется организация работ и взаимодействие в команде, формат документации, но при этом основные этапы сохраняются:</p><ol><li>Анализ системы (или внесенных в нее изменений).</li><li>Подготовка или актуализация модели нагрузки и методики НТ (основополагающего документа в процессе).</li><li>Подготовка или обновление стенда НТ.</li><li>Разработка или актуализация скриптов НТ, «заглушек», скриптов генерации тестовых данных.</li><li>Настройка мониторинга на стенде НТ.</li><li>Сборка и отладка всего, что разработали, на стенде НТ.</li><li>Проведение необходимых тестов.</li><li>Анализ результатов тестов.</li><li>Подготовка отчетности.</li></ol><p>И на каждом из перечисленных этапов требуются те или иные навыки специалиста по НТ.</p><h2>Основные навыки специалистов по нагрузочному тестированию</h2><p>Как уже было сказано выше, работа в НТ требует разностороннего развития. Ниже приведу «джентельменский» набор навыков для уровня «middle+», т.е. среднего самостоятельного специалиста, способного в одиночку вести не слишком сложный проект НТ:</p><ul><li>Умение читать и писать техническую документацию (технические задания, методика НТ, отчеты).</li><li>Умение вести переговоры — как телефонные, так и в переписке (приходится часто общаться с заказчиком и другими членами команды).</li><li>Навыки программирования (конечно, не на уровне разработчика системы, но на различных языках, позволяющих решить необходимую задачу наиболее оптимальным способом).</li><li>Навыки администрирования серверов приложения и баз данных (настройка стенда НТ, сбор логов и статистики).</li><li>Навыки установки и поддержки средств мониторинга (без сбора информации о состоянии системы под нагрузкой ценность тестирования сводится к минимуму).</li><li>Понимание архитектуры различных интеграционных решений и сетевых технологий (для построения модели нагрузки с учетом всех ее источников по различным протоколам обмена).</li><li>Знание основ математической статистики (необходимо для обработки статистики, расчета профиля нагрузки и обработки результатов тестов).</li><li>И, пожалуй, главный навык – умение искать необходимую информацию в интернете, т.к. почти каждый новый проект НТ вынуждает осваивать какую-нибудь новую технологию или заставляет искать решение проблем, с которыми ранее не сталкивались. Тут пригодится знание технического английского, без него будет сложно и при освоении новых инструментов НТ.</li></ul><p>Конечно, не все эти навыки приобретаются сразу, и это далеко не полный их перечень. Но он позволяет понять, в каких направлениях приходится развиваться почти всем, кто связывает свою жизнь с нагрузочным тестированием.</p><h2>Популярные инструменты нагрузочного тестирования</h2><p>Если в функциональном тестировании еще можно обойтись без специальных инструментов, то в АФТ и НТ необходимы программы, позволяющие не только разрабатывать скрипты, но и выполнять их, проводя тестирование.</p><p>Еще лет десять назад в российском ИT господствовали enterprise-решения для НТ. Как следствие, данный вид тестирования на необходимом уровне могли себе позволить только крупные компании с большими бюджетами. Остальные довольствовались немногочисленными бесплатными opensource-решениями с «сырым» кодом, бедным функционалом и слабой поддержкой. Но время шло, дефекты этих инструментов исправлялись, а благодаря развитию сообществ, занимающихся нагрузочным тестированием, появилось настолько много расширений, библиотек и интеграций с другими инструментами, что возможности некоторых бесплатных решений сравнялись с функционалом платных. А отсутствие официальной поддержки с лихвой компенсируется форумами и чатами сообществ.</p><p>Поэтому на текущий момент список популярных инструментов для НТ по большей части состоит из бесплатных решений за исключением нескольких «динозавров»:</p><figure><img src="https://media.tproger.ru/uploads/2021/01/table1.png" alt="" /></figure><p>Подчеркну, что это перечень инструментов, позволяющих создавать скрипты НТ и выполнять тесты.</p><p>Кроме этого приходится пользоваться различными дополнительными средствами:</p><figure><img src="https://media.tproger.ru/uploads/2021/01/table2.png" alt="" /></figure><p>Данный список далеко не полный, но позволяет ознакомиться с наиболее популярными инструментами, которые используются специалистами НТ, и оценить необходимые знания в этой области.</p><h2>Путь специалиста по нагрузочному тестированию от школы обучения до тимлида</h2><p>Как было сказано ранее, перечисленные навыки и инструменты невозможно освоить сразу, тем более без реального опыта на проектах и задачах. Как же попасть в нагрузочное тестирование? В вузах такую специальность не дают, можно ли самому освоить профессию?</p><p>Конечно, при наличии хорошей образовательной базы (по специальности программирование, системы и сети, прикладная математика) можно начать изучать инструментарий и теорию. Но основная проблема, с которой придется столкнуться, это отсутствие возможности создать полноценную среду для НТ (стенд с развернутой системой для тестирования и мониторингом). Поэтому наиболее рационально будет пройти обучение на специальных курсах. Многие аутсорсинговые компании предлагают программы подготовки, позволяющие получить необходимые навыки и опыт с последующим трудоустройством. Тем самым, они пополняют свой штат, в том числе выпускниками технических вузов. Аналогичная школа обучения по специальности НТ работает с 2016 года и в нашей компании.</p><p>Обычно курсы идут 4-5 недель и включают в себя теоретическую часть, позволяющую разобраться в целях, методологии и процессе тестирования, и практическую, куда входит освоение 1-2 инструментов НТ и средств мониторинга. Ученики получают практические навыки: от разработки методики и скриптов до проведения тестов и подготовки отчета. Задачи выполняются на мощностях компании, предоставляющей обучение. Уроки ведут действующие специалисты по НТ, готовые поделиться своим опытом с реальных проектов. Выпускники школы НТ проходят стажировку уже на действующих проектах под присмотром наставников и по результатам выпускного экзамена зачисляются в штат компании на позицию младших специалистов по нагрузочному тестированию.</p><p>Дальнейшая карьера зависит исключительно от способностей и настойчивости. Среднестатистический выпускник курсов, поработав на 2-3 проектах, достигает уровня middle за 1.5 года, а звание senior можно получить уже на третьем году работы. При этом важно, что специалистам НТ предоставляется возможность менять проекты, осваивая различные технологии и инструменты, заниматься наставничеством выпускников школы обучения и принимать участие в преподавательской деятельности. Тем самым компания выращивает столь важное звено тимлидов, а сотрудникам дает шанс реализовать свой технический и управленческий потенциал.</p><h2>Вместо заключения</h2><p>Надеюсь, данная статья внесет немного ясности в то, что такое нагрузочное тестирование, чем занимается данный специалист, и поможет развеять миф, что тестирование – это для тех, кто не умеет программировать. Как видим, специальность нагрузочное тестирование дает широчайший кругозор и бескрайнее поле для развития технического специалиста. Здесь никогда не бывает скучно!</p>]]></content:encoded>
    </item>
    <item>
      <title>Почему не hadoop: создаём свое решение на node + mongo + lxd</title>
      <link>https://tproger.ru/articles/highload-mongo-node-lxd</link>
      <comments>https://tproger.ru/articles/highload-mongo-node-lxd?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/highload-mongo-node-lxd</guid>
      <description><![CDATA[<p>Клиент рассчитывал применить Hadoop для отчётов объёмом более 100 тысяч строк, каждый из которых создавался от 12 до 24 часов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/highload-mongo-node-lxd">Почему не hadoop: создаём свое решение на node + mongo + lxd</a>»</p>]]></description>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Aug 2020 07:50:29 GMT</pubDate>
      <content:encoded><![CDATA[<p>Иногда к нам приходят клиенты с уже определенным стеком технологий для своего проекта. Так было и в этот раз. Клиент хотел проект по обработке больших объемов данных, твердо уверенный, что Hadoop это серебряная пуля.</p><p>Disclaimer В данной статье речь пойдет о проекте которому на текущий момент около трех лет. Некоторые решения, в том числе и выбор технологий обуславливался временем разработки.</p><p>Клиенту нужно было регулярно проводить электронную инвентаризацию оборудования, каждый отчет по такой инвентаризации содержал более 100k строк. Клиент видел лишь одну проблему — отчеты генерировались слишком долго (в районе 12 часов – 24 часа на каждый отчет). По мнению клиента, эта проблема вытекала из следующих факторов:</p><ul><li>Используется неподходящая СУБД. MongoDB не может в много данных и их обсчет. В результате этого, сложный анализ этих данных занимал слишком много времени и памяти.</li><li>Выходной формат отчетов — excel (xlsx). Для этого использовались скрипты на Node.js, каждый из которых выдавал отчет в своем виде. При построении таких отчетов, оперативная память заполнялась (~8Гб) и любое обращение к базе данных —  MongoDB просто падало с ошибкой.</li></ul><p>Задача: Поднять Hadoop кластер, настроить миграцию данных из БД Клиента и обработку этих данных средствами Hadoop.</p><p>На тот момент времени, у Hadoop была очень слабая поддержка, неразвитая инфраструктура, длительное время не было обновлений и неполная документация. Это всегда накладывало свой отпечаток на время и стоимость проекта.</p><p>Примечание На текущий момент, Hadoop имеет более дружелюбную инфраструктуру, благодаря docker и k8s.</p><p>При анализе необходимых действий для того, чтобы перенести все необходимые данные в Hadoop, мы выявили что мало того, что данные не имеют четкой структуры, так и в некоторых местах существенно различаются по типу и свойствам (спасибо Mongo за гипергибкость, которая попадает в руки не заботящихся о проектировании данных людей). Ну и в чем проблема, спросите вы. А проблема заключается в том, что Hadoop это SQL-based система. Т.е. все интерфейсы взаимодействия с данными идут через структурированный SQL. И у нас нет возможности мигрировать в эту систему данные без схемы, типов и прочего.</p><p>Для того чтобы нормально проработать схемы данных, потребовалось бы очень много времени. А клиенту нужно было как можно скорее. Поэтому на очередной сессии мозгового штурма, мы выделили какие есть проблемы на наш взгляд и придумали как можно их решить.</p><p>После глубокого исследования, мы составили свой список причин, почему у них проблема с производительностью:</p><ul><li>Нет четкой схемы данных в БД. Это приводит к тому, что агрегации должны выполнять больше количество действий для расчета результата.</li><li>В текущей БД свалка данных. При разработке системы, которая генерировала эти данные, формат меняли несколько раз, при этом сама БД никогда не очищалась. В результате чего, операции обсчета документов выполнялись даже над теми документами, которые не соответствуют нужной схеме.</li><li>Часть логики по обработке данных было перенесено на сторону Node.js.</li><li>Отчеты генерировались в памяти, и после полной генерации сохраняли это все в excel файл (естественно, когда данных много, оперативной памяти не хватает и вся система рушится).</li></ul><p>А также придумали как эти проблемы решить.</p><ul><li>За архитектурную модель мы взяли принцип по которому работают все распределенные системы, в том числе Hadoop. (Есть один мастер и несколько агентов.)</li><li>Мастер управляет нагрузкой и взаимодействием с внешним миром.</li><li>Каждый из агентов выполняет свою задачу по обработке данных.</li><li>Все данные нужно разделить на несколько взаимонезависимых scope, основываясь на локальности данных при их использовании, для того чтобы можно было максимально распараллеливать задачи по обработке этих данных.</li><li>Каждый scope хранить в отдельной БД, для снижения нагрузки на БД.</li><li>Использовать документоориентированную базу данных, чтобы упростить переход, но прописать вариации схем данных.</li><li>Для отказоустойчивости и предотвращения потери данных, каждая БД должна быть представлена replica set как минимум на 3-х разных физических машинах.</li><li>Мы понимали, что система будет большой и сложной для поддержки. Поэтому нам необходим был инструмент, который бы автоматизировал большинство действий с системой за нас.</li></ul><p>Общую схему как выглядела система вы можете увидеть на следующем рисунке.</p><figure><img src="https://media.tproger.ru/uploads/2020/08/HA2.png" alt="" /></figure><p>Изображение компании Dunice</p><p>Superhost и каждый хост это отдельная физическая машина, со своими ресурсами и настроенным Raid 0 (или Raid 5).</p><p>Superhost (он же мастер) состоит из:</p><ul><li>Основного сервиса (Main Web Server, MWS), который обрабатывает запросы от пользователей по специальным ендпоинтам, мониторит состояние всех хостов, запускает и мониторит состояние миграций данных из внешней БД. Извне, мы в любой момент можем увидеть статистику по использованию ресурсов и текущему состоянию системы.</li><li>Metadata service — это сервис хранилище данных о состоянии кластера (какой scope на какой реплике, какой агент с этой репликой лучше работает, когда была последняя миграция для каждого scope и т.д.). Взаимодействовал с этим сервисов только MWS и CLI</li><li>CLI — это терминальный интерфейс для развертывания и управлением кластером. Назван в честь самой системы.</li><li>Планировщик задач. Этот сервис отвечал за запуск миграций в нужное время.</li></ul><p>Каждый из host N состоит из:</p><ul><li>Один или несколько контейнеров с агент-сервисом на каждом хосте. Нужен, для того чтобы взаимодействовать с базами данных, выполнять миграцию, запускать агрегацию, в режиме потока строить отчет нужного формата и отправлять на MWS.</li><li>Контейнер с базой данных, которая реплицирована на несколько хостов (min 3).<br />В базе данных хранились мигрированные данные из основной БД клиента, но разбиты по scope на разные группы реплик. При инициации миграции, данные брались с некоторым условием, так чтобы в одной группе реплик были данные только для одного scope.<br />Это позволило нам сократить нагрузку на обработку данных и увеличить скорость выдачи отчета. После окончания миграции, мы запускали процесс агрегации (предвычисления). Эта операция предназначена для того, чтобы посчитать все нужные данные для отчетов и положить их в отдельную таблицу. В итоге при построении отчета, мы просто берем данные с фильтрацией из этой таблицы-кеша (получается по сути индекс). Данное решение позволило нам генерировать отчеты на 30 колонок и 200к+ строк за пару минут.<br />Когда приходило время новой миграции, мы таблицу с закешироваными данными переименовывали и работали с ней. После того как миграция окончилась и появилась таблица с новыми закешироваными данными, мы удаляли старую и работали с новыми данными.</li></ul><p>А для того чтобы как то удобно говорить об этой системе, мы решили дать ей имя MoNoRe — по первым слогам ключевых технологий (Mongo, Node, Redis).</p><p>Принцип работы при миграции данных:</p><ol><li>Посылаем запрос на адрес &lt;superhost&gt;/migration/&lt;scopeId&gt;/start</li><li>При первом обращении к MWS с запросом на миграцию будет выбран наименее нагруженный хост и на нем создается первый «data» контейнер с настройками репликации. После этого по этому же принципу будут выбрано некоторое количество хостов для создания «data» контейнеров в количестве указанном в файле inventory.ini как replicaCount. Как только все необходимые контейнеры будут готовы, система инициирует создание replicaSet, дожидается окончания этого процесса и возвращает MWS IP адреса всех участников.</li><li>MWS создает расписание на ежедневную миграцию для указанного scope</li><li>Записывает данные о репликах в Redis</li><li>Запрашивает наименее нагруженный «compute» и отправляет ему команду на запуск процесса миграции для указанной фирмы.</li><li>Агент, получив команду на миграцию соединяется с replicaSet, создает(если она отсутствует) новую базу и начинается процесс миграции.</li><li>Прогресс миграции периодически отправляется в MWS и сохраняется в Redis. В любой момент, извне, мы можем запросить состояние миграции нужного scope у MWS &lt;superhost&gt;/migration/&lt;scopeId&gt;/status.</li><li>Когда все данные успешно перенесены, на суперхост будет отправлено сообщение об успешном выполнении миграции.</li><li>Запускается механизм агрегации данных для построения будущих отчетов в коллекцию report_rows, при этом, если на данный момент такая коллекцию существует — она будет переименована в report_rows_cache, а запись будет осуществляться в новую report_rows.</li><li>Прогресс агрегации периодически отправляется в MWS и сохраняется в Redis. В любой момент, извне, мы можем запросить состояние агрегации нужного scope у MWS &lt;superhost&gt;/migration/&lt;scopeId&gt;/status.</li><li>Когда коллекция report_rows будет готова, на суперхост будет отправлено сообщение об успешном выполнении агрегации.</li><li>Записывает данные о времени последней миграции в Redis</li></ol><p>При последующих запросах на миграцию суперхост берет всю необходимую информацию из Redis, запрашивает наименее нагруженный «compute» и отправляет ему команду на запуск процесса миграции для указанного scope.</p><p>Принцип работы при получении отчета:</p><ol><li>Посылаем запрос на адрес &lt;superhost&gt;/report/&lt;reportId&gt;?additionalParams="</li><li>При первом обращении к MWS с запросом на миграцию будет выбран наименее нагруженный хост и на нем создается первый «data» контейнер с настройками репликации. После этого по этому же принципу будут выбрано некоторое количество хостов для создания «data» контейнеров в количестве указанном в файле inventory.ini как replicaCount. Как только все необходимые контейнеры будут готовы, система инициирует создание replicaSet, дожидается окончания этого процесса и возвращает MWS IP адреса всех участников.</li></ol><p>Как видно из схемы для реализации нашей системы мы решили взять следующие инструменты:</p><ol><li>Node.js (with express) — Использовался для создания HTTP(S) серверов MWS и CS</li><li>MongoDB (with replication) — Так как у команды клиента есть опыт работы с MongoDB, при этом она была достаточно мощной для обработки больших массивов данных за счет Agregation Pipeline, было принято решение ее и использовать как основное хранилище данных.</li><li>ПримечаниеLXD / LXC (Linux Containers) — Система виртуализации, реализующая концепт контейнеров. Использовался для добавления слоя абстракции между элементами системы и серверами на которых происходит разворачивание.  В настоящее время имеет смысл использовать Docker + Docker Swarm)</li><li>SSH – Использовался как транспорт для управления между хостами</li><li>Node.js (with Yargs and Ora) — Использовался при построении CLI.</li><li>Cron(Linux) — выполнял роль планировщика задач.</li><li>PM2 — Использовался для повышения отказоустойчивости Node-Express сервисов.</li><li>Redis — Выполнял роль Metadata service.</li><li>Nginx — На master машине выполняет роль прокси сервера, для взаимосвязи с внешним миром. На каждом хосте выполняет роль прокси сервера для общения между MWS и агентом.</li></ol><h2>Развертывание и управление большой системой = боль?</h2><p>Система на первый взгляд выглядит непросто. Мы понимали что управлять всем этим руками будет не удобно и будет вызывать много вопросов и проблем у заказчика. Чтобы руками развернуть такую систему необходимо очень четко понимать все ее модули, взаимодействие между ними и потратить пару часов. А это очень не устраивало нас как 0-пользователей системы.</p><p>Чтобы решить эту проблему, мы создали CLI c набором команд, позволяющий привести систему в рабочее состояние за 5 минут. Для этого необходимо просто заполнить inventory.ini (см. рис 2) файл с необходимыми данными и запустить команду monore setup. Система сама зайдет на все указанные хосты системы, развернет там необходимые модули, создаст нужные файлы с настройками(nginx, mongo и так далее) и переведет систему в рабочее состояние.</p><figure><img src="https://media.tproger.ru/uploads/2020/08/image2-2.png" alt="" /></figure><p>Изображение компании Dunice</p><figure><img src="https://media.tproger.ru/uploads/2020/08/image4-1.png" alt="" /></figure><p>Изображение компании Dunice</p><p>На первом демо, у тех. директора со стороны заказчика был крайне негативный настрой (оказалось, что до самой демонстрации он не был подключен в наш разговор, и решение о замене Hadoop на наше решение Клиент принимал самостоятельно). Однако, по мере демонстрации возможностей и характеристик системы, интерес возрастал, негодование сменилось удовлетворением, а глаза начали блестеть.</p><p>Это было тяжелое демо с нашей стороны, но все участники были довольны достигнутым, оставалось лишь одно НО…. Уровень отказоустойчивости который у нас был на текущий момент, оказался недостаточным для инициирования процесса приёма-передачи продукта. У нас появилось новое требование, нужно чтобы с системой могло произойти все что угодно (отключили от сети или вышло из строя железо хоста или супер хоста, временные проблемы с доступностью хоста), но система должна продолжать работу, и при этом нормально реагировать на возращении хоста (предотвращение коллизий и несогласованности данных).</p><p>Таких жестких требований к жизнеспособности системы не мог поддержать и Hadoop. Однако мы не стали спорить с Клиентом, и принялись думать как нам это реализовать.</p><h2>Тот самый момент, когда грамотная архитектура решает проблемы за тебя</h2><p>На самом деле, часть этих требований у нас уже были покрыты за счет правильно подобранной архитектуры и программных решений. Например, вопросом коллизий и согласованности данных полностью занималась MongoDB с настроенным Replica Set. А за счет того, что мы храним некоторые метаданные о кластере, потеря одного хоста вообще не является проблемой.</p><p>Однако для достижения поставленных целей этого недостаточно. Все еще могут быть проблемы, если откажет Superhost или больше половины host.</p><p>Решить эту проблему мы смогли с помощью более крупной кластеризации за счет LXD Cluster (теперь контейнеры на всех хостах находились как бы на одном хосте, видели друг друга и могли спокойно общаться, однако появилось требование, чтобы хосты (в том числе и суперхост) должны быть в одной подсети (16 или 24 ранга)), обновлении логики работы MWS (упростился механизм выборки и взаимодействия с агентами, появилась логика регенерации) и CLI (усложнилась логика разворачивания системы, однако упростился механизм сбора статистики с каждого модуля, появилась логика регенерации), и обновление количества и качества хранимых метаданных о системе.</p><p>Шаг с кластеризацией, помог нам более гибко управлять кластером из любого места кластера. Т.е. по факту, любой хост мог стать супер хостом.</p><p>Общий алгоритм работы:</p><ul><li>Если теряется связь с хостом, то админу отправляется оповещение со всей необходимой информацией о хосте. А так же, о том что в систему имеет смысл добавить еще хостов, для поддержания высокой отказоустойчивости. При добавлении нового хоста, через CLI, система в автоматическом режиме начинает его полноценное использование.</li><li>Если выходит из строя суперхост, то устраивается кворум, и один из хостов становится суперхостом. Инициируется процесс регенерации. Устанавливается Redis, MWS, CLI. Происходит сбор информации о кластере (за счет того, что в каждой реплике БД есть минимальное количество метаданных о самой реплике, о данных которые в ней хранятся и о последней миграции). В итоге через примерно 30 секунд на кластере из 20 машин, система снова становится обрабатывать запросы извне. Так же отправляется письмо администратору, с информацией о произошедшем и результатом.</li></ul><figure><img src="https://media.tproger.ru/uploads/2020/08/image1-1.png" alt="" /></figure><p>Изображение компании Dunice</p><p>Итогом данного проекта стало успешное внедрение сначала в тестовый контур, а в последствии и в продакшен. Итоговые характеристики системы при построении отчета:</p><ol><li>Оперативная память не поднимается выше 500мб при формировании отчета ~200к строк из таблицы с &gt; 1млн записей</li><li>Время получения отчета ~60 секунд (для ~200к строк).</li></ol><p>А для нас, результатом был ценнейший опыт построения Enterprise систем. Мы еще раз убедились, что правильно подобрать инструмент под задачу, это всего лишь полдела, нужно еще уметь правильно готовить с помощью этого инструмента (ну, и грамотная архитектура дает огромную свободу развития и масштабирования приложения).</p><p>Изначально, клиент был недоволен результатом, который получился у его команды. Мы же, взяли те же инструменты, добавили немного новых, правильно определили архитектуру и применили весь наш опыт в разработке Enterprise систем.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как разрабатывается умный поиск — нюансы и сложности</title>
      <link>https://tproger.ru/articles/how-smart-search-is-created</link>
      <comments>https://tproger.ru/articles/how-smart-search-is-created?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/how-smart-search-is-created</guid>
      <description><![CDATA[<p>Архитектура высоконагруженного сервиса Searchanise: умный поиск с подсказками и исправлением ошибок, навигация, рекомендации и рост конверсии.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/how-smart-search-is-created">Как разрабатывается умный поиск — нюансы и сложности</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 15 Feb 2020 12:57:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Всем привет! Меня зовут Дима, я занимаюсь разработкой Searchanise — это облачный сервис для поиска товаров и повышения конверсии внутри интернет-магазинов.</p><p>Я расскажу про архитектуру быстрого высоконагруженного сервиса, который включает: умный поиск, навигацию, рекомендательную систему и инструменты повышения конверсии в интернет-магазине.</p><h2>Как развивалась функциональность сервиса</h2><p>Ядро сервиса — это поисковый движок, который угадывает запрос по первым введённым символам, исправляя ошибки и предлагая наиболее актуальные подсказки. Поиск сопровождается виджетом, где отображаются продукты с изображениями, ценой, остатком на складе, рейтингом, а также релевантные поисковому запросу контентные страницы, категории и подсказки.</p><p>Новые опции появлялись по мере сотрудничества с платформами. Когда мы приходили на новую платформу, то понимали, какой функциональности не хватает. Так появилась страница результатов поиска, фильтры, рекомендательные блоки, мерчендайзинг, промоинструменты, аналитика. Потом мы поняли, что клиентам нужны рекомендации и начали развиваться в этом направлении. Чтобы рекомендации хорошо работали, в планах развивать персонализацию поиска и внедрять машинное обучение.</p><h2>Архитектура</h2><p>Главное в системе — это архитектура. В нашем случае — доработка архитектуры с целью повышения скорости.</p><p>Хостимся на 10 железных серверах. Используем виртуализацию KVM, создали свое маленькое облако, в котором у нас больше 50 виртуалок. На одном железе — примерно 6 серверов, каждый из которых отвечает за что-то своё: какой-то принимает запросы, какой-то только хранит статистику, отдельный сервер для админки, отдельный сервер для индексации. Больше всего поисковых серверов — 30, так как Sphinx для организации быстрого поиска требуется много памяти.</p><p>Когда клиент устанавливает модуль, он регистрируется на сервере и начинает отправлять данные для поиска. Все эти данные попадают в очередь, а из неё — в базы данных. После того как импорт данных закончен, команда на индексацию попадёт в очередь индексации. Обработчики очереди API у нас расположены на 10 серверах, а обработчики индексации — на 19 серверах.</p><p>Очереди сделаны очень необычно: мы реализовали их сами в Redis с помощью LUA скриптов и встроенных в Redis типов данных. Получилось хорошо: мы смогли часть логики переложить в очередь и получили очереди, которые распараллеливаются по нужным нам условиям. Ещё наши очереди умеют повторять ошибочные запросы только фиксированное число раз и при падении обработчика данные не теряются.</p><p>Для каждой регистрации создается своя база — на данный момент у нас их 10 000. Это нестандартное решение, у которого есть огромное преимущество — мы реально изолируем базы. Удалить базу гораздо проще, чем вычищать информацию из таблиц. Помимо этого, решается еще одна проблема: при добавлении или частой работе с обновлениями базы, индекс тормозит. Когда базы отделены, не возникает проблем с шардированием. Просто раскладываем определенное число баз на каждый сервер Mysql.</p><p>Приложение для Shopify написано на Erlang, который оказался очень быстр и удобен для задач параллельного программирования: с его помощью не проблема поддерживать тысячи магазинов, делая по несколько миллионов запросов к API. У Shopify очень развитое API, с которым можно делать практически всё. С помощью API мы сделали индексацию, следим за обновлениями, статусами магазинов и т.д. Приложение изолировано для того, чтобы соблюсти общую монолитную структуру и иметь единый API для всех платформ.</p><p>Со всех серверов собираем метрики с помощью Zabbix. Это очень удобно — в каждый момент знать что происходит с сервером и насколько он загружен. Также в Zabbix настроены триггеры на разные «внештатные» ситуации — если что-то пойдет не так, придёт уведомление в Slack и на почту.</p><h2>Работа со Sphinx</h2><p>Благодаря Sphinx и тому, что мы много времени потратили на оптимизацию, скорость поиска Searchanise во много раз выше конкурирующих предложений — мы легко поддерживаем 500 000 продуктов в поиске. И эта возможность дана Sphinx. Ежедневно мы обрабатываем 15 млн поисковых запросов.</p><p>Но мы знаем и о проблемах Sphinx, и многие уже научились обходить. Но осталась одна: Sphinx периодически падает и с этим пока ничего не получается поделать. Поэтому мы один индекс держим на двух серверах: если Sphinx упадёт на одном, второй будет обслуживать запросы.</p><h2>Тестирование</h2><p>Мы не используем unit-тестирование. Когда система быстро развивается, поддержка unit-тестов в актуальном состоянии сильно тормозит процесс разработки.</p><p>Все метрики проверяем самописными короткими тестами; используем функциональные тесты для API. API у нас фиксировано и тесты не приходится часто менять.Считаем, что функциональное тестирование эффективнее регулярной правки unit-тестов под меняющиеся требования.</p><h2>Виджеты</h2><p>На некоторых платформах результаты поиска показываются в дизайне платформы. На других платформах (например Shopify) поиск отображается в JS-виджетах. Всё это управляется нашей встраиваемой админкой, которая тоже JS-виджет.</p><p>У нас огромное количество настроек для системы виджетов. Все настройки обновляются практически в режиме реального времени (в течение 10–20 секунд оказываются у клиента). У конкурентов иногда приходится ждать 10–15 минут.</p><p>Файлы виджетов мы храним на Amazon S3, но раздаем не напрямую, а используем CDN. Мы используем KeyCDN: недорого, хорошо работает, изменения быстро актуализируются, IP-адреса не заблокированы ни в одной стране.</p><h2>Вывод</h2><p>За счёт использования Sphinx мы построили сервис поиска для множества клиентов и обеспечили себестоимость практически в 10 раз ниже, чем у конкурентов. Но Sphinx из коробки очень неудобен. Неудобно его использовать со множеством индексов и организовать на его основе распределенный сервис. Нам пришлось преодолеть много трудностей и придумать много уникальных решений для налаживания процесса индексации, распараллеливания и faleover.</p>]]></content:encoded>
    </item>
  </channel>
</rss>