<?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>PostgreSQL</title>
    <description>PostgreSQL — это мощная, объектно-реляционная система управления базами данных с открытым исходным кодом. Она обеспечивает полное соответствие стандартам SQL и поддерживает многие функции, включая ACID-транзакции, сложные запросы, триггеры, представления, целостность данных и внешние ключи. PostgreSQL известна своей высокой производительностью, масштабируемостью и расширяемостью, что позволяет добавлять новые типы данных, функции и языки программирования. Она широко используется в веб-приложениях, аналитике данных и корпоративных системах благодаря своей надежности и богатому набору функций.</description>
    <link>https://tproger.ru/tag/postgresql</link>
    <atom:link href="https://tproger.ru/tag/postgresql/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 03 Oct 2026 14:38:28 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>PostgreSQL</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Эволюция архитектуры страниц данных в СУБД: от NSM до FastLanes</title>
      <link>https://tproger.ru/articles/evolyuciya-arhitektury-stranic-dannyh-v-subd-ot-nsm-do-fastlanes</link>
      <comments>https://tproger.ru/articles/evolyuciya-arhitektury-stranic-dannyh-v-subd-ot-nsm-do-fastlanes?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Виталий При]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/evolyuciya-arhitektury-stranic-dannyh-v-subd-ot-nsm-do-fastlanes</guid>
      <description><![CDATA[<p>Эволюция файлов данных в СУБД. Хотя NSM уже больше 15 лет, это архитектура продолжает использоваться ведущими  СУБД. Рассмотрим какие задачи решает модель PAX и ее оптимизированный вариант FastLanes.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/evolyuciya-arhitektury-stranic-dannyh-v-subd-ot-nsm-do-fastlanes">Эволюция архитектуры страниц данных в СУБД: от NSM до FastLanes</a>»</p>]]></description>
      <category><![CDATA[Big Data]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 10 Sep 2026 17:27:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда вы пишете SELECT * FROM users WHERE age &gt; 30, вы
редко задумываетесь о том, как именно СУБД физически хранит эти данные на
диске. А между тем, от архитектуры страницы данных зависит, сколько лишних байт
будет прочитано, насколько эффективно используется кэш
процессора, и во что обойдутся обновления и удаления. В этой статье разберём
три классические модели — NSM, DSM и PAX, а также заглянем в будущее — формат
FastLanes, созданный специально под SIMD и GPU.<b></b></p><h3>1. Классика всех времен: страница NSM</h3><p>Традиционная и самая распространённая архитектура
в OLTP-СУБД (PostgreSQL, Oracle) — слотированная страница,
относящаяся к семейству NSM (N-ary Storage Model). Страница, как правило, имеет
фиксированный размер, чаще всего 8 или 16 КБ (может настраиваться параметром
БД), и делится на три логические области:</p><p>·      
<b>Заголовок страницы</b> — содержит
метаданные: размер страницы, количество слотов, смещение до свободного
пространства и флаги.</p><p>·      
<b>Таблица слотов</b> — массив записей
фиксированной длины, каждая из которых хранит смещение (offset) до начала
соответствующей строки. Слоты упорядочены по позиции строки в таблице.</p><p>·      
<b>Область данных</b> — сами кортежи,
расположенные последовательно, но в обратном порядке относительно таблицы
слотов (данные растут с конца страницы в начало, а слоты — с начала в конец).
Это позволяет эффективно управлять фрагментацией.</p><p><br /></p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/393863ea-b164-4e8d-8cdd-1ed31ffbac59.webp" alt="Пример таблицы" /><figcaption>1.1 Пример таблицы</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/1523098a-dbbb-469e-a550-f3d7f8e23ee2.webp" alt="Пример файла данных для таблицы" /><figcaption>Рисунок 1.1 – Пример файла данных для таблицы</figcaption></figure><p><br /></p><h4>Особенности
работы с изменениями на уровне страницы:</h4><p>При обновлении строки, если её новый размер превышает старый,
на старом месте сохраняется указатель (forwarding pointer), а обновлённая
запись перемещается в свободную область страницы (или даже на другую страницу,
если свободного места недостаточно). Это порождает цепочки переадресации,
которые могут замедлять чтение.</p><p>При удалении строки соответствующий слот помечается как
недействительный (например, устанавливается флаг deleted или смещение
становится отрицательным). Физическое освобождение места происходит позже — при
сборке мусора (VACUUM в PostgreSQL) или при перестройке страницы.</p><h4>Главный недостаток:</h4><p>Для запросов, которые читают миллионы строк, но выбирают лишь 2–3 атрибута из 20, NSM необходимо просканировать всю страницу целиком. В результате в кэш CPU загружаются все атрибуты, включая ненужные. Это не только увеличивает время I/O, но и порождает промахи кэша (cache misses), поскольку полезные данные перемешиваются с не нужными.</p><h3>2. Колоночная страница DSM:</h3><p>Научная работа Джорджа П. Коупленда и Сетрага Н. Хошафяна «A
Decomposition Storage Model» (ACM SIGMOD) [1] предложила кардинально иной
подход к организации данных на странице, получивший название DSM (Decomposition
Storage Model).</p><p>В классической реализации DSM каждый атрибут таблицы хранится в
отдельном наборе страниц. При этом страницы внутри одного атрибута содержат
только значения этого столбца, расположенные в порядке строк. Для
восстановления полной записи используется либо позиционный идентификатор
(порядковый номер строки в странице), либо служебные битовые маски.</p><h4>Преимущества на уровне страниц:</h4><p>·      
Страница заполняется данными одного типа — это
даёт значительный прирост в сжатии (RLE, дельта-кодирование, битовые карты) по
сравнению с NSM-архитектурой.</p><p>·      
При сканировании одного-двух столбцов читается
ровно столько страниц, сколько нужно для этих атрибутов, без загрузки не используемых в запросе колонок.</p><h4>Обратная сторона:</h4><p>Вставка или обновление строки требуют записи в страницы всех
атрибутов, что превращается в доступ к множеству файлов и их соединение.
Запрос SELECT * для ограниченного числа строк также вынужден
выполнять дорогостоящее соединение страниц разных столбцов, что делает DSM
неэффективной для OLTP.</p><p>Первоначально модель не получила широкого распространения
именно из-за высокой стоимости сборки строк. Однако с ростом мощностей
процессоров и объёмов оперативной памяти она стала основой для колоночных СУБД
(Vertica, Greenplum, ClickHouse), где основная нагрузка — аналитические
запросы.</p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/31e86521-072e-4d3b-9983-21312d34a61b.webp" alt="Пример файла DSM" /><figcaption>Рисунок 2.1 – Пример файла DSM</figcaption></figure><p><br /></p><h3>3. PAX: гибридная модель данных</h3><p>В 2001 году на конференции VLDB была представлена работа
Анастасии Аламаки, Дэвида ДеВитта, Марка Хилла и Муниратнама Сивакумара
«Weaving Relations for Cache Performance» [2], в которой авторы предложили
комбинированный подход — PAX (Partition Attributes Crosswise).</p><h4>Ключевая идея модели:</h4><p>Страница остаётся целостной (содержит все атрибуты таблицы, как в
NSM), что позволяет избавиться от дорогостоящих соединений файлов данных. Но
внутри страницы данные разбиты по атрибутам: все значения первого атрибута
собираются в непрерывный мини-блок. Следом идёт мини-блок второго атрибута,
затем третьего, и так далее. В начале страницы располагается каталог
(directory), указывающий смещение и размер каждого мини-блока.</p><h4>Как происходит выборка данных:</h4><p>Для запроса, выбирающего два столбца, СУБД обращается к странице и читает только те два мини-блока — остальные не попадают в кэш
процессора, что снижает количество промахов.</p><p>Обновление
всей строки не требует записи в отдельные файлы (как в DSM) — достаточно
перезаписать соответствующие мини-блоки внутри одной страницы.</p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/09a94b94-0c05-469a-84ee-ff350607bddb.webp" alt="Схема страницы PAX" /><figcaption>Рисунок 3.1 – Схема страницы PAX</figcaption></figure><p><br /></p><h3>4. Современные реализации на основе PAX</h3><h4>Apache Parquet</h4><p>Прямой наследник PAX. Файл разбивается на Row Groups (группы строк,
типично 128 МБ – 1 ГБ), каждая из которых действует как крупная «страница» PAX.
Внутри Row Group данные организованы по Column Chunks — это и есть мини-блоки
разных атрибутов, только теперь они могут быть сжаты независимо друг от друга.
Parquet также добавляет индексы и статистику на уровне Column Chunk (min, max,
null count), что позволяет при сканировании пропускать целые блоки без
разжатия.</p><h4>Apache ORC (Optimized Row Columnar)</h4><p>Аналог Parquet, используемый в Hive, Presto и Trino. Внутри
ORC-файла выделяются Stripes (полосы), которые выполняют ту же роль, что и Row
Groups в Parquet. Внутри Stripe данные хранятся по колонкам с добавлением
индексов и словарей. По сути, это тоже PAX, но с более агрессивным сжатием и
встроенной фильтрацией.</p><h3>5. FastLanes — PAX, оптимизированный под SIMD и GPU</h3><p>PAX-архитектура значительно улучшила предыдущие модели
хранения данных, но она не учитывала характеристики процессора. Именно в этом
направлении происходит дальнейшее развитие архитектуры хранения данных. Петер
Бонч, учёный из исследовательского центра CWI (Нидерланды), предложил новый
формат FastLanes, который оптимизирует хранение данных под возможности
современных процессоров.</p><p>Файл FastLanes состоит из двух главных компонентов: Footer
(футер) и Data (данные). Футер содержит метаданные, описание данных и их
местонахождение в файле и может храниться отдельно от блока «Данные».</p><p>На верхнем уровне блок «Данные» повторяет архитектуру PAX:
данные делятся на группы строк и атрибуты. В отличие от существующих типов
файлов, в FastLanes группы строк содержат количество записей, кратное 1024. Это
позволяет избежать материализации данных в основной памяти и выполнять всю
работу на уровне процессора. Следующим важным нововведением является
использование сжатия LWC (Light-Weight-Compression).
Вместо тяжеловесных алгоритмов по типу Zstd, которые не позволяют
распараллелить обработку данных, применяются FSST, DICT, ALP при каскадном
(рекурсивном) применении которых достигается уровень сжатия Snappy за более
короткий промежуток времени [3]. Кроме этого, для каждой колонки данных могут
применяться разные операторы кодирования. Сжатые данные хранятся в сегментах, в
которых кроме самих данных хранятся смещения на отдельные вектора, что
позволяет читать данные на уровне одного вектора вместо целого блока, как в
старых форматах.</p><p>Когда данные читаются из
оперативной памяти в процессор, закодированный вектор, содержащий 1024
значения, разжимается и полностью помещается в кэш процессора. Напротив, старые
форматы файлов не только используют непараллельные алгоритмы сжатия, но и применяют
их к целым Row Group, что влечёт за собой использование основной памяти и
уменьшение скорости обработки [3].</p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/38442764-e882-48bd-abc8-e2389e2fbf91.webp" alt="Пример таблицы[3]" /><figcaption>Рисунок 5.1 – Пример таблицы[3]</figcaption></figure><p><br /></p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/53f16e51-def6-48b1-b0a6-3282b28622d7.webp" alt="Файл FastLane[3]" /><figcaption>Рисунок 5.2 – Файл FastLane[3]</figcaption></figure><p><br /></p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/b9a51ae2-6319-490c-bd67-4028b1b35e49.webp" alt="Футер файла FastLane[3]" /><figcaption>Рисунок 5.3 – Футер файла FastLane[3]</figcaption></figure><p><br /></p><figure><img src="https://media.tproger.ru/user-uploads/140096/2026-09-10/e52e3ea5-17fa-44d2-bc85-2f418e39150e.webp" alt="Операторы кодирования FastLane[3]" /><figcaption>Рисунок 5.4 – Операторы кодирования FastLane[3]</figcaption></figure><p><br /></p><h4>Использованные источники:</h4><ol><li>Copeland G.P., Khoshafian
     S.N. A Decomposition Storage Model. Proceedings of ACM
     SIGMOD, 1985.</li><li>Ailamaki A., DeWitt D., Hill
     M., Sivakumar M. Weaving Relations for Cache Performance. Proceedings
     of VLDB, 2001.</li><li>Boncz P., Afroozech A., et
     al. The FastLanes File Format: specification.</li></ol>]]></content:encoded>
    </item>
    <item>
      <title>Баги, которые не ловятся тестами: три расследования и общая методика</title>
      <link>https://tproger.ru/articles/bagi-kotorye-ne-lovyatsya-testami-tri-rassledovaniya-i-obshhaya-meto</link>
      <comments>https://tproger.ru/articles/bagi-kotorye-ne-lovyatsya-testami-tri-rassledovaniya-i-obshhaya-meto?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/bagi-kotorye-ne-lovyatsya-testami-tri-rassledovaniya-i-obshhaya-meto</guid>
      <description><![CDATA[<p>Три расследования редких дефектов: гонка в SQLite, потеря сообщений в TCP и гонки в биллинге. Разбираем общую методику поиска невоспроизводимых багов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/bagi-kotorye-ne-lovyatsya-testami-tri-rassledovaniya-i-obshhaya-meto">Баги, которые не ловятся тестами: три расследования и общая методика</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Баги и ошибки]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 09 Sep 2026 09:00:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Есть класс дефектов, которые проходят весь конвейер проверок и всплывают только в продакшене. Объединяет их не сложность кода. В двух случаях виновата форма проверки, написанной вежливой там, где реальность к сервису вежлива не бывает; в третьем проверка не поймала бы дефект вообще.</p><p>Разбираем три расследования — пропавшую запись в базе, три процента сообщений, терявшихся только на чистой машине, и гонки в биллинге, которые видит одна поддержка. У всех трёх разные предметные области и одна общая методика поиска невоспроизводимых багов.</p><p>Отсутствие закономерности само по себе является находкой: если сбой не привязан ни к шарду, ни к клиенту, ни к времени суток, это указывает на гонку, а не на данные.</p><p>Когда воспроизвести дефект синтетически нельзя, остаётся пассивная телеметрия в продакшене и последовательное отсечение гипотез данными.</p><p>Счётчики на каждом слое находят виновника быстрее логов: разрыв между двумя соседними числами прямо называет слой, в котором теряются сообщения.</p><p>Вежливый тест, который шлёт запрос и ждёт ответа, скрывает целый класс ошибок пакетирования. Пачечный тест их обнажает.</p><p>Отсутствие ошибок не доказывает, что дефект исправлен. Доказательством служит положительный сигнал: сработавшее предупреждение о том, что опасные условия возникли, а сбоя при этом не случилось.</p><h2>Случай первый: запись, которой не могло не быть</h2><p>Управляющий слой Tailscale разбит на шарды, у каждого своя база SQLite, и обращается к ней ровно один процесс. Такой однописательный режим — именно то, для чего SQLite и предназначен, что делает дальнейшее особенно неприятным.</p><p>Резервное копирование снимало полную копию базы каждые несколько минут и складывало файл в объектное хранилище. Работало это без единого происшествия с начала 2023 года, пока конвейер, читавший резервные копии, не сообщил об ошибке. Проверка встроенной командой контроля целостности подтвердила худшее: база повреждена.</p><p>Первый случай сочли единичным. Базу починили, причину не нашли. Потом это повторилось. И ещё раз. Всего до устранения первопричины набралось <a href="https://tailscale.com/blog/sqlite-wal-reset-bug">19 отдельных инцидентов за полгода</a>, и каждый означал простой: процесс на шарде останавливался, пока базу чинили или восстанавливали. На ранних инцидентах простой превышал час, и всё это время у клиентов на шарде не работали консоль администратора и API.</p><h3>Почему он не поддавался обычным приёмам</h3><p>Дефект сопротивлялся всем стандартным подходам сразу:</p><ul><li>Не на что было списать: низкоуровневый код работы с базой никто не трогал годами, а внимательное чтение ничего не дало.</li><li>Не нашлось общих факторов. Повреждения не привязывались ни к конкретному шарду, ни к клиенту, ни к функции продукта, ни ко времени суток, ни к уровню нагрузки.</li><li>Он не воспроизводился синтетически. Надёжного триггера не было, поэтому оставалось только развернуть пассивную телеметрию в боевой среде и ждать следующего случая.</li></ul><p>Расписания у инцидентов тоже не было: они случались то через часы, то через недели. Между октябрём и декабрём наступила шестинедельная тишина, после которой повреждения вернулись.</p><p>Команда сделала два шага, которые и составляют суть этой истории. Купила контракт поддержки у разработчиков SQLite, получив прямой доступ к людям, написавшим саму базу. И методично составила список гипотез, отсекая их данными, а не рассуждениями. В списке были сломанные блокировки при закрытии файла, неверная работа с памятью, принадлежащей базе, и обращение из нескольких потоков при отключённой потокобезопасности. Каждый инцидент приносил данные, каждая гипотеза отпадала по очереди.</p><h3>Улика: транзакция, которой не стало</h3><p>Пока первопричину искали, платформу надо было держать живой. Команда автоматизировала жёсткую остановку при обнаружении повреждения, поставила монитор, непрерывно проверявший целостность резервных копий, и переписала инструкции по восстановлению. Время восстановления упало ниже часа.</p><p>А затем построила конвейер журналирования транзакций. Идея простая: писать каждый изменяющий базу запрос в отдельный журнал. Поскольку писатель один, а транзакции сериализуемы, история изменений линейна и детерминирована, и её можно проиграть поверх последней заведомо целой копии, обойдя повреждённые страницы. Приём годится там, где порядок фиксаций известен: при единственном писателе он получается сам собой. Наивный журнал запросов на многописательной базе этого не даёт, потому что конкурентные транзакции переплетаются и без явного порядка фиксаций проигрывание не восстановит то же состояние.</p><p>Конвейер сработал и выдал улику. В двух инцидентах журналы не проигрывались чисто: данные, записанные и зафиксированные одной транзакцией, оказывались необъяснимо невидимы для последующих. Запись исчезла бесследно и без единой ошибки.</p><p>Этого не может быть. В сериализуемой однописательной базе зафиксированная запись не может пропасть. Значит, виноват слой с достаточной конкурентностью, чтобы такое спрятать, а такой слой ровно один — контрольные точки.</p><h3>Шестнадцатилетняя гонка</h3><p>SQLite с журналом предзаписи работает с двумя файлами. База — это набор страниц; при изменении данных новые страницы пишутся не в основной файл, а сначала в журнал. Позже контрольная точка переносит их в базу. Обычно момент переноса SQLite выбирает сам, но Tailscale управляла контрольными точками вручную, чтобы снимать быстрые согласованные копии. Именно этот нестандартный, хотя и полностью документированный выбор и вывел их на дефект.</p><p>Метрики во время инцидентов показывали, что SQLite сообщает о переносе большего числа страниц, чем в журнале вообще было. Разработчики базы как раз готовили инструмент для этого слоя: обёртку над виртуальной файловой системой, которая пишет дополнительные трассировочные журналы. Обёртку развернули в продакшене, и ждать пришлось недолго.</p><p>Журналы показали редкую гонку данных (race condition) между контрольной точкой и пишущей транзакцией. Если запись происходит в определённый момент работы контрольной точки, та сбивается: считает часть страниц перенесёнными в основной файл, хотя перенос не состоялся. Данные теряются навсегда, а страницы, которые на них ссылаются, например индексные, записываются как ни в чём не бывало. Файл становится структурно повреждённым, что проверка целостности всё это время и фиксировала.</p><p>Дефекту дали имя по сбросу журнала предзаписи и оценили его возраст минимум в шестнадцать лет. Он прожил так долго именно из-за редкости, это классический heisenbug: чтобы поймать его в тестовой среде, разработчикам пришлось дописать код, вызывающий гонку намеренно.</p><h3>Ложная тревога, чуть не сорвавшая исправление</h3><p>Исправление вышло в версии 3.52.0, и Tailscale раскатывала его осторожно, начав с нескольких канареечных шардов. После общей раскатки монитор резервных копий немедленно покраснел, сообщив о повреждении в тринадцати базах.</p><p>Настоящего повреждения не было. В ту же версию попала оптимизация, слегка изменившая округление при переводе текста в число с плавающей точкой, а Tailscale хранила метки времени высокой точности текстом и превращала их в числа в вычисляемом столбце. Индекс по вычисляемому выражению перестал соответствовать новому результату вычисления, и проверка целостности честно назвала это повреждением. Канареечные шарды дефект пропустили просто потому, что на них не оказалось меток времени, попадающих под изменённое округление.</p><p>Разбирали это с трёх сторон сразу. Разработчики SQLite отозвали версию целиком и выпустили 3.51.3, содержавшую только исправление гонки. Tailscale перешла на хранение меток времени целыми секундами, поскольку перевод текста в целое число однозначен. А в 3.53.0 появилось автоматическое восстановление таких индексов, чтобы проблема не возникала впредь.</p><p><b>Главный урок этого эпизода:</b><br />Канареечная выкатка проверяет только те формы данных, которые в канарейке есть. Если на канареечных узлах нет тех же значений, что в проде, канарейка не подтверждает ничего. Это касается и обновлений самой базы, драйверов и инструментов миграции, а не только кода приложения.</p><h3>Как доказали, что дефект действительно исправлен</h3><p>Самая дисциплинированная часть расследования пришлась на финал. Отсутствие повреждений доказательством не считалось: команда уже пережила шесть недель обманчивой тишины. Поэтому драйвер базы пропатчили так, чтобы он выдавал предупреждение всякий раз, когда пишущая транзакция и сброс журнала пересекаются во времени.</p><p>Логика прямая: если предупреждение сработает, а база останется целой, значит, исправление сработало ровно там, где раньше был бы инцидент. Ждали два месяца. Предупреждение сработало, подтвердив, что условия для гонки в их среде действительно возникают. С того момента прошло ещё четыре месяца без единого происшествия с базами.</p><h2>Случай второй: три процента, терявшиеся только на чистой машине</h2><p>Второй сюжет проще по масштабу и полезнее в быту. Сервис представлял собой небольшой пересыльщик TCP: принять соединение, читать текстовые строки, передавать дальше. На тестовом стенде входило 97 004 строки, а выходило 94 183. Ни ошибок, ни исключений, просто пропавшие сообщения.</p><p>На ноутбуке автора всё воспроизводилось идеально: сто тысяч строк на входе, сто тысяч на выходе. Это расхождение и было первой уликой — тест проверял не то, что делает продакшен.</p><h3>Сменить машину раньше, чем код</h3><p>Первый час, по его собственному признанию, ушёл впустую: менялись и бинарник, и машина, и профиль нагрузки разом, а выводов это не давало. Дальше автор поменял ровно одну переменную: взял чистый сервер с тем же бинарником и тем же скриптом нагрузки. Потери появились снова, 97 128 строк из ста тысяч. Среда меняла вероятность проявления, но не сам факт дефекта, а чистая машина без истории и без накопленных настроек работает как микроскоп для ошибок синхронизации.</p><h3>Считать, а не логировать</h3><p>Дальше нужен был не ещё один прогон, а способ понять, на каком слое теряются сообщения. Логи рассказывают истории, счётчики складываются. Автор расставил счётчик на каждом слое: клиент считает отправленные строки, сервер считает разобранные переводы строки, сервер считает отправленные ответы, клиент считает полученные ответы. Один прогон, четыре числа, и разрыв между соседними прямо называет виновный слой.</p><p>Сервер разобрал всё до последней строки, а ответов отправил меньше, чем разобрал. Это отпечаток пальца конкретного дефекта, и дальше оставалось найти его в коде ответа.</p><h3>read() ничего не обещает про сообщения</h3><p>Виновником оказалась одна строка: сервер отправлял по одному ответу на каждое чтение, а не на каждую разобранную строку.</p><p>TCP — это поток байтов, а не очередь сообщений. Вызов чтения не имеет понятия о том, что такое одно сообщение в вашем протоколе. Ядро вправе слить десяток сообщений в один сегмент, и одно чтение заберёт все десять, а ответ уйдёт один.</p><p>Вежливый локальный тест отправлял сообщение, дожидался подтверждения и отправлял следующее. Одно сообщение на сегмент — дефект спал. Нагрузка на стенде шла пачками, тысячами сообщений в секунду, ядро их группировало, одно чтение проглатывало сотню строк.</p><p>Исправление переносит ответ внутрь цикла по строкам и накапливает остаток в буфере, чтобы пережить строку, разорванную между двумя чтениями. Это вторая половина того же семейства ошибок, и без неё починка неполная:</p><p><b>Вывод автора расследования:</b><br />Локальный тест это не нагрузочный тест, ноутбук это не сервер, а одно чтение из сокета это не одно сообщение.</p><h2>Третий сюжет: гонки, которые видит только поддержка</h2><p>Третий сюжет про биллинг кредитов на бессерверном Postgres, где транзакции по условиям задачи были недоступны. Автор наткнулся на четыре гонки, разберём две самые показательные. Все они, по его собственной формулировке, относятся к тому сорту дефектов, которые не показываются в тестах и показываются в почте поддержки.</p><h3>Классический двойной расход</h3><p>Наивная версия, которую пишут первой:</p><p>Два одновременных запроса читают баланс, равный пяти, оба проходят проверку, оба записывают четыре. Пользователь получил две операции по цене одной. Дефект существует ровно между чтением и записью, и последовательный тест в это окно не попадает никогда.</p><h3>Инвариант переезжает в условие запроса</h3><p>Общее решение — сделать проверку и запись одним оператором, перенеся условие корректности в WHERE:</p><p>Одиночный UPDATE в Postgres атомарен. Не хватило баланса — условие не совпало, вернулось ноль строк, и вы точно знаете, что списание не произошло. Транзакция для этого не нужна вовсе. Приём обобщается: перенесите инвариант в условие выборки, и запись просто не случится, когда инвариант нарушен.</p><h3>Вебхук, доставленный дважды</h3><p>Платёжные провайдеры повторяют доставку уведомлений при таймаутах, пятисотках и сетевых сбоях, а иногда дублируют событие и в штатном режиме. Если обработчик начисляет кредиты, доставка «хотя бы один раз» означает начисление хотя бы один раз.</p><p>Обычное решение с таблицей обработанных событий требует транзакции, а её нет: падение между двумя операторами либо начислит дважды при повторе, либо потеряет начисление совсем. Рабочий вариант в один оператор использует изменяющее данные обобщённое табличное выражение, где вставка в журнал операций работает воротами: не прошла вставка, значит, не выполнилось и обновление баланса.</p><p>Деталь, которую стоит забрать отдельно: уникальный индекс под эту схему должен быть частичным. Начисления от администратора приходят с произвольным идентификатором из скрипта, и глобальный уникальный индекс рисковал бы столкнуть их друг с другом или с идентификатором операции другого типа. Приветственные начисления идут вообще без идентификатора, и с ними коллизии не будет в любом случае: Postgres не считает два пустых значения равными. Ограничение индекса двумя типами операций от платёжного провайдера держит проверку уникальности ровно там, где она нужна.</p><h2>Что из этого складывается</h2><p>Первые два расследования дают общую методику поиска, и она изложена ниже. Третий случай стоит особняком: это не детектив, а набор приёмов, которые убирают целый класс гонок ещё на этапе проектирования, до того как искать станет нечего.</p><h2>Что забрать с собой</h2><p>Общего у трёх расследований больше, чем различий. Во всех трёх случаях проверка была написана в форме, которая не воспроизводит реальность: последовательный запрос вместо пачки, одиночный вызов вместо конкуренции, одна машина вместо двух. И во всех трёх дефект спокойно проходил через тесты, а в случае с SQLite прожил так шестнадцать лет.</p><p>Соседний сюжет про то, как тесты перестают отражать реальность, разбирали в материале о том, <a href="https://tproger.ru/articles/pochemu-statichnye-moki-ubivayut-testirovanie--i-chto-my-s-etim-sdel">почему статичные моки убивают тестирование</a>.</p><p>Полезнее всего здесь дешёвые привычки. Счётчик на границе каждого слоя ставится за час. Пачечный клиент пишется за вечер. Датчик, доказывающий исправление положительным сигналом, добавляется одной строкой в драйвер. Всё это стоит несопоставимо меньше, чем полгода расследования.</p><p>Три постмортема, на которых строится разбор: <a href="https://tailscale.com/blog/sqlite-wal-reset-bug">разбор Tailscale о поиске шестнадцатилетнего бага в SQLite</a>, <a href="https://dev.to/datacpp_3670/the-3-drop-that-only-showed-up-on-a-clean-server-a-debugging-retrospective-1g3c">ретроспектива потери трёх процентов сообщений</a> и <a href="https://dev.to/xiaojun_mao_c154743594bc9/credit-billing-without-transactions-4-race-conditions-i-hit-on-serverless-postgres-4730">четыре гонки в биллинге на бессерверном Postgres</a>.</p><p>Возьмите самый подозрительный сервис и запустите по нему пачечный тест вместо последовательного. Это самый дешёвый способ узнать, какой из ваших дефектов сейчас спит.</p>]]></content:encoded>
    </item>
    <item>
      <title>Идемпотентность и Outbox: как не выполнить одну операцию дважды</title>
      <link>https://tproger.ru/articles/idempotentnost-i-outbox-kak-ne-vypolnit-odnu-operaciyu-dvazhdy</link>
      <comments>https://tproger.ru/articles/idempotentnost-i-outbox-kak-ne-vypolnit-odnu-operaciyu-dvazhdy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/idempotentnost-i-outbox-kak-ne-vypolnit-odnu-operaciyu-dvazhdy</guid>
      <description><![CDATA[<p>Как сделать ручку идемпотентной, где ломается наивная проверка ключа и зачем нужен transactional outbox. Забирайте код на Python, SQL и Node.js и чеклист.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/idempotentnost-i-outbox-kak-ne-vypolnit-odnu-operaciyu-dvazhdy">Идемпотентность и Outbox: как не выполнить одну операцию дважды</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 09 Sep 2026 05:00:35 GMT</pubDate>
      <content:encoded><![CDATA[<p>История, с которой начинает автор одного из разборов ниже, звучит буднично. Платёжный шлюз не ответил вовремя, клиентская библиотека повторила запрос, и покупателя списали дважды. Сумма небольшая, а возврат, тикет в поддержку и восстановление доверия заняли недели.</p><p>Виноват тут не шлюз. Виноват сервер, который исходил из того, что каждый запрос приходит ровно один раз. В сети, где теряются ответы, это допущение неверно всегда.</p><p>Идемпотентность — свойство операции, при котором повторное выполнение приводит к тому же состоянию, что и однократное. Сам ответ при этом может отличаться: повторный DELETE вернёт 404 вместо 200, и метод от этого идемпотентным быть не перестаёт. У HTTP это закреплено на уровне методов: <a href="https://www.rfc-editor.org/rfc/rfc9110">RFC 9110</a> относит к идемпотентным PUT, DELETE и безопасные методы, а POST идемпотентным по своей природе не является. Бизнес-операции почти всегда отправляют именно через POST.</p><p>Клиент не может отличить «сервер не получил запрос» от «сервер выполнил операцию, но ответ потерялся», поэтому повтор придёт в любом случае.</p><p>Ключ идемпотентности генерирует клиент, а сервер хранит связку ключа со слепком запроса и с готовым ответом, чтобы повтор получил тот же результат, а не новый.</p><p>Проверка «посмотреть и вставить» неатомарна: два одновременных повтора оба увидят отсутствие ключа. Нужен уникальный индекс или условная запись.</p><p>Запись в базу и отправка в очередь в одну транзакцию не помещаются. Обёртывать сетевой вызов в BEGIN и COMMIT вредно вдвойне: корректности не даёт, а пул соединений выедает.</p><p>Transactional outbox решает это одной таблицей: событие пишется в той же транзакции, что и бизнес-запись, а отдельный процесс доставляет его в очередь.</p><h2>Почему повтор неизбежен</h2><p>Сеть отказывает так, что установить факт доставки невозможно в принципе. Есть три типовых сценария, и внешне они неразличимы:</p><ul><li>Сервер обработал запрос, но ответ потерялся по дороге назад.</li><li>Сервер всё ещё считает, а у клиента уже сработал таймаут.</li><li>Балансировщик повторил запрос сам, никого об этом не уведомив.</li></ul><p>Для GET повтор безвреден. Для POST /payments это второе списание. Отсюда и правило: одна логическая операция должна приводить к одному записанному итоговому состоянию, сколько бы раз её ни отправили. Осознанно новая операция обязана прийти с новым ключом.</p><h2>Два способа сделать ручку идемпотентной и один в довесок</h2><h3>Способ первый: ключ идемпотентности</h3><p>Самый распространённый вариант: клиент генерирует уникальный идентификатор на одну логическую операцию и повторяет его при каждой попытке. Сервер хранит соответствие ключа и ответа, а на дубликате возвращает сохранённый результат вместо повторного выполнения работы.</p><p>Три детали, на которых ошибаются чаще всего. Ключ генерирует клиент, а не сервер: смысл в том, что сервер сам по себе не отличит новый запрос от повтора. Ключ должен быть с высокой энтропией, обычно это UUID v4; выводить его из изменяемого или малоразнообразного поля вроде номера клиента нельзя, потому что это повышает риск коллизии и переигрывания чужой операции.</p><p>И последнее: повтор должен получить <b>тот же самый ответ</b>. Если первая попытка вернула 201 с идентификатором платежа, то и повтор возвращает те же 201 и тот же идентификатор, а не 409 и не пустую двухсотку. Иначе клиент решит, что операция не прошла, и попробует ещё раз.</p><h3>Способ второй: сделать операцию идемпотентной по смыслу</h3><p>Иногда ключ не нужен вовсе, потому что семантику можно спроектировать идемпотентной с самого начала. Классический пример — PUT /users/42, который задаёт полное представление ресурса: отправьте его дважды, и состояние будет одним и тем же.</p><p>Для операций создания трюк в том, чтобы выводить идентификатор из самого запроса, а не генерировать случайный на каждый вызов:</p><p>Идентификатор детерминированно выводится из почты, поэтому повторный запрос даёт того же пользователя без дублирующей строки. Плата за простоту — необходимость естественного уникального ключа: почты, артикула, внешнего идентификатора. Хеш при этом считается от точной строки, поэтому почту нужно привести к нижнему регистру и обрезать пробелы до хеширования: иначе один и тот же ящик с заглавной буквы даст второго пользователя. И ключ должен быть неизменным: если пользователь сменит почту, выведенный из неё идентификатор либо останется прежним и перестанет соответствовать данным, либо изменится и оторвётся от всех ссылок на него в соседних таблицах. Нет подходящего ключа, возвращайтесь к первому способу.</p><h3>Довесок: оптимистичная блокировка</h3><p>Этот приём идемпотентности не даёт и в списке стоит по другой причине. Ключ защищает от повторов одного и того же запроса, но ничего не делает с двумя <b>разными</b> запросами, которые правят одну запись. Здесь работает проверка версии: клиент присылает версию, которую видел, а сервер отклоняет обновление при несовпадении.</p><p>Обратите внимание, что проверка версии живёт внутри самого UPDATE. Разнести её на отдельное чтение и последующую запись означало бы воспроизвести ровно ту гонку, о которой пойдёт речь в следующем разделе: два запроса с одной устаревшей версией оба прошли бы проверку и оба записали бы результат. Идемпотентным одиночный запрос этот приём не делает, зато закрывает частый источник задвоенных эффектов: двух писателей, затирающих работу друг друга.</p><h2>Где наивная реализация ключа разваливается</h2><h3>Гонка в проверке</h3><p>Последовательность «проверить наличие ключа, потом вставить» содержит зазор, в который помещаются оба одновременных повтора: обе стороны видят, что ключа нет, и обе выполняют работу. Резервировать ключ нужно атомарно, через уникальное ограничение базы, условную запись или транзакционный compare-and-set (атомарное сравнение с записью).</p><p>Это же относится и к примеру с платежом выше: замена словаря в памяти на Redis гонку не закрывает, пока проверка и вставка остаются двумя отдельными командами. Нужен атомарный примитив резервирования, вроде SET key value NX или INSERT ... ON CONFLICT DO NOTHING.</p><p>Проверяется это только настоящей конкуренцией. Юнит-тест, вызывающий функцию дважды подряд, гонку не поймает никогда. Отправьте полсотни одновременных запросов с одним ключом и убедитесь, что побочный эффект произошёл ровно один раз.</p><h3>Слепок запроса, а не только ключ</h3><p>Хранить один ключ недостаточно. Сервер канонизирует поля, определяющие бизнес-смысл операции, и считает от них хеш. Канонизация означает приведение к единому виду порядка полей, форматов чисел и дат, опущенных значений по умолчанию и незначащих пробелов. Если повторный вызов обязан воспроизвести решение, принятое по прежним правилам, в слепок включают ещё и версию политики. Пример: между первой попыткой и повтором поменялись тарифы, и повтор обязан вернуть старую цену, а не пересчитать по новой. Без версии в слепке сервер этого различия не увидит.</p><p>Когда тот же ключ приходит с другим слепком, это ошибка на стороне клиента, и отдавать ему старый результат нельзя. <a href="https://dev.to/seo_optimization_591fad6c/designing-idempotent-decision-endpoints-that-survive-real-retries-6c1">Разбор проектирования идемпотентных ручек</a> предлагает отвечать 409 Conflict; <a href="https://dev.to/sirmax/3-ways-to-make-your-api-requests-idempotent-with-working-code-4inl">автор практического руководства</a> в этом случае возвращает 422. Важно, чтобы выбранный код был задокументирован и никогда не подменяется молчаливой отдачей чужого ответа.</p><h3>Состояния и коды ответа</h3><p>Минимальная модель состояний записи выглядит так: PROCESSING, SUCCEEDED, FAILED_RETRYABLE и FAILED_FINAL. Рядом хранятся ключ операции, слепок, отметки времени, идентификатор решения, снимок ответа и версия политики. Клиенту нужна детерминированная карта из состояния в код ответа:</p><ul><li>201 или 200 — первый успешно завершённый результат.</li><li>200 с явной пометкой о повторе — проигрывание сохранённого ответа.</li><li>202 со ссылкой на статус — работу уже выполняет другой обработчик, начинать вторую не нужно.</li><li>409 — ключ переиспользован с другим содержимым.</li><li>Задокументированная финальная ошибка — обработка провалилась, и автоматическое продолжение небезопасно.</li></ul><p><b>Срок жизни ключей:</b><br />Хранить их вечно не нужно, это медленная утечка. Сутки покрывают практически любое реальное окно повторов, но выбирать срок стоит от риска предметной области: у платежей и у рекомендаций он разный. И помните, что ключ приходит снаружи: ограничьте длину и набор символов, привяжите его к арендатору и не дайте одному пользователю вытащить результат чужой операции.</p><h2>Вторая половина задачи: база и очередь</h2><p>Допустим, ручка стала идемпотентной. Остаётся более коварная проблема: почти всякая бизнес-операция пишет не в одно место. Заказ сохраняется в базу и публикует событие в очередь, чтобы склад начал сборку, почтовый сервис отправил подтверждение, а антифрод посмотрел на транзакцию.</p><p>Обе половины статьи растут из одного факта: ни HTTP, ни очередь не обещают доставку ровно один раз, они обещают её хотя бы один раз. Поэтому защищаться приходится дважды, на входе и на выходе.</p><p>Это две записи в две разные системы, и общей транзакции у них нет. Упал процесс, моргнула сеть, выкатился деплой между двумя вызовами — одна сторона зафиксирована, вторая нет. Заказ подтверждён на экране покупателя, а склад о нём не знает. Ошибка при этом нигде не залогирована и алерт не сработал.</p><h3>Почему обернуть это в транзакцию нельзя</h3><p>Соблазнительный и заведомо неверный вариант выглядит так:</p><p>Транзакция базы не имеет власти над очередью и умеет откатывать только операции базы. Если отправка прошла, а COMMIT упал, сообщение уже в очереди и забрать его оттуда нельзя.</p><p>Есть и вторая беда, чисто эксплуатационная. Такой код держит открытое соединение и блокировки строк всё время сетевого вызова. Обычно очередь отвечает быстро, но под нагрузкой, ретраями или деградацией вызов растягивается на секунды, и все запросы к тем же строкам стоят в очереди. Это надёжный способ исчерпать пул соединений и уронить заодно ни в чём не повинные части сервиса.</p><h3>Outbox: событие как строка в той же транзакции</h3><p>Идея паттерна в том, чтобы перестать считать публикацию второй записью. Вместо вызова очереди приложение вставляет строку в таблицу outbox в той же транзакции, что и бизнес-запись. Отдельный процесс читает таблицу и публикует сообщения дальше.</p><p>Откатилась транзакция, и вместе с ней исчезла строка outbox: осиротевшего сообщения в очереди не осталось. Упало приложение сразу после фиксации — строка на месте со статусом pending, и доставщик заберёт её на следующем проходе. Паттерн опирается ровно на одну гарантию, которую база и так даёт: атомарность одной транзакции.</p><p>Доставщик выбирает пачку необработанных строк и помечает их отправленными только после подтверждения очередью. Ключевая деталь здесь одна:</p><p>Этот SELECT и последующая простановка статуса выполняются в одной транзакции: блокировка живёт до фиксации. Благодаря SKIP LOCKED доставщик масштабируется горизонтально из коробки, каждый экземпляр берёт свой набор строк. А если он упадёт посреди пачки, вся пачка откатится и уйдёт повторно, что даёт ещё один довод в пользу идемпотентного потребителя.</p><p>Может показаться, что здесь мы делаем ровно то, что осудили выше: держим блокировку на время сетевого вызова. Разница в том, что блокируется не бизнес-таблица и соединение берётся не из пула, обслуживающего пользовательские запросы, а SKIP LOCKED не даёт одной медленной строке задержать остальные.</p><h3>Потребитель обязан быть идемпотентным</h3><p>Если доставщик упал посреди прохода, на следующем он переотправит те же строки. Очереди вроде SQS и Kafka в типовой конфигурации гарантируют доставку «хотя бы один раз», поэтому дедупликация на приёмной стороне обязательна, и уникальным ключом служит идентификатор события или решения.</p><p>Делает это условная запись. Важная деталь, на которой легко ошибиться: сама по себе она пустой операцией не становится. При несовпадении условия драйвер бросает исключение, и его нужно поймать явно, отличив штатный повтор от настоящей ошибки:</p><p>Настройки продюсера и подтверждения брокера снижают количество повторов, но не снимают с приложения ответственность за однократность бизнес-эффекта.</p><h3>Что добавить перед продакшеном</h3><p>Двух статусов мало. Нужен статус failed и счётчик попыток: после N неудач строка помечается провалившейся и перестаёт крутиться в цикле вечно. На стороне очереди настраивается очередь недоставленных сообщений, чтобы то, что потребитель не смог обработать, оседало в наблюдаемом месте, а не исчезало молча.</p><p>Когда задержка опроса становится критичной, полагающийся на периодический опрос доставщик заменяют захватом изменений: инструменты вроде Debezium читают журнал предзаписи PostgreSQL и публикуют изменения без паузы на опрос. Таблица outbox и потребитель при этом не меняются. Но это заметно более тяжёлое эксплуатационное обязательство, поэтому начинать почти всегда стоит с опроса.</p><h2>Что забрать с собой</h2><p>Обе части задачи выглядят избыточными ровно до первого инцидента. Тридцать строк кода с ключом идемпотентности стоят дешевле одного тикета с заголовком «вы списали дважды», а таблица outbox дешевле расследования, почему заказ есть у клиента и отсутствует на складе.</p><p>Коварство проблемы двух записей в том, что наивная реализация работает правильно почти всегда. Она отказывает в зазоре между двумя системами, и зазор этот становится виден только когда что-то пошло не так в самый неподходящий момент. К моменту, когда расхождение заметят в продакшене, данные уже разъехались, и красивого способа их починить не будет.</p><p>Как одно неверное допущение о порядке вызовов обернулось эпидемией задвоенных операций, показано в <a href="https://tproger.ru/articles/skrytyj-sboj-idempotentnosti-v-finteh-sisteme-razbor-incidenta">разборе реального инцидента в финтех-системе</a>.</p><p>Материалы, на которых основан разбор: <a href="https://dev.to/sirmax/3-ways-to-make-your-api-requests-idempotent-with-working-code-4inl">три паттерна идемпотентности с рабочим кодом</a>, <a href="https://dev.to/seo_optimization_591fad6c/designing-idempotent-decision-endpoints-that-survive-real-retries-6c1">проектирование ручек, переживающих реальные повторы</a> и <a href="https://www.freecodecamp.org/news/how-to-fix-the-dual-write-problem-in-node-js-with-the-outbox-pattern/">пошаговая сборка outbox на Node.js</a>.</p><p>Откройте самый денежный обработчик в своём сервисе и попробуйте отправить в него один и тот же запрос дважды. Если во второй раз что-то произошло, вы уже знаете, с чего начать понедельник.</p>]]></content:encoded>
    </item>
    <item>
      <title>NULL в SQL: почему запрос отрабатывает и молча отдаёт неверное число</title>
      <link>https://tproger.ru/articles/null-v-sql-pochemu-zapros-otrabatyvaet-i-molcha-otdayot-nevernoe-ch</link>
      <comments>https://tproger.ru/articles/null-v-sql-pochemu-zapros-otrabatyvaet-i-molcha-otdayot-nevernoe-ch?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/null-v-sql-pochemu-zapros-otrabatyvaet-i-molcha-otdayot-nevernoe-ch</guid>
      <description><![CDATA[<p>Почему WHERE x = NULL не находит строки, как одно пустое значение обнуляет весь NOT IN и на что делится среднее. Разбираем на примерах Postgres.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/null-v-sql-pochemu-zapros-otrabatyvaet-i-molcha-otdayot-nevernoe-ch">NULL в SQL: почему запрос отрабатывает и молча отдаёт неверное число</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Анализ данных]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 08 Sep 2026 06:08:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>В SQL деление на ноль Postgres остановит с ошибкой. Приведение строки «abc» к числу тоже. А деление на NULL пройдёт, и запрос вернёт результат. Просто не тот, которого вы ждали.</p><p>Это главная особенность работы с отсутствующими значениями: ошибок нет, есть тихо неправильные числа. Разбираем, откуда они берутся в фильтрах, в арифметике, в агрегатах и в соединениях, и какими операторами это лечится.</p><p>Отправная точка одна: NULL — не значение, а отметка «неизвестно». Неизвестность распространяется дальше по всему выражению: через сравнения, арифметику, склейку строк, агрегаты, оконные функции и условия отбора. Результат при этом строго определён правилами языка, он просто может не совпасть с тем, что вы имели в виду.</p><p>В SQL три логических исхода, а не два: истина, ложь и неизвестность. Условие отбора оставляет только строки с истиной, поэтому неизвестность отбрасывается наравне с ложью.</p><p>Сравнение = NULL не почти верно, а отвечает на другой вопрос. Для проверки на отсутствие есть отдельные операторы, которые сравнением не являются.</p><p>Одно значение NULL в списке для NOT IN обнуляет всю выдачу целиком, а не сужает её.</p><p>Соединение по равенству отбрасывает строки, где ключ отсутствует с обеих сторон, и то же самое делает проверка уникальности.</p><p>Запрос, который отработал, прошёл только проверку грамматики. Число становится верным, когда с вопросом совпали строки, фильтры и знаменатель.</p><h2>Три логических исхода вместо двух</h2><p>Начнём с простого случая. В таблице клиентов у одного из них не заполнен телефон, и это прямо видно глазами. Запрос находит ноль строк:</p><p>Условие phone = NULL спрашивает: «равно ли это неизвестное значение тому неизвестному значению?» Ответить на такое нельзя, поэтому <a href="https://dev.to/systemcraftdev/why-where-x-null-never-works-in-sql-and-what-to-use-instead-3p4h">для каждой строки возвращается неизвестность</a>, включая ту самую строку с пустым телефоном. А отбор оставляет только строки, где условие истинно. Неизвестность не проходит ровно так же, как не прошла бы ложь.</p><p>Правило действует единообразно: NULL = NULL тоже не истина, а неизвестность. Отсюда и главный вывод — оператор равенства нельзя «подправить», чтобы он здесь заработал. Он не почти прав, он отвечает на другой вопрос.</p><p>В Postgres это проверяется одной строкой. Что вернёт такое выражение?</p><p>Оба внутренних сравнения неизвестны, поэтому внешнее сравнивает неизвестность с неизвестностью и тоже даёт неизвестность. Операторы сравнения возвращают NULL, если хотя бы одна сторона неизвестна. Именно поэтому в языке есть отдельный оператор проверки на отсутствие: узнать, равны ли две неизвестности, нельзя, а узнать, является ли значение неизвестным, можно.</p><h3>Как ведут себя И, ИЛИ и НЕ</h3><p>Логические связки тоже работают в трёх значениях, и запомнить стоит два исключения:</p><p>То есть ИЛИ всё ещё истинно, если истинна вторая сторона, а И всё ещё ложно, если ложна вторая сторона. Всё остальное с участием неизвестности схлопывается в неизвестность.</p><p>Последствия неочевидны. Вот запрос, который отбрасывает строку, которую вы почти наверняка хотели оставить:</p><p>В обычной двузначной логике «активно или не активно» — тавтология, утверждение, истинное при любом значении. В SQL это не так.</p><h3>Операторы, которые никогда не возвращают неизвестность</h3><p>Лечится это выходом из трёхзначной логики. Сначала решите, что NULL означает в вашей предметной области, а потом скажите это явно:</p><p>Проверки IS TRUE, IS NOT TRUE, IS FALSE, IS NOT FALSE и IS UNKNOWN никогда не возвращают неизвестность, поэтому строку не потеряют.</p><p>Аналог того же для равенства — IS NOT DISTINCT FROM. Обычное равенство спрашивает, известно ли, что значения совпадают. Этот оператор спрашивает, одно ли это значение, обращаясь с отсутствием как с полноценным состоянием. Две неизвестности неразличимы, поэтому предикат истинен.</p><p><b>Где это пригодится:</b><br />Соединение по условию равенства отбрасывает строки, где ключ отсутствует с обеих сторон. Если два отсутствующих ключа должны считаться совпадением, замените равенство на IS NOT DISTINCT FROM. То же касается проверок уникальности и условий отбора, где «отсутствует» должно означать «отсутствует», а не «неизвестно».</p><h2>Ловушка NOT IN, из-за которой пропадает вся выдача</h2><p>Это самый дорогой из всех эффектов, потому что он не сужает результат, а стирает его целиком. Операторы IN и NOT IN разворачиваются в цепочки сравнений, а NOT IN — в цепочку через И:</p><p>Разберём оба исхода. Если значение совпало с одним из перечисленных, срабатывает то самое правило «И спасает ложь справа», и выражение честно ложно. Если не совпало ни с одним, множитель со сравнением с пустым значением делает всё выражение неизвестным.</p><p>Для условия отбора разницы между этими исходами нет: оно оставляет только истину, а ложь и неизвестность отбрасывает одинаково. Поэтому итог один — если в списке или в подзапросе есть хотя бы одно отсутствующее значение, NOT IN не вернёт ни одной строки. Никакой ошибки при этом не будет.</p><p>Обычный IN ведёт себя мягче, поскольку разворачивается в цепочку через ИЛИ: совпадение остаётся истиной независимо от того, что ещё есть в списке. В простом условии отбора пустое значение в списке вообще ничего не меняет: несовпавшая строка отсеется что при неизвестности, что при лжи. Разница вылезает там, где результат сравнения используется дальше: под отрицанием, в выражении CASE или в ограничении целостности.</p><p>Надёжная замена — NOT EXISTS, который работает через равенство внутри условия отбора и потому никогда не трактует сравнение с отсутствующим значением как совпадение. Тот же смысл выражает антисоединение, которое вдобавок часто даёт лучший план:</p><p>Вычистить отсутствующие значения из подзапроса тоже можно, но это помогает, только если вы уверены, что их следует игнорировать. Вариант с NOT EXISTS делает это намерение явным, а не подразумеваемым.</p><h2>Арифметика: одно значение NULL обнуляет строку</h2><p>Любая арифметическая операция с участием отсутствующего значения даёт отсутствующее значение. Сложение, умножение, деление, модуль, возведение в степень — результат один.</p><p>В отчётах это выглядит как пустые ячейки, а в обновлениях данных как стёртые колонки. Классический пример, который каждый когда-нибудь писал:</p><p>Подставлять значение по умолчанию нужно в той точке, где вам известно правило предметной области, а не механически везде. В разборе Кристофера Уинслетта из Crunchy Data приводится удачная иллюстрация: <a href="https://www.crunchydata.com/blog/postgres-calculations-and-the-ambiguity-of-null">отсутствующее количество почти всегда означает ноль, отсутствующая ставка налога тоже, а вот отсутствующая цена нулём не является</a> и должна оставаться неизвестной, пока её кто-нибудь не заполнит.</p><h2>Агрегаты и оконные функции считают не то, что кажется</h2><p>Здесь отсутствующие значения ведут себя иначе, чем везде: агрегаты их пропускают. Функция COUNT(*) считает строки, а COUNT(колонка) — только непустые значения; SUM, AVG, MIN и MAX пропускают пустые входы.</p><p>У товара с двумя незаполненными оценками среднее и сумма пусты, а число строк равно двум. Отсюда практическое правило, которое экономит часы разбирательств с аналитикой: среднее — это сумма, делённая на количество непустых значений, а не на количество строк. Смешивать SUM(x) / COUNT(*) и ожидать совпадения со средним нельзя.</p><p>Оговорка про типы тоже важна: если сумма и счётчик целочисленные, деление усечёт дробную часть. Шесть, делённое на два, случайно даст ровно три, а оценки 5, 1 и 2 дадут при целочисленном делении двойку вместо 2,67.</p><h3>Где ломаются оконные функции</h3><p>Суммирование и усреднение в окне пропускают отсутствующие значения так же, как при группировке, а ROW_NUMBER считает строку в любом случае. Расхождение начинается у функций, которые смотрят в конкретную позицию окна: LAG, LEAD, FIRST_VALUE, LAST_VALUE и NTH_VALUE.</p><p>Такая функция возвращает то, что лежит в запрошенной позиции. Если там пусто, результат пуст. Ближайшее реальное значение она не ищет, и на рядах измерений с пропущенным отсчётом это даёт разрывы там, где ожидалась непрерывность.</p><h2>Проверка чужого запроса, включая сгенерированный</h2><p>Всё описанное складывается в одну проблему: запрос, который отработал, прошёл только проверку грамматики. База ловит опечатку в имени таблицы. Она не ловит суммирование не той колонки, соединение, задваивающее строки, и фильтр, поставленный не на том этапе. Каждая из этих ошибок — синтаксически корректный SQL.</p><p>Со сгенерированными запросами есть <a href="https://dev.to/michaelnocito/how-to-review-ai-generated-sql-before-you-trust-the-number-19ek">отдельная сложность</a>: они беглые. Псевдонимы аккуратные, форматирование чистое, форма выглядит как работа внимательного человека. Беглость читается как правильность, хотя это разные вещи.</p><h3>Проверка первая: посчитайте строки до того, как поверите сумме</h3><p>Задача звучала как «чистая выручка по завершённым заказам». Полученный запрос:</p><p>Он отрабатывает и возвращает 1830. Правильный ответ 1330, и это легко проверить руками: валовая сумма одиннадцати завершённых заказов равна 1605, возвраты составляют 275.</p><p>Виновато соединение. Два заказа возвращались частями, по две записи на каждый, поэтому одиннадцать строк превращаются в тринадцать, а сумма по заказам считает эти два заказа дважды: 2105 вместо 1605. Лишние 500 — это ровно стоимость задвоенных заказов. Явление называется размножением строк: соединение множит строки всякий раз, когда ключ на другой стороне встречается больше одного раза.</p><p>Проверка стоит двух запросов:</p><p>Одно это сравнение всё решает. Второе число выросло, значит, соединение размножило строки, и любая сумма или среднее по колонкам левой таблицы под подозрением. Число совпало — соединение безопасно, идём дальше.</p><h3>Проверка вторая: ищите отсутствующие значения в каждом фильтре</h3><p>Следующая просьба звучала как «та же выручка, но без служебных аккаунтов», и запрос получился такой:</p><p>Он возвращает пустоту, полученную из нуля строк. Не меньшее число, а вообще ничего. Механизм вы уже знаете: в справочнике служебных аккаунтов есть одна строка с незаполненным идентификатором, а справочники в реальной жизни такими и бывают. Одна такая строка бесшумно опустошает результат целиком.</p><h2>Что забрать с собой</h2><p>Правила про отсутствующие значения не сложны, они просто действуют не там, где их ждут. Из фильтра строка пропадает молча, арифметика превращает результат в пустоту, соединение по равенству теряет пары без ключа, а среднее делит на другой знаменатель. Ошибки при этом нигде не возникает, и потому такие дефекты живут в отчётах годами.</p><p>Самый надёжный способ не разбираться со всем этим каждый раз — не хранить отсутствующие значения там, где они не нужны. Если колонка обязана иметь значение, скажите это в схеме. Ограничение NOT NULL выглядит формальностью ровно до первого расследования, почему выручка в отчёте оказалась на пятьсот единиц больше настоящей.</p><p>Материалы разбора: <a href="https://dev.to/systemcraftdev/why-where-x-null-never-works-in-sql-and-what-to-use-instead-3p4h">почему сравнение с NULL никогда не срабатывает</a>, <a href="https://www.crunchydata.com/blog/postgres-calculations-and-the-ambiguity-of-null">поведение NULL в вычислениях Postgres</a> и <a href="https://dev.to/michaelnocito/how-to-review-ai-generated-sql-before-you-trust-the-number-19ek">проверка сгенерированного SQL до того, как поверить числу</a>.</p><p>Откройте последний отчёт, который вы отдавали наружу, и сравните в нём количество строк до и после соединений. Проверка занимает пять минут и иногда меняет цифру, на которую уже сослались в переписке.</p>]]></content:encoded>
    </item>
    <item>
      <title>Postgres Pro закрыл 28 уязвимостей PostgreSQL внеочередными релизами</title>
      <link>https://tproger.ru/news/postgres-pro-zakryl-28-uyazvimostej-postgresql-vneocherednymi-reli</link>
      <comments>https://tproger.ru/news/postgres-pro-zakryl-28-uyazvimostej-postgresql-vneocherednymi-reli?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/postgres-pro-zakryl-28-uyazvimostej-postgresql-vneocherednymi-reli</guid>
      <description><![CDATA[<p>Postgres Professional выпустила «нулевые» релизы Postgres Pro Enterprise с 28 исправлениями безопасности PostgreSQL. Что закрыто и что переиндексировать после апдейта.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/postgres-pro-zakryl-28-uyazvimostej-postgresql-vneocherednymi-reli">Postgres Pro закрыл 28 уязвимостей PostgreSQL внеочередными релизами</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Sep 2026 11:40:05 GMT</pubDate>
      <content:encoded><![CDATA[<p>Postgres Professional 2 сентября <a href="https://habr.com/ru/companies/postgrespro/news/1076556/">сообщила</a> о выходе «нулевых» релизов Postgres Pro Enterprise: внеочередных обновлений безопасности, которые переносят в корпоративную редакцию исправления 28 уязвимостей и более 110 ошибок из августовского обновления PostgreSQL. По словам компании, она первая и пока единственная среди коммерческих форков на российском рынке, кто довёл эти исправления до редакции уровня enterprise.</p><p>Если ваш прод стоит на Postgres Pro Enterprise, это тот случай, когда обновляться нужно не по плану, а сейчас: среди закрытых проблем четырнадцать с оценкой CVSS 8,8, и для одиннадцати из них upstream прямо пишет о выполнении произвольного кода, причём часть срабатывает через обычные SQL-функции вроде to_char() или через регулярные выражения. Если вы на ванильном PostgreSQL, те же исправления вышли ещё 13 августа в версиях 18.6, 17.11, 16.15, 15.19 и 14.24, и проверить стоит, что вы их уже накатили.</p><ul><li>«Нулевые» релизы Postgres Pro Enterprise содержат только исправления безопасности и ошибок, без новых функций; новые возможности придут в плановых минорных версиях вида 17.11.1.</li><li>Закрыты 28 CVE и более 110 багов из обновления PostgreSQL от 13 августа 2026 года (18.6, 17.11, 16.15, 15.19, 14.24).</li><li>Самые опасные: 14 CVE с оценкой 8,8, из них 11 на выполнение произвольного кода, включая переполнения буфера в regexp, to_char(), PL/Perl, pg_stat_statements и pg_dump.</li><li>Обновление накопительное, pg_upgrade не нужен: остановить сервер и заменить бинарники; после этого проверить GIN-, btree_gist- и ltree-индексы.</li><li>Компания связывает скорость выпуска с приказом ФСТЭК №117 для госорганов и ГИС: критические уязвимости устранять за 24 часа, высокие за 7 дней.</li></ul><h2>Что такое «нулевой» релиз</h2><p>Обычный цикл коммерческого форка выглядит так: выходит минорный релиз upstream PostgreSQL, вендор переносит исправления в свою ветку, тестирует вместе с собственными доработками и выпускает очередную минорную версию, где безопасность идёт вперемешку с новыми функциями. Для заказчика это означает выбор: либо ждать плановый релиз с открытыми дырами, либо ставить его сразу и получать вместе с патчами новую функциональность, которую никто не тестировал в его контуре.</p><p>«Нулевой» релиз разрывает эту связку. Он собирается на базе предыдущего минорного релиза Postgres Pro Enterprise, в него переносятся только исправления из актуальной версии PostgreSQL, и никаких новых возможностей там нет. Доработки, отложенные ради скорости, выйдут позже в привычных минорных версиях по обычному циклу. Технический директор Postgres Professional Юлия Рыденкова объясняет это так: «Заказчик может установить необходимые исправления сразу, не дожидаясь следующего планового обновления и не внедряя одновременно с этим новые возможности продуктов».</p><p>Подход не новый для индустрии: примерно так устроены security-only ветки у дистрибутивов Linux. Для российского рынка СУБД, где заказчики часто сидят на сертифицированных редакциях с долгим циклом обновления, разделение потоков «безопасность» и «функции» снимает главный аргумент против быстрого патчинга.</p><h2>Какие уязвимости закрыты</h2><p>Все 28 CVE перечислены в <a href="https://www.postgresql.org/about/news/postgresql-186-1711-1615-1519-1424-and-19-beta-3-released-3365/">анонсе PostgreSQL</a> от 13 августа. Четырнадцать из них имеют максимальную в этом наборе оценку CVSS 8,8; Postgres Professional выделяет одиннадцать, где по описанию upstream возможно выполнение произвольного кода:</p><ul><li>CVE-2026-14664: переполнение буфера в обработке регулярных выражений.</li><li>CVE-2026-14669: переполнение буфера в функции to_char().</li><li>CVE-2026-14670: переполнение буфера в связанных (tied) объектах PL/Perl.</li><li>CVE-2026-14671: путаница типов в кэше планов contrib/refint.</li><li>CVE-2026-14676: переполнение буфера в pg_stat_statements.</li><li>CVE-2026-14680: путаница типов через аргументы типа internal.</li><li>CVE-2026-15741: SQL-инъекция через аргумент функции EXTRACT() при обратном разборе (deparse) выражений.</li><li>CVE-2026-16238 и CVE-2026-16239: путаница типов в pg_restore_attribute_stats() и в связке CLOSE + DECLARE курсоров.</li><li>CVE-2026-18408: команда psql \unrestrict позволяла суперпользователю сервера-источника pg_dump выполнить произвольный код в клиенте psql при восстановлении дампа.</li><li>CVE-2026-19385: переполнение буфера в pg_dump.</li></ul><p>Ещё две проблемы стоят отдельно. CVE-2026-6471 (CVSS 7,2): пользователь с правами на репликацию мог заставить логическое декодирование подгрузить произвольную библиотеку через dlopen. После исправления список разрешённых плагинов вывода ограничен новым параметром output_plugin_libraries, и если у вас работает логическая репликация с нестандартными плагинами, их нужно туда прописать. CVE-2026-6464 (CVSS 8,1) касается psql: при раннем сбое команды COPY FROM STDIN или \copy FROM STDIN строки данных могли быть разобраны как команды psql. Для эксплуатации нужен контроль и над серверной ошибкой, и над данными COPY; вариант COPY FROM с именем файла не затронут.</p><p>Ещё три уязвимости с оценкой 8,8 в этот список компания не включила: недоразмерные выделения памяти в tsvector и tsquery (CVE-2026-14662), в 32-битных pltcl и plperl (CVE-2026-14677) и запись по произвольным адресам в fuzzystrmatch (CVE-2026-15742). Остальные пункты списка, от раскрытия существования пользователя через нестандартное число итераций SCRAM (CVE-2026-14672, CVSS 5,3) до чтения за границей буфера в функции ascii() (CVE-2026-18024, CVSS 4,3), имеют оценки от 3,8 до 8,2. Компания отмечает, что несколько уязвимостей, в частности CVE-2026-16239 и CVE-2026-14680, найдены исследователями при участии ИИ-инструментов Claude и Codex Security.</p><h2>Что делать после обновления</h2><p>Обновления накопительные: выгружать и загружать базы или запускать pg_upgrade не нужно, достаточно штатно остановить сервер и заменить бинарные файлы. Но после этого Postgres Professional, как и upstream в своём анонсе, просит выполнить несколько проверок, потому что часть исправлений затрагивает индексы:</p><ol><li>Проверить таблицы с GIN-индексами и выполнить ANALYZE, если значение reltuples выглядит некорректным (исправлена ошибка параллельной сборки GIN).</li><li>Переиндексировать btree_gist-индексы на столбцах типов float4, float8, bit и bit varying, если они есть.</li><li>Переиндексировать B-tree-индексы по столбцам ltree, если значения могут содержать больше 14 653 меток.</li><li>Проверить конфигурацию логического декодирования и добавить доверенные плагины в output_plugin_libraries.</li></ol><p>Пользователям ванильного PostgreSQL стоит помнить ещё об одном: ветка 14 перестанет получать исправления 12 ноября 2026 года, а версии 18.4 и 18.5 не выходили вовсе, ветка 18 перескочила с 18.3 сразу на 18.6 из-за регрессии в 18.5.</p><h2>Почему компания торопится</h2><p>Postgres Professional прямо связывает формат «нулевых» релизов с регуляторикой. С 1 марта 2026 года действует приказ ФСТЭК России №117 от 11 апреля 2025 года о защите информации в государственных информационных системах и системах госорганов и госучреждений: уязвимости критического уровня нужно устранить или закрыть компенсирующими мерами за 24 часа, высокого уровня за 7 календарных дней, а если уязвимости нет в БДУ ФСТЭК, сведения о ней нужно направить в службу в течение 5 рабочих дней. На коммерческие компании приказ напрямую не распространяется, но именно госзаказчики составляют заметную часть пользователей сертифицированных редакций, и для них ждать плановый релиз вендора с патчем невозможно: сроки считаются с момента выявления.</p><p>Второй фактор, который называет компания: ИИ-инструменты резко ускорили поиск дефектов. В качестве примера Postgres Professional ссылается на программу координированного раскрытия уязвимостей Anthropic, в которой модель Claude нашла и передала мейнтейнерам сотни проблем в проектах с открытым кодом; две CVE из сегодняшнего списка тоже найдены с участием ИИ. Чем быстрее находят, тем важнее способность вендора быстро адаптировать и протестировать upstream-патч для своей редакции.</p><p>Чего в сообщении нет: точных номеров «нулевых» версий по веткам и ссылок на страницы загрузки. Не сказано и о сроках аналогичных релизов для редакции Postgres Pro Standard. Следующая точка на календаре для всех пользователей PostgreSQL, плановое квартальное обновление upstream в ноябре; будет ли к нему «нулевой» релиз и как быстро, компания не обещала.</p><p>Источники: <a href="https://habr.com/ru/companies/postgrespro/news/1076556/">Postgres Professional: новость на Хабре</a>, <a href="https://www.postgresql.org/about/news/postgresql-186-1711-1615-1519-1424-and-19-beta-3-released-3365/">PostgreSQL 18.6, 17.11, 16.15, 15.19, 14.24 and 19 Beta 3 Released</a>, <a href="https://www.postgresql.org/support/security/">PostgreSQL: Security Information</a></p><p>Изображение на обложке: Изображение: Postgres Professional</p>]]></content:encoded>
    </item>
    <item>
      <title>Бесплатный WAF инструмент кибербезопасности, который я использую</title>
      <link>https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu</link>
      <comments>https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Неопознанный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu</guid>
      <description><![CDATA[<p>Разбор бесплатного open-source WAF SafeLine для защиты от OWASP Top 10, DDoS и ботов. Сравнение с ModSecurity и Cloudflare по точности обнаружения атак, минимальные ложные срабатывания, простая установка одной командой Docker.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu">Бесплатный WAF инструмент кибербезопасности, который я использую</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[CSR]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Jul 2026 05:55:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Решения с открытым исходным кодом достигли такого уровня зрелости, что сегодня они действительно могут конкурировать с коммерческими продуктами — не только по функциональности, но и по удобству использования и поддержке сообщества. Если вы управляете собственной инфраструктурой, больше нет оправдания тому, чтобы оставлять дверь открытой для угроз.</p><p>SafeLine WAF — это бесплатный инструмент, который я лично тестировал.</p><p>Это полностью open-source решения, продукт с действительно бесплатной Community Edition, где ключевые функции не урезаны.</p><p><b>SafeLine WAF — веб-приложенийный межсетевой экран, который действительно поставляется с разумными настройками по умолчанию</b></p><p><b>Что он делает:</b></p><p>Защищает веб-приложения от SQL-инъекций, XSS-атак, командных инъекций, CSRF, SSRF, атак включения файлов и других угроз из списка OWASP Top 10. Также поддерживает защиту от CC/DDoS-атак, управление ботами и может работать как шлюз аутентификации.</p><p><b>Почему он:</b></p><p>Большинство WAF с открытым исходным кодом достаточно сложно настроить. Можно потратить часы на настройку правил, пытаясь остановить ложные срабатывания, из-за которых легитимные пользователи блокируются.</p><p>SafeLine использует другой подход — вместо того чтобы полностью полагаться на сигнатурное обнаружение, он применяет движок семантического анализа, который фактически анализирует и понимает входящие HTTP-запросы. Это позволяет добиться более высокого уровня обнаружения при значительно меньшем количестве ложных срабатываний по умолчанию.</p><p>Некоторые показатели, которые стоит учитыват</p><ol><li>Уровень обнаружения - SafeLine (Balanced) (71.65%), ModSecurity (Level 1) (69.74%), Cloudflare (Free) (10.7%)</li><li>Уровень ложных срабатываний - SafeLine (Balanced) (0.07%), ModSecurity (Level 1) (17.58%), Cloudflare (Free) (0.07%)</li><li>Точность - SafeLine (Balanced) (99.45%), ModSecurity (Level 1) (82.20%), Cloudflare (Free) (98.40%)</li></ol><p>Сбалансированный профиль SafeLine обнаруживает более 70% атак, при этом блокируя легитимный трафик ошибочно всего в 0.07% случаев. Это именно тот уровень настроек по умолчанию, который можно использовать в промышленной среде без постоянного ручного контроля.</p><p>Установка выполняется одной командой</p><p>После запуска он разворачивается как набор Docker-контейнеров: Tengine (форк Nginx) используется в качестве reverse proxy, отдельный сервис отвечает за семантический анализ, PostgreSQL хранит конфигурации и логи, а удобная веб-панель администратора работает на порту 9443.Community Edition поддерживает до 10 сайтов, чего достаточно для большинства личных проектов и небольших бизнес-сценариев.</p><p>Сайт: <a href="https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fcodeby.net%2Fgoto%2Flink-confirmation%3Furl%3DaHR0cHM6Ly9jeWJlcnNlcnZhbC50ZWNoL2xhbmRpbmcvc2FmZWxpbmXvv7xHaXRIdWI%253D%26s%3D7008b60d8a0849ba0be350fe25edfa72&amp;postId=3005263" rel="nofollow noopener">https://cyberserval.tech/landing/safeline</a></p><p>GitHub:<a href="https://api.vc.ru/v2.8/redirect?to=http%3A%2F%2Fgithub.com%2Fchaitin%2FSafeLine&amp;postId=3005263" rel="nofollow noopener"> github.com/chaitin/SafeLine</a> (более 21 тыс. звёзд)</p><p>Лицензия: GPL-3.0 / MIT (Community Edition)</p>]]></content:encoded>
    </item>
    <item>
      <title>Как приручить legacy-код: безопасная модернизация без заморозки фич</title>
      <link>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</link>
      <comments>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[KODE]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</guid>
      <description><![CDATA[<p>Как модернизировать legacy-код без остановки продукта: Strangler Fig Pattern, feature flags, shadow testing и безопасная миграция данных. Практика и антипаттерны.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki">Как приручить legacy-код: безопасная модернизация без заморозки фич</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Twitter]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[OpenTelemetry]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Техника]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Jun 2026 06:16:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Legacy-код — одна из самых болезненных тем в инженерных командах. Обычно все понимают, что система устарела: архитектура мешает быстро выпускать изменения, новые фичи приходится встраивать через обходные пути, тесты либо неполные, либо отсутствуют, а любое изменение в одном модуле неожиданно ломает другой.</p><p>Но при этом к такому коду часто боятся прикасаться. И не без причины. В старых системах редко бывает понятная карта зависимостей. Документация устарела, часть знаний живет только в головах нескольких разработчиков, а бизнес при этом продолжает ждать новых релизов, интеграций и продуктовых экспериментов.</p><p>Так появляется классическая ловушка legacy: систему надо модернизировать, но остановить развитие нельзя. Переписать всё с нуля страшно, поддерживать как есть — всё дороже. В результате продукт обрастает временными решениями, скорость разработки падает, а стоимость каждого следующего изменения растет.</p><p>Хорошая новость в том, что модернизация legacy-кода не обязана быть большим взрывом. Старую систему можно менять постепенно, сохраняя рабочий продукт, не замораживая фичи и не устраивая один критический релиз, от которого зависит всё.</p><h2>Почему Big Bang-переписывание чаще всего заканчивается плохо</h2><p>Когда команда долго живет с устаревшей системой, идея переписать всё с нуля выглядит очень соблазнительно. Кажется, что можно наконец избавиться от технического долга, выбрать нормальную архитектуру, перепроектировать модули, покрыть всё тестами и начать «правильно».</p><p>На старте такой план часто звучит логично. Особенно если текущая система действительно мешает развитию. Например, мобильное приложение растет, у него уже миллионы пользователей, бэкенд написан несколько лет назад как монолит, а каждая новая фича требует изменений в десятке мест. Команда устала чинить регрессии, бизнес устал ждать, и всем хочется «один раз нормально переписать».</p><p>Проблема не в самой идее переписывания, а в условиях, при которых оно проваливается. Большой риск возникает, когда совпадают четыре фактора: переписывание занимает много месяцев, в это время бизнес продолжает развивать старую систему, новая версия покрывает сразу большую часть функциональности, а откат связан с миграцией данных. Если все четыре пункта присутствуют, Big Bang почти гарантированно превратится в долгий и дорогой проект.</p><p>Допустим, команда решила переписать модуль заказов в e-commerce-продукте. В старой версии есть корзина, промокоды, доставка и оплата. Команда планирует за полгода сделать новый сервис заказов. Но за эти полгода бизнес добавляет подписки, подарочные сертификаты, частичную оплату бонусами и новую логику возвратов. В итоге новая система, которую проектировали под старые требования, к моменту релиза уже нуждается в доработке.</p><p>Есть и другая проблема: большой релиз почти всегда несет максимальный риск. Если вы заменяете крупный кусок системы целиком, ошибка влияет сразу на большую часть пользователей. Откат тоже становится сложным, потому что новая логика уже связана с новыми данными, контрактами и интеграциями.</p><p>Big Bang всё-таки бывает оправдан — но в узких условиях. Если кодовая база молодая (год-два), пользователей мало, у системы нет критичного состояния в БД и продукт можно временно заморозить или вести в обоих контурах параллельно, полное переписывание может оказаться дешевле постепенной миграции. Это редкая ситуация, и она быстро исчезает по мере роста продукта. В зрелых системах безопаснее работает другой подход — постепенная архитектурная эволюция.</p><h2>Пример: как команда переписала сервис документов и потеряла полгода</h2><p>Команда сопровождала сервис — старый модуль на aiohttp с Pydantic v1, через который проходила вся обработка путевых листов и актов осмотра транспорта. Сервис существовал шесть лет, был покрыт тестами фрагментарно, а его API использовали мобильное приложение водителей, диспетчерская веб-панель и пакетный импорт.</p><p>Команда решила переписать сервис целиком: перейти на FastAPI, обновить Pydantic до v2, заодно почистить контракты и заменить внутреннее хранилище документов с MongoDB на PostgreSQL. План был рассчитан на четыре месяца.</p><p>Через восемь месяцев проект всё ещё не был готов к выкатке, а к десятому месяцу команда откатила миграцию полностью. Причин было несколько.</p><p>Во-первых, переписывание шло параллельно с продуктовой разработкой. За время миграции бизнес добавил два новых типа документов и изменил правила подписи актов. Новая система проектировалась под старые требования и к моменту готовности уже не соответствовала продукту.</p><p>Во-вторых, команда не написала характеристических тестов. Поведение «как есть» нигде не было зафиксировано, и расхождения находились только в продакшене после переключения.</p><p>В-третьих, у старого сервиса были скрытые побочные эффекты, о которых никто не помнил. При смене статуса документа публиковал событие в Kafka, которое читал биллинг и сервис аналитики. В новой реализации это поведение не было воспроизведено, потому что в коде оно выглядело как «лишний» вызов. После переключения биллинг перестал получать события, и расхождение обнаружили только через две недели — по жалобе финансового отдела.</p><p>В-четвёртых, переключение было сделано «в лоб»: маршрут в API Gateway просто перенаправили на новый сервис. Фича-флага не было, теневого запуска не было, плана отката не было. Когда выяснилось, что новый сервис строже валидирует исторические форматы документов и отклоняет часть старых записей, быстро вернуться на старую реализацию не получилось — её к тому моменту уже отключили на стенде, а в БД успели уйти записи в новом формате.</p><p>В итоге миграцию свернули, потратив около десяти человеко-месяцев и потеряв доверие бизнеса. Сервис до сих пор работает в исходной реализации, а команда переходит к плану, описанному ниже.</p><h2>Strangler Fig Pattern: как заменить систему по частям</h2><p>Один из самых практичных подходов к модернизации legacy-кода — Strangler Fig Pattern. В софтверном виде паттерн был сформулирован Мартином Фаулером в 2004 году под названием StranglerFigApplication. Идея проста: не переписывать систему целиком, а постепенно выносить отдельные части в новую реализацию.</p><p>Название пришло из биологии. Фикус-душитель растет вокруг дерева-хозяина и постепенно вытесняет его. В архитектуре принцип похожий: старая система продолжает работать, новая функциональность появляется рядом, а затем отдельные потоки постепенно переводятся на новую реализацию.</p><p>Представим старый монолит интернет-магазина. Внутри него есть каталог, корзина, заказы, платежи, скидки, личный кабинет и уведомления. Переписать всё сразу — рискованно. Но можно начать с относительно изолированного участка, например с уведомлений.</p><p>Сначала команда описывает текущий контракт: какие события приходят в модуль уведомлений, какие каналы используются, какие шаблоны отправляются, какие ошибки считаются допустимыми. Затем рядом создается новый сервис уведомлений, который реализует тот же контракт. На первом этапе он может даже не отправлять реальные сообщения, а только принимать события и логировать результат. После проверки часть трафика переводится на новую реализацию. Когда сервис стабилизируется, старый код уведомлений удаляется из монолита.</p><p>Strangler Fig хорошо работает там, где между старым и новым кодом есть сетевая граница: HTTP, message bus, RPC. Если такой границы нет — например, нужно постепенно заменить функцию или класс внутри одного процесса — используется родственный паттерн Branch by Abstraction: над старой реализацией создается абстракция, рядом пишется новая реализация, переключение происходит через конфигурацию или фича-флаг, после стабилизации старая ветка удаляется. Снаружи это выглядит как Strangler Fig, но без сетевого прокси.</p><p>Такой подход снижает риск. В системе нет одного большого релиза, где всё меняется сразу. Есть серия небольших контролируемых изменений. Каждое можно протестировать, измерить и откатить.</p><h2>Главное правило: сначала повторить поведение, потом улучшать</h2><p>Одна из частых ошибок при модернизации legacy-кода — попытка одновременно переписать систему и улучшить бизнес-логику. Команда смотрит на старый модуль и думает: «Раз уж мы его трогаем, давайте сразу сделаем нормальную архитектуру, изменим контракты, уберем странные кейсы и перепишем поведение».</p><p>Это опасный путь. В legacy-системах странное поведение часто существует не случайно. За ним может стоять неочевидное бизнес-правило, старый клиент, интеграция с внешней системой или исторический баг, на который уже кто-то завязался.</p><p>Например, в системе расчета налогов может быть правило: для контрактов, заключенных до 2018 года, НДС округляется в меньшую сторону до целого рубля, а для всех остальных — по математическим правилам. Новый разработчик может решить, что это ошибка, и «исправить» округление. Но потом выяснится, что часть крупных клиентов держит это поведение в своих сверках, а смена правила приведет к расхождениям в актах и претензиям.</p><p>Прежде чем менять поведение, его нужно зафиксировать. Для этого пишут характеристические тесты (characterization tests, иногда называемые golden master или approval tests). Идея простая: на реальных данных или их обезличенных копиях прогоняется старая реализация, её ответы сохраняются как эталон, и любые будущие изменения, отклоняющиеся от эталона, отлавливаются автоматически. Тесты пишутся не для красоты, а для того, чтобы зафиксировать существующее поведение — даже странное — перед тем, как его трогать. Подробно эта техника описана у Майкла Физерса в книге Working Effectively with Legacy Code; на практике её удобно реализовать через библиотеки семейства approval-tests (approvaltests-python, approvaltests-java и аналоги).</p><p>Поэтому первый этап модернизации — не улучшение, а воспроизведение текущего поведения. Новая реализация должна вести себя так же, как старая. Даже если старое поведение кажется странным. Только после стабилизации можно отдельно обсуждать, что именно стоит менять.</p><h2>Feature toggles: как включать новую логику без риска</h2><p>Feature toggles, или фича-флаги, — один из главных инструментов безопасной миграции. Они позволяют включать и выключать новую логику без деплоя.</p><p>В обычной разработке релиз часто выглядит бинарно: код либо выкатили, либо нет. При миграции legacy это неудобно. Гораздо безопаснее иметь возможность включить новую реализацию для 1% пользователей, затем для 10%, потом для половины аудитории и только после этого для всех.</p><p>Например, команда переносит расчет стоимости доставки из монолита в новый сервис. С помощью фича-флага это выглядит так:</p><p>user_id передается явно, чтобы решение «попал ли пользователь в новый сегмент» было стабильным от запроса к запросу. Иначе один и тот же клиент будет получать разные ответы при обновлении страницы, и поведение системы станет непредсказуемым.</p><p>На первом этапе флаг включают только для внутренней команды. Потом для тестового сегмента пользователей. Затем для небольшой доли реального трафика. Если метрики стабильны, долю увеличивают. Если появляются ошибки, флаг выключают, и пользователи снова идут в старую реализацию.</p><p>Важно различать два разных типа флагов. Флаг постепенной выкатки (rollout flag) меняется редко и контролирует, какой процент пользователей видит новую логику. Kill switch — отдельный флаг, единственная задача которого — мгновенно выключить новую реализацию при инциденте. Kill switch должен опрашиваться на каждом запросе, его кэширование должно жить секунды, а не минуты, и он принципиально не должен зависеть от той системы, которую он выключает. Иначе в момент аварии может оказаться, что выключатель сам недоступен.</p><p>В качестве инфраструктуры для флагов команды обычно берут одну из платформ: LaunchDarkly, Unleash, Flagsmith, GrowthBook, либо собирают собственную поверх Redis или конфигурационного сервиса. Для миграции важны три свойства: быстрое распространение изменений (секунды, а не минуты), поддержка таргетинга по пользователю/сегменту и аудит — кто и когда менял флаг.</p><p>Важно, что фича-флаг — это не просто if в коде. Для серьезной миграции нужны правила: кто может включать флаг, как быстро его можно отключить, какие метрики отслеживаются, когда флаг должен быть удален.</p><p>Последний пункт особенно важен. Если флаги не удалять, система быстро превращается в набор ветвлений, где никто уже не понимает, какая логика актуальна.</p><h2>Shadow testing: как проверить новую систему на реальном трафике</h2><p>Feature toggles помогают безопасно переключать пользователей. Но перед этим хорошо бы понять, совпадает ли новая логика со старой. Для этого используют shadow testing.</p><p>Shadow testing — это запуск новой реализации параллельно старой, но без влияния на пользователя. Пользовательский запрос по-прежнему обрабатывает старая система, а новая получает копию запроса и считает результат «в тени». Пользователю этот результат не показывается. Команда только сравнивает ответы.</p><p>Например, есть старый модуль расчета скидок. Он учитывает промокоды, сегмент пользователя, историю покупок, регион и партнерские условия. Команда пишет новый сервис скидок. Чтобы не переключать пользователей сразу, можно запустить теневой режим:</p><p>Два момента, на которые стоит обратить внимание в этом коде. Теневой вызов запускается через asyncio.create_task — корутина сразу планируется в event loop и начнёт выполняться, как только функция вернёт управление. И весь блок завернут в try/except: исключение в новой логике не должно ронять основной запрос. Без этих двух свойств shadow testing рискует ухудшить продакшен вместо того, чтобы безопасно его проверить.</p><p>Небольшая оговорка для продакшена: event loop держит на task только слабую ссылку, и без сохранённой ссылки задача может быть собрана сборщиком мусора прямо во время выполнения. В реальном коде Task имеет смысл класть в set фоновых задач и удалять оттуда через add_done_callback. В примере выше эта обвязка опущена для читаемости.</p><p>Для критичной доменной логики — платежей, биллинга, расчета тарифов — допустимый уровень расхождения должен быть около нуля: цель в shadow-режиме не «как можно меньше различий», а «понимаем каждое расхождение». Для менее чувствительных доменов (рекомендации, ранжирование результатов поиска) можно жить с расхождением в долях процента, но и там расхождения нужно классифицировать, а не игнорировать. Возможно, это баги новой реализации. А возможно, старая система содержит устаревшую логику, которую нужно отдельно обсудить с бизнесом.</p><p>Shadow testing особенно полезен для критичных доменных частей: платежей, биллинга, расчета тарифов, персональных предложений, транзакций. Там нельзя просто «попробовать на пользователях» и посмотреть, что будет.</p><p>При этом важно отличать теневую проверку чтения от теневой проверки записи. Чтение проверить относительно дёшево: запрос идёт в обе системы, ответы сравниваются, никаких внешних эффектов нет. С записью всё сложнее. Если новая реализация в shadow-режиме действительно создаст заказ, спишет деньги или отправит письмо, у пользователя возникнут двойные эффекты. Поэтому для writes либо вводят идемпотентные ключи и shadow-режим без реальных побочных действий (внешние вызовы заменены no-op-стабами, БД — отдельной shadow-копией), либо вообще отказываются от теневой проверки записи в пользу постепенной выкатки за фича-флагом.</p><p>Сравнение ответов в реальной системе тоже не сводится к одной функции compare. Нужно отдельно решать, как игнорировать «нормальный» шум (метки времени, идентификаторы, порядок коллекций), как сэмплировать трафик, чтобы не утопить хранилище расхождений, и как организовать триаж — кто и в каком ритме разбирает накопившиеся диффы. Готовые решения этого класса — GitHub Scientist (Ruby и его порты в другие языки), Twitter Diffy, либо собственный лёгкий регистратор поверх Kafka и таблицы расхождений.</p><h2>С чего начинать модернизацию</h2><p>Начинать лучше не с самого больного и не с самого центрального модуля. Это звучит контринтуитивно, потому что обычно хочется сразу взяться за главный источник проблем. Но если начать с ядра системы, команда быстро упрется в максимальное количество зависимостей и рисков.</p><p>Удобный способ выбрать первый кусок — оценить кандидатов по двум осям: насколько модуль критичен для бизнеса (low / high) и насколько сильно он связан с остальной системой (low / high). Начинать стоит с квадранта low-criticality + low-coupling: ошибки в нем не уронят бизнес-показатели, а малое количество зависимостей позволит провести миграцию полностью, не утянув за собой смежные модули. Высоко-критичные и сильно связанные части (платежи, ядро авторизации) трогают в последнюю очередь — на этот момент команда уже наберёт опыт безопасной миграции.</p><p>Хорошие точки входа обычно: уведомления, генерация отчетов, поиск, история операций, профиль пользователя, отдельная часть каталога. Важно, чтобы у команды была возможность описать контракт: какие данные входят, какие выходят, какие ошибки возможны, какие внешние системы участвуют.</p><p>Допустим, в банковском приложении есть старый модуль истории операций. Он медленный, сложно расширяется, но при этом не выполняет сами транзакции. Это хороший кандидат для первой миграции. Ошибка в истории операций неприятна, но обычно менее критична, чем ошибка в списании денег.</p><p>Команда может вынести чтение истории в отдельный сервис, сначала запустить его в shadow-режиме, потом включить для части пользователей, затем полностью перевести чтение на новую реализацию. При этом критичная транзакционная логика останется в старой системе до тех пор, пока команда не наберет опыт безопасной миграции.</p><h2>Миграция данных: самая сложная часть</h2><p>Большая часть статьи говорит о маршрутизации запросов и переключении трафика. Но в реальных проектах основная сложность лежит ниже — в данных. Старая и новая реализации почти всегда работают с общим состоянием: одной БД, одним хранилищем документов, одним набором очередей. Переехать туда «одним коммитом» нельзя.</p><p>Базовый рабочий приём — Expand-Contract (он же Parallel Change). Изменение схемы делается в три такта. На этапе expand в БД добавляются новые поля, таблицы или индексы, при этом старое поведение полностью сохраняется. Затем — migrate: обе реализации начинают писать и в старое, и в новое место (dual writes), а отдельный фоновый процесс делает backfill — заполняет новые поля историческими данными. После этого читатели по одному переключаются на новую схему. Только когда никто из читателей не использует старую структуру, наступает contract — удаление лишних колонок и таблиц.</p><p>Несколько практических деталей, которые часто упускают:</p><p>·         Dual writes — это не бесплатная операция. Две записи означают две точки отказа. Если одна из них упала, нужно решать, что делать: продолжать ли работу, ставить ли событие в очередь на повтор, помечать ли запись как несогласованную. Простое «сначала пишем туда, потом сюда» в продакшене на нагрузке приводит к расхождениям.</p><p>·         Backfill часто длиннее, чем кажется. На большой таблице миграция в одном UPDATE блокирует продакшен. Поэтому backfill делают батчами по N тысяч строк с паузами, отслеживают прогресс и предусматривают возможность остановить и продолжить.</p><p>·         Онлайн-изменения схемы на крупных таблицах делаются не штатным ALTER TABLE, а специализированными инструментами: gh-ost или pt-online-schema-change для MySQL, встроенные онлайн-механизмы PostgreSQL для индексов и колонок, Liquibase/Flyway — для управления версионированием изменений в репозитории.</p><p>·         Shadow testing данные не покрывает. Можно сравнить, что новая реализация возвращает то же, что и старая, но если за этим стоит другая схема в БД, проверка корректности самой миграции данных — это отдельная работа: сверки, контрольные суммы, выборочный аудит исторических записей.</p><p>Без этих шагов любая красивая фасадная архитектура наталкивается на разъезжающиеся данные — и тогда даже идеальный Strangler Fig снаружи не спасает.</p><h2>Прокси-слой как точка контроля</h2><p>Чтобы постепенно заменять legacy-код, нужно управлять маршрутизацией запросов. Для этого часто создают прокси-слой, API Gateway или фасад, через который проходит обращение к старой и новой логике. В терминах Domain-Driven Design такой слой часто называют Anti-Corruption Layer: он защищает новую реализацию от старых контрактов и наоборот, позволяя двум моделям сосуществовать без взаимного «загрязнения».</p><p>Без такой точки контроля миграция становится хаотичной. Часть клиентов ходит напрямую в старый модуль, часть — в новый, часть использует обходные пути, а команда теряет возможность централизованно переключать трафик.</p><p>Прокси-слой решает несколько задач. Он скрывает детали реализации от клиентов, позволяет направлять часть запросов в новую систему, поддерживает фича-флаги, собирает метрики и упрощает откат.</p><p>В качестве технической основы команды обычно берут один из трех вариантов: классический API gateway (Kong, AWS API Gateway), service mesh (Envoy, Istio) или более простой reverse proxy (NGINX, HAProxy). Service mesh особенно удобен, когда трафик уже идёт внутри Kubernetes-кластера: маршрутизацию можно менять конфигурацией, без правок кода клиентов и сервисов.</p><p>Например, мобильное приложение обращается к endpoint /orders/history. Раньше этот endpoint напрямую обслуживал монолит. После введения API Gateway приложение продолжает ходить по тому же контракту, но внутри gateway может решать, куда направить запрос: в legacy-модуль или новый сервис истории заказов.</p><p>Управление маршрутизацией обычно делается не «всё или ничего», а на основании атрибутов запроса: значения заголовка (X-Migration-Cohort: new), куки, хэша от user-id (стабильное разбиение пользователей на сегменты) или географического региона. Это позволяет выкатывать новую реализацию сначала на одну страну, на сотрудников самой компании или на тестовый сегмент — и только потом расширять охват.</p><p>Для клиента ничего не меняется. Для команды появляется управляемость.</p><h2>Наблюдаемость: без метрик миграция превращается в гадание</h2><p>Постепенная модернизация невозможна без нормальной наблюдаемости. Если команда не видит, что происходит внутри системы, она не сможет безопасно переключать трафик.</p><p>Минимальный набор — это логи, метрики и распределенная трассировка (distributed tracing). Нужно понимать, сколько запросов идет в старую и новую реализацию, сколько ошибок возникает, как меняется latency, где появляются таймауты, какие статусы возвращаются, какие бизнес-метрики проседают.</p><p>Технические метрики стоит формулировать не как «средний ответ» и «процент ошибок», а в терминах SLI и SLO: целевые показатели вида «99.9% запросов на /orders/history отвечают быстрее 300 ms за 30 дней» с явным error budget. Latency измеряется по перцентилям (p50, p95, p99) — среднее значение почти всегда обманчиво, а хвосты распределения говорят о реальном опыте пользователя. На время миграции имеет смысл выставить отдельные SLO для нового и старого пути и сравнивать их.</p><p>В качестве инструментов де-факто стандартом стал OpenTelemetry для трассировок, метрик и логов — единый протокол, который пишет в практически любое хранилище. Дальше — Prometheus и Grafana для метрик, Jaeger или Tempo для traces, Sentry или аналог для ошибок. Для миграции важна возможность фильтровать метрики по «варианту» — отдельно по старому и новому пути — иначе все цифры смешаются и реальную динамику будет не видно.</p><p>Технических метрик недостаточно. Если команда переносит оформление заказа, важно смотреть не только на 500 ошибки и время ответа, но и на конверсию в оплату, количество брошенных корзин, повторы запросов, обращения в поддержку.</p><p>Пример: новая система формально отвечает быстрее старой и не дает ошибок. Но после включения на 10% пользователей падает конверсия в оплату. Причина может быть не в серверной ошибке, а в изменении порядка полей, другом тексте сообщения или потере какого-то edge-case. Без бизнес-метрик команда может решить, что миграция успешна, хотя для продукта она уже создает проблему.</p><h2>Практическая последовательность миграции</h2><p>Рабочая последовательность обычно выглядит так.</p><p>Сначала команда выбирает ограниченный участок системы. На этом этапе важно не просто назвать модуль, а описать его границы. Какие сценарии он закрывает? Кто его вызывает? Какие данные он читает и пишет? Какие внешние интеграции использует? Какие неочевидные бизнес-правила в нем есть?</p><p>Затем поверх legacy-логики создается стабильный контракт. Это может быть API, фасад, gateway или отдельный слой внутри приложения. Главная задача — сделать так, чтобы клиенты зависели не от внутренней реализации, а от понятного интерфейса. На этом этапе полезно вспомнить про contract testing (Pact, Spring Cloud Contract): автотесты со стороны потребителей фиксируют, что именно они ожидают от API, и предупреждают о ломающих изменениях до того, как они доедут до продакшена.</p><p>После этого рядом пишется новая реализация. Она должна повторять текущее поведение, а не сразу становиться «идеальной версией будущего». На этом этапе полезно фиксировать все расхождения: где старая система работает странно, где требования не описаны, где бизнес-правила требуют уточнения.</p><p>Следующий этап — shadow testing. Новая система получает копии реальных запросов, считает результат, но пользователю по-прежнему возвращается ответ legacy. Команда сравнивает результаты и устраняет расхождения.</p><p>Когда новая реализация достаточно стабильна, начинается постепенное переключение через feature toggles. Сначала внутренние пользователи, потом 1% реального трафика, затем 5–10%, затем 50% и только после этого 100%.</p><p>На каждом этапе команда смотрит на метрики. Если всё стабильно, движение продолжается. Если появляются проблемы, флаг выключается, трафик возвращается в legacy, а команда разбирает причины.</p><p>Последний этап — удаление старого кода. Это не формальность, а обязательная часть миграции. И «удалить старый код» — это не один коммит, а явный Definition of Done: вырезана старая ветка кода, удалён фича-флаг, обновлена документация и схемы архитектуры, переименованы или удалены устаревшие дашборды и алерты, обновлены runbook’и для on-call и проведено короткое внутреннее обучение. Если этого не сделать, через полгода никто уже не вспомнит, какой путь актуален, и легаси-ветвление останется в коде навсегда.</p><h2>Откат миграций: дешёвый только пока не пошли записи</h2><p>Откатить миграцию, в которой ещё не было записи в БД, легко: достаточно переключить фича-флаг, и трафик снова идёт через старую реализацию. Откатить миграцию, в которой новая система уже неделю писала данные в новые таблицы, — отдельный, гораздо более тяжёлый разговор.</p><p>Поэтому ещё на этапе проектирования каждое изменение должно сопровождаться явным планом отката. Удобно различать три типа шагов.</p><p>Полностью обратимые шаги. Чтение через новый сервис, расчёт «в тени», новые метрики. Откат — выключить флаг. Это самый комфортный режим, и в нём стоит держать миграцию как можно дольше.</p><p>Обратимые с компенсацией. Новая реализация пишет дополнительные данные (например, дублирует операции в новую таблицу), но старый источник тоже обновляется. Откат возможен, но требует решить, что делать с уже записанными данными: оставить, очистить, синхронизировать. План этих действий должен быть написан до выкатки, не во время инцидента.</p><p>Forward-only. После некоторой точки откат становится невозможен — например, после того, как старая схема удалена или внешние интеграции перенастроены на новый сервис. Такие шаги допустимы, но к ним нужно приходить отдельно, осознанно, с особенно строгими SLO в предыдущем этапе. До forward-only-перехода имеет смысл подержать систему в режиме параллельной работы дольше, чем по графику.</p><p>Базовое правило: ни один шаг миграции не должен уходить в продакшен, если у команды нет письменного ответа на вопрос «как мы откатываемся в случае проблемы». Иначе при инциденте откатываться будут на ходу — и не факт, что успешно.</p><h2>Пример: как тот же сервис мигрировали со второй попытки</h2><p>После неудачного опыта команда взялась за тот же сервис заново, но изменила подход.</p><p>На первом шаге они зафиксировали поведение существующего сервиса. На самые часто используемые сценарии (создание путевого листа, подпись акта осмотра, выгрузка пакета документов за период) написали характеристические тесты на реальных продакшен-данных, обезличенных и сохранённых как фикстуры. Любое будущее изменение поведения теперь падало в CI как явное расхождение.</p><p>Параллельно команда провела инвентаризацию побочных эффектов. Из исходного кода и логов выяснилось, что сервис не только хранит документы, но и: публикует событие в Kafka при смене статуса, инкрементирует счётчик в Redis для рейтинга водителей, отправляет webhook во внешнюю систему партнёра, пишет в таблицу аудита. Каждый из этих эффектов попал в отдельный пункт чек-листа «что должно остаться» в новой реализации.</p><p>Затем команда выбрала первый кусок для выноса — не весь сервис, а только чтение документов (GET /documents/{id} и GET /documents/by-driver/{driver_id}). Это была наименее рискованная часть: ошибки в чтении неприятны, но не ломают финансовые потоки.</p><p>Новый сервис написали на FastAPI рядом со старым. На уровне API Gateway появилось правило маршрутизации: запросы на чтение шли в старый сервис, но в фоне дублировались в новый. Ответ пользователю всегда возвращал legacy, а ответ нового сервиса сравнивался с эталоном и записывался в отдельную таблицу для разбора. Использовали обёртку поверх asyncio.create_task — на ответ пользователя теневой вызов не влиял.</p><p>За три недели shadow-режима команда нашла четыре расхождения. Два оказались багами новой реализации (округление времени, неправильная сортировка вложений). Два — давно забытыми особенностями старого сервиса (одно поле возвращалось в UTC, другое — в локальной зоне; так было исторически, бизнес не возражал, но в новой реализации захотели единый формат). Все четыре зафиксировали явно: баги — починили, особенности — согласовали с продуктовой командой как осознанное изменение.</p><p>Когда расхождений не осталось, включили фича-флаг на сотрудников самой компании. Через неделю — на 1% реальных водителей. Дальше шаг по 5%, 25%, 50%, 100% с паузой в несколько дней между этапами. На каждом шаге следили не только за HTTP-ошибками и latency, но и за продуктовыми метриками: количество подписанных актов, время от открытия документа до подписи, доля повторных запросов. Один раз пришлось откатиться с 25% на 5% — в одном из регионов выросло время отклика из-за неэффективного запроса. Исправили, выкатили снова.</p><p>Через два месяца чтение полностью перешло в новый сервис. Старый код чтения и фича-флаг удалили в том же релизе. После этого по той же схеме мигрировали запись документов, потом публикацию событий, потом импорт из внешних систем. Полная миграция заняла девять месяцев — почти столько же, сколько провалившийся Big Bang, — но продукт всё это время продолжал развиваться, инцидентов не было, и в конце команда осталась с системой, которую понимает.</p><h2>Типичные ошибки при работе с legacy</h2><p>Первая ошибка — пытаться улучшить всё сразу. Команда одновременно меняет архитектуру, бизнес-логику, контракты и инфраструктуру. В результате становится невозможно понять, какая именно часть вызвала проблему. Правильнее сначала воспроизвести поведение, стабилизировать новую реализацию и только потом улучшать.</p><p>Вторая ошибка — недооценивать скрытые зависимости и побочные эффекты. Legacy-код часто делает больше, чем кажется. На один и тот же вызов могут быть навешаны: запись в таблицу аудита, инкремент счётчика в кэше, публикация события в очередь, обновление статуса связанной сущности, инвалидация кэша, дёрганье webhook’а во внешнюю систему. Если в новой реализации воспроизвести только явный путь, скрытые потребители молча перестанут получать данные — и узнают об этом через жалобу бизнеса, а не через ошибку в логах. Поэтому перед выносом любого модуля имеет смысл составить инвентаризацию побочных эффектов: пройтись по коду и логам и выписать каждое нелогичное действие отдельным пунктом чек-листа.</p><p>Третья ошибка — отсутствие наблюдаемости. Без логов, метрик и трассировки команда не управляет миграцией, а угадывает. Особенно опасно смотреть только на технические ошибки и игнорировать бизнес-показатели.</p><p>Четвертая ошибка — не договариваться с бизнесом. Модернизация не должна быть невидимой «инженерной активностью в стол». Её нужно встраивать в roadmap, объяснять эффект и договариваться о приоритетах. Если бизнес не понимает, зачем команда тратит время на миграцию, работа будет постоянно проигрывать новым фичам.</p><p>Пятая ошибка — не удалять старый код. Временное сосуществование старой и новой логики нормально. Вечное сосуществование — нет. Если legacy не удаляется, технический долг не уменьшается, а просто меняет форму.</p><p>Шестая ошибка — не удалять фича-флаги после миграции. Флаг, который сыграл свою роль и больше никогда не выключается, превращается в постоянное ветвление в коде. Через год команда не помнит, можно ли удалить такую ветку или там сидит важный edge-case. Через два — кода с такими «мёртвыми» флагами становится больше, чем основной логики. Поэтому каждый флаг должен заводиться с условием удаления («после полной выкатки и двух недель стабильной работы») и иметь ответственного, кто этим удалением займётся.</p><p>Отдельно стоит упомянуть организационную сторону. Закон Конвея работает и в обратную сторону: если новый и старый код владеются разными командами с разными приоритетами, миграция будет тормозиться независимо от выбранного паттерна. На время миграции имеет смысл явно проговорить, кто отвечает за переход, и не разделять старую и новую реализации между несовместимыми roadmap’ами.</p><h2>Компромиссы, к которым нужно быть готовыми</h2><p>Постепенная модернизация безопаснее Big Bang-переписывания, но она не бесплатна. Некоторое время система будет сложнее, чем раньше. В ней появятся старый и новый код, прокси-слой, фича-флаги, дублирование логики, дополнительные метрики.</p><p>Shadow testing увеличит нагрузку на инфраструктуру, потому что часть запросов будет обрабатываться дважды. Команде придется поддерживать дисциплину: документировать контракты, отслеживать флаги, удалять старую реализацию после миграции, поддерживать contract-тесты в актуальном состоянии.</p><p>Но это контролируемая сложность. Она распределена во времени и управляется инженерными практиками. В отличие от Big Bang-риска, где команда долго работает с минимальной обратной связью, а потом выкатывает один большой релиз с максимальной неопределенностью.</p><h2>Когда Strangler Fig особенно оправдан</h2><p>Постепенная миграция особенно хорошо подходит для систем, где downtime невозможен или слишком дорог. Это финтех, e-commerce, биллинг, мобильные бэкенды с большой аудиторией, высоконагруженные продукты, старые монолиты и системы с большим количеством интеграций.</p><p>Если продуктом ежедневно пользуются сотни тысяч или миллионы людей, нельзя позволить себе «переписать и посмотреть, что будет». Нужно менять архитектуру так, чтобы пользователь не замечал процесса миграции.</p><p>Этот подход также полезен там, где бизнес продолжает активно развивать продукт. Если фичи нельзя заморозить на полгода, модернизация должна идти параллельно с продуктовой разработкой.</p><h2>Когда модернизацию лучше не делать</h2><p>Постепенная миграция — мощный инструмент, но у неё тоже есть стоимость, и иногда правильный ответ — оставить систему как есть. Несколько сценариев, в которых модернизация плохо окупается.</p><p>Продукт, который уходит из эксплуатации. Если через год сервис будет выключен или заменён на покупное решение, тратить квартал на его рефакторинг бессмысленно. Достаточно стабилизировать то, что есть.</p><p>Модуль, который никто не трогает. Если код десятилетней давности продолжает работать, не падает, не требует изменений и не вызывает инцидентов, его «уродливость» — не повод его переписывать. Цель модернизации — упростить будущие изменения; если будущих изменений нет, цели тоже нет.</p><p>Регулируемые системы с тяжёлой ресертификацией. В банковских, медицинских и государственных контурах любое изменение в критичной системе может потребовать повторной сертификации, перепрохождения аудитов, обновления договорной обвязки. В таких условиях стоимость модернизации может на порядок превышать стоимость поддержки текущей реализации, и решение нужно принимать вместе с владельцем продукта и юристами, а не только инженерным составом.</p><p>Простой тест: если на вопрос «какой бизнес-сценарий мы откроем после миграции» нет внятного ответа — модернизацию имеет смысл отложить и заняться чем-то другим.</p><h2>Что получает команда</h2><p>Главный результат постепенной модернизации — управляемость. Команда начинает лучше понимать систему, контролировать изменения и снижать риск инцидентов.</p><p>Появляются понятные контракты, наблюдаемость, практика безопасных релизов, культура удаления старого кода. Разработчики перестают бояться legacy, потому что у них появляется метод, а не только желание «когда-нибудь всё переписать».</p><p>Для бизнеса это тоже выгодно. Продукт продолжает развиваться, сроки становятся более прогнозируемыми, риски крупных сбоев снижаются, а технический долг постепенно уменьшается.</p><h2>Модернизация — это процесс, а не проект</h2><p>Legacy нельзя «починить за квартал». Если система развивалась годами, она не станет простой после одного рефакторинга. Но её можно системно улучшать.</p><p>Strangler Fig Pattern, Branch by Abstraction, feature toggles, shadow testing и аккуратная миграция данных дают рабочую модель: выбрать ограниченный участок, описать контракт, реализовать новую версию, проверить её на реальном трафике, постепенно переключить пользователей и удалить старый код.</p><p>Это не самый быстрый путь. Зато он управляемый. А в зрелых продуктах управляемость важнее скорости.</p><p>Потому что цель модернизации — не написать красивую новую систему. Цель — сделать так, чтобы продукт продолжал развиваться, команда могла безопасно вносить изменения, а пользователи не становились участниками инженерного эксперимента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Семь ошибок индексации БД, которые убивают производительность SaaS на корню</title>
      <link>https://tproger.ru/articles/sem-owibok-indeksacii-bd-kotorye-ubivayut-proizvoditelnost-sa</link>
      <comments>https://tproger.ru/articles/sem-owibok-indeksacii-bd-kotorye-ubivayut-proizvoditelnost-sa?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/sem-owibok-indeksacii-bd-kotorye-ubivayut-proizvoditelnost-sa</guid>
      <description><![CDATA[<p>Разбираем 7 типичных ошибок индексации в PostgreSQL и MySQL: переиндексация, низкая селективность, раздутие индексов, мультитенантность и внешние ключи. Проверьте свою БД перед релизом.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/sem-owibok-indeksacii-bd-kotorye-ubivayut-proizvoditelnost-sa">Семь ошибок индексации БД, которые убивают производительность SaaS на корню</a>»</p>]]></description>
      <category><![CDATA[Алгоритмы и структуры данных]]></category>
      <category><![CDATA[Масштабируемость и ограничения памяти]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 03 Jun 2026 05:30:09 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ваш код чист, архитектура продумана, а запросы на staging укладываются в 12 мс. Но при 500 000 записей всё встаёт: панели мониторинга тормозят, пользователи жалуются, а дежурный инженер в полночь разглядывает план выполнения запроса и не понимает, что пошло не так. В девяти случаях из десяти причина — не отсутствие индексов, а <b>неправильные индексы</b>.</p><p><b>Индекс в базе данных</b> — это вспомогательная структура (чаще всего B-дерево; хеш-индексы, GiST, GIN и другие типы применяются в узких специфических сценариях), которая ускоряет выборку строк по заданным колонкам. По аналогии с оглавлением книги: вместо перелистывания всех страниц СУБД сразу переходит к нужной главе. Но если оглавление построено плохо, пользы от него нет — а вот накладные расходы на поддержку остаются.</p><p>В этой статье разберём семь самых разрушительных ошибок индексации в production-SaaS: от параноидального создания индексов «на всякий случай» до игнорирования раздутия и особенностей мультитенантных схем. Каждая ошибка — с примерами SQL, метриками и конкретным фиксом.</p><p>Индексы — это налог на запись: каждый INSERT, UPDATE и DELETE обновляет все индексы таблицы.</p><p>Индекс на колонке с низкой селективностью (boolean, статус) почти бесполезен — используйте частичные (partial) индексы.</p><p>В составном индексе порядок колонок критичен: PostgreSQL может использовать (a, b, c) только если условие начинается с a.</p><p>Раздутые индексы на высокоизменяемых таблицах могут занимать в 8 раз больше места, чем нужно — планируйте REINDEX CONCURRENTLY.</p><p>В мультитенантных системах индекс по tenant_id один часто недостаточен: добавляйте диапазон времени или тип события.</p><p>Внешние ключи в PostgreSQL не индексируются автоматически — после каждого FOREIGN KEY создавайте индекс вручную.</p><p>Без EXPLAIN ANALYZE индексы создаются вслепую. Проверяйте реальный план выполнения перед деплоем.</p><h2>Ошибка 1. Индексировать всё подряд «на всякий случай»</h2><p>Самая распространённая ошибка — не недостаток индексов, а их избыток из тревожности. Особенно часто в неё попадают junior-разработчики: добавляют индекс на каждую колонку, которая встречается в WHERE, «на всякий случай». Кажется ответственным, но на самом деле вредно.</p><p>Каждый индекс — это налог на запись. При INSERT, UPDATE и DELETE PostgreSQL (или MySQL) вынуждена обновлять <b>все</b> индексы таблицы. На таблице с 8 индексами каждая запись трогает 8 структур данных. При низкой нагрузке это невидимо, но при 10 000 записей в минуту это становится узким местом.</p><p><b>Аудит неиспользуемых индексов в PostgreSQL:</b><br />Запрос к pg_stat_user_indexes покажет, сколько раз каждый индекс применялся с момента сброса статистики. Если idx_scan = 0 — индекс кандидат на удаление.</p><p>Не удаляйте индекс сразу — сначала убедитесь, что он не нужен для редких, но критичных отчётов. Но если он месяцами не используется, смело избавляйтесь.</p><h2>Ошибка 2. Не понимать селективность</h2><p>Индекс на булеву колонку — почти всегда бесполезен. <b>Селективность</b> измеряет, сколько различных значений содержится относительно общего числа строк. У boolean всего два значения. Если 95% строк имеют is_active = true, планировщик запросов проигнорирует индекс и сделает Seq Scan — и будет прав.</p><p>Правило большого пальца: если у колонки меньше 10–20 уникальных значений относительно размера таблицы, простой индекс по ней один не справится. Используйте частичные или составные индексы.</p><h2>Ошибка 3. Неверный порядок колонок в составном индексе</h2><p>Составные индексы мощны, но часто неправильно понимаются. PostgreSQL может использовать индекс (a, b, c) для фильтрации по a, a и b, a, b и c. Но <b>не может</b> эффективно использовать его, если запрос фильтрует только по b или c — ведущая колонка пропущена.</p><p>Решение: первыми ставьте колонки с equality-условиями, затем — по селективности, и проектируйте индексы вокруг <b>реальных паттернов запросов</b>, а не вокруг схемы таблицы. Также учитывайте ORDER BY и необходимость покрывающего индекса. Перед созданием обязательно запускайте EXPLAIN ANALYZE.</p><h2>Ошибка 4. Игнорировать раздутие индексов</h2><p>Индексы деградируют со временем. Многие инженеры воспринимают их как «поставил и забыл», но это заблуждение. В PostgreSQL при обновлении или удалении строки старые записи в индексе устаревают и накапливаются как <b>раздутие</b> (bloat); их физическое удаление происходит при выполнении VACUUM. На высокоизменяемых таблицах (заказы, события, логи, сессии) раздутие накапливается стремительно.</p><p>Таблица с 1 млн живых строк может иметь индекс, раздутый до размеров 8 млн записей. Каждый запрос через такой индекс делает в 8 раз больше работы, чем должен.</p><p><b>REINDEX CONCURRENTLY</b> — ключевое слово. Обычный REINDEX блокирует таблицу, а в production-SaaS это прямой путь к инциденту. CONCURRENTLY перестраивает индекс без блокировок, хотя и медленнее.</p><p>Также убедитесь, что autovacuum настроен под вашу реальную нагрузку на запись. Значения по умолчанию в PostgreSQL консервативны и часто недостаточны для SaaS с высокой интенсивностью записи.</p><h2>Ошибка 5. Индексы на колонках с малым числом уникальных значений в мультитенантных системах</h2><p>В мультитенантной архитектуре почти каждый запрос фильтрует по tenant_id. Естественное желание — проиндексировать эту колонку. Но для крупных тенантов индекс по tenant_id вернёт слишком много строк, и планировщик предпочтёт Seq Scan. Для маленьких тенантов отдельный индекс по tenant_id может быть полезен.</p><p>На серьёзном масштабе правильное решение — партиционирование таблиц по tenant_id, но это архитектурное решение. Практический первый шаг — составные индексы с временными диапазонами.</p><h2>Ошибка 6. Не индексировать внешние ключи</h2><p>В PostgreSQL внешние ключи <b>не индексируются автоматически</b>. При удалении родительской строки СУБД должна проверить все дочерние таблицы на наличие ссылающихся записей — и без индекса на внешнем ключе это Seq Scan по каждой дочерней таблице. На таблице orders с 50 млн строк удаление пользователя вызывает полное сканирование.</p><p>Сделайте это командным соглашением: в чек-листе миграций обязательный пункт «после каждого FOREIGN KEY — CREATE INDEX».</p><h2>Ошибка 7. Не использовать EXPLAIN ANALYZE перед деплоем</h2><p>Большинство решений об индексах принимаются интуитивно. Интуиция ошибается достаточно часто, чтобы это стало проблемой. EXPLAIN ANALYZE показывает, что именно делает планировщик: какие индексы использует, какие игнорирует, сколько строк реально прочитал против оценки, где тратится время.</p><p>На что обращать внимание:<br />• <b>Seq Scan</b> на большой таблице при выборке малой доли строк — возможно, пропущен индекс или планировщик не может использовать существующий индекс.<br />• <b>Rows Removed by Filter</b> в десятки тысяч — индекс есть, но неправильные колонки или низкая селективность.<br />• <b>Buffers: shared hit=0 read=45000</b> — данные не закэшированы (cold cache), страницы читаются с диска. Для диагностики раздутия смотрите общее число буферов и сравнивайте размер индекса с ожидаемым.<br />• Высокое <b>actual time</b> — проверьте раздутие, актуальность статистики, количество буферов, дисковую подсистему и наличие блокировок. Запустите ANALYZE tablename, чтобы обновить статистику планировщика.</p><h2>Чек-лист индексации для SaaS</h2><ul><li>У каждой колонки внешнего ключа есть индекс?</li><li>Составные индексы упорядочены по селективности, а не по удобству?</li><li>Булевы и низкокардинальные фильтры используют частичные индексы вместо полных?</li><li>Вы запускали EXPLAIN ANALYZE на 10 самых медленных запросов за неделю?</li><li>Есть процесс поиска и удаления неиспользуемых индексов?</li><li>Высокоизменяемые таблицы регулярно проходят REINDEX CONCURRENTLY?</li><li>Autovacuum настроен под реальный объём записи, а не под значения по умолчанию PostgreSQL?</li><li>В мультитенантных таблицах индексы начинаются с tenant_id и включают диапазон времени?</li></ul><h2>Выводы</h2><p>Индексы — не фича производительности, которую добавляют, когда всё начинает тормозить. Это проектное решение, которое принимается вместе со схемой, и пересматривается по мере эволюции паттернов запросов. Команды, которые уверенно масштабируются, — не те, у кого больше всего индексов, а те, кто понимает, что каждый индекс стоит, что даёт и когда его пора убирать.</p><blockquote>База данных, которая быстра на 10 000 строках и быстра на 50 миллионах, — не случайность. Это результат того, что кто-то считал планирование запросов первоклассной инженерной задачей, а не рутинным дополнением.</blockquote><p>Проверьте свои самые медленные запросы этой недели — возможно, одна из этих семи ошибок уже сидит в вашей production-базе.</p><p><b>Источник и материалы:</b><br />• <a href="https://dev.to/outworktech/database-indexing-mistakes-that-kill-saas-performance-at-scale-4j8e">Database Indexing Mistakes That Kill SaaS Performance at Scale</a> — оригинальная статья OutworkTech<br />• <a href="https://www.postgresql.org/docs/current/indexes.html">PostgreSQL Index Types</a> — официальная документация<br />• <a href="https://www.postgresql.org/docs/current/sql-reindex.html">REINDEX</a> — документация по перестроению индексов</p>]]></content:encoded>
    </item>
    <item>
      <title>Паттерн Transactional Outbox с Kafka: как не потерять события при синхронизации баз данных</title>
      <link>https://tproger.ru/articles/pattern-transactional-outbox-s-kafka-kak-ne-poteryat-sobytiya-pr</link>
      <comments>https://tproger.ru/articles/pattern-transactional-outbox-s-kafka-kak-ne-poteryat-sobytiya-pr?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Торопов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pattern-transactional-outbox-s-kafka-kak-ne-poteryat-sobytiya-pr</guid>
      <description><![CDATA[<p>Описание паттерна Transactional Outbox</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pattern-transactional-outbox-s-kafka-kak-ne-poteryat-sobytiya-pr">Паттерн Transactional Outbox с Kafka: как не потерять события при синхронизации баз данных</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Паттерны проектирования]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 20 May 2026 04:25:03 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Боль: данные разошлись, и вы не знаете когда</b></p><p>В нашей системе две базы данных:</p><p>- <b>Остатки по счетам</b> - текущий остаток по каждому счёту</p><p>- <b>Остатки по клиентам</b> - агрегированный баланс клиента по всем его счетам.</p><p>При каждом изменении остатка по счёту нужно обновить <b>Остатки по счетам</b> и уведомить <b>Остатки по клиентам</b> через Kafka. Логика простая. Но в какой-то момент клиент звонит в поддержку: его баланс в приложении не совпадает с реальным. Вы смотрите в обе базы — данные разошлись. Когда именно это произошло — непонятно.</p><p>Причина почти всегда одна и та же:</p><p>Транзакция закоммичена, событие не ушло. Базы разошлись. Никто не узнал.</p><p><b>Почему очевидные решения не работают</b></p><p>Первая реакция разработчика — обернуть отправку в try-catch и повторить при ошибке:</p><p>Не работает: транзакция уже закоммичена до отправки. При сбое Kafka данные обновлены, событие потеряно. Retry помогает только если Kafka временно недоступна — но не при падении самого сервиса между коммитом и отправкой.</p><p>Вторая идея — отправить событие до коммита:</p><p>Тоже не работает: если коммит упадёт, Kafka уже получила событие об изменении, которого нет в базе. Данные снова разошлись, но в другую сторону.</p><p>Третья идея — двухфазный коммит (2PC). Это протокол, который координирует атомарный коммит сразу в нескольких системах. Звучит как решение, но на практике Kafka его не поддерживает в классическом смысле, а реализации 2PC с брокерами сообщений крайне сложны в эксплуатации и плохо переносят сбои координатора.</p><p>Все три пути упираются в одну проблему: **невозможно атомарно закоммитить транзакцию в базе и отправить сообщение в Kafka** — это две разные системы без общего менеджера транзакций.</p><p><b>Принцип решения</b></p><p>Раз нельзя сделать две операции атомарными, нужно свести их к одной. Именно это делает паттерн **Transactional Outbox**.</p><p>Вместо того чтобы отправлять событие в Kafka напрямую, мы записываем его в таблицу `outbox` — в той же базе, в той же транзакции, что и изменение остатка. Одна транзакция, одна база, полная атомарность за счёт ACID.</p><p>Доставкой события из `outbox` в Kafka занимается отдельный процесс — уже без транзакционных рисков, с возможностью повторных попыток.</p><p>Это и есть весь паттерн. Дальше — вопрос реализации.</p><p><b>Два способа реализации</b></p><p>Есть два принципиально разных подхода к тому, как читать `outbox` и доставлять события в Kafka. Выбор между ними определяет операционную сложность и задержку доставки.</p><p><b>Способ 1: Polling Relay</b></p><p>Фоновый воркер периодически опрашивает 'outbox' и отправляет неотправленные события в Kafka.</p><figure><img src="https://media.tproger.ru/user-uploads/115582/2026-05-19/dfe8e7cf-f864-432d-a00b-66775ce77f8b.webp" alt="" /></figure><p><b>Структура таблицы outbox:</b></p><p><b>Бизнес-транзакция:</b></p><p><b>Relay-процесс:</b></p><p>При нескольких экземплярах ретранслятора важно, чтобы одно событие забирал только один из них. Используем `FOR UPDATE SKIP LOCKED`:</p><p><b>Когда выбирать:</b> задержка доставки в сотни миллисекунд допустима, хочется минимум зависимостей, команда не готова к операционной сложности CDC.</p><p><b>Способ 2: CDC через Debezium</b></p><p><b>CDC (Change Data Capture)</b> — подход, при котором события читаются не опросом таблицы, а напрямую из журнала транзакций базы данных (WAL в PostgreSQL). [Debezium](https://debezium.io/) подключается к PostgreSQL как репликационный слот и стримит каждое изменение в `outbox` в Kafka в реальном времени.</p><p>Relay-процесс при этом не нужен вообще.</p><figure><img src="https://media.tproger.ru/user-uploads/115582/2026-05-19/db09dce3-7ec8-4b27-b2b0-655904fd43cb.webp" alt="" /></figure><p>Бизнес-транзакция остаётся той же — пишем в `accounts` и `outbox` атомарно. Debezium сам следит за WAL и публикует новые записи в Kafka с минимальной задержкой.</p><p><b>Когда выбирать:</b> нужна задержка доставки в миллисекунды, команда готова к Debezium + Kafka Connect в инфраструктуре.</p><p>Что выбрать для синхронизации остатков</p><figure><img src="https://media.tproger.ru/user-uploads/138533/2026-05-15/4e568b33-b8d1-43dc-b9a0-1324859a2112.webp" alt="" /></figure><p>Для большинства задач с остатками по счетам<b> polling relay достаточен</b>. CDC имеет смысл, если бизнес требует обновления клиентского баланса быстрее чем за секунду.</p><p><b>Получатель: защита от дублей</b></p><p>Оба способа доставляют события <b>как минимум один раз</b> — при повторных попытках одно событие может прийти дважды. На стороне <b>Остатков по клиентам</b> нужна защита.</p><p>Самый надёжный способ — inbox-таблица с уникальным constraint:</p><p>&gt;<b>Почему не `existsById` перед вставкой?</b> При параллельной обработке два консюмера могут одновременно получить `false` и оба начать обработку. Уникальный constraint на уровне БД закрывает эту гонку.</p><p><b>Что сломается при небрежной реализации</b></p><p><b>Relay внутри API-сервиса.</b> Если ретранслятор живёт в том же процессе, что и API, горизонтальное масштабирование до 10–30 реплик создаёт столько же потоков, опрашивающих `outbox`. База тратит CPU не на запросы, а на управление блокировками. Relay — отдельный деплоймент, который масштабируется по объёму событий, а не по HTTP-трафику.</p><p><b>Таблица outbox незаметно растёт.</b> Без очистки запросы замедляются, индексы раздуваются. Настройте автоматическую очистку:</p><p><b>Отсутствие мониторинга outbox.</b> Outbox — скрытая очередь внутри базы. Если relay начнёт отставать, вы узнаете об этом от клиентов, а не от алертов. Следите за количеством и возрастом необработанных событий — это главные сигналы проблемы.</p><p><b>Итог</b></p><p>Проблема потери событий при синхронизации баз — не баг конкретной реализации. Это фундаментальное ограничение: нельзя атомарно закоммитить транзакцию в базе и отправить сообщение в Kafka.</p><p>Transactional Outbox обходит это ограничение, сводя две операции к одной: событие пишется в `outbox` в той же транзакции, что и основные данные. Дальше — дело техники: polling relay, если нужна простота, CDC, если нужна скорость.</p><p>Остатки по счетам и клиентам будут согласованы — даже если между сервисами что-то пойдёт не так.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как я написал E2EE-мессенджер на Spring Boot и WebCrypto — и почему сервер не видит сообщения</title>
      <link>https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch</link>
      <comments>https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Василенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch</guid>
      <description><![CDATA[<p>Разбор архитектуры E2EE-мессенджера на Spring Boot 3, React и WebCrypto: X3DH, symmetric ratchet, AES-GCM, WebSocket, multi-device и ограничения реализации.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch">Как я написал E2EE-мессенджер на Spring Boot и WebCrypto — и почему сервер не видит сообщения</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Stack Overflow]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Алиса]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[5g]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 05:35:02 GMT</pubDate>
      <content:encoded><![CDATA[<figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/240e412b-4307-49f9-b24f-bde7e0a7fd9a.webp" alt="" /></figure><p>Я Java-разработчик и в основном работаю с backend: Spring Boot, базы данных, интеграции, авторизация, WebSocket — всё то, что обычно находится за интерфейсом.</p><p>В какой-то момент я поймал себя на мысли: я каждый день пользуюсь мессенджерами, но плохо понимаю, как они устроены внутри. Окей, JWT, WebSocket, PostgreSQL, Redis — это понятно. Но что технически означает фраза "end-to-end encryption"? Как сервер доставляет сообщения, если он не должен их читать? Где живут ключи? Что хранится в базе? Что происходит, если у пользователя два устройства?</p><p>Решил разобраться через практику. Написал мессенджер с нуля. Назвал Chaos Messenger.</p><p>Сразу честно: криптографическую часть я изучал вместе с Claude и ChatGPT — читал спецификации X3DH и Double Ratchet, разбирал примеры, задавал вопросы, пока не сложилась цельная картина. Frontend тоже делался с активной помощью ChatGPT: я backend-разработчик, React для меня не основная среда. Но архитектура, backend, интеграция WebCrypto, модель конвертов, хранение сообщений и принципиальные решения — мои.</p><p>Для меня AI здесь был не заменой понимания, а инструментом — примерно как документация, Stack Overflow и ревью коллег. Без понимания threat model и архитектуры такой проект всё равно не собрать.</p><p>В статье расскажу, как работает E2EE изнутри: как устанавливается сессия через X3DH, как каждое сообщение получает отдельный ключ через Symmetric Ratchet, почему сервер хранит только зашифрованные конверты, и какие ошибки я допустил по дороге.</p><p>Стек: Spring Boot 3, React 18, WebCrypto API, PostgreSQL, Redis, WebSocket/STOMP, Prometheus, Grafana.</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/4b028f37-2de1-46ea-a247-567f74fb3081.webp" alt="" /></figure><h2>Важная оговорка про web-E2EE</h2><p>Когда я говорю, что сервер не может прочитать сообщения, я имею в виду backend, базу данных, WebSocket-слой и уже сохранённые ciphertext-конверты. У них нет ключей и plaintext.</p><p>Но у web-E2EE есть отдельная проблема: frontend-код тоже приходит с сервера. Теоретически скомпрометированный сервер может отдать изменённый JavaScript, который украдёт ключи или plaintext до шифрования. Это ограничение не конкретно моего проекта, а браузерной модели в целом.</p><p>Поэтому корректная формулировка такая: backend не получает ключи и не может расшифровать уже переданные или сохранённые сообщения. Защита от подмены клиентского кода — отдельный слой безопасности: подпись сборок, независимая верификация клиента, desktop/mobile-приложения, reproducible builds.</p><h2>Почему обычный подход не работает</h2><p>Большинство "мессенджеров" на GitHub выглядят примерно так:</p><p>Сервер знает всё. Видит каждое сообщение. Если БД утекла — утекла вся переписка. Если сервер взломали — читай что хочешь. Если завтра компания решит продать данные — технически ничего не мешает.</p><p>E2EE решает это радикально: backend не получает ключи и не хранит plaintext. Сообщение шифруется на устройстве отправителя до отправки в сеть, а расшифровывается только на устройстве получателя.</p><p>Это уже не вопрос политики конфиденциальности в стиле "мы обещаем не читать". Это архитектурное ограничение: если у сервера нет ключа, он не может превратить ciphertext обратно в текст.</p><p>Звучит как магия. На самом деле — два протокола и немного WebCrypto.</p><h2>Главная идея: конверты</h2><p>Представь что Алиса хочет написать Бобу. Вместо того чтобы положить письмо на стол и надеяться что никто не прочитает — она кладёт его в запечатанный конверт. Конверт может открыть только Боб своим ключом. Сервер просто передаёт конверт не заглядывая внутрь.</p><p>Именно так это работает в коде. В базе данных у меня это выглядит так:</p><p>Когда я впервые увидел</p><p>в своей БД вместо текста — стало понятно, что модель наконец работает правильно: сервер создал сообщение, доставил его, сохранил метаданные, но так и не узнал содержимое.</p><p>А вот что сервер возвращает при запросе списка чатов через API:</p><p>Не</p><p>. Не</p><p>. Буквально</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/b466ad91-20da-4e64-8b78-f6e08d2851d5.webp" alt="" /></figure><p>(DevTools → Network → ответ API с</p><p>)</p><h2>Откуда берутся ключи: X3DH</h2><p>Главный вопрос: как Алиса и Боб получают общий секрет, если они никогда раньше не общались? И как сделать это так, чтобы сервер только помог передать публичные данные, но сам не смог вычислить итоговый ключ?</p><p>Для этого используется X3DH — Extended Triple Diffie-Hellman, протокол из экосистемы Signal. Его задача — установить общий секрет между двумя устройствами, используя долгосрочные и временные ключи.</p><h2>Что хранится на сервере</h2><p>Когда пользователь регистрирует устройство, он загружает на сервер пакет публичных ключей:</p><p>На сервер уходят только публичные части. Приватные ключи сериализуются и хранятся локально в браузере — и никогда не покидают устройство в сеть.</p><p>Здесь важно сказать честно: хранение приватных ключей в</p><p>Более строгий вариант — использовать Web Crypto API с</p><p>, чтобы приватный ключ жил внутри браузерного crypto runtime и его нельзя было экспортировать в байты. Но у этого подхода есть практическая сложность: ключи нужно переживать между перезагрузками страницы, синхронизировать с IndexedDB, аккуратно восстанавливать состояние устройства и не сломать UX.</p><p>В браузерных E2EE-приложениях обычно приходится выбирать между несколькими вариантами:</p><ul><li>Сериализуемые ключи в localStorage или IndexedDB — проще реализовать, но нужно очень серьёзно относиться к XSS и целостности frontend-кода.</li><li>extractable: false + IndexedDB — безопаснее, но сложнее в реализации и восстановлении состояния.</li><li>Нативное secure storage вроде Android Keystore или iOS Secure Enclave — лучший вариант для мобильных клиентов, но он недоступен обычному web-приложению.</li></ul><p>В текущей версии Chaos Messenger используется первый вариант. Это осознанный компромисс для pet/open-source проекта и удобного запуска в браузере. Переход на non-extractable ключи и более строгую модель хранения стоит в roadmap.</p><p>Ключевой момент: backend всё равно не получает приватные ключи и не может расшифровать сохранённые ciphertext-конверты. Но защита ключей на клиенте — отдельная задача, и её нельзя честно замалчивать.</p><h2>Установка сессии</h2><p>Когда Алиса открывает переписку с Бобом впервые, происходит следующее:</p><p>В классическом X3DH четвёртая DH-операция с one-time prekey опциональна: она выполняется, если сервер выдал доступный OPK получателя. В моей реализации устройство публикует набор one-time prekeys при регистрации, поэтому первое сообщение обычно использует DH4. Если OPK закончились, сессию всё равно можно установить через остальные DH-компоненты, но это уже менее сильный вариант.</p><p>Боб, получив конверт с эфемерным публичным ключом Алисы, повторяет те же операции со своими приватными ключами и получает тот же самый</p><p>. Математика симметрична.</p><p>Сервер в этот момент видит только публичные ключи и зашифрованный конверт. Он помогает устройствам найти друг друга, но не участвует в вычислении секрета.</p><p>Получить</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/e7bbacf3-4fd2-4710-863a-2c710b1f6759.webp" alt="" /></figure><h2>Как шифруется каждое сообщение: Symmetric Ratchet</h2><p>X3DH даёт нам стартовый</p><p>. Но использовать один и тот же ключ для всех сообщений — плохая идея. Если использовать один ключ для всей переписки, компрометация этого ключа сразу открывает весь поток сообщений.</p><p>Решение — симметричный ratchet. После каждого сообщения цепочка ключей продвигается вперёд:</p><p>Визуально это выглядит так:</p><p>используется для шифрования одного сообщения через AES-GCM, после чего уничтожается. Если атакующий компрометирует</p><p>— он прочитает только второе сообщение.</p><p>В рамках такой симметричной цепочки это даёт forward secrecy назад по цепочке: зная текущий или отдельный</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/939a74f7-60c5-4816-85f0-05b5afdc9845.webp" alt="" /><figcaption>(диаграмма схемы chainKey → messageKey)</figcaption></figure><p>Само шифрование сообщения:</p><p>А вот что уходит на сервер — живой пример из DevTools:</p><p>Сервер получает</p><p>и</p><p>. Расшифровать без</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/b5e24cda-6fd9-4b15-9f27-3eb9b4f843b0.webp" alt="" /></figure><h2>Важная оговорка: это ещё не полный Double Ratchet</h2><p>В этом проекте реализован Symmetric Ratchet — цепочка, где из</p><p>для каждого сообщения выводится отдельный</p><p>Это защищает прошлые сообщения: если атакующий узнает текущий ключ или отдельный</p><p>, он не сможет откатить HMAC назад и получить старые ключи.</p><p>Но это не полный Double Ratchet из Signal Protocol.</p><p>В полном Double Ratchet есть ещё DH ratchet step: стороны периодически выполняют новый Diffie-Hellman обмен и обновляют root key. Это даёт break-in recovery — возможность восстановить безопасность будущих сообщений после компрометации части состояния.</p><p>В моей реализации DH ratchet step пока нет. Если атакующий получит актуальное состояние сессии на устройстве и сможет продолжать его читать, он сможет расшифровывать будущие сообщения до переустановки сессии. Это честное ограничение текущей версии, и оно стоит первым пунктом в roadmap.</p><h2>Мультиустройство: один пользователь, несколько конвертов</h2><p>Первый неочевидный момент: в E2EE сообщение адресуется не просто пользователю, а конкретным устройствам пользователя.</p><p>Если у Боба два устройства — телефон и ноутбук — нужен отдельный encrypted envelope для каждого устройства. Сервер не может взять один конверт, расшифровать его и "переупаковать" для второго устройства: у него нет ключей и он не знает plaintext.</p><p>Значит при отправке сообщения нужно зашифровать его отдельно для каждого устройства каждого участника чата.</p><p>Для чата где у каждого по 2 устройства — 4 конверта на одно сообщение. Для группы из 10 человек — потенциально 20 конвертов. Это нормально, это цена безопасности.</p><h2>Сервер: хранение и доставка конвертов</h2><p>На сервере сообщение создаётся с контентом</p><p>, а конверты сохраняются отдельно:</p><p>После сохранения — fanout по WebSocket. Каждое устройство получает свой конверт и только его:</p><p>Это важное отличие от обычного WebSocket-чата. В обычном чате сервер рассылает одно и то же событие всем участникам. В E2EE-чате сервер рассылает разные события разным устройствам: payload для каждого устройства содержит свой</p><p>Топик</p><p>— строго персональный. Устройство А не получает конверт устройства Б. Никакого broadcast — только адресная доставка.</p><h2>Архитектура целиком</h2><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/de0e3257-d893-459f-86ed-7ed8eace5d56.webp" alt="" /></figure><h2>Баг который долго не замечал</h2><p>В панели чатов показывается превью последнего сообщения. Я реализовал это через</p><p>Запускаю — в списке чатов у всех написано</p><p>.</p><p>Конечно. Сервер же не знает что там написано.</p><p>Я полчаса думал как решить это на сервере. Потом дошло: нельзя решить это на сервере — у него нет ключей. Решение только на клиенте.</p><p>После того как пользователь открыл чат и сообщения расшифровались — кешируем последнее в памяти:</p><p>Это хороший пример того, как E2EE меняет привычное мышление backend-разработчика. В обычном приложении preview — это поле в SQL-запросе. В E2EE-приложении preview — это локальное клиентское состояние, потому что только клиент видел plaintext.</p><p>Простое решение. Но чтобы к нему прийти нужно было полностью принять идею что сервер здесь просто не при делах — и перестать пытаться решить задачу на его стороне.</p><h2>Rate limiting: дыра которую легко не заметить</h2><p>Эндпоинт</p><p>отправляет SMS с кодом. Без защиты любой скрипт может дёргать его тысячи раз — это называется SMS pumping fraud, SMS стоят реальных денег.</p><p>Redis у нас уже был для хранения онлайн-статусов. Добавил rate limiting поверх него:</p><p>При превышении — HTTP 429 с заголовком</p><p>. Клиент знает через сколько секунд можно повторить.</p><p>Важный нюанс: в текущей реализации, если Redis недоступен, сервис не блокирует авторизацию полностью. Для pet-проекта это приемлемый компромисс: лучше рискнуть одним лишним SMS, чем положить вход в приложение.</p><p>В production я бы сделал строже: fallback in-memory лимит на инстанс, отдельные лимиты по IP и телефону, антифрод-логику и алерты на всплески отправки кодов.</p><h2>Авторизация WebSocket</h2><p>Отдельная история — авторизация WebSocket соединений. HTTP-эндпоинты защищены Spring Security автоматически, но WebSocket — другое дело. STOMP-соединение устанавливается один раз, и нужно проверять JWT при каждом подключении.</p><p>Отдельно важно не только проверить JWT, но и связать WebSocket-соединение с конкретным устройством. Пользователь может быть один, но устройств у него несколько, а encrypted envelope адресован именно</p><p>Поэтому при подключении я проверяю не только токен, но и</p><p>: устройство должно быть зарегистрировано и принадлежать текущему пользователю. Иначе легко случайно превратить per-device E2EE-доставку обратно в обычный broadcast по пользователю.</p><h2>Что получилось — живые скрины</h2><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/1fdfa006-f5c6-4731-a40f-50559be8832d.webp" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/c99164a5-021c-49ac-bcc4-3e38f9cd1c31.webp" alt="" /></figure><p>Что реализовано:</p><ul><li>E2EE-модель с per-device encrypted envelopes</li><li>X3DH session setup + Symmetric Ratchet + AES-GCM</li><li>Мультиустройство</li><li>Личные и групповые чаты</li><li>Realtime доставка через WebSocket/STOMP</li><li>Статусы SENT → DELIVERED → READ</li><li>Редактирование и soft delete сообщений</li><li>Online presence, typing indicator</li><li>Фото-вложения</li><li>Поиск пользователей</li><li>Rate limiting на SMS через Redis</li><li>Prometheus метрики + Grafana дашборд</li><li>Swagger UI с JWT авторизацией</li><li>24 backend-теста на Testcontainers, 12 frontend на Vitest, E2E на Playwright</li><li>GitHub Actions CI</li></ul><p>Что ещё не сделано:</p><ul><li>Полный Double Ratchet с DH ratchet step и break-in recovery</li><li>Ротация signed prekey и аккуратное пополнение one-time prekeys</li><li>Более строгая модель хранения приватных ключей на клиенте: non-extractable CryptoKey + IndexedDB</li><li>Защита от подмены frontend-кода: подпись сборок, независимая верификация клиента, reproducible builds</li><li>Android-клиент с Android Keystore</li><li>Реальный SMS-провайдер вместо кода в backend-логах</li><li>Push-уведомления без утечки содержимого сообщений</li><li>Более строгая metadata-модель для групповых чатов</li></ul><h2>Главный инсайт</h2><p>E2EE — это архитектурное решение, а не библиотека.</p><p>Нельзя взять обычный Spring Boot чат и просто "включить шифрование". Нужно с самого начала проектировать систему так, чтобы backend не был участником доверенной зоны: он не должен получать plaintext, не должен иметь ключи и не должен уметь пересобирать сообщение из данных в базе.</p><p>Это меняет почти всё:</p><ul><li>структуру БД — вместо текста появляются encrypted envelopes</li><li>API — сервер отдаёт [encrypted], а не preview сообщения</li><li>WebSocket — доставка идёт не по пользователю, а по конкретному устройству</li><li>мультиустройство — одно сообщение превращается в несколько ciphertext-конвертов</li><li>frontend — становится полноценной криптографической частью системы, а не просто UI</li></ul><p>Второй инсайт: мессенджер — это не "чат с WebSocket". В E2EE-модели это система доставки зашифрованных конвертов с адресацией по устройствам. Как только это принимаешь, многие странные на первый взгляд решения становятся логичными.</p><h2>Репозиторий</h2><p>Код открыт: <a href="https://github.com/vaazhen/chaos-messenger">github.com/vaazhen/chaos-messenger</a></p><p>В репозитории есть README на русском и английском, диаграммы, скриншоты, security audit, Docker Compose и запуск одной командой.</p><p>Проект не претендует на уровень production-криптомессенджера вроде Signal. Это учебный и инженерный open-source прототип, цель которого — показать, как E2EE меняет архитектуру backend, frontend и realtime-доставки.</p><p>Если вы делали что-то похожее — особенно интересно сравнить подходы к ротации prekey-ов, хранению non-extractable ключей в браузере и реализации DH ratchet step. Вопросы и критика приветствуются.</p>]]></content:encoded>
    </item>
    <item>
      <title>pgBackRest перестали поддерживать — главный open-source бэкап PostgreSQL остался без мейнтейнера</title>
      <link>https://tproger.ru/news/pgbackrest-perestali-podderzhivat-glavnyj-open-source-bekap-po</link>
      <comments>https://tproger.ru/news/pgbackrest-perestali-podderzhivat-glavnyj-open-source-bekap-po?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/pgbackrest-perestali-podderzhivat-glavnyj-open-source-bekap-po</guid>
      <description><![CDATA[<p>Дэвид Стил после 13 лет разработки прекратил работу над pgBackRest. Главный open-source бэкап Postgres помечен obsolete. Разбираем альтернативы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/pgbackrest-perestali-podderzhivat-glavnyj-open-source-bekap-po">pgBackRest перестали поддерживать — главный open-source бэкап PostgreSQL остался без мейнтейнера</a>»</p>]]></description>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 27 Apr 2026 09:40:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если у вас на проде PostgreSQL под защитой <a href="https://github.com/pgbackrest/pgbackrest">pgBackRest</a> — обновлений и security-патчей больше не будет. Сегодня, 27 апреля 2026 года, автор инструмента <b>David Steele</b> добавил в README репозитория блок «NOTICE OF OBSOLESCENCE» и <a href="https://github.com/pgbackrest/pgbackrest">архивировал репозиторий</a> на GitHub.</p><p>pgBackRest — основной open-source инструмент резервного копирования и восстановления PostgreSQL последние ~10 лет: parallel backup, асинхронная архивация WAL, шифрование, поддержка S3/Azure/GCS-хранилищ, до десяти одновременно поддерживаемых major-версий Postgres (политика 5 supported + 5 EOL). Текущий стабильный релиз — <a href="https://github.com/pgbackrest/pgbackrest/releases/tag/release/2.58.0">v2.58.0</a>, выпущен в январе 2026.</p><ul><li>Дата объявления: 27 апреля 2026 года</li><li>Мейнтейнер: David Steele, 13 лет разработки</li><li>Репозиторий помечен archived — release-веток и патчей больше не будет</li><li>Текущий стабильный релиз: v2.58.0 (январь 2026)</li><li>Главные альтернативы: <a href="https://github.com/wal-g/wal-g">wal-g</a>, <a href="https://pgbarman.org/">Barman</a></li><li>Автор просит форки выбирать новое имя</li></ul><h2>Почему закрывают</h2><p>Прямой повод — продажа компании <a href="https://www.crunchydata.com/">Crunchy Data</a>, в которой David Steele работал и которая корпоративно спонсировала разработку pgBackRest. После сделки автор искал позицию, которая позволила бы продолжить работу над проектом, и параллельно собирал спонсорство — но обе попытки оказались безуспешны.</p><blockquote>pgBackRest 13 лет был моим личным проектом. После продажи Crunchy Data я искал позицию, позволяющую продолжать работу, и пытался собрать спонсорство — но усилий не хватило, чтобы сделать проект жизнеспособным. Как и всем остальным, мне нужно зарабатывать. Лучше сделать жёсткий стоп, чем тянуть проект кое-как.</blockquote><h2>Что это значит для пользователей</h2><p>Существующие установки продолжат работать — релиз v2.58.0 не отзывают. Но дальше будет так:</p><ul><li>Security-патчей больше нет. Если в pgBackRest найдут CVE, никто не выпустит фикс — придётся либо мигрировать, либо патчить самим в форке.</li><li>Поддержки следующих major-версий Postgres не будет. v2.58.0 уже поддерживает PG13–18, но когда выйдет PG19 (ожидается осенью 2026), pgBackRest не получит обновлённых WAL-форматов и сломается на новых кластерах.</li><li>Открытые issues (68 на момент архивации) останутся без ответов. Pull-request-ы тоже.</li><li>Документация на <a href="https://pgbackrest.org">pgbackrest.org</a> пока на месте, но судьба сайта после ухода автора неясна.</li></ul><h2>Альтернативы pgBackRest</h2><h3>wal-g</h3><p><a href="https://github.com/wal-g/wal-g">wal-g</a> — продолжатель WAL-E, создан в Citus Data в 2017 (Daniel Farina + Katie Li). Активная разработка сейчас спонсируется <a href="https://yandex.cloud/">Yandex Cloud</a>, поддерживается распределённой командой и сообществом. Поддерживает PostgreSQL, MySQL/MariaDB, MS SQL Server, MongoDB и Redis (последние два — beta). Бэкап в S3/GCS/Azure/Swift, параллельная обработка, delta-копии. Релизы выходят регулярно.</p><h3>Barman</h3><p><a href="https://pgbarman.org/">Barman</a> — инструмент от <a href="https://www.enterprisedb.com/">EDB</a> (бывший 2ndQuadrant). Делает full и incremental бэкапы, point-in-time recovery, поддерживает streaming-репликацию и WAL-archiving. Сильнее других ориентирован на on-prem-сценарии и enterprise-сетапы. У EDB есть коммерческие подписки на Barman — это снижает риск похожего сценария.</p><h3>pg_basebackup</h3><p><a href="https://www.postgresql.org/docs/current/app-pgbasebackup.html">pg_basebackup</a> — встроенный инструмент Postgres. Подходит для небольших БД, простых сетапов, разовых снимков. С PG17 умеет page-level incremental backup (через summarize_wal и pg_combinebackup), но без удобной обвязки. Не покроет parallel backup, multi-repo retention и продвинутые retention-полиси.</p><h2>Что делать прямо сейчас</h2><ol><li>Проверьте текущую версию pgBackRest на серверах: pgbackrest version</li><li>Подпишитесь на список рассылки <a href="https://www.postgresql.org/list/pgsql-announce/">pgsql-announce</a> — туда придут уведомления о CVE Postgres, требующих внимания и от backup-tooling.</li><li>Запланируйте миграцию на wal-g или Barman в течение 6–12 месяцев. До PG19 (релиз ожидается осенью 2026) — окно есть, после — будет жать.</li><li>Если рассматриваете форк pgBackRest — David Steele явно просит дать форку новое имя. Это не хулиганство, а защита пользователей от путаницы между поддерживаемой и заброшенной кодовой базой.</li><li>Перед миграцией протестируйте новый инструмент на staging: восстановление до точки, retention-полиси, скорость parallel backup на ваших объёмах. У wal-g и Barman разная философия — на каких-то нагрузках различия в скорости в разы.</li></ol><h2>Выводы</h2><p>История pgBackRest — это не «open-source умер», это про то, что donations и star-driven sponsorship не работают как модель устойчивости infrastructure-проектов. 13 лет работы, страница на <a href="https://github.com/sponsors/dwsteele">GitHub Sponsors</a> — и всё равно один человек на длинной дистанции не вытягивает. Backup-инструмент Postgres-уровня требует коммерческого стейкхолдера. У wal-g он есть (Yandex Cloud, исторически Citus Data), у Barman — <a href="https://www.enterprisedb.com/">EDB</a>, у pgBackRest был Crunchy Data, и его не стало. Похожую модель устойчивости open-source проектов мы недавно разбирали на примере <a href="https://tproger.ru/news/raswirenie-honker-vstroilo-v-sqlite-ochered-zadach-i-pub-sub">расширения honker для SQLite</a> — где спонсорство сразу зашито в распределённую команду.</p><p>Для DBA практический вывод простой: ревизия инфры на «один человек = один мейнтейнер = single point of failure» и проверка, кто поддерживает критичные инструменты — продуктовая компания или энтузиаст в свободное время.</p>]]></content:encoded>
    </item>
    <item>
      <title>Индексы в Postgres: почему ваш индекс не работает и что такое INCLUDE</title>
      <link>https://tproger.ru/translations/indeksy-v-postgres-pochemu-vaw-indeks-ne-rabotaet-i-chto-takoe-in</link>
      <comments>https://tproger.ru/translations/indeksy-v-postgres-pochemu-vaw-indeks-ne-rabotaet-i-chto-takoe-in?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/indeksy-v-postgres-pochemu-vaw-indeks-ne-rabotaet-i-chto-takoe-in</guid>
      <description><![CDATA[<p>B-tree, композитные, функциональные, частичные, покрывающие индексы Postgres — разбираем на примерах, где lower() убивает индекс и когда реально нужен INCLUDE.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/indeksy-v-postgres-pochemu-vaw-indeks-ne-rabotaet-i-chto-takoe-in">Индексы в Postgres: почему ваш индекс не работает и что такое INCLUDE</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 16 Apr 2026 15:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ваш SELECT всё ещё тормозит, хотя вы добавили индекс? Вот три главные причины, почему Postgres его не использует: вы обернули колонку в lower(), перепутали порядок колонок в композитном индексе или полагаетесь на INCLUDE ради скорости записи. Индекс — это отсортированная структура, по которой база делает бинарный поиск вместо чтения всей таблицы. Но даже правильно созданный индекс легко выключить одной лишней функцией.</p><p>Джон Чартер в статье <a href="https://jon.chrt.dev/2026/04/15/things-you-didnt-know-about-indexes.html" rel="noopener">«Things you didn't know about indexes»</a> разбирает не только базовые принципы B-tree, но и три типа индексов, о которых новичкам не рассказывают: функциональные, частичные и покрывающие. Переводим полностью, с примерами на таблице покемонов и объяснением, почему EXPLAIN — ваш лучший друг.</p><p>Индексы ускоряют чтение, но замедляют запись. INSERT, UPDATE и DELETE обновляют каждый индекс — восемь индексов на таблице значат восемь дополнительных обновлений.</p><p>Композитный индекс (type_1, type_2) работает для запросов на type_1 и на обе колонки вместе, но не для запросов только на type_2. Порядок колонок важен.</p><p>Функция над индексированной колонкой убивает индекс. WHERE lower(name) = 'pikachu' не использует индекс на name — нужен функциональный индекс на lower(name).</p><p>Частичный индекс с WHERE покрывает только нужные строки. Для soft-delete или редких флагов экономит место и ускоряет запись.</p><p>Покрывающий индекс с INCLUDE отвечает на запрос без похода в таблицу — в EXPLAIN это Index Only Scan.</p><p>Не угадывайте — используйте EXPLAIN ANALYZE. Он показывает реальный план запроса и реальное время выполнения.</p><h2>Начнём с того, что вы, вероятно, уже знаете</h2><p>Индекс в базе данных похож на алфавитный указатель в конце учебника. Хотите найти страницы про фосфор? Идёте в конец, находите тему и номера страниц рядом с ней:</p><p>Представим таблицу покемонов:</p><p>Без индекса поиск Пикачу означает, что база прочитает каждую строку, проверяя колонку name. На четырёх строках это мгновенно. На десяти миллионах — уже проблема. Такое чтение называется full table scan, и оно не медленное само по себе: современные базы легко прошивают миллионы строк в секунду. Проблема в линейной сложности — удваиваете число строк, удваиваете время. Индексный поиск этой разницы почти не замечает.</p><p>Но если добавить индекс на name, получится примерно то же, что указатель в учебнике:</p><p>Данные отсортированы, поэтому база может сделать бинарный поиск по имени и найти нужную строку, а не сканировать всю таблицу. Под капотом Postgres хранит это как B-tree (сбалансированное дерево), но идея такая же, как в учебнике: отсортированные данные, по которым можно быстро искать.</p><p>Итак, индексируем всё подряд, верно? Не так быстро.</p><h2>Цена индексации</h2><p>Как бы ни хотелось проиндексировать всё, у индексов есть компромиссы. Главное правило:</p><blockquote>Чтение ускоряется, запись замедляется.</blockquote><p>С новым блестящим индексом каждый INSERT, UPDATE и DELETE должен обновить и индекс тоже. Когда мы добавляем нового покемона, база находит правильное место в отсортированном индексе имён и вставляет его туда. А индексов может быть несколько — умножайте эту работу на каждый из них.</p><p>Плюс индексы — это реальные структуры данных, и их нужно хранить. Они живут на диске и подгружаются в память: в Postgres это shared_buffers. У таблицы с восемью индексами девять объектов, которые конкурируют за буфер, а не один.</p><p>И не забываем про планировщик (query planner) — компонент, который перед каждым запросом оценивает варианты доступа к данным и выбирает самый дешёвый. Чем больше индексов, тем больше вариантов он взвешивает, так что время планирования растёт и на быстрых выборках может даже превысить время выполнения.</p><p><b>Отдельный риск на проде.</b> Обычный CREATE INDEX блокирует таблицу на запись до конца построения. На таблице в десятки миллионов строк это минуты недоступности. В production используйте CREATE INDEX CONCURRENTLY — он строит индекс без эксклюзивной блокировки, ценой чуть большего времени и того, что операция может быть прервана и оставить индекс в состоянии INVALID (который надо пересобрать).</p><h2>Почему ваш индекс не работает</h2><p>Вы взвесили компромиссы, решили, что индекс уместен. Отлично. Но он не работает как ожидалось: улучшения нет или, хуже того, скорость падает. Разберём типичные грабли.</p><h3>Композитные индексы и порядок колонок</h3><p>Возвращаясь к таблице покемонов: вы могли решить, что хороший индекс — это индекс на type_1 и type_2. «Покажи всех покемонов типа Water и Flying» — вполне разумный запрос.</p><p>Этот индекс определённо поможет запросам вроде:</p><p>Но вот этому — уже нет:</p><p>Удивлены? Когда вы создаёте композитный индекс (type_1, type_2), вы просите базу построить структуру примерно такого вида:</p><p>Сначала сортировка по type_1, затем по type_2 внутри каждой группы. Для запросов по type_1 индекс отличный, для запросов по type_1 AND type_2 — ещё лучше, но для запросов только по type_2 он не будет использован так, как вы надеетесь. Посмотрите на Flying: он разбросан под Bug, Electric, Fire и Water — базе некуда прыгнуть.</p><p>Задайте себе вопрос: какие запросы будут частыми? Если по type_2 вы будете искать так же часто, как по type_1, создайте второй индекс на type_2.</p><h3>Функции убивают индекс</h3><p>Поиск без учёта регистра — частая фича. Пользователям всё равно, пишут ли они «Pikachu», «pikachu» или «PiKaChU» — они просто хотят результат. Поэтому можно написать так:</p><p>Я бы не обратил на такой запрос особого внимания. Выглядит нормально. У нас есть индекс на name, запрос должен летать. Но, конечно, он не летает.</p><p>Почему? Индекс на name, а не на lower(name). Для базы это две совершенно разные вещи. Ваш индекс — это отсортированный список значений вида Bulbasaur, Charmander, Squirtle, Pikachu, а не bulbasaur, charmander, squirtle, pikachu. Так что когда вы просите строки, где lower(name) = 'pikachu', у базы нет отсортированной структуры для этого — и она откатывается к сканированию всей таблицы, приводя каждое имя к нижнему регистру по ходу дела.</p><p>Это касается любой функции, оборачивающей колонку. Если база не видит индексированную колонку слева от сравнения, индекс выбывает из игры.</p><p>И вот настоящие грабли: неявные преобразования тоже считаются. Классический пример — колонка user_id типа bigint сравнивается со строкой (WHERE user_id = '42') или timestamp сравнивается со строковой датой. Postgres тихо добавит приведение типа — и индекс работать перестанет с тем же эффектом, что и явная обёртка функцией.</p><p>Как обойти это? К счастью, можно построить индекс на выражении. Индекс на lower(name) абсолютно валиден, и запрос выше будет использовать его без проблем. К этому мы ещё вернёмся.</p><h3>Как избежать этих ловушек</h3><p>Короткий ответ: не гадайте. Измеряйте. Как? Спросите базу.</p><p>В Postgres есть инструмент EXPLAIN, который показывает, как именно база собирается выполнить запрос. Поставьте его перед любым SELECT — и получите отчёт:</p><p>Index Scan — это то, что вы хотите видеть. Значит, база использует индекс. Сравните с проблемным запросом:</p><p>Seq Scan значит, что читается каждая строка. Никаких индексов.</p><p>Если хотите реальные тайминги вместо оценок планировщика, используйте EXPLAIN ANALYZE. Он действительно запускает запрос и сообщает, что произошло. Попробуйте на запросе, который, как вам кажется, вы понимаете — результаты часто удивляют. А если Postgres тормозит не из-за индексов — у нас есть <a href="https://tproger.ru/articles/tormozit-postgres--12-wagov-diagnostiki" rel="noopener">12 шагов диагностики</a>, от pg_stat_activity до auto_explain.</p><h2>Чего вам не рассказывали</h2><p>Мы разобрали базовый индекс на одной колонке и его композитного брата. Вместе они покрывают большинство случаев. Но есть ещё несколько видов индексов, которые иногда оказываются именно тем, что нужно.</p><p><b>Сначала оговоримся про типы индексов в целом.</b> Всё, о чём мы пока говорили, — это B-tree, тип по умолчанию в Postgres. Но для нестандартных задач есть другие: GIN для jsonb и полнотекстового поиска, GiST для геоданных и диапазонов, BRIN для огромных таблиц с физически упорядоченными данными (логи, временные ряды), Hash для точного равенства. Ниже речь идёт именно о B-tree — но идеи функциональных, частичных и покрывающих индексов применимы и к другим типам.</p><h3>Функциональные индексы</h3><p>Мы затрагивали это в разделе про функции. Проблемный запрос был такой:</p><p>Индекс на name не помогает, потому что база ищет строки с lower(name) = ..., а отсортированной структуры для lower(name) у неё нет. Исправление — дать ей такую структуру:</p><p>Это функциональный индекс (его ещё называют индексом на выражении). Вместо того, чтобы индексировать сырую колонку, вы индексируете результат выражения, применённого к ней. Конечно, это не ограничивается lower(). Можно индексировать любое детерминированное выражение:</p><p>Годится любая функция с меткой IMMUTABLE — в Postgres это означает, что она возвращает одинаковый результат для одинаковых аргументов при любых условиях (в отличие от STABLE, которая детерминирована только в рамках одной транзакции, и VOLATILE).</p><p>Но осторожно. Если тянуться к функциональному индексу при первом же случае, это часто плохой запах. Если мы так часто ищем по имени в нижнем регистре, почему мы вообще не храним имя в нижнем регистре? Альтернативы: отдельная колонка name_lower, которую заполняете на вставке; тип citext (case-insensitive text) из одноимённого расширения; или COLLATE с регистронезависимой коллацией. Функциональный индекс — когда изменить хранение уже нельзя.</p><h3>Частичные индексы</h3><p>Большинство индексов покрывает каждую строку таблицы. Но иногда вы запрашиваете только её небольшой срез — и индексировать всё подряд расточительно. Напомню: индексы не бесплатны.</p><p>В нашей таблице покемонов есть колонка is_legendary. На момент написания существует около 1000 видов покемонов, из которых легендарными считаются всего 80 — меньше 10%.</p><p>Представьте приложение с опцией «показать всех легендарных». Изначально так и хочется создать составной индекс:</p><p>Это работает, но это перебор. Индекс теперь содержит запись для каждого покемона, а подавляющее большинство — не легендарные. Мы будем платить за хранение и запись 1000 строк, чтобы обслуживать запросы, которым интересны только 80. Более того, поскольку is_legendary — булево, получается структура, где сначала идёт разделение на False и True, и первая группа — это 920 записей мёртвого груза, оплачивающих свою долю каждой записи в таблицу ради запросов, которые их игнорируют.</p><p>Частичный индекс покрывает только строки, которые подходят под условие:</p><p>Теперь в индексе 80 записей вместо 1000. Он меньше, быстрее в запросах; а запросы вида WHERE is_legendary = true используют его без вопросов. Запросы, которые не подходят под условие (WHERE is_legendary = false), откатываются к full table scan — что вам и нужно. Эти запросы и так матчат почти каждую строку, так что индекс им не особо помог бы.</p><p>Любая колонка, где вы почти всегда запрашиваете одно значение, — кандидат на частичный индекс. Представьте индекс на колонке email в таблице users, где у вас реализован soft-delete:</p><p>Soft-deleted строки почти никогда не запрашиваются, но без фильтра всё равно раздували бы ваши индексы.</p><h3>Покрывающие индексы</h3><p>Когда база использует индекс, чтобы найти строку, это только половина работы. Индекс указывает, где строка лежит, но потом база должна сходить в саму таблицу и забрать остальные колонки, которые запросил запрос. Две поездки.</p><p>А что, если я скажу, что так делать необязательно?</p><p>Если в индексе уже есть все колонки, которые нужны запросу, база может ответить на запрос из одного только индекса. Это покрывающий индекс. В EXPLAIN вы увидите его как Index Only Scan — три самых сладких слова из возможного вывода EXPLAIN.</p><p><b>Одна важная оговорка.</b> Даже при Index Only Scan Postgres всё же заглядывает в visibility map — битовую карту, которая для каждой страницы таблицы отмечает, видимы ли все её строки всем активным транзакциям. Если страница «грязная» (были недавние UPDATE/DELETE), Postgres всё равно пойдёт в heap за проверкой MVCC. Так что на интенсивно пишущих таблицах регулярный VACUUM (автовакуум обычно справляется) критичен для того, чтобы Index Only Scan оставался «онли».</p><p>Вот запрос:</p><p>Наш частичный индекс из предыдущего раздела идеально покрывает этот запрос. Индекс на name, отфильтрованный по легендарным, — и запрос просит name легендарных. Всё, что нужно запросу, уже в индексе. Поход в таблицу не нужен.</p><p>Покрывающие индексы можно строить и специально. Postgres позволяет добавить к индексу дополнительные колонки через INCLUDE:</p><p>Теперь на такой запрос можно ответить прямо из индекса:</p><p>Почему не положить base_attack прямо в индексируемые колонки? Потому что база считает индексируемые колонки тем, по чему нужно сортировать и искать. Если добавить base_attack в ключевые колонки индекса, вы скажете базе сортировать индекс сначала по name, потом по base_attack — дополнительная работа, которая не нужна, если вы ищете только по name. INCLUDE говорит: «тащи эту колонку с собой, но не морочься сортировкой».</p><h3>Правка автора: когда на самом деле нужен INCLUDE</h3><p>В комментариях на Reddit автор получил поправку от <a href="https://www.reddit.com/user/therealgaxbo/" rel="noopener">u/therealgaxbo</a> и обновил статью. Скорость записи — не главная причина использовать INCLUDE для покрывающих индексов: в обоих случаях (колонка в ключе или в INCLUDE) индекс обновляется при каждой записи, разница по нагрузке скромная.</p><p>Реальные причины использовать INCLUDE:</p><p>Можно включать колонки, у которых типы данных не имеют подходящего operator class для типа индекса (operator class — набор функций сравнения, по которым Postgres строит индекс для конкретного типа; для некоторых типов он просто не определён). Например, колонку box (геометрический прямоугольник) нельзя добавить в B-tree индекс как ключевую — нет оператора «меньше/больше». А через INCLUDE можно.</p><p>Можно добавить колонки в уникальный индекс без изменения его семантики уникальности:</p><p>Это обеспечивает уникальность только по email, но при этом покрывает запросы, которым нужен user_id.</p><h2>Выводы</h2><p>Индексы могут казаться новичку чем-то второстепенным. Даже опытные инженеры часто создают их не задумываясь или не создают вовсе. Но грамотная индексация делает или ломает производительность вашей базы.</p><p>Хотите глубже? Сайт <a href="https://use-the-index-luke.com/" rel="noopener">Use The Index, Luke</a> научит вас всему, что только можно знать про индексы в разных СУБД. А если вы только начинаете с Postgres — загляните в наши <a href="https://tproger.ru/articles/osnovy-postgresql-dlya-nachinayushhih--ot-ustanovki-do-pervyh-zaprosov-250851" rel="noopener">основы PostgreSQL</a>: от установки до первых запросов.</p><p>И не забудьте запустить EXPLAIN ANALYZE хотя бы на одном запросе сегодня — результаты могут вас удивить.</p><p>Источник: <a href="https://jon.chrt.dev/2026/04/15/things-you-didnt-know-about-indexes.html" rel="noopener">jon.chrt.dev — Things you didn't know about indexes</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Инженер AWS обнаружил: Linux 7.0 вдвое снижает производительность PostgreSQL</title>
      <link>https://tproger.ru/news/inzhener-aws-obnaruzhil--linux-7-0-vdvoe-snizhaet-proizvoditelnost</link>
      <comments>https://tproger.ru/news/inzhener-aws-obnaruzhil--linux-7-0-vdvoe-snizhaet-proizvoditelnost?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/inzhener-aws-obnaruzhil--linux-7-0-vdvoe-snizhaet-proizvoditelnost</guid>
      <description><![CDATA[<p>Инженер AWS обнаружил: на Linux 7.0 с PREEMPT_LAZY throughput PostgreSQL падает до 0,51x — 50 751 tps вместо 98 565 tps. Причина — удаление режима PREEMPT_NONE.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/inzhener-aws-obnaruzhil--linux-7-0-vdvoe-snizhaet-proizvoditelnost">Инженер AWS обнаружил: Linux 7.0 вдвое снижает производительность PostgreSQL</a>»</p>]]></description>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 06 Apr 2026 10:58:53 GMT</pubDate>
      <content:encoded><![CDATA[<p>PostgreSQL — одна из самых нагруженных баз данных в мире, и её производительность критична для тысяч продуктов. Но инженер AWS обнаружил, что обычное обновление ядра Linux может вдвое обрушить throughput — без каких-либо изменений в самой СУБД.</p><p>Сальваторе Дипьетро (Salvatore Dipietro) из AWS <a href="https://www.phoronix.com/news/Linux-7.0-AWS-PostgreSQL-Drop">сообщил</a>: на Linux 7.0 с планировщиком PREEMPT_LAZY throughput PostgreSQL упал до <strong>0,51x</strong> по сравнению с Linux 6.x. То есть база данных стала работать почти вдвое медленнее — и виновата одна строка в ядре.</p><ul><li>Linux 7.0 убрал режим PREEMPT_NONE — остались только Full и Lazy preemption</li><li>Throughput PostgreSQL на Linux 7.0 упал до 0,51x (50 751 tps против 98 565 tps на Linux 6.x)</li><li>Причина: планировщик прерывает поток, держащий spinlock, — 55% CPU уходит на spinning в ожидании</li><li>Revert-патч восстанавливает производительность до 1,94x</li><li>Linux 7.0 stable выйдет примерно через 2 недели; Ubuntu 26.04 LTS будет на нём</li></ul><h2>Как обнаружили регрессию</h2><p>Дипьетро тестировал на EC2 m8g.24xlarge с 96-vCPU процессором Graviton4. Стенд: PostgreSQL 17, утилита pgbench, 1024 клиента, 96 потоков, длительность теста — 1200 секунд. Это типичная нагрузка высоконагруженного OLTP-сервиса.</p><p>На Linux 6.x результат составил <strong>98 565 tps</strong>. На Linux 7.0 с PREEMPT_LAZY — <strong>50 751 tps</strong>, то есть падение до 0,51x. После применения revert-патча производительность выросла до <strong>1,94x</strong> относительно Linux 6.x — и достигла 98 565 tps.</p><h2>Почему ядро изменили и при чём здесь spinlocks</h2><p>Виновен <a href="https://winbuzzer.com/2026/04/05/aws-engineer-reports-postgresql-perf-halved-by-linux-7-kernel-change-xcxwbn/">коммит 7dadeaa6e851</a> за авторством Питера Зийлстры (Peter Zijlstra) из Intel. В Linux 7.0 убрали режим PREEMPT_NONE: теперь доступны только Full и Lazy preemption. По умолчанию включён PREEMPT_LAZY.</p><p>Проблема в том, как PostgreSQL реализует spinlocks. Функция s_lock() в StrategyGetBuffer/GetVictimBuffer крутится в ожидании блокировки. При PREEMPT_LAZY планировщик может вытеснить поток прямо в тот момент, когда он держит spinlock. Все остальные потоки, ожидающие этот замок, начинают активно спиниться — и по замерам 55% CPU уходит именно на это бесполезное ожидание. Затронуты все основные архитектуры: arm64, x86, powerpc, riscv, s390, loongarch.</p><blockquote>PREEMPT_NONE означает, что задача будет выполняться до явного вызова schedule() или возврата из системного вызова/прерывания. Это исторически использовалось для серверных нагрузок с активным ожиданием, но мы убираем этот режим — он маскирует проблемы с блокировками вместо того, чтобы их решать.</blockquote><h2>Патовая ситуация: кто должен чинить?</h2><p>Разработчики ядра считают, что проблема на стороне PostgreSQL: база данных должна использовать механизм rseq (Restartable Sequences) — расширение Linux, позволяющее коду пространства пользователя эффективно работать с критическими секциями без spinlock-спиннинга.</p><blockquote>Правильное решение — использовать rseq time slice extension. Spinlock-спиннинг в пространстве пользователя изначально является проблемным паттерном в вытесняющей многозадачной среде.</blockquote><p>Но PostgreSQL rseq не поддерживает, и никаких сроков интеграции нет. Это классический тупик: ядро меняет поведение, опираясь на «правильную» архитектуру, а прикладное ПО годами использует привычные примитивы. В итоге пострадают администраторы баз данных, которые просто обновят ядро.</p><h2>Что делать администраторам PostgreSQL</h2><p>До тех пор, пока проблема не решена на уровне ядра или PostgreSQL, администраторам баз данных стоит учитывать следующее:</p><ul><li>Не обновляться на Linux 7.0 в production до появления официального патча или workaround</li><li>Отслеживать параметр preemption model ядра при обновлении дистрибутива</li><li>Ubuntu 26.04 LTS, выходящая примерно в конце апреля 2026, будет использовать Linux 7.0 — проверить совместимость заранее</li><li>При необходимости использовать кастомное ядро с revert-патчем коммита 7dadeaa6e851</li><li>Следить за обновлениями в PostgreSQL hackers mailing list и linux-kernel mailing list</li></ul><p>Регрессия производительности PostgreSQL на Linux 7.0 — наглядный пример того, как изменение в ядре может затронуть критическую инфраструктуру. До появления официального решения (патч ядра или поддержка rseq в PostgreSQL) администраторам баз данных следует воздержаться от обновления ядра в production-окружениях. Отслеживать развитие ситуации можно на <a href="https://www.phoronix.com/news/Linux-7.0-AWS-PostgreSQL-Drop">Phoronix</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Паттерны управления трафиком к PostgreSQL в production</title>
      <link>https://tproger.ru/translations/patterny-upravleniya-trafikom-k-postgresql-v-production</link>
      <comments>https://tproger.ru/translations/patterny-upravleniya-trafikom-k-postgresql-v-production?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/patterny-upravleniya-trafikom-k-postgresql-v-production</guid>
      <description><![CDATA[<p>Практические паттерны на Go для контроля нагрузки на Postgres: SQLCommenter-теги, изоляция сервисов через роли, лимиты по тарифам и обработка SQLSTATE 53000. Разбираем с кодом.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/patterny-upravleniya-trafikom-k-postgresql-v-production">Паттерны управления трафиком к PostgreSQL в production</a>»</p>]]></description>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 03 Apr 2026 11:30:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>Один неудачный аналитический запрос способен положить весь checkout. PlanetScale предлагает решение — Database Traffic Control: ресурсные бюджеты для разных «слоёв» трафика к Postgres. Разбираем паттерны на Go, которые можно перенести на любой стек.</p><ul><li>SQLCommenter — формат тегов в SQL-комментариях, по которым Traffic Control различает запросы</li><li>Изоляция микросервисов через Postgres-роли и application_name</li><li>Автоматическая маркировка запросов по HTTP-роутам через middleware</li><li>Контроль новых деплоев и фича-флагов через теги feature</li><li>Tier-based лимиты для мультитенантных SaaS-приложений</li><li>Обработка ошибки SQLSTATE 53000 при блокировке запроса</li></ul><p><i>Перевод статьи <a href="https://planetscale.com/blog/patterns-for-postgres-traffic-control">Patterns for Postgres Traffic Control</a> Джоша Брауна из блога PlanetScale.</i></p><h2>Настройка: SQLCommenter и передача тегов через контекст</h2><p>Большинство паттернов опираются на пользовательские теги, прикреплённые к запросам. Traffic Control читает их в формате <a href="https://google.github.io/sqlcommenter/">SQLCommenter</a> — это SQL-комментарий с URL-кодированными парами ключ=значение, добавляемый в конец запроса:</p><p>Эти теги затем доступны для правил Traffic Control. Вот минимальный хелпер на Go, который добавляет теги в этом формате:</p><p>Если вы используете pgx с включённым PrepareThreshold, комментарий SQLCommenter станет частью ключа кэша prepared statement. Это может привести к разрастанию кэша планов. Решение — отключить PrepareThreshold для подключений с тегированием или использовать SimpleProtocol.</p><p>Примеры кода рассчитаны на Go 1.22+. В частности, r.Pattern (поле http.Request) и range по целому числу (for attempt := range maxRetries) появились именно в этой версии.</p><p>Также понадобится способ пробрасывать теги через стек вызовов без изменения каждой сигнатуры функции. Ключ контекста отлично подходит для этого:</p><p>С этими двумя хелперами паттерны ниже просто устанавливают ключи и значения в контексте. Тегирование происходит автоматически при выполнении запроса.</p><h2>Изоляция сервисов через Postgres-роли</h2><p>В микросервисной архитектуре один «взбесившийся» сервис не должен деградировать все остальные сервисы, использующие ту же базу данных. Простейший способ изолировать сервис — создать правило Traffic Control на основе уникальной строки подключения или application_name.</p><p>Бюджет на username='pscale_api_123abc' изолирует весь трафик от этой роли. Это также помогает при инцидентах — можно мгновенно ограничить долю ресурсов сервиса без передеплоя.</p><p>Имя пользователя — это внутреннее Postgres-имя роли, а не имя роли в дашборде. Также можно целиться в кастомные роли, созданные через CREATE ROLE, если ваши микросервисы строго разделяют права на таблицы.</p><p>Также можно использовать application_name, добавив его к строке подключения:</p><h2>Маркировка запросов по HTTP-роутам</h2><p>Когда вы запускаете монолит или крупный API-сервис, проблема обычно не в целом сервисе — а в конкретных роутах. Эндпоинт /api/export, генерирующий CSV-отчёты, не должен убивать /api/checkout.</p><p>HTTP-middleware может инжектировать роут в контекст во время выполнения, до запуска любого обработчика:</p><p>Оберните вызовы к базе данных, чтобы они автоматически подхватывали теги:</p><p>Теперь каждый запрос несёт информацию о роуте, из которого пришёл. Можно создать бюджет Traffic Control для route='/api-export' и задать ему консервативный лимит CPU.</p><p>Это также упрощает управление инцидентами. Если вы видите всплеск и не знаете, какой роут виноват — график нарушений в Traffic Control покажет, какой именно тег route достигает лимитов.</p><h2>Фича-флаги и новые деплои</h2><p>Выкатка новой фичи в production всегда несёт риск. Может, новый паттерн запросов нормально работает под тестовой нагрузкой, но становится дорогим на масштабе. Traffic Control позволяет ограничить радиус поражения до того, как ситуация превратится в инцидент.</p><p>Простейшая версия устанавливает тег из переменной окружения при старте:</p><p>Установите DEPLOYMENT_TAG=new_checkout_v2 при раскатке новых подов и оставьте переменную пустой на старых. Traffic Control может иметь бюджет на feature='new_checkout_v2' в режиме Warn с первого дня — так вы увидите, как новый код себя ведёт, прежде чем он вызовет проблемы.</p><p>Для фича-флагов, управляемых в рантайме, подход тот же, но определяется результатом проверки флага:</p><h2>Tier-based лимиты для мультитенантных приложений</h2><p>В SaaS-приложении пользователи бесплатного тарифа не должны деградировать работу enterprise-клиентов. Traffic Control позволяет обеспечить это на уровне базы данных, а не только на уровне приложения.</p><p>Инжектируйте тариф пользователя в SQL-теги сразу после аутентификации:</p><p>В middleware аутентификации:</p><p>Теперь создайте два бюджета Traffic Control:</p><ul><li>tier='free' — консервативные лимиты на долю сервера и максимальное число параллельных запросов</li><li>tier='pro' — умеренные лимиты</li></ul><p>Enterprise-трафик оставьте без бюджета или задайте высокий потолок. Когда пользователь бесплатного тарифа запускает тяжёлый дашборд или триггерит медленный запрос — бюджет сбросит этот трафик до того, как он затронет enterprise-нагрузки.</p><p>Паттерны можно комбинировать. Бюджет tier='free' AND route='api-export' будет строже, чем бюджет только на tier='free'. Enterprise-экспорты получат больше ресурсов, чем бесплатные.</p><h2>Фоновые задачи и скрипты</h2><p>Фоновые задачи — частая причина инцидентов с базой данных. Миграция, ночная синхронизация или одноразовый бэкфилл данных могут случайно насытить БД, если выполняются быстрее ожидаемого. Traffic Control — чистый способ задать потолок ресурсов без настройки таймаутов на уровне каждого запроса.</p><p>Для долгоживущих фоновых воркеров используйте выделенный пул подключений с отдельным application_name:</p><p>Функция newJobDB принимает DSN базы и устанавливает application_name в background-jobs перед подключением. Максимум подключений ограничен четырьмя, чтобы фоновая задача не занимала больше воркеров, чем положено.</p><p>Установка application_name на уровне строки подключения в коде гарантирует, что имя всегда задано для этого сервиса — независимо от конкретного запроса или переменных окружения. Это можно комбинировать с SQL-комментариями для ещё более гранулярного контроля.</p><p>Для одноразовых скриптов и миграций — аналогичный подход. Здесь идентичность скрипта кодируется прямо в строке подключения:</p><p>Создайте бюджет Traffic Control для application_name='background-jobs' в режиме Warn. Понаблюдайте, сколько ресурсов базы обычно потребляет фоновая работа. Затем переключите на Enforce, чтобы ограничить её на уровне, при котором она не сможет вытеснить интерактивный трафик.</p><h2>Обработка заблокированных запросов</h2><p>Когда Traffic Control в режиме Enforce и запрос превышает бюджет, Postgres возвращает SQLSTATE 53000 с сообщением, начинающимся с [PGINSIGHTS] Traffic Control:. Приложение должно обрабатывать это без падения.</p><p>С pgx/v5:</p><p>Правильная реакция зависит от роли запроса в приложении. Для некритичных нагрузок — аналитики, отчётов — возвращайте 503 или закэшированный результат:</p><p>Для критичных путей можно реализовать короткий retry с экспоненциальным backoff:</p><h3>Наблюдение за Warn-режимом</h3><p>Прежде чем переключить бюджет в Enforce, запустите его в режиме Warn. В этом режиме запросы выполняются успешно, но драйвер получает Postgres-notice. С pgx/v5 можно логировать их, чтобы понять, что именно будет заблокировано:</p><p>Соберите логи за несколько часов репрезентативного трафика. Паттерн срабатываний подскажет, нужно ли корректировать лимиты.</p><h2>Собираем всё вместе</h2><p>Паттерны компонуются. В реальном приложении можно наслоить несколько из них:</p><p>Traffic Control видит всё это как комбинацию тегов. Бюджет на tier='free' покрывает весь free-трафик независимо от роута. Бюджет на route='api-export' AND tier='free' — конкретную комбинацию. Несколько совпадающих бюджетов применяются одновременно, и запрос должен удовлетворять каждому из них.</p><p>Начните в режиме Warn, понаблюдайте, какие бюджеты срабатывают при нормальной нагрузке, ужесточайте лимиты, пока не будут триггериться только патологические случаи — затем переключите на Enforce.</p><h2>Выводы</h2><p>Разница между падением базы и деградированным опытом часто сводится к тому, решили ли вы заранее, какой трафик сбрасывать. Traffic Control делает это решение явным и конфигурируемым — вместо того чтобы оставлять его на милость гонки за ресурсы.</p><p>Полный текст оригинальной статьи — в <a href="https://planetscale.com/blog/patterns-for-postgres-traffic-control">блоге PlanetScale</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>JOIN — не дорогая операция: бенчмарк на миллиарде строк это доказывает</title>
      <link>https://tproger.ru/translations/join---ne-dorogaya-operaciya--benchmark-na-milliarde-strok-eto-doka</link>
      <comments>https://tproger.ru/translations/join---ne-dorogaya-operaciya--benchmark-na-milliarde-strok-eto-doka?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/join---ne-dorogaya-operaciya--benchmark-na-milliarde-strok-eto-doka</guid>
      <description><![CDATA[<p>Тесты на DuckDB и PostgreSQL показали: JOIN на 1 млрд строк быстрее и дешевле по CPU, чем One Big Table. Смотрите графики и SQL-код бенчмарка.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/join---ne-dorogaya-operaciya--benchmark-na-milliarde-strok-eto-doka">JOIN — не дорогая операция: бенчмарк на миллиарде строк это доказывает</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 31 Mar 2026 12:49:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вы наверняка слышали: «JOIN — это дорого, сделайте одну большую таблицу». Это заблуждение — одно из самых живучих в мире баз данных. Особенно часто его повторяют те, кто продвигает Data Lake и подход «One Big Table» (OBT). Но так ли это на самом деле?</p><p>Автор блога <a href="https://www.database-doctor.com/">Database Doctor</a> провёл серию бенчмарков на <a href="https://duckdb.org/">DuckDB</a> и <a href="https://www.postgresql.org/">PostgreSQL</a> (подробнее о нём — в нашем <a href="https://tproger.ru/articles/postgresql-basics">гайде по PostgreSQL</a>), сравнив классическую размерную модель (dimensional model) с подходом «One Big Table». Результаты оказались неожиданными для многих — JOIN не просто «не дорогой», он зачастую <b>быстрее</b> плоской таблицы.</p><p>— JOIN в колоночных СУБД (DuckDB) обходится дешевле, чем сканирование широкой OBT-таблицы, уже начиная с 4–6 колонок</p><p>— Стоимость сканирования OBT растёт нелинейно (примерно O(n log n)) с увеличением числа колонок</p><p>— В строковых хранилищах (PostgreSQL) JOIN тоже выигрывает на большинстве сценариев</p><p>— Ральф Кимбалл описал эти закономерности ещё в 1996 году в своей классической книге о размерном моделировании</p><p>— Даже при «бесконечном I/O» денормализация не экономит CPU — она его тратит</p><h2>Постановка эксперимента</h2><p>Рассмотрим два конкурирующих подхода к моделированию данных:</p><ul><li><b>Размерная модель (dimensional model)</b> — атрибуты продуктов хранятся в отдельной таблице product, и мы делаем JOIN с таблицей sales каждый раз при чтении</li><li><b>One Big Table (OBT)</b> — все атрибуты продуктов заранее «вклеены» в таблицу sales_obt, и мы читаем данные через SELECT без JOIN</li></ul><p>Очевидно, что вторую таблицу дороже строить в ETL-пайплайне. Но какая из них потребляет <b>меньше CPU при чтении</b>?</p><h3>Размерная модель</h3><p>Схема данных:</p><p>Здесь c01 ... c20 — строковые колонки с атрибутами продуктов. Кардинальности:</p><ul><li>product — 100 000 строк; каждая из колонок c01–c20 содержит ~100 уникальных значений (MD5-хеши)</li><li>sales — <b>1 миллиард строк</b> со случайным v и равномерно распределённым id_product</li></ul><p>Эта модель, где сущность (product) хранится отдельно от фактов (sales), называется <b>размерной моделью</b> (dimensional model). Подробнее о ней — в конце статьи.</p><h3>Генерация тестовых данных</h3><p>Сначала создаём seed-таблицу — универсальный способ генерации последовательности чисел, который работает практически на всех SQL-платформах:</p><p><i>Примечание: да, можно было бы использовать INSERT ... VALUES с несколькими кортежами, но не каждая аналитическая БД поддерживает этот синтаксис. Зато UNION ALL работает, кажется, вообще везде.</i></p><p>С помощью seed-таблицы генерируем миллиард строк для sales:</p><p>Таблицу product заполняем MD5-хешами для получения строковых значений с контролируемой кардинальностью:</p><p><i>Примечание: да, можно было бы взять ровно 100 различных значений вместо ~101 для c01–c20, но с приведённым выше кодом проще.</i></p><h3>Модель «One Big Table»</h3><p>На другой стороне ринга — заранее объединённая широкая таблица:</p><h3>Гипотеза: JOIN медленнее, чем плоская таблица</h3><p>Итак, вопрос: что быстрее?</p><p>Размерная модель с JOIN:</p><p>Или OBT без JOIN:</p><p>Если «JOIN — это дорого», то размерная модель должна быть медленнее. Мы также должны увидеть более высокое потребление CPU.</p><p>Чтобы быть <i>максимально нечестным</i> по отношению к размерной модели, автор запускает тесты на системе, где <b>вся база помещается в оперативную память</b>. Так мы моделируем «бесконечный I/O» и не платим за дисковые операции.</p><h2>Результаты DuckDB</h2><p>Тестовая машина: ноутбук с 14 ядрами, 32 ГБ RAM, SSD на 3 ГБ/с. Размер базы — 45 ГБ, из которых sales_obt занимает ~40 ГБ. DuckDB отлично утилизирует ядра: CPU загружен на 100% во время выполнения запросов.</p><p>Для тестов автор использовал серию запросов с нарастающим числом колонок:</p><p><i>Примечание: DuckDB использует написание EXPLAIN ANALYZE (а не ANALYSE). В оригинале автор шутит, что DuckDB «правильно» использует британское написание — но на самом деле в DuckDB работает американский вариант.</i></p><p>Базовый замер (measurement 0) — просто чтение v: мы платим за JOIN, но не запрашиваем колонки из product. Читатели, которых интересует эта крайняя ситуация и способы оптимизации, могут изучить тему <a href="https://www.databasedoctor.co/posts/join-elimination">join elimination в планировщиках запросов</a>. Каждый запрос выполняется трижды, берётся лучшее время.</p><h3>Время выполнения (wall clock)</h3><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-31/2511523a-e4c0-4871-a3c5-0b0e772d1c07.webp" alt="График: Wall Clock Dim vs OBT в DuckDB" /><figcaption>Время выполнения: размерная модель (Dim) vs One Big Table (OBT) в DuckDB</figcaption></figure><p>Выводы из графика:</p><ul><li>При запросе 1–2 колонок OBT <i>незначительно</i> быстрее</li><li>С ростом числа колонок стоимость OBT <b>взлетает</b> — до 15 секунд при 20 колонках</li><li>JOIN остаётся <b>практически константным</b> по времени (~1 секунда) независимо от числа колонок</li><li>Рост OBT напоминает O(n log n) — нелинейная зависимость</li></ul><h3>Потребление CPU</h3><p>DuckDB позволяет замерить CPU-время по каждому оператору в запросе:</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-31/3eac03af-20e8-4c61-8eef-f31b8965a9c9.webp" alt="График: CPU usage OBT vs Dim в DuckDB" /><figcaption>Потребление CPU: OBT vs Dim (CPU по всем ядрам суммарно). Для размерной модели показаны stacked-значения: scan + join</figcaption></figure><p>Та же закономерность: OBT при 20 колонках потребляет <b>~200 секунд CPU</b>, тогда как размерная модель — всего <b>~15 секунд</b> (scan + join). Разница — на <b>порядок</b>.</p><h3>Почему JOIN быстрее при масштабировании?</h3><p>Казалось бы, мы читаем каждую строку. Почему не быстрее просто отдать её из плоской таблицы?</p><p>Ответ кроется в том, как работают <b>колоночные хранилища</b> (DuckDB, Parquet и другие):</p><ol><li><b>Декомпрессия колонок.</b> Сжатые строки хранятся в словаре (dictionary encoding). Чтобы получить данные, движок «соединяет» указатели в сегментах сжатия со словарём. Это по сути тоже своего рода JOIN — но уже внутри Storage Engine. В размерной модели строки уже «материализованы» в таблице product, и эта «декомпрессия» фактически заранее выполнена</li><li><b>Сборка строк из колонок.</b> В колоночном формате данные каждой колонки хранятся отдельно. Чтобы собрать строку, нужно пройти по метаданным, найти местоположение каждой колонки и скопировать данные в финальный результат. Каждая колонка — это отдельная аллокация (и деаллокация) памяти. Именно этот механизм, вероятно, и даёт <b>нелинейный рост</b> стоимости сканирования широкой OBT-таблицы</li></ol><h2>А что насчёт строковых хранилищ?</h2><p>Не все базы данных используют колоночное сжатие. Строковые хранилища (row stores) хранят данные в формате строк (аналогично AVRO в мире Data Lake).</p><p>У строковых хранилищ есть интересное свойство: им <b>не нужно «собирать» строку</b> из отдельных колонок — строка уже хранится целиком. Правда, они занимают больше места на диске и хуже работают при чтении отдельных колонок.</p><p>Вопрос: может быть, для OBT лучше использовать строковое хранилище? Давайте проверим.</p><h3>Гипотеза автора</h3><p><b>В пользу OBT в строковом хранилище:</b></p><ul><li>Данные можно отдать напрямую, без «сборки» строк из колонок</li><li>Не нужна «неявная декомпрессия» сжатых строк</li><li>JOIN на строковых форматах медленнее, чем на колоночных — нельзя векторизовать хеширование</li></ul><p><b>В пользу JOIN:</b></p><ul><li>Если нужна часть колонок, проекция (отбрасывание ненужных) стоит CPU — это неявный memcpy</li><li>Больший объём данных при сканировании — больше работы с буферами</li><li>У JOIN лучше кеш-локальность для строк — меньше TLB-промахов</li></ul><p>Интуиция автора подсказывает, что строковые хранилища могут сдвинуть «точку пересечения» дальше от одной колонки и дать больше преимуществ OBT — хотя бы потому, что не нужна «сборка» строки. Давайте проверим.</p><h3>Тест на PostgreSQL 17</h3><p>Для теста автор выбрал PostgreSQL 17 — классическое строковое хранилище. Датасет уменьшен до 1% (10 млн строк в sales, 10 000 строк в product), но и так sales_obt занимает 7 ГБ.</p><p>Чтобы убрать стоимость сериализации результата для клиента, вместо SELECT * используется:</p><p><i>Примечание: PostgreSQL сериализует результат в клиентский формат даже при EXPLAIN ANALYZE. Это дополнительная работа, которой лишены системы, использующие Arrow-буферы, — там промежуточная сериализация не нужна.</i></p><p>Чтобы убедиться, что PostgreSQL не «хитрит» с NULL-проверкой в COUNT, автор проверил план выполнения. Видно, что агрегат действительно работает со строкой, ширина которой пропорциональна числу входных колонок:</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-31/c2bb9fe1-f7f0-46f5-a79a-12b37d21aae4.webp" alt="График: Wall Time Row Store PostgreSQL" /><figcaption>Время выполнения: PostgreSQL OBT vs JOIN (строковое хранилище)</figcaption></figure><p>Выводы:</p><ul><li>Как и предполагалось, стоимость «проекции» (отбрасывания ненужных колонок) доминирует при малом числе колонок — OBT проигрывает</li><li><b>Вопреки ожиданиям</b>, даже в базовом случае (0 колонок из JOIN) размерная модель оказывается быстрее</li><li>Красивая <b>линейная</b> зависимость: строковое хранилище масштабируется предсказуемо в обоих случаях</li><li>JOIN выигрывает или проигрывает OBT <b>с минимальной разницей</b> — но тренд в пользу JOIN</li></ul><h3>Глубокое погружение: что именно тормозит PostgreSQL?</h3><p>С помощью EXPLAIN (ANALYZE, BUFFERS) автор убедился, что запрос работает полностью в памяти:</p><p>shared hit=909120 означает, что все буферы были прочитаны из памяти (shared buffers), без обращения к диску. PostgreSQL форкает процесс на каждое соединение, поэтому профилировать конкретный запрос можно через SELECT pg_backend_pid().</p><p>Автор использовал Windows Performance Recorder для профилирования PostgreSQL на 16-колоночном запросе:</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-31/9e988bc4-1aee-40f1-9a2f-8c9434939fc4.webp" alt="Скриншот: PostgreSQL trace в Windows Performance Recorder" /><figcaption>Трассировка PostgreSQL: горячие функции при сканировании OBT</figcaption></figure><p>Два самых горячих вызова:</p><ol><li><b>tts_buffer_heap_getsomeattrs</b> (файл execTuples.c) — по сути, неоптимальный memcpy. Эта функция копирует данные из буферного пула в представление кортежа. Именно та «проекция», которую автор предсказывал — но реализованная неэффективно</li><li><b>ExecInterpExpr</b> (файл execExprInterp.c) — интерпретатор выражений. Современные БД используют векторизованное или компилированное выполнение; PostgreSQL по умолчанию интерпретирует через гигантский switch-блок (JIT-компиляция через LLVM доступна с PG 11, но не используется на дефолтных настройках для дешёвых запросов). Основной вызывающий — ExecAgg: подсчёт COUNT обходится почти так же дорого, как само чтение данных</li></ol><p>Важная оговорка: PostgreSQL — <b>не идеальный представитель строковых хранилищ</b>. Базы данных с компилируемыми запросами могут быть значительно быстрее при «сыром сканировании». Тем не менее, строковые хранилища, похоже, почти всегда выигрывают от использования JOIN — если только вы не планируете выбирать практически все колонки из OBT в каждом запросе. Даже денормализация одной колонки ради экономии CPU может оказаться ошибочной.</p><h3>Как автор собирал PostgreSQL с отладочными символами</h3><p>Для профилирования PostgreSQL нужны debug-символы. Ни пакет Chocolatey, ни установщик EnterpriseDB их не включают — пришлось собирать из исходников на Windows.</p><p>Необходимые пакеты:</p><p>Файл msvc.ini в корне репозитория PostgreSQL:</p><p>Сборка:</p><h2>Размерная модель: уроки прошлого</h2><p>Всё, что мы наблюдаем, не ново. Ещё в 1996 году <b>Ральф Кимбалл</b> опубликовал книгу <a href="https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/books/data-warehouse-dw-toolkit/">«The Data Warehouse Toolkit»</a>, которая до сих пор переиздаётся и считается классикой.</p><p>Кимбалл аргументировал:</p><ul><li>Большие аналитические таблицы (<b>факты</b>) должны содержать только метрики (то, что агрегируется) и <b>целочисленные ключи измерений</b> (то, по чему делается JOIN)</li><li>Все атрибуты сущностей хранятся в отдельных <b>таблицах измерений</b> (dimension tables), к которым присоединяются через foreign key</li><li>Колонки с высокой кардинальностью и единственным значением лучше хранить прямо в таблице фактов — <b>«вырожденные измерения»</b> (degenerate dimensions). Это идеально соответствует нашему наблюдению: чтение одной колонки через JOIN действительно немного медленнее</li></ul><p>Кимбалл также рекомендовал объединять связанные таблицы <i>внутри</i> самого измерения (делая таблицу измерения шире) — но только для измерений, <b>не для фактов</b>. И делал он это не ради производительности, а для упрощения работы оптимизатора запросов.</p><h2>Итоги</h2><p>Главный вывод:</p><blockquote>«JOIN — НЕ дорогая операция по сравнению с альтернативами»</blockquote><p>Что мы выяснили:</p><ul><li>Даже при чтении <b>всех</b> строк JOIN зачастую дешевле, чем сканирование One Big Table</li><li>В колоночных хранилищах (DuckDB) преимущество JOIN проявляется начиная с 4–6 колонок и растёт <b>нелинейно</b></li><li>В строковых хранилищах (PostgreSQL) JOIN тоже выигрывает на большинстве сценариев</li><li>«Жертвовать диском ради экономии CPU на JOIN» — это миф, который противоречит измерениям</li><li>Размерное моделирование (Кимбалл, 1996) — не устаревшая методология, а эффективный инженерный подход</li></ul><p>Важно помнить: мы тестировали JOIN большой таблицы (1 млрд строк) с маленькой (100 000 строк). Что произойдёт при JOIN двух больших таблиц — вопрос для отдельного исследования.</p><p>В следующей статье автор обещает разобрать, что происходит с производительностью при добавлении <b>фильтров</b>. Спойлер: разрыв между OBT и JOIN становится ещё больше в пользу JOIN — благодаря bloom-фильтрам и pushdown-оптимизациям.</p><p><i>Перевод и адаптация статьи <a href="https://www.database-doctor.com/posts/joins-are-not-expensive">«Joins are NOT Expensive!»</a> из блога Database Doctor. Если вы хотите глубже разобраться в SQL — рекомендуем нашу <a href="https://tproger.ru/articles/sql-cheat-sheet">шпаргалку по SQL</a>.</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое SQL: основы языка запросов для начинающих</title>
      <link>https://tproger.ru/articles/chto-takoe-sql--osnovy-yazyka-zaprosov-dlya-nachinayushhih</link>
      <comments>https://tproger.ru/articles/chto-takoe-sql--osnovy-yazyka-zaprosov-dlya-nachinayushhih?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-takoe-sql--osnovy-yazyka-zaprosov-dlya-nachinayushhih</guid>
      <description><![CDATA[<p>SQL — язык запросов к базам данных. Разбираем SELECT, INSERT, JOIN, WHERE с примерами, типы данных, сравнение СУБД. Начните писать запросы уже сегодня.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-takoe-sql--osnovy-yazyka-zaprosov-dlya-nachinayushhih">Что такое SQL: основы языка запросов для начинающих</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 Mar 2026 05:09:29 GMT</pubDate>
      <content:encoded><![CDATA[<p>Каждый разработчик рано или поздно сталкивается с базами данных. Неважно, пишете ли вы веб-приложение, мобильный сервис или скрипт для анализа данных — в основе почти всегда лежит реляционная база данных, а значит, SQL. Этот язык не устаревает десятилетиями: он появился в 1970-х годах и до сих пор остаётся стандартом де-факто для работы с данными. По данным опроса Stack Overflow Developer Survey 2023, SQL занимает третье место среди профессиональных разработчиков — его используют 51,5% из них (Stack Overflow Developer Survey 2023).</p><p><b>SQL (Structured Query Language)</b> — это декларативный язык запросов для управления реляционными базами данных. С его помощью можно создавать таблицы, добавлять, изменять и удалять данные, а также делать выборки по заданным условиям. SQL стандартизирован организацией ISO и поддерживается всеми основными СУБД: PostgreSQL, MySQL, SQLite, Microsoft SQL Server и Oracle.</p><p>- SQL расшифровывается как Structured Query Language — язык структурированных запросов.</p><p>- Язык создан в 1973 году в IBM, стандарт ISO принят в 1987 году.</p><p>- SQL используют 51,5% профессиональных разработчиков по всему миру (Stack Overflow, 2023).</p><p>- Основные операции: SELECT, INSERT, UPDATE, DELETE — охватывают 90% повседневных задач.</p><p>- SQL работает с реляционными базами данных, где данные хранятся в связанных таблицах.</p><p>- Один SQL-запрос может обработать миллионы строк за доли секунды.</p><h2>Зачем нужен SQL — где используется и кому пригодится</h2><p>SQL нужен везде, где есть структурированные данные. Вот лишь несколько примеров из реальной практики:</p><ul><li><b>Веб-разработка</b> — интернет-магазины, блоги, социальные сети хранят пользователей, товары и записи в реляционных БД.</li><li><b>Аналитика данных</b> — аналитики используют SQL для агрегации, фильтрации и построения отчётов.</li><li><b>Backend-разработка</b> — серверные приложения взаимодействуют с PostgreSQL или MySQL через SQL-запросы.</li><li><b>Data Science</b> — учёные по данным выгружают датасеты из хранилищ (Redshift, BigQuery) с помощью SQL.</li><li><b>DevOps и администрирование</b> — DBA оптимизируют запросы, настраивают индексы, следят за производительностью.</li></ul><p>SQL востребован как у начинающих разработчиков, так и у опытных инженеров. По данным Glassdoor, знание SQL входит в топ-3 навыков для вакансий Data Analyst и Backend Developer в 2024 году. Даже фронтендеры, которые редко работают напрямую с БД, рано или поздно сталкиваются с SQL при отладке или настройке.</p><h2>Основные команды SQL</h2><p>Все команды SQL делятся на группы. Самые важные — это DDL (Data Definition Language) для создания структур и DML (Data Manipulation Language) для работы с данными. Рассмотрим ключевые команды подробнее.</p><h3>SELECT — выборка данных</h3><p>SELECT — самая используемая команда SQL. Она позволяет извлекать данные из одной или нескольких таблиц. Базовый синтаксис:</p><p>Звёздочка * означает «все столбцы», но на практике лучше перечислять нужные явно — это ускоряет запрос и делает код читаемым. Чтобы отфильтровать дубликаты, используют SELECT DISTINCT.</p><p>Можно также ограничить количество строк в результате:</p><h3>INSERT, UPDATE, DELETE — изменение данных</h3><p>Три команды, отвечающие за создание, изменение и удаление записей:</p><p><b>Важно:</b>
Всегда используйте WHERE в командах UPDATE и DELETE. Без условия изменения применятся ко всем строкам таблицы, и восстановить данные без бэкапа не получится.</p><h3>CREATE TABLE — создание таблиц</h3><p>Прежде чем работать с данными, нужно создать таблицу. Команда CREATE TABLE задаёт структуру: имена столбцов, их типы и ограничения:</p><p>SERIAL (или AUTO_INCREMENT в MySQL) автоматически генерирует уникальный числовой идентификатор. PRIMARY KEY — уникальный ключ строки. REFERENCES создаёт внешний ключ — связь между таблицами.</p><h3>JOIN — объединение таблиц</h3><p>Реляционные базы данных хранят информацию в нескольких связанных таблицах. Чтобы получить данные из нескольких таблиц одним запросом, используется JOIN. Существует несколько видов объединений:</p><ul><li>INNER JOIN — только совпадающие строки из обеих таблиц.</li><li>LEFT JOIN — все строки из левой таблицы, совпадения из правой (или NULL).</li><li>RIGHT JOIN — все строки из правой таблицы, совпадения из левой (или NULL).</li><li>FULL OUTER JOIN — все строки из обеих таблиц, NULL там, где нет совпадений.</li></ul><h3>WHERE, ORDER BY, GROUP BY — фильтрация и сортировка</h3><p>Три важнейших инструмента для управления результатом выборки. Подробный разбор ORDER BY с примерами читайте в нашем <a href="https://tproger.ru/articles/sortirovka-v-sql--order-by--asc-i-desc-s-primerami">гайде по сортировке в SQL</a>.</p><p>Ключевое отличие: WHERE фильтрует строки <i>до</i> группировки, HAVING — <i>после</i>. Агрегатные функции (COUNT, SUM, AVG, MIN, MAX) работают с группами строк.</p><h2>Типы данных в SQL</h2><p>При создании таблицы каждому столбцу нужно указать тип данных. Правильный выбор типа экономит место на диске и ускоряет запросы. Основные типы:</p><ul><li><b>Числовые:</b> INT / INTEGER — целые числа; BIGINT — большие целые; DECIMAL(p,s) — дробные с фиксированной точностью; FLOAT — числа с плавающей запятой.</li><li><b>Строковые:</b> VARCHAR(n) — строка до n символов; TEXT — строка без ограничений; CHAR(n) — строка фиксированной длины.</li><li><b>Дата и время:</b> DATE — дата (YYYY-MM-DD); TIME — время; TIMESTAMP — дата и время; INTERVAL — интервал.</li><li><b>Логический:</b> BOOLEAN — значения TRUE / FALSE / NULL.</li><li><b>Специальные:</b> UUID — уникальный идентификатор; JSON / JSONB — JSON-данные (PostgreSQL); ARRAY — массив значений.</li></ul><p>Практическое правило: используйте наименьший подходящий тип. Для возраста достаточно SMALLINT, для идентификатора пользователя — INT, для финансовых сумм — DECIMAL, а не FLOAT (чтобы избежать ошибок округления).</p><h2>SQL vs NoSQL — когда что использовать</h2><p>SQL-базы данных хранят данные в таблицах с фиксированной схемой. NoSQL-базы (MongoDB, Redis, Cassandra) используют другие модели: документы, ключ-значение, графы, колонки. Вот когда выбирать каждый подход:</p><ul><li><b>SQL подходит, когда:</b> данные структурированы и схема стабильна; важна целостность и транзакции (банки, интернет-магазины); нужны сложные запросы с JOIN и агрегацией; команда умеет работать с реляционными БД.</li><li><b>NoSQL подходит, когда:</b> структура данных гибкая или меняется часто; нужна горизонтальная масштабируемость под огромные объёмы; данные неструктурированы (логи, события, JSON); требуется сверхнизкая латентность (кэш в Redis).</li></ul><blockquote>SQL и NoSQL — не конкуренты, а инструменты для разных задач. В одном проекте вполне можно использовать PostgreSQL для бизнес-данных и Redis для кэша.</blockquote><h2>Популярные СУБД: PostgreSQL, MySQL, SQLite, MS SQL</h2><p>SQL-синтаксис стандартизирован, но каждая СУБД добавляет свои расширения. Вот краткое сравнение четырёх самых популярных:</p><ul><li><b>PostgreSQL</b> — мощная open-source СУБД с богатым набором типов данных, поддержкой JSON, полнотекстового поиска и оконных функций. Лучший выбор для серьёзных проектов. Подробнее читайте в нашем <a href="https://tproger.ru/articles/osnovy-postgresql-dlya-nachinayuschih--rukovodstvo-s-primerami">руководстве по PostgreSQL для начинающих</a>.</li><li><b>MySQL / MariaDB</b> — самая распространённая СУБД для веб-приложений, особенно в связке с PHP (WordPress, Drupal). Простая в настройке, быстрая для чтения.</li><li><b>SQLite</b> — встроенная база данных в одном файле, без сервера. Идеально подходит для мобильных приложений, тестирования и небольших проектов. Используется в Android, iOS, браузерах.</li><li><b>Microsoft SQL Server</b> — корпоративная СУБД от Microsoft, тесно интегрированная с экосистемой .NET и Azure. Популярна в крупных компаниях.</li></ul><p>Если вы только начинаете, рекомендуем PostgreSQL или SQLite. PostgreSQL — для полноценной разработки, SQLite — для обучения без установки сервера.</p><h2>Как начать учить SQL — ресурсы, песочницы, советы</h2><p>SQL — один из самых практичных языков для изучения. Базовые команды можно освоить за неделю, а первые реальные запросы писать уже через несколько часов практики.</p><p>Подробную дорожную карту с последовательностью тем и рекомендуемыми ресурсами смотрите в нашей <a href="https://tproger.ru/articles/dorozhnaya-karta-sql-dlya-nachinayuschih-v-2024-godu">дорожной карте SQL для начинающих</a>.</p><ul><li><b>SQLiteOnline.com</b> — онлайн-песочница без регистрации. Запустите первый запрос прямо в браузере за 30 секунд.</li><li><b>SQLBolt.com</b> — интерактивный курс с упражнениями от SELECT до сложных JOIN. Полностью бесплатный, на английском.</li><li><b>Stepik.org</b> — бесплатный курс «Введение в базы данных» на русском языке с практическими заданиями.</li><li><b>LeetCode / HackerRank</b> — задачи на SQL для подготовки к техническим собеседованиям.</li><li><b>Официальная документация PostgreSQL</b> — самый полный и точный источник по возможностям СУБД.</li></ul><p>Советы для эффективного обучения: практикуйтесь на реальных данных (импортируйте CSV-файл в SQLite), сразу изучайте индексы — они кардинально влияют на производительность. Читайте наш материал об <a href="https://tproger.ru/articles/sql-indeksy-za-10-minut--kak-uskorit-zaprosy-v-baze-dannyh">SQL-индексах за 10 минут</a> и <a href="https://tproger.ru/articles/optimizaciya-sql-zaprosov--10-sovetov-dlya-nachinayushhih">10 советов по оптимизации запросов</a>.</p><h2>Выводы</h2><p>SQL — фундаментальный навык для любого, кто работает с данными. За полвека существования язык не только не устарел, но и стал ещё более востребованным: облачные хранилища BigQuery и Redshift, аналитические инструменты, современные ORM — всё это работает поверх SQL или совместимо с ним.</p><p>Что делать дальше:</p><ol><li>Установите PostgreSQL или откройте SQLiteOnline.com и напишите первый SELECT.</li><li>Пройдите интерактивный курс на SQLBolt.com — займёт 3–5 часов.</li><li>Попрактикуйтесь на реальных данных: загрузите любой CSV-датасет с Kaggle.</li><li>Изучите индексы — это самый быстрый способ ускорить запросы.</li><li>Посмотрите нашу дорожную карту SQL и двигайтесь по ней системно.</li></ol><p>SQL знают и продолжают учить потому, что он действительно работает. Сотни миллионов строк в банках, маркетплейсах и SaaS-сервисах каждый день обрабатываются именно с помощью SQL-запросов. Это инвестиция в навык, который окупится независимо от выбранного стека.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как ускорить Prisma до производительности ванильного SQL</title>
      <link>https://tproger.ru/articles/kak-uskorit-prisma-do-proizvoditelnosti-vanilnogo-sql</link>
      <comments>https://tproger.ru/articles/kak-uskorit-prisma-do-proizvoditelnosti-vanilnogo-sql?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Тысячи Енотов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-uskorit-prisma-do-proizvoditelnosti-vanilnogo-sql</guid>
      <description><![CDATA[<p>Как приблизиться к производительности «чистого SQL», сохранив удобство разработки и типизацию Prisma.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-uskorit-prisma-do-proizvoditelnosti-vanilnogo-sql">Как ускорить Prisma до производительности ванильного SQL</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 07 Feb 2026 08:55:02 GMT</pubDate>
      <content:encoded><![CDATA[<p><br />Движок Prisma добавляет накладные издержки примерно в 2–7 раз даже в версии 7. В этом руководстве показано, как приблизиться к производительности «чистого SQL», сохранив удобство разработки и типизацию Prisma.</p><h2>Проблема: почему Prisma медленнее «чистого SQL»</h2><p>Prisma — удобная ORM, но каждый запрос проходит через несколько уровней обработки:</p><p>Каждый уровень добавляет задержку. Улучшения в Prisma v7 не устраняют фундаментальные ограничения этой архитектуры.</p><p>Практический эффект:</p><p>Для высоконагруженных API, которые обрабатывают тысячи запросов в секунду, разница в 0.17 ms на запрос быстро превращается в заметную прибавку к общей задержке.</p><h2>Решение: выполнять SQL напрямую</h2><p>Единственный способ добиться производительности «чистого SQL» — обойти Query Engine Prisma, но при этом сохранить привычный API Prisma клиента.</p><h2>Сравнение архитектур</h2><p>Обычная Prisma:</p><p>Оптимизированный подход:</p><p>Если генерировать SQL прямо из JSON-запроса и выполнять его через проверенные драйверы, накладные расходы Query Engine исчезают. Процесс подготовки становится обычным превращением JSON в строку.</p><h2>Реализация</h2><h2>1) Установка зависимостей</h2><p>PostgreSQL:</p><p>SQLite:</p><h2>2) Базовая настройка (runtime-режим)</h2><p>PostgreSQL:</p><p>SQLite:</p><p>Готово. Код запросов менять не нужно. Все операции чтения теперь выполняются быстрее.</p><h2>3) Продвинутый режим: generator (предварительная генерация SQL)</h2><p>Для максимальной производительности можно «запечь» самые частые запросы на этапе сборки.</p><p>Добавьте в schema.prisma:</p><p>Сгенерируйте код:</p><p>Подключите сгенерированное расширение:</p><p>Сравнение накладных издержек:</p><ul><li>Prisma v7: ~0.34 ms</li><li>Runtime-режим: ~0.20 ms (примерно в 1.7 раза быстрее)</li><li>Generator-режим: ~0.03 ms (примерно в 11 раз быстрее)</li></ul><h2>Результаты бенчмарков</h2><p>Тесты на 137 E2E-запросах, сравнивающих идентичные операции.</p><h2>PostgreSQL</h2><p>В среднем: в 2.10 раза быстрее, чем Prisma v7</p><h2>SQLite</h2><p>В среднем: в 5.48 раза быстрее, чем Prisma v7</p><h2>Конфигурация для production</h2><h2>1) Режим отладки</h2><p>Можно видеть сгенерированный SQL для каждого запроса:</p><h2>2) Мониторинг производительности</h2><p>Можно отслеживать время выполнения запросов в production:</p><h2>3) Выборочная оптимизация</h2><p>Можно ускорять только «горячие» модели:</p><h2>4) Настройка пула соединений</h2><p>Пример конфигурации postgres.js для production:</p><h2>Поддерживаемые возможности</h2><h2>✅ Что ускоряется (выполняется через «чистый SQL»)</h2><p>Запросы:</p><ul><li>findMany, findFirst, findUnique</li><li>count</li><li>aggregate (_count, _sum, _avg, _min, _max)</li><li>groupBy с условиями having</li></ul><p>Фильтры:</p><p>Связи:</p><p>Пагинация и сортировка:</p><h2>❌ Что остаётся на стандартной Prisma (без изменений)</h2><p>Запись:</p><ul><li>create, update, delete, upsert</li><li>createMany, updateMany, deleteMany</li></ul><p>Продвинутые возможности:</p><ul><li>Транзакции ($transaction)</li><li>Сырые запросы ($queryRaw, $executeRaw)</li><li>Middleware</li><li>Другие расширения Prisma Client</li></ul><h2>Поддержка Edge Runtime</h2><h2>Vercel Edge Functions</h2><h2>Cloudflare Workers</h2><h2>Руководство по миграции</h2><h2>Со стандартной Prisma</h2><p>Было:</p><p>Стало:</p><h2>С Drizzle ORM</h2><p>Было:</p><p>Стало:</p><h2>Частые проблемы и решения</h2><p>1)</p><p>Проблема:</p><p>Решение:</p><h2>2) Исчерпан пул соединений</h2><p>Проблема:</p><p>Решение:</p><h2>3) Результаты отличаются от стандартной Prisma</h2><p>Проблема:</p><p>Решение:</p><p>Если результаты действительно расходятся, создайте issue: <a href="https://github.com/multipliedtwice/prisma-sql/issues">https://github.com/multipliedtwice/prisma-sql/issues</a></p><h2>4) Производительность почти не выросла</h2><p>Проблема: ожидалось ускорение в 2–7 раз, но прирост минимальный.</p><p>Возможные причины:</p><ol><li>Доминирует сеть: на удалённой БД задержка сети (10–50 ms) «затмевает» накладные издержки (0.2 ms)</li><li>Очень простые запросы: findUnique по индексированному ID и так быстрый</li><li>Нет индексов: запросы упираются в план выполнения БД</li></ol><p>Что сделать:</p><h2>Когда это не стоит применять</h2><h2>Оставьте стандартную Prisma, если:</h2><ol><li>Преобладает запись: больше 50% операций — запись</li><li>Простой CRUD: одна таблица, минимум связей</li><li>Команда не готова: нет опыта с postgres.js / better-sqlite3</li><li>Нужны неподдерживаемые функции Prisma: активное использование возможностей, которые здесь не покрыты</li></ol><h2>Этот подход подходит, когда:</h2><ol><li>Преобладает чтение: более 70% операций — чтение</li><li>Высокая пропускная способность: &gt;1000 rps, где важны миллисекунды</li><li>Сложные запросы: много связей, агрегаций, условий</li><li>Оптимизация затрат: меньше задержка → меньше ресурсов</li></ol><h2>Заключение</h2><p>Можно добиться 100% производительности «чистого SQL», не отказываясь от удобства Prisma.</p><p>Основные преимущества:</p><ul><li>Ускорение чтения в 2–7 раз без переписывания запросов</li><li>Те же типы и тот же API Prisma Client</li><li>Подходит для production (по заявлению авторов) и покрыто E2E-тестами</li><li>Работает в существующих проектах Prisma</li></ul><p>Быстрый старт:</p><ol><li>Установите prisma-sql и postgres/better-sqlite3</li><li>Подключите расширение</li><li>Задеплойте и измерьте эффект</li></ol><p>Дальнейшая оптимизация:</p><ol><li>Подключите generator для «горячих» запросов</li><li>Включите мониторинг через onQuery</li><li>Настройте пул соединений</li></ol><p>Ресурсы:</p><ul><li>NPM: <a href="https://www.npmjs.com/package/prisma-sql">https://www.npmjs.com/package/prisma-sql</a></li><li>GitHub: <a href="https://github.com/multipliedtwice/prisma-to-sql">https://github.com/multipliedtwice/prisma-to-sql</a></li><li>Документация: <a href="https://github.com/multipliedtwice/prisma-sql#readme">https://github.com/multipliedtwice/prisma-to-sql#readme</a></li><li>Примеры E2E-тестов: <a href="https://github.com/multipliedtwice/prisma-to-sql/tree/main/tests/e2e">https://github.com/multipliedtwice/prisma-to-sql/tree/main/tests/e2e</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>СУБД 2026: что выбирают российские компании</title>
      <link>https://tproger.ru/articles/subd-2026--chto-vybirayut-rossijskie-kompanii</link>
      <comments>https://tproger.ru/articles/subd-2026--chto-vybirayut-rossijskie-kompanii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/subd-2026--chto-vybirayut-rossijskie-kompanii</guid>
      <description><![CDATA[<p>5 систем управления базами данных, которые закрывают разные сценарии: от транзакционных нагрузок до аналитики петабайтных хранилищ.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/subd-2026--chto-vybirayut-rossijskie-kompanii">СУБД 2026: что выбирают российские компании</a>»</p>]]></description>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 25 Dec 2025 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Российский рынок СУБД за последние годы изменился. Компании ищут решения, которые закрывают требования по импортозамещению, сертификации и работе с персональными данными, но при этом не уступают по функциональности привычным системам.</p><p>В этой подборке — пять системы управления базами данных, которые закрывают разные сценарии: от транзакционных нагрузок до аналитики петабайтных хранилищ. Каждый продукт решает свой класс задач — одни оптимизированы под OLTP с частыми операциями чтения-записи, другие под OLAP с обработкой миллиардов строк, третьи дают задержки в миллисекунды для real-time систем.</p><h2>1. РЕД База Данных: реляционная СУБД с режимом встраивания</h2><p>Тип: реляционная СУБД общего назначения, OLTP</p><p><a href="https://rdb.red-soft.ru/?utm_source=tproger&amp;utm_medium=issledovanie&amp;utm_campaign=obzor_SUBD_tproger">РЕД База Данных</a> — реляционная OLTP-система общего назначения, которая включена в реестр российского ПО и имеет сертификат ФСТЭК России по 4 классу защиты. Команда разрабатывает продукт параллельно с Firebird уже 20 лет: общие ошибки исправляются в обеих ветках, доработки переносятся между проектами.​</p><h3>Где используют</h3><p>Один из публичных кейсов — АИС ФССП России. СУБД работает с терабайтными базами данных, скорость обработки запросов сопоставима с другими реляционными OLTP-системами на рынке.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-23/fe3d2fad-75ea-4a00-a490-a0251cb3de11.jpeg" alt="" /></figure><h3>Два режима работы</h3><p>РЕД База Данных может работать как классическая серверная СУБД или в режиме встраивания — без выделенного сервера, как SQLite. В встраиваемом режиме функциональность сохраняется полностью, кроме сетевого доступа. Это позволяет использовать одну СУБД и для серверных задач, и для локальных приложений.</p><p>Поддерживаются Windows, Linux (включая РЕД ОС, Альт Линукс, AstraLinux, ROSA) и Android. Архитектуры: x86_64 (Intel, AMD), Эльбрус (e2k), Байкал (aarch64), ARM.</p><h3>Отказоустойчивость и репликация</h3><p>Есть три режима репликации: синхронная, асинхронная и адаптивная. Адаптивная репликация переключается в асинхронный режим при проблемах со связью и возвращается обратно после восстановления. Отказоустойчивый кластер включён в текущую версию, шардинг планируется в версии 6.​</p><p>Механизм записи страниц БД позволяет СУБД восстанавливаться сразу после сбоя без длительной фазы recovery, которая есть в системах с журналом упреждающей записи. Поддерживаются логический бэкап, файловый бэкап консистентной БД и инкрементальные бэкапы.</p><h3>Сборка мусора и метаданные</h3><p>Сборка мусора работает автоматически в разных режимах и не требует блокировки таблицы. Механизм сборки промежуточных версий снимает проблему версионного сервера и длительных транзакций. Метаданные можно обновлять на лету, без блокировки таблицы для запросов.​</p><p>Многопоточная архитектура позволяет запускать множество транзакций в рамках одного подключения и поддерживать несколько подключений одновременно.​</p><h3>Интеграция и инструменты</h3><p>В экосистеме РЕД Базы Данных есть два основных инструмента:</p><p><a href="https://rdb.red-soft.ru/product/expert/">РБД Эксперт</a> для разработки и администрирования баз данных</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-22/3aee94b5-509b-42c0-8599-9773b641907e.png" alt="" /></figure><p><a href="https://rdb.red-soft.ru/product/monitor/">РБД Монитор</a> для мониторинга.​</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-22/4ddb8d2a-8620-4fb1-b9fc-56ee8c0ccee4.png" alt="" /></figure><p>СУБД имеет сертификаты совместимости с 80+ продуктами: медицинские информационные системы, банковское ПО, СКАДА-системы, системы резервного копирования. Полная совместимость с другими продуктами РЕД СОФТ (РЕД Виртуализация, РЕД ОС, РЕД Платформа и другие) позволяет собирать инфраструктуру на базе одного вендора.</p><p>Поддерживаются популярные языки и фреймворки: Java (Spring, Hibernate, Liquibase, FlyWay), NodeJS, Python (Django, SQLAlchemy), Ruby (Active Record), GO (GORM), C, C++, .NET, Rust, QT, ODBC, OLE DB, PHP, Erlang.</p><h3>Доступность и поддержка</h3><p>Продукт представлен в облаках VK Cloud и Яндекс Облако. Для VK Cloud есть бесплатная версия для тестирования. Покупка через <a href="https://rdb.red-soft.ru/product/buy/">интеграторов</a>, лицензирование поядерное — минимум 2 ядра на установку. Для разработчиков прикладного ПО предусмотрена отдельная лицензия без ограничений.​</p><p>Техническая поддержка работает на двух уровнях: стандартном и расширенном. Для пользователей доступны <a href="https://rdb.red-soft.ru/product/docs/">техническая документация</a> и <a href="https://rdb.red-soft.ru/base/">база знаний</a>, статьи на Хабре, каналы на RuTube и Дзен, чат в Telegram с разработчиками. Ежегодно проводится конференция, посвящённая Firebird, где можно пообщаться с командой напрямую.​</p><h3>Что будет в версии 6</h3><p>Шестая версия запланирована на 2026 год с фокусом на производительность и новые функции. В релиз войдут: геометрические типы данных, гетерогенные запросы, ROW-тип данных, партиционирование, катастрофоустойчивый кластер, восстановление на точку во времени, создание и удаление индексов без блокировки, улучшенные JSON-функции, новые методы доступа (HASH/MERGE OUTER JOIN, HASH GROUP BY), общий кеш метаданных и поддержка TRUNCATE.</p><h2>2. Tantor Postgres: СУБД для высоких нагрузок и защищённых систем, в том числе 1С</h2><p>Тип: универсальная СУБД на базе PostgreSQL</p><p><a href="https://tantorlabs.ru/products/dbms">Tantor Postgres</a> — это СУБД для высоконагруженных систем на основе PostgreSQL с глубокими доработками. Продукт выпускается в четырёх редакциях: Special Edition для нагруженных OLTP-систем и корпоративных хранилищ до 100 ТБ, Special Edition 1C с оптимизацией под приложения 1С, Certified с сертификацией ФСТЭК для защищённых ГИС и КИИ, и Basic Edition с базовыми улучшениями и поддержкой вендора.</p><h3>Где применяют</h3><p>СУБД Tantor Postgres в различных редакциях, включая сертифицированную ФСТЭК, используется в большинстве ключевых отраслей бизнеса, коммерческих и государственных организациях, в том числе на объектах КИИ. Так, правительство одного из крупнейших городов России использует продукты Tantor в большинстве комитетов, а АО "Губернские аптеки" — крупнейшая аптечная госсеть Красноярского края — мигрировала на Tantor Postgres при объёме данных свыше 2 ТБ и более 17 млн совершаемых транзакций в день. Проект охватил более 2000 рабочих мест. Инструменты мониторинга Tantor помогли выявить неоптимальные запросы и передать данные 1С-разработчикам для доработки, и в результате время массовых расчётов и перепроведения документов в 1С сократилось на 50%, что сэкономило массу времени десяткам бухгалтеров.</p><h3>Производительность под 1С</h3><p>Tantor располагает собственным центром экспертизы 1С, который решает технические вопросы клиентов и ставит конкретные задачи по развитию СУБД под специфику 1С. Для крупных внедрений 1С предлагается машина баз данных Tantor XData. С СУБД Tantor Postgres для 1С пройдены тесты на высоконагруженных системах: 30 000 одновременных пользователей 1С с APDEX 0.859 на МБД Tantor XData 2Y, 20 000 одновременных пользователей с APDEX 0.846 на МБД Tantor XData 2B, и 15 000 одновременных пользователей с APDEX 0.950 на МБД Tantor XData 2Y в альтернативном тестировании.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2026-01-13/771f3461-b4df-4d15-bd68-c4b239166343.png" alt="" /><figcaption><br /></figcaption></figure><h3>Отличия от PostgreSQL</h3><p>Полный список отличий от "ванильной" версии доступен в <a href="https://docs.tantorlabs.ru/tdb/ru/17_7/se/differences.html">документации</a>.</p><p>Среди реализованных в 2025 году технологий и оптимизаций – технология Transparent Data Encryption (TDE) для прозрачного шифрования данных на диске + шифрование WAL, поддержка протокола аутентификации 0Auth 2.0, новый механизм работы с временными таблицами, улучшенная поддержка широких таблиц и таблиц с неравномерным распределением значений, множество оптимизаций производительности для систем «1С», оптимизация обработки дизъюнкций подзапросов, расширенная поддержка параллельного выполнения операций с временными таблицами, раздельное управление детализацией статистики для постоянных и временных таблиц. Таким образом, СУБД Tantor Postgres глубоко оптимизирована для более высокой производительности, в том числе для высоконагруженных систем 1С.</p><ul><li>Расширение Tantor PipelineDB обеспечивает агрегацию и вычисления на данных в реальном времени.</li><li>Расширение columnar предоставляет колоночное хранение и обработку данных с возможностью транзакционного выполнения операций UPDATE и DELETE.</li><li>Расширение transp_anon реализует динамическую анонимизацию данных.</li></ul><p>В каждую редакцию СУБД Tantor Postgres входит графическая Платформа Tantor для администрирования и мониторинга баз данных на основе PostgreSQL.</p><p>Стратегическим направлением развития СУБД Tantor Postgres является реализация технологии разделения вычислений и хранения для независимого масштабирования под высокие и смешанные нагрузки (НТАР), адаптация к облачному использованию и использованию с ИИ.</p><h3>Новые расширения в релизах 17.7 и 16.11</h3><ul><li><b>pg_stat_kcache</b> фиксирует физические операции чтения и записи, позволяя выявлять узкие места производительности, недоступные для обнаружения другими инструментами мониторинга.</li><li><b>pgvector</b> предоставляет тип данных vector и оптимизированные алгоритмы поиска по сходству для работы с многомерными представлениями данных.</li><li><b>pg_ivm</b> реализует инкрементальные материализованные представления, обновляя их по мере изменения данных в исходных таблицах.</li><li><b>pg_throttle</b> позволяет ограничивать скорость выполнения отдельных запросов и создавать пользовательские профили для управления ресурсами путём контроля нагрузки на систему.</li><li><b>pg_trace</b> обеспечивает глубокий анализ и профилирование SQL-запросов.</li><li><b>pg_archive </b>автоматически архивирует исторические данные из партиционированных таблиц.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/99854/2026-01-13/8d3fcf6c-1c1f-4cd5-bafe-b81f9d9e0cb5.png" alt="" /><figcaption><br /></figcaption></figure><h3>Отказоустойчивость и надёжность</h3><p>Для гарантии надёжности используются pg_cluster и wal-g. Эти инструменты отвечают за механизмы отказоустойчивости, резервное копирование и восстановление после сбоев.</p><h3>Безопасность и сертификация</h3><p>Модуль ЗСУБД операционной системы Astra Linux Special EditionLSE 1.8 имеет сертификацию ФСТЭК по 1 категории, редакция Tantor Certified сертифицирована ФСТЭК по 4 категории. Поддерживается прозрачное шифрование данных (Transparent Data Encryption, TDE).</p><p>СУБД совместима с ОС Astra Linux Special Edition во всех режимах функционирования. Отдельное приложение pg_sec_check проводит комплексный аудит безопасности СУБД. Протокол аутентификации OAuth 2.0 позволяет приложениям получать защищённый доступ к данным без передачи паролей пользователей.</p><p>Реализован контроль целостности баз данных и конфигурации СУБД, удаление объектов баз данных без возможности восстановления: очистка файлов во внешней памяти перед удалением, очистка версий строк, очистка страниц перед удалением, очистка оперативной памяти перед освобождением, очистка журнала упреждающей записи перед удалением или перезаписью.</p><h3>Экосистема и совместимость</h3><p>Платформа Tantor, входящая в поставку каждой редакции, обеспечивает самый широкий функционал для администрирования и управления БД среди решений для PostgreSQL.</p><p><b>Поддерживаемые ОС:</b> Astra Linux, Alt Linux, МСВСфера, Ред Софт, CentOS, Red Hat, Rocky Linux, Ubuntu, Debian, Oracle Linux.</p><p>Tantor предоставляет единое окно технической поддержки для продуктов Tantor и «Группы Астра», что обеспечивает качество и скорость решения вопросов. Вендорская поддержка доступна для всех редакций СУБД, полное описание <a href="https://docs.tantorlabs.ru/tdb/ru/17_7/se/limits.html">ограничений СУБД</a> опубликовано в документации.</p><h3>Лицензирование</h3><p>Классическая модель — поядерное лицензирование физических или виртуальных ядер сервера. Для СУБД под 1С есть адаптированная схема для SMB-рынка, где стоимость лицензии рассчитывается исходя из количества работников заказчика.</p><h3>Планы на 2026 год</h3><p>Запланирована сертификация ФСТЭК для Tantor Postgres 17.x, выпуск СУБД Tantor Postgres 18, выпуск редакции с разделением Compute и Storage. В разработке интеграция RocksDB, реорганизация таблиц без блокировок, реализация Tantor Postgres DBaaS в Astra Cloud, развитие PipelineDB в сторону более тесной интеграции с Columnar, поддержка сжатия на уровне JDBC-драйвера.</p><h2>3. Postgres Pro: форк PostgreSQL с российской разработкой и встроенным кластером</h2><p>Тип: реляционная СУБД общего назначения на базе PostgreSQL</p><p><a href="https://postgrespro.ru/">Postgres Pro</a> — российская разработка на основе PostgreSQL. Компания объединяет 70% российских контрибьюторов PostgreSQL, входит в ТОП-5 мировых разработчиков этой СУБД. Продукт включён в реестр российского ПО, сертифицирован ФСТЭК России. На рынке 10 лет, в команде более 400 специалистов.</p><h3>Где используют</h3><ul><li>Один из масштабных кейсов — миграция ГИС ГМП Федерального казначейства на Postgres Pro Shardman. Система обрабатывает платежи национального масштаба и работает в распределённой архитектуре.</li><li>«Авито» перенесли базы данных 1С с Microsoft SQL Server на Postgres Pro Enterprise. Объём данных — более 10 ТБ. Платформа обрабатывает 220 млн объявлений ежемесячно, обслуживает 62 млн пользователей и до 10 сделок в секунду.</li><li>Газпромбанк мигрировал ключевую АБС с Oracle на Postgres Pro Enterprise. Проект потребовал перестройки архитектуры и детального тестирования под пиковыми нагрузками.</li><li>«Росатом» развернул автоматизированную систему управления финансами и перенёс СЭД на Postgres Pro Enterprise Certified. Решение обслуживает более 250 предприятий атомной отрасли.</li></ul><h3>Редакции и специализация</h3><p>Линейка включает пять основных редакций:</p><ul><li><b>Postgres Pro Enterprise</b> — флагманская версия для высоконагруженных систем с более чем 100 дополнительными функциями относительно PostgreSQL. Поддерживает до 10 000 одновременно работающих пользователей.</li><li><b>Postgres Pro Enterprise для 1С</b> — оптимизирована под платформу 1С. Ускоряет ключевые операции, закрыть месяц можно до 10 раз быстрее по сравнению с базовыми решениями.</li><li><b>Postgres Pro Enterprise Certified</b> — сертифицированная ФСТЭК версия Enterprise со встроенными средствами защиты.</li><li><b>Postgres Pro Standard </b>— улучшенная версия PostgreSQL с повышенной производительностью и полнотекстовым поиском.</li><li><b>Postgres Pro Certified</b> — сертифицированная ФСТЭК версия Standard.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-22/cfecb81e-4106-440f-aade-7a7c506f0fd5.png" alt="" /></figure><h3>BiHA: встроенный отказоустойчивый кластер</h3><p>BiHA (Built-in High Availability) — встроенный отказоустойчивый кластер, работает «из коробки» без внешних компонентов. При сбое основного узла система автоматически переключается на реплику. Механизм не требует отдельной настройки Pacemaker, Corosync или других решений для управления кластером — всё интегрировано в ядро СУБД.</p><h3>Масштабирование: Shardman и Citus</h3><p>Для горизонтального масштабирования доступны две технологии:</p><p><b>Postgres Pro Shardman</b> — распределённая СУБД с автоматическим управлением шардами. Данные распределяются по узлам, система сама отслеживает топологию и балансирует нагрузку. Использовался в проекте миграции ГИС ГМП.</p><p><b>Citus</b> — расширение для распределённых запросов и параллельной обработки. Подходит для аналитических задач и работы с большими объёмами данных.</p><h3>Proxima и управление жизненным циклом данных</h3><p><b>Proxima</b> — встроенный пулер соединений и прокси-сервер. Оптимизирует управление подключениями, снижает накладные расходы на создание новых сессий.</p><p><b>ILM (Information Lifecycle Management)</b> — управление жизненным циклом данных. Позволяет автоматически перемещать старые или редко используемые данные на более дешёвые носители без остановки системы.</p><h3>Миграция с Oracle и других СУБД</h3><p>Postgres Pro включает инструменты для упрощённой миграции с Oracle: поддержка PL/SQL-совместимого языка, эмуляция пакетов Oracle, совместимость типов данных.</p><h3>Экосистема инструментов</h3><p><b>Postgres Pro Enterprise Manager (PPEM)</b> — графическая платформа для управления кластерами, мониторинга производительности и резервного копирования. Интерфейс позволяет управлять несколькими инстансами одновременно.</p><p><b>Postgres Pro Backup Enterprise</b> — инструмент для инкрементального резервного копирования. Поддерживает восстановление на точку во времени (PITR) и сжатие данных.</p><h3>Техническая поддержка и документация</h3><p>Техническая поддержка работает 24/7, два уровня: базовая и расширенная. Расширенная включает решение задач, требующих изменений в ядре СУБД. Доступен портал техподдержки с личным кабинетом и базой знаний.</p><p>Документация включает книги, курсы, демобазу для обучения, глоссарий и HOW-TO видео. Для студентов и вузов есть отдельные программы.</p><h3>Доступность</h3><p>Продукты доступны через интеграторов и дистрибьюторов. Лицензирование поядерное. Для разработчиков прикладного ПО предусмотрены отдельные условия. Можно протестировать через личный кабинет на сайте.</p><p>Компания проводит регулярные мероприятия: PGPro TechDay, PGMeetup по шардированию и другим техническим темам.</p><h2>4. Tarantool DB: in-memory СУБД для real-time систем</h2><p>Тип: NoSQL in-memory СУБД, key-value/документная</p><p><a href="https://www.tarantool.io/ru/tarantooldb/">Tarantool DB</a> — российская in-memory СУБД с открытым кодом, разработка VK. Включена в реестр отечественного ПО (№ 23005 от 28.06.2024), сертифицирована ФСТЭК России. Основной фокус — системы реального времени с требованиями к задержке в единицы миллисекунд.</p><h3>Где используют</h3><ul><li>Tarantool применяют как кэш-слой для автоматизированных банковских систем и дисковых СУБД. Вместо полной замены core-систем создаётся быстрый промежуточный слой, который снижает нагрузку на основное хранилище.</li><li>В банковской архитектуре СУБД работает как оперативное хранилище между клиентскими приложениями и базовой АБС. Это позволяет обрабатывать запросы без обращения к медленным дисковым системам.</li><li>В телекоме и ритейле используют для организации «золотой записи» клиента, цифрового профиля, единой авторизации и real-time биллинга. В e-commerce — для обработки потоков событий и маркетинга в реальном времени.</li></ul><h3>Drop-in замена Redis</h3><p>В поставке есть механизм замены Redis с минимальными изменениями кода. Поддерживаются 60+ команд Redis, типы данных Redis, Redis ACL для управления доступом и настройки, совместимые с Redis.</p><p>Есть логирование событий и шифрование TLS. Переход с Redis на Tarantool не требует переписывать клиентское приложение — достаточно изменить конфигурацию подключения.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-22/57280546-f3d5-4168-986f-c54349f2572a.png" alt="" /></figure><h3>Схемы данных и работа с памятью</h3><p>Tarantool поддерживает несколько схем: key-value, таблицы и документы. Данные хранятся в оперативной памяти с возможностью сжатия для экономии ресурсов.</p><p>Для сохранности предусмотрена упреждающая журнализация (WAL) и создание снимков состояния БД. При сбое система восстанавливается быстро благодаря механизму быстрого восстановления.</p><p>CRUD-операции работают с объектами в кластерном хранилище. Поддерживаются вторичные индексы и управление временем жизни данных (TTL). Справочники можно хранить прямо в кластере.</p><h3>Репликация и шардирование</h3><p>Доступна синхронная и асинхронная репликация. Шардирование (сегментирование данных) встроено в платформу — не нужны внешние инструменты для горизонтального масштабирования.</p><p>Failover для отказоустойчивости работает автоматически: при падении узла система переключается на реплику. Управление кластером реализовано через собственную технологию Tarantool.</p><h3>API и интеграция</h3><p>Для работы с данными из бизнес-приложений есть коннекторы на Java и Go. API поддерживает чтение и запись данных в кластерное хранилище.</p><p>Метрики мониторинга экспортируются в Prometheus и Grafana. Развёртывание возможно в Kubernetes. Поддерживаются российские ОС: Astra Linux и РЕД ОС.</p><h3>Экосистема продуктов</h3><p>Помимо Tarantool DB, в экосистеме есть:</p><ul><li>Tarantool Enterprise Edition — коммерческая версия с расширенной поддержкой</li><li>Tarantool CDC — Change Data Capture для синхронизации с другими системами</li><li>Tarantool Graph DB — графовая база данных</li><li>Tarantool Queue Enterprise — система очередей</li><li>Tarantool Column Store — колоночное хранилище для аналитики</li><li>Tarantool Clusters Federation — управление федерацией кластеров</li><li>Tarantool Kubernetes Operator — оператор для Kubernetes</li><li>Tarantool Cloud Edition — облачная версия</li></ul><h3>Горизонтальное масштабирование</h3><p>Переход с вертикального масштабирования (более мощное железо) на горизонтальное (больше узлов) снижает расходы на оборудование. Создание копий данных с быстрым доступом распределяет нагрузку между серверами.</p><p>Встроенные инструменты шардирования автоматически распределяют данные по узлам. Не нужно вручную настраивать балансировку или разбивать таблицы.</p><h3>Документация и поддержка</h3><p>Техническая документация доступна на русском языке. Есть руководства по началу работы для Enterprise Edition и Community Edition, документация по модулям и Data Grid.</p><p>Сообщество общается в Telegram, VK, GitHub и Stack Overflow. Есть блог с техническими статьями.</p><h2>5. ClickHouse: колоночная СУБД для аналитики</h2><p>Тип: колоночная OLAP-СУБД для онлайн-аналитической обработки</p><p><a href="https://clickhouse.com/docs/ru/intro">ClickHouse</a> — колоночная СУБД для аналитических задач, доступна как open-source проект и облачный сервис. Разработка началась в Яндексе, сейчас развивается как независимый проект. Основной фокус — обработка больших объёмов данных в режиме реального времени с возвратом результата за время менее секунды.</p><h3>OLAP vs OLTP</h3><p>ClickHouse решает задачи онлайн-аналитической обработки (OLAP): SQL-запросы со сложными вычислениями, агрегациями и арифметикой по миллиардам и триллионам строк. Аналитические запросы обрабатывают большие объёмы данных, в отличие от транзакционных (OLTP), которые читают и записывают несколько строк за запрос.</p><h3>Колоночное хранение</h3><p>Таблицы хранятся как набор столбцов: значения каждого столбца располагаются последовательно. Это затрудняет восстановление отдельных строк (между значениями строк появляются разрывы), но операции над столбцами — фильтрация, агрегация — выполняются значительно быстрее, чем в построчной базе.</p><p>При выполнении запроса с диска читаются только те столбцы, которые требуются. Если в таблице 100 столбцов, а запрос обращается к пяти, остальные 95 не загружаются в память. В построчной СУБД даже при обращении к одному столбцу приходится загружать данные всей строки, так как блоки на диске содержат значения всех столбцов вместе.</p><h3>Производительность</h3><p>На примере реальных данных веб-аналитики: запрос по 100 миллионам строк с фильтрацией и группировкой выполняется за 92 миллисекунды. Пропускная способность — около 1 миллиарда строк в секунду или около 7 ГБ данных в секунду.</p><h3>Приблизительные вычисления</h3><p>ClickHouse может жертвовать точностью ради производительности. Некоторые агрегатные функции вычисляют приблизительное количество различных значений, медиану и квантили. Запросы можно выполнять по выборке данных для быстрого получения приблизительного результата.</p><p>Агрегацию можно выполнять с ограниченным числом ключей вместо всех. При смещённом распределении ключей это даёт достаточно точный результат при меньших затратах ресурсов по сравнению с точным расчётом.</p><h3>SQL и стандарт ANSI</h3><p>ClickHouse поддерживает декларативный язык запросов на основе SQL, который во многих случаях соответствует стандарту ANSI SQL. Поддерживаются GROUP BY, ORDER BY, подзапросы в FROM, JOIN, оператор IN, оконные функции и скалярные подзапросы.</p><p>Синтаксис знаком разработчикам, работавшим с реляционными СУБД, но внутренняя логика выполнения запросов отличается из-за колоночного хранения.</p><h3>Репликация и целостность данных</h3><p>Используется асинхронная мультимастерная схема репликации для избыточного хранения данных на нескольких узлах. После записи на любую доступную реплику остальные реплики в фоновом режиме получают копию. Система поддерживает одинаковое состояние данных на разных репликах.</p><p>Восстановление после большинства сбоев выполняется автоматически или полуавтоматически в сложных случаях. Ролевое управление доступом (RBAC) реализовано через SQL-запросы, аналогично стандарту ANSI SQL и популярным реляционным СУБД.</p><h3>Адаптивные алгоритмы соединения</h3><p>ClickHouse адаптивно выбирает алгоритм соединения таблиц: начинает с быстрых хеш-соединений и переходит к merge-соединениям, если в запросе участвует более одной крупной таблицы. Система сама определяет оптимальную стратегию на основе характеристик данных.</p><h3>Сценарии использования</h3><p>ClickHouse применяют для веб-аналитики, логирования событий, мониторинга инфраструктуры, анализа временных рядов, обработки данных с датчиков IoT. Везде, где нужно агрегировать большие объёмы данных с низкой задержкой.</p><p>Типичный паттерн — сбор событий в реальном времени (клики, просмотры, логи) и построение дашбордов с обновлением каждые несколько секунд. ClickHouse обрабатывает миллиарды записей и возвращает результаты агрегации быстрее, чем традиционные хранилища данных.</p><h3>Open-source и облако</h3><p>Проект доступен на GitHub под лицензией Apache 2.0. Есть коммерческое облачное предложение ClickHouse Cloud с управляемой инфраструктурой. Можно развернуть на собственных серверах или использовать облачный вариант без управления кластером.</p><p>Выбор СУБД зависит от типа задач и архитектуры проекта. Для транзакционных систем с частыми операциями чтения-записи подходят РЕД База Данных и Postgres Pro — обе работают по модели OLTP, поддерживают ACID и совместимы с существующими инструментами разработки. Универсальная СУБД Tantor Postgres имеет специализированную версию для работы с 1С, производительность которой подтверждена тестами с одновременной работой десятков тысяч пользователей. Tarantool закрывает сценарии, где критична задержка в миллисекунды: кэширование, сессии, real-time биллинг. ClickHouse и Arenadata DB решают аналитические задачи, но по-разному: первый оптимизирован под скорость отдельных запросов с колоночным хранением, второй — под корпоративные хранилища данных с MPP-архитектурой и полной совместимостью с PostgreSQL.</p>]]></content:encoded>
    </item>
    <item>
      <title>Тормозит Postgres: 12 шагов диагностики</title>
      <link>https://tproger.ru/articles/tormozit-postgres--12-wagov-diagnostiki</link>
      <comments>https://tproger.ru/articles/tormozit-postgres--12-wagov-diagnostiki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Диана Тажетдинова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/tormozit-postgres--12-wagov-diagnostiki</guid>
      <description><![CDATA[<p>Эксперты собрали системный подход из 12 шагов, чтобы найти узкие места и пофиксить проблемы</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/tormozit-postgres--12-wagov-diagnostiki">Тормозит Postgres: 12 шагов диагностики</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 18 Nov 2025 14:10:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Производительность PostgreSQL может проседать постепенно. Сначала запросы зависают и растёт нагрузка растёт, а затем CPU начинает работать на 100%, хотя данных больше не стало. База тормозит, что сказывается на работе всего проекта. Возможных причин много: от неоптимальных запросов до ошибок конфигурации. В таких ситуациях важно не паниковать, а действовать постепенно — от простого к сложному.</p><p>Вместе с экспертами собрали системный подход из 12 шагов, чтобы найти узкие места и пофиксить проблемы.</p><h2>Шаг 1. Проверьте CPU, память и диск</h2><p>Начинаем с базы — проверяем аппаратные и системные ресурсы. Иногда проблема кроется в том, что серверу объективно тяжело. CPU перегружен, память закончилась, диск устал, и PostgreSQL просто не из чего строить производительность. База работает как сениор-разработчик в последней стадии выгорания.</p><p>На что ориентироваться:</p><ul><li>Если CPU постоянно упирается в предел — анализируем активность запросов или рассматриваем масштабирование.</li><li>Если Swap активен — не хватает памяти.</li><li>Если видите высокий iowait или высокий %util диска, то кандидаты: медленное хранилище, случайные чтения, VACUUM, большие запросы.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/114509/2025-11-13/26993566-d258-4ad7-b0c4-906ac404ef7c.jpeg" alt="" /></figure><h2>Шаг 2. Изучите активность в pg_stat_activity</h2><p>Представляет информацию о текущей активности каждого процесса в реальном времени. Благодаря pg_stat_activity можно увидеть, какие запросы сейчас ждут запуска, какие в работе, а какие съедают больше всего ресурсов производительности. Если смотреть сюда регулярно, большинство проблем видно ещё до аварии.</p><p>На что обратить внимание</p><ul><li>долгие транзакции;</li><li>wait_event_type = 'Lock';</li><li>idle in transaction — признак некорректной работы приложения с транзакциями.</li></ul><blockquote>Однажды в проде столкнулись с резким ростом задержек запросов, далее — массовые ошибки <i>canceling statement due to lock timeout</i>. Выяснилось: в ETL начали повсеместно использовать транзакции, в том числе там, где они не нужны. Долгие этапы блокировали частые операции. Перезапуск PostgreSQL помогал до следующего запуска ETL. <br /><br />Решение: идентифицировать и завершить блокирующие процессы, переработать ETL на более короткие транзакции. В дальнейшем — маркировать подобные процессы и мониторить их отдельно.</blockquote><h2>Шаг 3. Найдите медленные запросы в pg_stat_statements</h2><p>Этот модуль отслеживает статистику выполнения сервером всех операторов SQL. Сюда стоит заглянуть, если зависание и торможение повторяются. Сама база может работать нормально, а один или два плохо написанных запроса — нет.</p><p>Что искать:</p><ul><li>запросы, потребляющие больше всего времени;</li><li>случаи, когда чтение идёт с диска, а не из буфера (shared_blks_read &gt;&gt; shared_blks_hit).</li></ul><figure><img src="https://media.tproger.ru/user-uploads/114509/2025-11-13/59a21ae2-2db3-4af4-943e-67f3c9846fe2.jpeg" alt="" /></figure><h2>Шаг 4. Выявите блокировки</h2><p>Ищите ситуации, когда несколько запросов пытаются работать с одними и теми же данными одновременно. Если один процесс держит строку или таблицу, остальные ждут. Тогда база не падает, а просто стоит в очереди.</p><p>Ищем цепочки блокировок. Частые причины:</p><ul><li>долгие транзакции,</li><li>миграции без окон обслуживания,</li><li>запросы без нужных индексов.</li></ul><h2>Шаг 5. Проанализируйте план запроса с EXPLAIN ANALYZE</h2><p>Эта команда сначала выполняет запрос, а затем выводит фактическое число строк и время выполнения, накопленное в каждом узле плана. Так можно найти место, которое съедает больше всего ресурсов. Неэффективный расход времени и памяти происходит, когда база выбирает неоптимальный план, чтобы выполнить запрос.</p><h2>Шаг 6. Проверьте и оптимизируйте индексы</h2><p>Индекс работает как указатель в книге, чтобы быстро искать нужную страницу. Но если поставить закладки везде, то книга станет толстой и неудобной. PostgreSQL ведёт себя так же: без индекса он перебирает строки вручную, а с перегруженной структурой дольше обновляет таблицу и тратит лишнюю память</p><p>Как оптимизировать:</p><ul><li>не создавать индекс на каждый столбец;</li><li>использовать частичные индексы, если данные распределены неравномерно;</li><li>регулярно проводить REINDEX для крупных объектов.</li></ul><h2>Шаг 7. Устраните раздувание таблиц — bloat</h2><p>PostgreSQL не удаляет ненужные данные сразу, а копит «мёртвые» строки. Если их становится слишком много, таблицы разрастаются. Тогда база тратит ресурсы впустую.</p><p>Диагностика:</p><p>Очистка:</p><h2>Шаг 8. Настройте и проверьте autovacuum</h2><p>Этот фоновый процесс нужен в PostgreSQL, чтобы автоматически обслуживать базу. Пока он работает, система в порядке. Если его выключить или не настроить, то накопится мусор, вырастут таблицы, а база замедлится.</p><p>Проверьте эффективность процессов:</p><p>Настройки должны соответствовать нагрузке и объёму данных.</p><blockquote>Если отключить автовакуум или не управлять им, может произойти быстрое раздувание таблиц и резкое падение производительности.</blockquote><figure><img src="https://media.tproger.ru/user-uploads/114509/2025-11-13/e757d893-9ecc-4db6-a811-06226bdbbbb9.jpeg" alt="" /></figure><blockquote>Если <i>n_dead_tup</i> растёт, а <i>autovacuum_count</i> нет — это сигнал будущих проблем с производительностью и ростом <i>bloat</i>. Также важно следить за <i>WAL</i>: резкий рост записи может указывать на массовые обновления, проблемы с репликацией или приближающееся заполнение диска.</blockquote><h2>Шаг 9. Обновите статистику и настройте планировщик</h2><p>PostgreSQL формирует план выполнения запроса на основе статистики о распределении данных в таблицах. Если статистика устарела, оптимизатор может выбрать неэффективный план.</p><p>Регулярно выполняйте команду ANALYZE, чтобы освежить статистику и корректно оценивать операции.</p><p>Учитывайте важные параметры:</p><ul><li>random_page_cost для SSD ≈ 1.1</li><li>effective_cache_size ≈ 50–75% RAM</li></ul><h2>Шаг 10. Контролируйте соединения</h2><p>Каждое активное соединение потребляет ресурсы сервера, включая память и процессы планировщика. Избыточное количество соединений может привести к деградации производительности.</p><p>Текущее состояние соединений можно просмотреть с помощью:</p><p>Чтобы решить проблему, используйте пул соединений — например, через пулер PgBouncer или аналоги. Такие программы перераспределяют нагрузку между клиентами.</p><figure><img src="https://media.tproger.ru/user-uploads/114509/2025-11-13/98526be9-c2f6-4945-8992-a29f2164d12b.jpeg" alt="" /></figure><h2>Шаг 11. Проанализируйте логи</h2><p>PostgreSQL предоставляет гибкую систему протоколирования, чтобы фиксировать длительные операции, ожидания блокировок и создание временных файлов. Для диагностики посмотрите все логи, связанные с производительностью.</p><p>Рекомендуемые параметры в postgresql.conf:</p><h2>Шаг 12. Оптимизируйте конфигурацию</h2><p>Значения по умолчанию предназначены для минимальных нагрузок — для работы на ноутбуке. Они не дают достаточной мощности в производственной среде.</p><p>Измените ключевые параметры конфигурации:</p><ul><li>shared_buffers ~25% RAM</li><li>effective_cache_size ~50–75% RAM</li><li>work_mem 4–16 MB per operation</li><li>checkpoint_timeout 15–30 min</li><li>random_page_cost = 1.1 для SSD</li></ul><blockquote>Многие думают, что 16 мегабайт — это глобальный лимит на соединение. На самом деле это лимит на операцию. Один запрос может использовать <i>work_mem</i> много раз.</blockquote><h2>Качество и целостность данных: типовые проблемы и решения</h2><p>Качество данных — основа устойчивой IT-системы. Проблемы с ними часто приводят к сбоям и некорректной работе приложений. В PostgreSQL есть встроенные механизмы, которые помогают поддерживать надёжность информации.</p><p>Какие ошибки встречаются чаще всего:</p><ul><li>дубли,</li><li>неверные типы,</li><li>конфликтующие или устаревшие значения,</li><li>частичные и повреждённые записи.</li></ul><p>Как поддерживать целостность данных:</p><ul><li>Проводить регулярный аудит и мониторинг качества данных.</li><li>Внедрять автоматические проверки на дубликаты, пропуски и нарушения правил ещё на этапе загрузки данных.</li><li>Использовать резервное копирование и инструменты восстановления после сбоев.</li><li>Повышать осознанность пользователей и разработчиков — качество данных это часть инженерной культуры.</li></ul><p>Контроль качества данных включает также стратегию восстановления. Даже идеально настроенная валидация не спасает от сбоя диска или человеческого фактора. Резервные копии и репликации должны стать частью общей стратегии.</p><p>На прикладном уровне используйте SAVEPOINT, чтобы аккуратно откатывать операции внутри транзакции. На уровне инфраструктуры работает та же логика:</p><ul><li>проверенные бэкапы возвращают к нормальному состоянию,</li></ul><ul><li>репликация сохраняет доступность, если падает основной сервер.</li></ul><p>SAVEPOINT помогает в рамках одной транзакции, бэкапы и репликация — в рамках всей системы.</p><figure><img src="https://media.tproger.ru/user-uploads/114509/2025-11-13/1aa309ba-009d-48fc-8abc-893d3d20bc1b.jpeg" alt="" /></figure><h3>Как проверять входные данные</h3><p><b>Задавайте допустимые форматы и диапазоны.</b> Указывайте, какие значения вы считаете корректными. Пример:</p><ul><li>дата рождения не может быть позже текущего дня;</li><li>возраст — только числа ≥ 18;</li><li>формат email должен содержать @ и домен.</li></ul><p><b>Проверяйте данные на двух уровнях.</b>  Чтобы пользователь увидел ошибку сразу, смотрите на клиенте — например, в форме сбора контактов.</p><p>Чтобы защититься, если приложение пропустило проблему — на сервере.</p><p><b>Используйте ограничения в базе.</b> SQL-ограничения — это тот самый  встроенный механизм надёжности:</p><ul><li>NOT NULL — поле не может быть пустым;</li><li>UNIQUE — значение должно быть уникальным;</li><li>CHECK — значение должно соответствовать условию;</li><li>FOREIGN KEY — связь с другой таблицей;</li><li>триггеры — дополнительная логика проверки.</li></ul><p><b>Давайте понятные сообщения об ошибках.</b> Пользователь должен понимать, что он сделал не так. Например, вместо Error 400 — invalid data напишите: <i>«Возраст должен быть от 18 лет. Введено: 15»</i>.</p><p><b>Актуализируйте правила проверки.</b> Если вчера минимальная сумма заявки была 5 тысяч, а сегодня 10 — проверка должна обновиться.</p><p><b>Отдайте контроль машине.</b> Используйте автоматизированные проверки:</p><ul><li>поиск дублей;</li><li>контроль пустых полей;</li><li>сверка с бизнес-правилами;</li><li>регулярный скрипт на аномалии.</li></ul><p><b>Документируйте и обучайте.</b> Опишите, какие данные нужны, в каком виде и почему. Покажите команде и пользователям. Чем понятнее правила, тем меньше ошибок.</p><p>Идеальный сценарий: регулярные тестируемые бэкапы + репликация с мониторингом лагов.</p><h2>Чек-лист диагностики за 15 минут</h2><ol><li>pg_stat_activity — долгие транзакции, ожидания</li><li>pg_locks — есть ли блокировки</li><li>pg_stat_statements — тяжёлые запросы</li><li>iostat, htop, free — ресурсы железа</li><li>Проверка автовакуума</li><li>Проверка WAL и места на диске</li><li>Анализ логов</li></ol><h3>Ещё 4 неочевидные причины деградации производительности</h3><p>Что делать, если диагностика по стандарту не помогла? Владимир Васильев рассказал нам, где ещё можно найти источник проблем:</p><ul><li>«Тихое» повреждение данных на диске. Дисковая подсистема не сообщала об ошибках: контроллер RAID с кэшем-бутербродом, где батарея отжила своё. Некоторые страницы данных на диске были битые. Postgres при чтении таких страниц не падал, а уходил в бесконечные ожидания I/O, которые выглядели как резкий скачок нагрузки на диск. Вылечили включением zero_damaged_pages на свой страх и риск, с последующим дампом/рестором. Потом, конечно, заменили железо.</li><li>Конфликт расширений. Была история с pg_stat_statements и auto_explain, которые при определённой настройке (совместная загрузка и высокая частота сэмплирования) начинали сильно тормозить из-за конкуренции за локи в общей памяти. Симптом — высокий wait_event типа LWLock для простых запросов.</li><li>Проблема на уровне файловой системы. Очень старый, но запоминающийся случай: файловая система была заполнена почти под завязку, больше 95%. Это привело к драматическому падению производительности, так как механизмам VACUUM и CREATE INDEX не хватало места для создания временных файлов. Симптомы были самые странные, пока не посмотрели на df -h.</li><li>Субтильный баг в версии PostgreSQL. Однажды апгрейд на минорную версию в рамках одного major привёл к деградации конкретного типа запросов с JOIN. Оказалось, баг в планировщике — он неправильно оценивал стоимость при определённом условии. Помог откат или установка enable_&lt;type&gt;scan = off в качестве временного костыля.</li></ul><h2>Выводы</h2><p>Основные источники проблем:</p><ul><li>долгие транзакции и блокировки</li><li>неэффективные планы выполнения</li><li>недостаточная память и I/O-узкие места</li><li>неверные настройки work_mem, autovacuum, max_connections</li><li>игнорирование метрик и логов</li></ul><p>Универсального решения проблем нет. Чтобы понять причину торможения и разобраться с ней, стоит последовательно уточнять контекст.</p><p>Краткий чек-лист диагностики:</p><ul><li>понять, что происходит сейчас,</li><li>найти узкое место,</li><li>проверить спрос со стороны запросов, а не только предложения со стороны конфигурации,</li><li>убедиться, что данные и процессы здоровы.</li></ul><p>Читайте также</p><ul><li><a href="https://tproger.ru/articles/osnovy-postgresql-dlya-nachinayushhih--ot-ustanovki-do-pervyh-zaprosov-250851">Основы PostgreSQL для начинающих: от установки до первых запросов</a></li><li><a href="https://tproger.ru/articles/postgresql-vs--clickhouse-vs--duckdb--kakuyu-opensors-bazu-vybrat-dlya-analitiki-v-2025-godu-">PostgreSQL vs. ClickHouse vs. Duck DB: какую опенсорс базу выбрать для аналитики в 2025 году?</a></li><li><a href="https://tproger.ru/articles/vrednye-sovety-po-rabote-s-bazami-dannyh--ili-kak-rasstroit-dba">Вредные советы по работе с базами данных, или как расстроить DBA</a></li><li><a href="https://tproger.ru/articles/sql-optimizaciya--5-zaprosov--kotorye-lomayut-bazu">SQL-оптимизация: 5 запросов, которые ломают базу</a></li><li><a href="https://tproger.ru/articles/postgresql--chto-nuzhno-znat-o-schyotchike-tranzakcij">PostgreSQL: что нужно знать о счётчике транзакций</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Разработчик Yandex Cloud вошел в топ-50 контрибьюторов PostgreSQL в мире</title>
      <link>https://tproger.ru/news/razrabotchik-yandex-cloud-vowel-v-top-50-kontribyutorov-postgresql-v-mire</link>
      <comments>https://tproger.ru/news/razrabotchik-yandex-cloud-vowel-v-top-50-kontribyutorov-postgresql-v-mire?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/razrabotchik-yandex-cloud-vowel-v-top-50-kontribyutorov-postgresql-v-mire</guid>
      <description><![CDATA[<p>Разработчик Yandex Cloud Андрей Бородин вошел в топ-50 контрибьюторов PostgreSQL — 10 лет в проекте и сотни апстрим-патчей в ядро</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/razrabotchik-yandex-cloud-vowel-v-top-50-kontribyutorov-postgresql-v-mire">Разработчик Yandex Cloud вошел в топ-50 контрибьюторов PostgreSQL в мире</a>»</p>]]></description>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Яндекс]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 10 Nov 2025 06:35:33 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Андрей Бородин</b>, руководитель разработки СУБД с открытым исходным кодом в <b>Yandex Cloud</b>, <a href="https://www.cnews.ru/news/line/2025-11-10_razrabotchik_yandeksa_voshel">вошел</a> в список <b>топ-50 крупнейших контрибьюторов PostgreSQL</b>.</p><h2>10 лет в развитии PostgreSQL</h2><p>Бородин получил статус топ-контрибьютора спустя <b>10 лет активного участия</b> в развитии сообщества и кодовой базы PostgreSQL.</p><p>При этом и команда Yandex Cloud активно сотрудничает с сообществом PostgreSQL. Каждый год в релизы СУБД попадает множество доработок от инженеров компании.</p><p>Процесс принятия изменений в ядро PostgreSQL считается одним из самых строгих в мире open-source, поэтому успешный апстрим-патч — <b>знак качества и зрелости кода</b>.</p><p>Кроме ядра, команда Яндекса развивает собственные опенсорс-решения. Например, <b>SPQR</b> — на его основе в сентябре 2025 года был запущен сервис <b>Managed Service for Shared PostgreSQL</b>.</p><p>Он обеспечивает <b>горизонтальное масштабирование</b> баз данных через шардирование — разделение данных между разными серверами.</p><h2>Кто такой Андрей Бородин</h2><p>До работы в Yandex Cloud, Бородин был инженером в <b>AWS</b>, а сейчас совмещает разработку с преподаванием в <b>ШАД «Яндекса»</b> и <b>Уральском федеральном университете</b>.</p><p>Первый патч в PostgreSQL он закоммитил еще в <b>2016 году</b>. С тех пор он уже <b>четырежды попадал в годовой топ-50 контрибьюторов проекта</b>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Вышел Bun 1.3: full-stack рантайм, поддержка Redis и новый SQL API. Разобрались, что еще нового</title>
      <link>https://tproger.ru/news/vywel-bun-1-3--full-stack-rantajm--podderzhka-redis-i-novyj-sql-api--razobralis--chto-eshhe-novogo</link>
      <comments>https://tproger.ru/news/vywel-bun-1-3--full-stack-rantajm--podderzhka-redis-i-novyj-sql-api--razobralis--chto-eshhe-novogo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/vywel-bun-1-3--full-stack-rantajm--podderzhka-redis-i-novyj-sql-api--razobralis--chto-eshhe-novogo</guid>
      <description><![CDATA[<p>Bun 1.3 стал full-stack рантаймом с Redis, SQL API, поддержкой MySQL и PostgreSQL, новым тест-раннером и ускорением сборки до 2,5 раз</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/vywel-bun-1-3--full-stack-rantajm--podderzhka-redis-i-novyj-sql-api--razobralis--chto-eshhe-novogo">Вышел Bun 1.3: full-stack рантайм, поддержка Redis и новый SQL API. Разобрались, что еще нового</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 13 Oct 2025 04:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда <b>Oven</b> <a href="https://bun.com/blog/bun-v1.3">представила</a> <b>Bun 1.3</b> — крупнейший релиз в истории JavaScript-рантайма.</p><p>Теперь Bun официально позиционируется как <b>full-stack платформа</b> для фронтенда и бэкенда. И она объединяет сервер, сборщик, менеджер пакетов вместе с тест-раннером в одном инструменте.</p><p>В новую версию добавлены десятки ключевых функций: встроенные клиенты для <b>Redis</b>, <b>MySQL</b>, <b>PostgreSQL</b> и <b>SQLite</b>, единый <b>SQL API</b>, улучшенные <b>WebSocket-модули</b>, переработанный <b>тест-раннер</b> и поддержка <b>VSCode Test Explorer</b>.</p><h2>Full-stack по-умному</h2><p>Главное новшество — режим <b>full-stack Bun.serve()</b> с поддержкой роутинга, cookies и WebSockets.</p><p>Теперь фронтенд и бэкенд можно запускать в одном процессе без проблем с CORS, а приложение собрать в <b>единый исполняемый файл</b> с помощью bun build --compile.</p><p>Разработчики могут напрямую импортировать HTML, запускать React-приложения с хот-перезагрузкой и собирать проект одной командой bun init --react. По данным команды, скомпилированные React-приложения в Bun работают <b>до 1,8 раза быстрее, чем через nginx</b>.</p><h2>Новый SQL и встроенный Redis</h2><p>Bun 1.3 представил унифицированный <b>Bun.SQL API</b> — теперь один и тот же код работает с MySQL, PostgreSQL, SQLite и MariaDB. Добавлен хелпер sql.array() для работы с массивами в PostgreSQL, улучшена поддержка JSON и Unix-сокетов.</p><p>Кроме того, в рантайм встроен <b>Redis-клиент</b>, который поддерживает 66 команд, автоматическое переподключение, очереди сообщений и Pub/Sub. По данным разработчиков, он <b>значительно быстрее ioredis</b>, а поддержка кластеров и Lua-скриптов появится в будущих релизах.</p><h2>Новые возможности</h2><p>Среди прочих улучшений — <b>Zstandard-сжатие</b>, нативная поддержка <b>YAML</b>, API для безопасного хранения секретов (<b>Bun.secrets</b>), и серьезный прирост производительности: операции с криптографией ускорены <b>до 400х</b>, установка пакетов — <b>до 2,5х</b>.</p><p>Также обновлен менеджер пакетов с <b>интерактивным bun update</b>, изолированными установками и API для проверки безопасности зависимостей.</p><h2>Почему это важно</h2><p>Bun 1.3 превращает экспериментальный рантайм в <b>полноценную платформу для веб-разработки</b>, способную заменить Node.js, Vite и Redis-CLI одновременно.</p><p>Разработчики называют релиз «началом новой эпохи», цель которой — сделать Bun лучшим способом писать и развертывать JavaScript-приложения.</p>]]></content:encoded>
    </item>
    <item>
      <title>PostgreSQL 18 вышел: новый асинхронный I/O ускоряет запросы в 3 раза</title>
      <link>https://tproger.ru/news/--postgresql-18-vywel--novyj-asinhronnyj-i-o-uskoryaet-zaprosy-v-3-raza</link>
      <comments>https://tproger.ru/news/--postgresql-18-vywel--novyj-asinhronnyj-i-o-uskoryaet-zaprosy-v-3-raza?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--postgresql-18-vywel--novyj-asinhronnyj-i-o-uskoryaet-zaprosy-v-3-raza</guid>
      <description><![CDATA[<p>PostgreSQL 18 вышел с асинхронным I/O, ускоряющим запросы в 3 раза, быстрее pg_upgrade, новыми индексами, OAuth 2.0 и улучшенным текстовым поиском</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--postgresql-18-vywel--novyj-asinhronnyj-i-o-uskoryaet-zaprosy-v-3-raza">PostgreSQL 18 вышел: новый асинхронный I/O ускоряет запросы в 3 раза</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 26 Sep 2025 04:43:56 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вышла финальная версия <b>PostgreSQL 18</b> — одного из самых популярных СУБД с открытым исходным кодом.</p><p>Главное нововведение — <b>асинхронный ввод-вывод</b>, который в ряде сценариев ускоряет работу с диском <b>до трех раз</b>.</p><p>Но на этом список улучшений не заканчивается: PostgreSQL 18 ускорил обновления между версиями, добавил удобства разработчикам, улучшил текстовые операции и получил поддержку OAuth 2.0.</p><h2>До трех раз быстрее благодаря новому вводу-выводу</h2><p>До этого момента PostgreSQL полагался на механизм операционной системы под названием readahead, чтобы предсказывать, какие данные будут востребованы.</p><p>В PostgreSQL 18 появилась полноценная <b>поддержка асинхронного I/O</b>, благодаря которой база может отправлять сразу несколько I/O-запросов — и не ждать завершения каждого по отдельности.</p><p>Это позволяет достичь <b>серьезного прироста производительности </b>при последовательном чтении, bitmap heap scan и даже во время VACUUM.</p><p>В зависимости от настроек (io_method) можно выбрать подходящий механизм — от worker до io_uring, или оставить синхронный режим (sync). Подробные параметры конфигурации описаны в официальной документации.</p><h2>Обновления между версиями больше не обнуляют производительность</h2><p>Одной из болезненных сторон мажорных обновлений PostgreSQL всегда было то, что после pg_upgrade приходилось заново собирать статистику — иначе планировщик начинал выбирать неоптимальные запросы.</p><p>В PostgreSQL 18 это <b>исправлено</b>: теперь можно сохранять собранную статистику между версиями, чтобы после обновления система сразу показывала ожидаемую производительность.</p><p>Помимо этого, утилита pg_upgrade теперь работает быстрее на базах с большим количеством таблиц, может выполнять параллельные проверки (через --jobs) и поддерживает флаг --swap — для моментальной замены директорий без копирования файлов.</p><h2>Что еще улучшили</h2><p>В PostgreSQL 18 появилось множество изменений, не связанных напрямую с I/O, но делающих жизнь разработчиков и администраторов проще. Среди них:</p><ul><li><b>Новые методы индексирования</b> (вроде skip scan), которые позволяют задействовать индексы даже без фильтрации по первым столбцам.</li><li>Улучшения в JOIN: быстрее работают hash join, merge join и incremental sort.</li><li>Поддержка <b>виртуальных вычисляемых колонок</b>, которые вычисляются на лету и не хранятся на диске.</li><li>Новый генератор uuidv7() — UUID с временной сортировкой, который лучше индексируется и ускоряет выборки.</li><li>Возможность использовать оба значения (OLD и NEW) в RETURNING при INSERT, UPDATE, DELETE и MERGE.</li><li>Улучшения в полнотекстовом поиске и обработке текста, включая новый casefold() и быструю сортировку PG_UNICODE_FAST.</li></ul><p>Также PostgreSQL теперь проще интегрировать с <b>OAuth 2.0</b>, появилась валидация для FIPS-режима, улучшено логгирование репликации и по умолчанию включены <b>контрольные суммы страниц</b> (page checksums), что может повлиять на стратегию обновления через pg_upgrade.</p><p><b>PostgreSQL 18</b> уже доступен для загрузки. Полный список изменений можно найти в<a href="https://www.postgresql.org/docs/18/release-18.html"> официальных release note</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Redis против Postgres в роли кэша: неожиданные итоги бенчмарка</title>
      <link>https://tproger.ru/news/redis-protiv-postgres-v-roli-kewa--neozhidannye-itogi-benchmarka</link>
      <comments>https://tproger.ru/news/redis-protiv-postgres-v-roli-kewa--neozhidannye-itogi-benchmarka?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/redis-protiv-postgres-v-roli-kewa--neozhidannye-itogi-benchmarka</guid>
      <description><![CDATA[<p>Бенчмарк показал: Redis быстрее в роли кэша, но PostgreSQL с unlogged-таблицами выдаёт до 7400 rps и подходит для многих проектов</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/redis-protiv-postgres-v-roli-kewa--neozhidannye-itogi-benchmarka">Redis против Postgres в роли кэша: неожиданные итоги бенчмарка</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 25 Sep 2025 10:00:51 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчик <a href="https://dizzy.zone/2025/09/24/Redis-is-fast-Ill-cache-in-Postgres/">провел</a> собственное исследование, сравнив производительность Redis и PostgreSQL в роли кэша.</p><p>Он ожидал увидеть очевидное превосходство Redis, но результаты оказались не такими однозначными — особенно с учетом unlogged-таблиц в Postgres.</p><h2>Как проводили тест</h2><ul><li>Был написан простой HTTP-сервер на Go с двумя эндпоинтами: GET и SET.</li><li>В качестве кэша использовались: Redis (через go-redis) и PostgreSQL с unlogged-таблицей (через pgx).</li><li>Оба сервиса запускались в k8s с лимитами: 2 CPU и 8 ГБ ОЗУ.</li><li>Генерация нагрузки — с помощью k6, с предзаполнением кэша 30 млн записей.</li><li>Тестировались три типа нагрузки: только чтение, только запись, смешанная (80% чтения и 20% записи).</li></ul><h2>Что показали тесты</h2><h3>1. Redis быстрее почти по всем метрикам</h3><ul><li>При чтении Redis обработал более 11 000 запросов в секунду против 7400 у PostgreSQL.</li><li>Задержки в Redis в среднем были на 20–30 мс ниже.</li><li>При записи разрыв еще больше: Redis справлялся с ~10 700. запросов в секунду, а PostgreSQL — с ~6000.</li></ul><h3>2. Unlogged-таблицы действительно ускоряют PostgreSQL</h3><ul><li>При использовании обычных таблиц производительность записи в Postgres падала почти в 3 раза.</li><li>На смешанной нагрузке unlogged-таблицы дали прирост примерно в 25%.</li></ul><h3>3. Redis стабильно использовал меньше ресурсов</h3><ul><li>Redis не превышал 1.3 CPU и держал стабильное потребление памяти (~4–4.5 ГБ).</li><li>PostgreSQL упирался в лимит CPU и требовал до 6 ГБ ОЗУ при нагрузке.</li></ul><h2>Когда стоит выбрать Postgres</h2><p>Автор поста подчеркивает: несмотря на более высокую производительность Redis, он лично предпочитает Postgres в небольших и средних проектах:</p><ul><li>База данных все равно уже используется в проекте.</li><li>Нет нужды в сложных TTL или автоудалении.</li><li>Не хочется тянуть в проект еще одну зависимость.</li><li>От 7000 до 8000 запросов в секунду — более чем достаточно для большинства задач.</li></ul><p>7425 запросов в секунду — это больше полумиллиарда в день. Все на 10-летнем железе и обычном PostgreSQL. Мало кто работает на таких нагрузках.</p>]]></content:encoded>
    </item>
    <item>
      <title>«SQL хорош для данных, но плох для логики» — почему все больше разработчиков выносят бизнес-логику из базы</title>
      <link>https://tproger.ru/news/-sql-horow-dlya-dannyh--no-ploh-dlya-logiki----pochemu-vse-bolwe-razrabotchikov-vynosyat-biznes-logiku-iz-bazy</link>
      <comments>https://tproger.ru/news/-sql-horow-dlya-dannyh--no-ploh-dlya-logiki----pochemu-vse-bolwe-razrabotchikov-vynosyat-biznes-logiku-iz-bazy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/-sql-horow-dlya-dannyh--no-ploh-dlya-logiki----pochemu-vse-bolwe-razrabotchikov-vynosyat-biznes-logiku-iz-bazy</guid>
      <description><![CDATA[<p>SQL отлично справляется с данными, но неудобен для бизнес-логики: разработчики выносят её в код ради гибкости, скорости и независимости</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/-sql-horow-dlya-dannyh--no-ploh-dlya-logiki----pochemu-vse-bolwe-razrabotchikov-vynosyat-biznes-logiku-iz-bazy">«SQL хорош для данных, но плох для логики» — почему все больше разработчиков выносят бизнес-логику из базы</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Oracle]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 24 Sep 2025 11:06:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Современные приложения все чаще используют базы данных исключительно как «хранилище», а не как движок для бизнес-логики. <i>Почему? </i></p><p>Потому что SQL, несмотря на свое превосходство в работе с данными, неудобен, ограничен и рискован в роли полноценного языка программирования.</p><h2>Логика не по адресу</h2><p>Как <a href="https://ewaldbenes.com/en/blog/why-i-keep-business-logic-out-of-sql">отмечает</a> Эвальд Бенс, фуллстек разработчик и авторов популярного блога об IT, он <b>предпочитает держать как можно больше логики в приложении</b>, а не в SQL-хранилищах, представлениях и процедурах:</p><blockquote>Я отношусь к базе как к тупому хранилищу данных. Вся логика — в коде. SQL просто не предназначен для сложных сценариев.</blockquote><p>И дело не в том, что SQL чего-то «не умеет». Умеет — особенно с расширениями вроде PL/pgSQL или Oracle PL/SQL.</p><p><b>Но выразительность этих языков — далека от Python, TypeScript, Rust или C#</b>, особенно когда речь идет о бизнес-логике, объектной модели или сложных расчетах.</p><h2>Зачем выносить логику из базы?</h2><h2>1. SQL невыразителен</h2><p>Для манипуляций с табличками и JOIN — он король. Но как только начинается рекурсия, классы, вложенные состояния или обработка ошибок — SQL превращается в монстра с BEGIN, IF, LOOP, EXCEPTION, RAISE, CURSOR, FETCH, WHILE и т.д...</p><h2>2. Развертывание — боль</h2><p>Обновить приложение можно за минуту, откатить — за две. А вот миграции на проде — это:</p><ul><li>повышенные права доступа;</li><li>согласование с DBA;</li><li>боязнь сломать что-то «наживую»;</li><li>ручной откат схем.</li></ul><h2>3. Лочит на вендора</h2><p>Логика, написанная на PL/SQL — это билет в один конец к Oracle. Переезд на PostgreSQL или SQL Server становится в 5 раз сложнее.</p><h2>4. Меньше инструментов</h2><p>Вокруг SQL есть утилиты, но полноценной среды с юнит-тестами, статическим анализом, форматтерами, профайлерами, линтерами и отладчиками — почти нет.</p><h2>А что с производительностью?</h2><p>Да, есть нюанс: <b>иногда лучше обработать данные прямо в базе</b>, чтобы не гонять десятки тысяч строк по сети. Это особенно актуально, если не хочется получить классическую проблему N+1-запросов.</p><p>Но даже в этом случае большинство специалистов советует <b>сначала делать «просто и понятно», а не «оптимально заранее»</b>. До тех пор, пока не уперлись в реальные метрики, выносить логику в базу — преждевременная оптимизация.</p><h2>Что делать?</h2><p>Подход <i>«база — хранилище, логика — в коде»</i> стал де-факто стандартом во многих командах. Но это не догма:</p><ul><li>Для отчетности или простых ETL сценариев логика в SQL может быть уместной.</li><li>Для монолитных решений без CI/CD и DevOps — процедурный SQL вполне оправдан.</li><li>Но в современной разработке с частыми релизами, микросервисами и отказоустойчивостью <b>бизнес-логика в приложении — просто удобнее и безопаснее</b>.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Как сеньоры документируют проекты: протокол архитектурных решений</title>
      <link>https://tproger.ru/articles/kak-senory-dokumentiruyut-proekty--protokol-arhitekturnyh-rewenij</link>
      <comments>https://tproger.ru/articles/kak-senory-dokumentiruyut-proekty--protokol-arhitekturnyh-rewenij?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Даровская Маша]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-senory-dokumentiruyut-proekty--protokol-arhitekturnyh-rewenij</guid>
      <description><![CDATA[<p>Как сеньоры документируют архитектуру без боли. Обзор подхода ADR: шаблоны, примеры из практики и комментарии экспертов. Ускорьте онбординг и перестаньте объяснять одно и то же.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-senory-dokumentiruyut-proekty--protokol-arhitekturnyh-rewenij">Как сеньоры документируют проекты: протокол архитектурных решений</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Scala]]></category>
      <category><![CDATA[Amazon]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Lua]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 09 Sep 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p><i>Это перевод <a href="https://dev.to/koladev/how-senior-software-engineers-document-their-project-1nf4">статьи</a> автора <a href="https://dev.to/koladev">Мангабо Колаволе</a> с портала DevTo с комментариями экспертов.</i></p><p>Есть одна задача, которую программисты терпеть не могут — но именно она отличает хорошего инженера от посредственного: как они документируют свой проект? Несколько лет назад я отвечал за запуск финтех-проекта. Мы выбрали стратегию быстрого старта, поэтому масштабируемость не стала для нас приоритетом. Главной целью было проверить гипотезу — и мы двигались вперёд, разрабатывая API, архитектуру и системы —  с упором на простоту, не особенно задумываясь о будущем.</p><p>Но я отвечал за бэкенд и инфраструктуру — и понимал: как бы хороша ни была моя память, через шесть месяцев я не смогу вспомнить все технические детали.</p><p>Во время работы я наткнулся на подход, который мне очень понравился: ADR — Architectural Decision Record, или «протокол архитектурных решений».</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-09-05/7d1206a7-6729-4bcb-ab55-63d59240df12.png" alt="" /></figure><p>По сути, это документ, в котором
фиксируются все изменения, внесённые в архитектуру: само решение, его влияние и
полученные уроки.</p><p>Проще говоря, это как личный дневник —
только для всей команды.</p><h2>Почему это важно?</h2><p><b>Память
— ненадёжна.</b> Мы часто забываем, почему выбрали одну
архитектурную модель, а не другую. Документирование изменений помогает
восстановить ход мыслей и избежать повторения одних и тех же ошибок.</p><p><b>Это
усиливает команду.</b> Представьте, что вы перепробовали
несколько вариантов решения проблемы и зафиксировали как удачные, так и
неудачные попытки. Это не просто ваш личный опыт — это знание, которым могут
воспользоваться все, включая тех, кто придёт после вас.</p><p><b>Будущие
разработчики скажут вам спасибо.</b> Подумайте о человеке,
который через пять лет будет разбираться в вашем коде. Если вы не оставили
объяснений, он, скорее всего, будет мучиться, пытаясь понять, зачем было
сделано то или иное изменение. А теперь представьте другого разработчика в
другой компании, который находит ADR-документ с чётким объяснением принятого
решения. Он, без сомнения, будет вам благодарен.</p><p>Синьор-фронтендер из ВК Маргарита Лукина, автор телеграм-канала <a href="https://t.me/frontend_kitchen">«Фронтенд кухня»</a>:</p><blockquote>Ценность ADR я впервые осознала в 2019 году. В команду, где работала, активно набирали новых ребят, и приблизительно раз в неделю кто-нибудь из новых разработчиков спрашивал "а почему это сделано так, а не иначе?" Приходилось постоянно давать ответы на одни и те же вопросы, и тогда-то я и поняла, насколько будет удобно записывать ответы где-нибудь в документацию в confluence и просто кидать ссылку новичкам. <br /><br />В 2019 году я еще не знала сам термин ADR и говорила "документация". С термином я познакомилась совсем недавно — этим летом, на курсе по архитектуре монолитных приложений. Тогда я поняла, насколько эффективно можно использовать ADR для ускорения разработки и уменьшения TTM. Дело в том, что начиная разрабатывать новый проект, разработчик первое время (от месяца до полугода! всё зависит от размера проекта) погружается в проект — разбирается, как всё устроено, чтобы вносить изменения соответственно архитектуре. В этот период разработчик, по сути, составляет собственные adr —  обычно в виде мыслеобразов в своей голове :) Если записать основные решения, разработчик сможет намного быстрее погрузиться в проект.</blockquote><h2>Как писать ADR?</h2><p>Существует несколько общепринятых правил, но
вы всегда можете адаптировать их под себя.</p><p>Вдохновившее меня соглашение можно найти на <a href="https://adr.github.io/madr/">GitHub</a>
. Вы также можете ознакомиться с процессом <a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html">ADR на Amazon</a>.</p><p>Вот пример шаблона, который вы можете
использовать.</p><p>Такой тип документа может находиться прямо в репозитории проекта, в Confluence или, например, в JIRA.</p><p>В моей последней компании, где я работал фронтенд-разработчиком, не существовало одного централизованного документа, фиксирующего все архитектурные изменения. Вместо этого мы использовали задачи GitLab и привязывали каждое архитектурное изменение к соответствующей ветке. Это позволяло отслеживать причины изменений даже спустя месяцы после их внедрения.</p><p>Практика спасала нас бесчисленное количество раз. Как я всегда говорю: не важно, насколько вы или ваши коллеги умны — будь то технический директор, менеджер или любой другой участник команды — никто не помнит каждое техническое решение, принятое два года назад.</p><p>Синьор-фронтендер из ВК Маргарита Лукина, автор телеграм-канала <a href="https://t.me/frontend_kitchen">«Фронтенд кухня»</a>:</p><blockquote>Многие руководители хотят видеть на своём проекте разработчиков, которые "сразу, без раскачки" начнут перформить. Совсем избежать периода погружения невозможно, но можно ускорить его в десятки раз за счёт ADR</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Куда двигаться после изучения Django: советы для Python-разработчиков</title>
      <link>https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299</link>
      <comments>https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгения Епихина]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299</guid>
      <description><![CDATA[<p>В статье разбираемся, почему Django — далеко не финиш в карьере, и в каких направлениях можно двигаться Python-разработчику.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299">Куда двигаться после изучения Django: советы для Python-разработчиков</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Raspberry Pi]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Асинхронное программирование]]></category>
      <category><![CDATA[Data Science]]></category>
      <category><![CDATA[NoSQL]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Neo4j]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 12 Aug 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Django — это веб-фреймворк на языке Python, который позволяет быстро создавать сложные веб-приложения. Он включает в себя готовые компоненты для работы с базами данных, маршрутизацией URL, обработкой форм, аутентификацией пользователей и админ-панелями, что значительно ускоряет разработку и упрощает поддержку проектов.</p><p>Владение Django — это старт, а не финиш. Чтобы оставаться востребованным, нужно постоянно расширять знания и навыки. В этой статье разберем пути и направления для улучшения своих компетенций.</p><h2>Почему владение Django — не предел для разработчика</h2><h2>Особенности Django</h2><p>Django используют для разработки веб-приложений разной сложности: при работе с большими базами данных, для создания сервисов, способных обслуживать большое количество пользователей. На нём создают соцсети, новостные сайты, веб-версии приложений, онлайн-магазины.</p><p>Основные плюсы:</p><ul><li><b>Полноценный стек</b>: ORM для работы с базой, мощная система маршрутизации URL, шаблоны для рендеринга, встроенная админка, формы, система аутентификации и авторизации.</li><li><b>Архитектура MTV (Model-Template-View)</b>: похожа на классический MVC, но с особенностями, которые упрощают разделение логики, представления и данных.</li><li><b>Безопасность</b>: Django автоматически защищает от CSRF, XSS, SQL-инъекций и других распространенных атак. Не нужно писать много дополнительного кода.</li><li><b>Активное сообщество и экосистема</b>: тысячи сторонних пакетов, расширений и готовых решений.</li><li><b>Поддержка нескольких баз данны</b>х: PostgreSQL, MySQL, SQLite, Oracle и др.</li></ul><p>Ограничения:</p><ul><li><b>Синхронная природа Django</b>.</li><li><b>Монолитность</b>: архитектура фреймворка ориентирована на создание крупных приложений, но в микросервисах может быть избыточна.</li><li><b>Ограниченная гибкость ORM</b>: нестандартные SQL-запросы иногда сложно выразить средствами ORM, приходится использовать raw SQL или сторонние библиотеки для запросов.</li><li><b>Строгие правила организации кода</b>: требуют дисциплины и могут ограничивать свободу в архитектурных решениях.</li><li><b>Недостаточная производительность</b>: уступает лёгким асинхронным фреймворкам (например, FastAPI), особенно под высокими нагрузками. Но для большинства проектов пока это не критично.</li></ul><h2>В каком направлении двигаться после изучения Django</h2><blockquote>Задача — создавать продукт, который будет нужен конечному потребителю.</blockquote><h3>Первое направление для развития — расширить инструментарий для решения разных задач в веб-разработке</h3><p>Возможные пути:</p><ul><li>Изучить другие веб-фреймворки (Flask, FastAPI)</li><li>Углубиться в асинхронное программирование (asyncio, aiohttp)</li><li>Работать с API и микросервисами</li></ul><h4>Flask и FastAPI</h4><p>Flask — минималистичный микрофреймворк, даёт полную свободу в выборе компонентов. Используют для небольших приложений и микросервисов.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-08-12/bbe7c040-14de-426d-9a10-c556f7319bee.png" alt="" /><figcaption>Пример простой команды на Flask</figcaption></figure><p>FastAPI — современный асинхронный фреймворк, ориентирован на создание высокопроизводительных API. Поддерживает стандарт OpenAPI и автоматическую генерацию документации. Он быстрее Flask и Django благодаря asyncio и Pydantic.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-08-12/33a27277-5136-4a03-8af2-f436db42fa99.png" alt="" /><figcaption>Пример простого API на FastAPI</figcaption></figure><h4>Асинхронное программирование</h4><p>Веб-разработка всё активнее использует асинхронные технологии. Django не всегда справляется с задачами высокой конкурентной нагрузки.</p><p>Поэтому изучение asyncio — стандартной библиотеки Python для асинхронного программирования — откроет перед вами новые возможности. Вместе с aiohttp или тем же FastAPI вы сможете создавать приложения, которые обрабатывают тысячи одновременных соединений. Это особенно важно для real-time сервисов, чат-приложений и систем с интенсивным обменом данными.</p><h3>Второе направление — расширить навыки в смежных областях</h3><p>Можно пойти по пути расширения компетенций за пределы основной специализации. Важно не только уметь писать код, но и понимать, как приложения разворачиваются и работают в продакшене. Знание DevOps-практик помогает наладить эффективное взаимодействие между разработкой и эксплуатацией.</p><h4>Изучение DevOps и контейнеризации</h4><p>Контейнеры позволяют запускать приложения в изолированной среде, это упрощает настройку и развертывание. Например, Docker помогает упаковать приложение с зависимостями в один контейнер, а Kubernetes — управлять такими контейнерами в продакшене. Знание этих технологий улучшит взаимодействие с операционной командой и ускорит выпуск новых версий приложений.</p><h4>CI/CD и автоматизация процессов</h4><p>Непрерывная интеграция (Continuous Integration) и непрерывное развертывание (Continuous Deployment) — ключевые практики современной разработки ПО. Они позволяют автоматизировать сборку, тестирование и доставку приложений, масштабировать процессы.</p><p>Инструменты CI/CD (например, Jenkins, GitLab CI/CD, GitHub Actions) помогают настроить автоматические пайплайны, которые обеспечивают быструю обратную связь и минимизируют человеческий фактор в релизах. Автоматизация процессов снижает количество ошибок и позволяет сосредоточиться на разработке новых функций.</p><p>Настройка непрерывной интеграции и доставки (Continuous Integration / Continuous Delivery) снижает поток ошибок при релизах и экономит время. Пример: GitHub Actions для автоматического запуска тестов и сборки проекта при каждом коммите.</p><h4>Больше знаний в области баз данных</h4><p>Помимо классических реляционных баз данных (PostgreSQL, MySQL), современные приложения часто используют NoSQL для специфичных задач. MongoDB, Redis, Cassandra обеспечивают гибкость в хранении данных, горизонтальное масштабирование и высокую производительность при работе с большими объемами информации.</p><p>Графовые базы данных (Neo4j, ArangoDB) предназначены для эффективного хранения и анализа связей между объектами, что важно для социальных сетей, рекомендательных систем и других приложений с богатой структурой.</p><p>Так, Redis хорошо подходит для кэширования данных, а Neo4j — для сложных связей между объектами.</p><h3>Третье направление — переход к другим аспектам Python-разработки</h3><p>Рассмотрим четыре варианта карьерного развития для Python-программиста: Data Science и машинное обучение, автоматизация бизнес-процессов, разработка десктопных приложений и встраиваемые системы (IoT).</p><p>Почему стоит попробовать?</p><ul><li>Высокий спрос на специалистов. Они востребованы в банках и инвестиционных компаниях, в сфере медицины и биотехнологии, в консалтинге,  автомобильной промышленности и т.д..</li><li>Широкий набор библиотек: pandas, NumPy, scikit-learn, TensorFlow, PyTorch.</li><li>Возможность работать с реальными задачами: от бизнеса до науки.</li></ul><h4>Автоматизация и скрипты для бизнеса</h4><p>Python часто используется для автоматизации рутинных задач: парсинга данных, обработки файлов, интеграции систем, генерации отчетов. Создание скриптов для автоматизации бизнес-процессов помогает повысить эффективность работы и снизить количество ошибок.</p><p>Знание таких библиотек, как openpyxl (работа с Excel), requests (HTTP-запросы), BeautifulSoup и Scrapy (парсинг веб-страниц), а также умение писать скрипты под конкретные задачи, делают разработчика ценным специалистом в корпоративной среде.</p><p>Примеры задач:</p><ul><li>Автоматическая загрузка данных из Excel и их преобразование</li><li>Скрипты для отправки email-рассылок</li><li>Интеграция с CRM и другими сервисами через API</li></ul><h4>Разработка десктопных приложений (PyQt, Kivy)</h4><p>Хотя сейчас популярность уходит к вебу и мобильным платформам, десктопные приложения на Python востребованы в таких сферах: инструменты для анализа, редакторы, утилиты.</p><p>Инструменты для создания:</p><ul><li>PyQt — мощный фреймворк для создания кроссплатформенных GUI.</li><li>Kivy — библиотека для разработки приложений с поддержкой сенсорных экранов.</li></ul><p>Этот путь подходит тем, кто хочет создавать удобные инструменты с графическим интерфейсом для пользователей на Windows, macOS или Linux.</p><h4>Встраиваемые системы и IoT</h4><p>В области IoT и встроенных систем Python набирает популярность благодаря легкости освоения и поддержке на маломощных устройствах. Помогают в этом  платформы по типу Raspberry Pi и MicroPython.</p><p>Изучение этого направления открывает возможности работы с аппаратным обеспечением, созданием прототипов и внедрением инновационных решений в промышленности и бытовой технике.</p><p>Например, с помощью Python на Raspberry Pi можно  разрабатывать датчики для мониторинга состояния оборудования на производстве и разрабатывать прототипы носимых устройств для сбора данных о здоровье.</p><blockquote>Если рассматривать профессию “Python-разработчик на Django”, то сразу получится сужение до конкретной библиотеки на конкретном языке. Если же в резюме у специалиста стоит, что он “разработчик Python”, возможностей сильно больше. Если написать про себя “разработчик”, будет не понятно, разработчик чего. Но изменив резюме на “DevOps инженера”, становится понятен карьерный трек.</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Вредные советы по работе с базами данных, или как расстроить DBA</title>
      <link>https://tproger.ru/articles/vrednye-sovety-po-rabote-s-bazami-dannyh--ili-kak-rasstroit-dba</link>
      <comments>https://tproger.ru/articles/vrednye-sovety-po-rabote-s-bazami-dannyh--ili-kak-rasstroit-dba?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/vrednye-sovety-po-rabote-s-bazami-dannyh--ili-kak-rasstroit-dba</guid>
      <description><![CDATA[<p>Сборник самых раздражающих ошибок в работе с базами данных — с примерами и советами, как делать правильно. По выпуску подкаста «Техно.Логично».</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/vrednye-sovety-po-rabote-s-bazami-dannyh--ili-kak-rasstroit-dba">Вредные советы по работе с базами данных, или как расстроить DBA</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Oracle]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Инновации]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 08 Aug 2025 08:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда разработчик говорит «база упала», администратор баз данных вздыхает и открывает логи. Снова кто-то решил, что временные файлы бесконечны. Или создал 47 индексов на одной таблице. Или оставил транзакцию висеть на выходные.</p><p>Классические ошибки повторяются с завидным постоянством. В недавнем выпуске подкаста «Техно.Логично» наши коллеги Владимир Герциков и Николай Волынкин как раз обсуждали типичные проблемы с базами данных — от выбора инструментов до падений в продакшне. Послушав коллег, мы решили не пересказывать их беседу целиком, а на основе их беседы сделать практический список вредных советов.</p><p>Получился антигайд: как гарантированно завалить базу данных — и что делать правильно. Если узнаете себя в этих советах, не расстраивайтесь. Через подобное проходят все. А если хотите услышать полную дискуссию о современных СУБД, инструментах и миграции на open source — послушайте <a href="https://vk.com/video-145457488_456239847?access_key=b17a8de1d4db2dde5d">оригинальный выпуск</a>.</p><h2>1. Временные файлы бесконечны — лейте терабайты джойнов</h2><p>Берите две таблицы по миллиону записей каждая, смело делайте JOIN без WHERE, сортируйте результат — и удивляйтесь, почему закончилось место под временные данные.</p><p><b>Что происходит</b>: PostgreSQL создает временные файлы в pg_tmp для обработки больших запросов. Когда места не хватает, падают конкретные запросы с ошибкой <i>No space left on device</i>, а не весь сервер. Особенно болезненно там, где несколько таких запросов запускаются параллельно — временное пространство переполняется быстрее, чем успевает сработать мониторинг.</p><p><b>Как делать правильно</b>: Планируйте размер временных данных заранее. Добавляйте фильтры перед джойнами, разбивайте сложные запросы на этапы. Настройте temp_file_limit для ограничения временных файлов на запрос и мониторинг заполнения. Если ваш запрос генерирует терабайты промежуточных результатов, скорее всего, есть способ сделать это эффективнее.</p><h2>2. Суперпользователь для всех задач — что может пойти не так</h2><p>Создайте пользователя с правами суперадминистратора, используйте его для всех подключений и смело устанавливайте любые расширения, найденные в интернете.</p><p><b>Реальная история:</b> Разработчик развернул постгрес на виртуалке с дефолтными настройками — порт 5432 открыт, пользователь <i>postgres/postgres</i> с правами суперпользователя. Через семь (!) секунд в базу начали ломиться боты. Боты сканируют интернет на стандартные порты СУБД постоянно и превращают сервер в майнинг-ферму быстрее, чем вы успеете допить кофе. Диск переполнился от созданных таблиц, установились неизвестные расширения, начались HTTP-вызовы из базы наружу. Сервер превратился в часть ботнета.</p><p><b>И так все понятно, но еще раз напомним</b>: Суперпользователь может подключить postgres_fdw, dblink и читать/писать любые базы кластера, создавая запросы, которые переполнят временное пространство за минуты. Неподписанные расширения могут содержать что угодно — от бэкдоров до майнеров. А если расширение вызовет <i>segmentation fault</i>, упадет вообще все.</p><p><b>Принцип минимальных прав:</b> Создавайте отдельных пользователей с минимально необходимыми правами. Устанавливайте только официально поддерживаемые расширения. Закрывайте базу от внешнего доступа файрволом, настройте TLS для шифрования трафика, используйте fail2ban против брутфорса и уникальные пароли. Это кажется очевидным, но количество баз с дефолтными паролями в интернете говорит об обратном.</p><h2>3. Держите транзакции открытыми — счетчик XID все стерпит</h2><p>Открывайте длинные транзакции и держите их днями. Постгерс умный, сам разберется.</p><p><b>Что сломается:</b> У PostgreSQL есть счетчик транзакций (XID), который может переполниться. Когда возраст транзакций становится критическим, сервер блокирует обычные подключения и пускает только суперпользователя для выполнения <i>VACUUM FULL</i>. Все приложения встают, начинается паника.</p><p><b>Как избежать:</b> Настройте timeout для idle in transaction состояний. Разбивайте большие батчи на маленькие операции. Мониторьте возраст самых старых транзакций. И запомните: транзакция, которая висит неделю, — это не фича, это бомба замедленного действия.</p><h2>4. На каждый SELECT — свой индекс</h2><p>Создавайте индекс под каждый запрос. Чем больше индексов, тем быстрее будет работать.</p><p><b>Почему это убивает PostgreSQL: </b>В отличие от других СУБД, PostgreSQL при UPDATE создает новую версию записи, а старую помечает как мертвую. Если у таблицы 30 индексов, каждый UPDATE генерирует 30 мертвых ссылок в индексах. VACUUM начинает работать постоянно, производительность рушится.</p><p><b>Правило 20/80: </b>Покройте индексами 20% самых частых запросов, которые дают 80% нагрузки. Остальную аналитику выносите на реплику для чтения. Регулярно анализируйте статистику использования индексов — неиспользуемые безжалостно удаляйте .</p><h2>5. Сайзинг не нужен</h2><p>Ресурсы бесконечны. А DBA разберутся, как бэкапить ваши 100 терабайт.</p><p><b>Физические ограничения:</b> Таблица в PostgreSQL не может быть больше 32 терабайт при дефолтном размере блока. Ограничение можно обойти партиционированием или пересборкой с увеличенным размером блока, но лучше планировать заранее.</p><p><b>Экономика:</b> «Эта функция будет стоить как два сервера, потому что нам нужно оборудование для бэкапа 50-терабайтной базы». В этот момент «бизнес» делает большие глаза и внезапно появляется мотивация оптимизировать архитектуру.</p><p><b>Планирование:</b> Считайте размер данных на год-два вперед. Внедряйте партиционирование с первого дня, если ожидаете рост. Архивируйте старые данные. Удалить лишнее проще, чем добыть дополнительные терабайты дискового пространства в пятницу вечером.</p><h2>6. Пихайте СУБД в контейнеры</h2><p>Kubernetes решает все проблемы! Поэтому переносим в контейнеры все, базы данных тоже. Если что-то работает на виртуалках, то в контейнерах точно будет работать лучше.</p><p><b>Проблемы слоеного пирога:</b> Мы слышали, тебе нравится виртуализация, поэтому мы добавили виртуализацию в твою виртуализацию. В результате кратное усложнение отладки. Где тормозит база: железо, гипервизор, менеджер контейнеров?</p><p><b>Где контейнер оправдан?</b>  В CI/CD, локальной разработке, тестовых средах. В продакшне контейнеры тоже работают, если использовать Kubernetes-операторы (Patroni, CloudNativePG), правильно настроить Persistent Volumes и протестировать поведение при рестартах. База должна жить в памяти, прогревать кэши, работать стабильно. Но это требует серьезной экспертизы в Kubernetes и готовности разбираться с проблемами на стыке технологий. Если команда не готова изучать все тонкости — лучше не начинать.</p><p><b>Компромисс:</b> Если выбираете контейнеры для продакшна, используйте StatefulSet, настройте правильные storage-классы и OOM-политики. Для stateless-сервисов контейнеры — отличный выбор.</p><h2>7. Всю бизнес-логику держим в хранимках — так быстрее</h2><p>Переносите всю логику в базу. Зачем нужны сервисы приложений?</p><p><b>Пример из практики:</b> Система с хранимыми процедурами Oracle обыграла Java-реализацию в тестах производительности. Логика выполнялась рядом с данными, без сетевых задержек. Но когда нагрузка выросла в разы, уперлись в лимит CPU на сервере баз данных. Добавить ресурсы оказалось сложнее, чем масштабировать stateless-сервисы.</p><p><b>Компромисс:</b> Тяжелые агрегации и отчеты делайте в функциях базы. CRUD-операции выносите в сервисы приложений. Следите за загрузкой CPU на сервере БД — когда она приближается к пределу, начинайте выносить логику наружу.</p><h2>8. Коммерческая СУБД — единственный путь</h2><p>Только коммерческие решения подходят для серьезных задач. Oracle и SQL Server проверены временем, а всякие open source базы — это для студентов и стартапов.</p><p><b>Что изменилось:</b> События последних лет заставили многие компании пересмотреть подход к выбору СУБД. Компании массово переходят на PostgreSQL Pro и другие open source решения. Тренд только усиливается — игнорировать open source значит отстать от рынка и пропустить инновации, которые часто появляются именно в открытых проектах.</p><p><b>НО:</b> Vanilla PostgreSQL без поддержки — это действительно риск. Когда расширение Oracle FDW падает с разными структурами таблиц, а автор из коммьюнити отвечает «мне в голову не приходило, что кто-то будет так делать», понимаешь ценность платной поддержки. Поэтому open source, но с поддержкой от надежных вендоров.</p><h2>Заключение</h2><p>Продовые пожары в базах данных всегда случаются в самый неподходящий момент. Но большинство из них можно предотвратить, следуя простым правилам: планировать ресурсы, ограничивать права, мониторить метрики.</p><p>Выберите один совет из этой статьи и примените его сегодня. Возможно, это сэкономит вам несколько часов сна в будущем. А коллеги-DBA скажут спасибо.</p>]]></content:encoded>
    </item>
    <item>
      <title>Энтузиаст замедлил PostgreSQL в 42 000 раз с помощью 32 параметров — и ни одной строчки кода</title>
      <link>https://tproger.ru/news/--entuziast-zamedlil-postgresql-v-42-000-raz-s-pomoshhyu-32-parametrov---i-ni-odnoj-strochki-koda</link>
      <comments>https://tproger.ru/news/--entuziast-zamedlil-postgresql-v-42-000-raz-s-pomoshhyu-32-parametrov---i-ni-odnoj-strochki-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--entuziast-zamedlil-postgresql-v-42-000-raz-s-pomoshhyu-32-parametrov---i-ni-odnoj-strochki-koda</guid>
      <description><![CDATA[<p>Энтузиаст замедлил PostgreSQL в 42 000 раз без кода — только с помощью 32 настроек в конфиге. От 7000 TPS до 0,016 за 2 минуты</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--entuziast-zamedlil-postgresql-v-42-000-raz-s-pomoshhyu-32-parametrov---i-ni-odnoj-strochki-koda">Энтузиаст замедлил PostgreSQL в 42 000 раз с помощью 32 параметров — и ни одной строчки кода</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 28 Jul 2025 03:58:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Один энтузиаст решил выяснить не <b>как ускорить</b>, а <b>как максимально замедлить PostgreSQL</b>.</p><p>И ему это <a href="https://byteofdev.com/posts/making-postgres-slow/">удалось</a>: производительность упала с <b>7082 транзакций в секунду до 0,016 TPS</b>, то есть более чем в <b>42 000 раз</b>.</p><p>Причем он не трогал железо, не удалял индексы и не вмешивался в код — все только через postgresql.conf.</p><h2>Минимальный кэш и перегруженный autovacuum</h2><p>Первый шаг — почти отключить кэш: shared_buffers = 2MB. Это резко снижает буферизацию страниц и увеличивает обращения к диску.</p><p>Затем — заставить Postgres непрерывно запускать autovacuum и analyze после каждой вставки. В итоге в логи будут падать десятки операций в секунду. Почти без пользы, но с большим I/O.</p><h2>WAL, как у Брэндона Сандерсона</h2><p>Потом автор усложнил систему логов WAL: настроил частые чекпоинты (checkpoint_timeout = 30, max_wal_size = 32MB) и принудил Postgres писать каждый байт максимально медленно (wal_sync_method = open_datasync, wal_level = logical).</p><p>Производительность упала до <b>менее 1 TPS</b>.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-07-28/3df2f851-d3ea-40df-b64b-7447af3bbb93.jpeg" alt="" /></figure><h2>Отключение индексов и однопоточный I/O</h2><p>Без удаления самих индексов автор просто сделал их бессмысленными для планировщика запросов: random_page_cost и cpu_index_tuple_cost были задраны до 1e300.</p><p>Вдобавок, Postgres был переведен на io_method = worker с io_workers = 1, чтобы все дисковое I/O выполнялось одним потоком.</p><h2>Финал</h2><p>В итоге Postgres смог обработать <b>всего 11 транзакций за 2 минуты</b> со 100 подключениями.</p><p>Эксперимент не только впечатляющий, но и полезный: он показывает, насколько надежно Postgres защищен от «случайного самоуничтожения». Но если очень захотеть — можно все.</p>]]></content:encoded>
    </item>
    <item>
      <title>10 библиотек Python, которые меняют карьеру</title>
      <link>https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru</link>
      <comments>https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru</guid>
      <description><![CDATA[<p>10 библиотек Python, которые помогут прокачаться в аналитике, ML и разработке. Как они работают и почему меняют карьеру.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru">10 библиотек Python, которые меняют карьеру</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Jupyter Notebook]]></category>
      <category><![CDATA[Визуализация]]></category>
      <category><![CDATA[Образование]]></category>
      <category><![CDATA[OpenAI]]></category>
      <category><![CDATA[Анализ данных]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 17 Jul 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>У Python тысячи библиотек, но лишь немногие действительно меняют карьеру. Они помогают не просто решать задачи, а ускорять проекты, прокачивать навыки и выходить на следующий уровень в аналитике, машинном обучении и разработке. В этом материале мы собрали 10 библиотек, которые помогут зарабатывать на Python и развивать навыки.</p><h2>1. Pandas</h2><p>Pandas — библиотека для работы с данными в Python, позволяющая легко загружать, анализировать, очищать и преобразовывать числовую информацию в удобной табличной форме. По сути, это Excel, который смог, и позволяет делать всё автоматизировано и на порядки быстрее.</p><p>Библиотека строится вокруг двух ключевых структур: <b>Series</b> (одномерный массив с индексами); <b>DataFrame </b>(таблица с индексами и колонками).</p><h3>Какие задачи решает библиотека</h3><p>Pandas полезна для следующих задач:</p><ul><li>Сам анализ данных: можно быстро фильтровать, группировать, агрегировать и строить сводные таблицы.</li><li>Очистка данных: удаляем пустые строки, заменяем значения, приводим типы.</li><li>Загрузка данных из CSV, Excel, SQL.</li><li>Визуальная разведка данных (EDA) перед построением моделей.</li><li>Подготовка данных для ML и отчётов.</li><li>Автоматизация отчётов и ETL-пайплайнов.</li></ul><p>Благодаря Pandas аналитик превращается в инженера данных, а ML-специалист может сосредоточиться на моделях, а не на ручной подготовке датасетов.</p><h3>Как пользоваться</h3><p>Ниже разберём простейший кейс: нужно загрузить данные о зарплатах разработчиков из CSV, посчитать среднюю зарплату по языкам программирования и отобрать топ-5.</p><h3>Почему это меняет карьеру</h3><p>Работа с Pandas становится границей между знанием Python и умением решать задачи бизнеса. Для <b>джуна </b>это шанс сразу показать практическую пользу: выгрузки, отчёты и базовый анализ можно делать в десятки раз быстрее и аккуратнее, чем вручную в эксельке.</p><p>Для <b>аналитика</b> Pandas превращается в главный рабочий инструмент, позволяя не просто проверять гипотезы и делать сводные таблицы, а строить полноценные отчётные пайплайны, автоматизировать рутинные выгрузки и концентрироваться на сути данных, а не на правках ручками.</p><p>Для <b>ML-инженера</b> владеть Pandas — значит уметь готовить датасеты качественно; быстро очищать и приводить данные к нужному виду, что напрямую влияет на результат моделей. Без этого работа над проектами машинного обучения часто превращается в бесконечную возню с данными.</p><p>Наконец, даже для <b>разработчиков</b> Pandas может стать неожиданным бустом в карьере. Например, когда нужно автоматизировать отчёты для бизнеса или быстро анализировать логи и данные из БД без поднятия дашбордов — Pandas даёт гибкость и скорость, которые редко даёт что-то ещё в экосистеме Python.</p><h2>2. Django</h2><p>Django — фреймворк для веб-разработки на Python, который позволяет быстро создавать надежные и масштабируемые веб-приложения. Он следует принципам DRY (Don’t Repeat Yourself — не повторяй себя), предоставляя разработчику ORM, роутинг, систему авторизации, админку, работу с формами, шаблонами и инструментами безопасности из коробки.</p><p>Django подходит как стартапам, которым нужно быстро выйти на рынок, так и крупным проектам с миллионами пользователей. Это не просто библиотека, а полноценный каркас для построения и сопровождения веб-сервисов.</p><h3>Какие задачи решает библиотека</h3><p>Каркас, действительно, каркасный. Задачи следующие:</p><ul><li>Создание веб-приложений и API любой сложности.</li><li>Быстрая разработка MVP, прототипов и коммерческих проектов.</li><li>Упрощение работы с базами данных через ORM, без написания сырого SQL.</li><li>Построение административных панелей для управления данными без ручной разработки.</li><li>Гибкая маршрутизация и работа с формами, валидацией и шаблонами.</li><li>Реализация аутентификации, авторизации и защиты приложений.</li></ul><p>Django позволяет сосредоточиться на бизнес-логике и продукте, не тратить недели на настройку инфраструктуры.</p><h3>Как пользоваться</h3><p>Устанавливаем:</p><p>Создаем проект и приложение:</p><p>Пример модели:</p><p>Миграция базы данных:</p><p>Создание админки:</p><p>После этого можно запустить сервер:</p><p>И перейти по адресу http://127.0.0.1:8000/admin для управления записями через готовую админ-панель.</p><h2>3. PyTorch</h2><p>PyTorch — мощная библиотека Python. Она позволяет строить и обучать нейронные сети, проводить вычисления с автоматическим дифференцированием и работать с GPU для ускорения самих вычислений.</p><p>Главное отличие PyTorch от других ML-фреймворков — динамическая вычислительная графика (define-by-run): модель строится и изменяется во время выполнения кода, что даёт гибкость при создании и отладке сложных моделей.</p><p>Сегодня PyTorch используется в продакшен системах, научных исследованиях, компьютерном зрении, NLP и генеративных моделях, занимая ведущее место в индустрии.</p><h3>Какие задачи решает библиотека</h3><p>В функционал PyTorch входят:</p><ul><li>Построение нейронных сетей любой сложности (CNN, RNN, трансформеры);</li><li>Обучение и тестирование моделей на CPU и GPU;</li><li>Реализация кастомных слоёв и loss-функций;</li><li>Разработка и деплой ML/AI моделей в продакшен;</li><li>Быстрая итерация гипотез с удобной отладкой.</li></ul><p>С PyTorch можно начать с простых нейронных сетей, а затем перейти к реализации современных архитектур.</p><h3>Как пользоваться</h3><p>Установим PyTorch (на CPU, для GPU потребуется версия с CUDA):</p><p>Рассмотрим кейс обучения простой нейронной сети для классификации рукописных цифр MNIST.</p><p>После обучения можно использовать torch.save() для сохранения модели и torch.load() для загрузки в продакшн.</p><h3>Почему это меняет карьеру</h3><p>PyTorch — билет в мир современной разработки AI и машинного обучения. Владение инструментом даёт <b>разработчику</b> возможность уверенно войти в области, которые продолжают оставаться топовыми на рынке: искусственный интеллект, компьютерное зрение, NLP, генерация изображений и видео и т.д.</p><p>Для <b>начинающего ML/AI-специалиста </b>PyTorch помогает лучше понять, как устроены нейронные сети, и под капотом увидеть, как происходят вычисления. Это ускоряет рост навыков и делает разработчика востребованным в исследованиях и R&amp;D-проектах.</p><p>Для <b>дата-сайентистов</b> PyTorch позволяет превратить исследовательские ноутбуки в готовые к деплою модели, благодаря PyTorch Lightning, TorchScript и ONNX.</p><p>Для<b> разработчиков, которые хотят выйти на рынок AI</b>, PyTorch — это мастхев: проекты в стартапах и крупных компаниях всё чаще строятся вокруг него. Умение писать кастомные loss-функции, проектировать сложные пайплайны обучения, настраивать обучение на кластерах и GPU — компетенции, которые существенно бустят зарплату.</p><p>PyTorch в целом помогает расширять портфолио: с ним можно создавать генеративные модели, строить LLM, участвовать в соревнованиях и работать с самыми современными подходами в машинном обучении.</p><h2>4. Polars</h2><p>Polars — современная библиотека для обработки данных в Python, созданная как альтернатива Pandas. Она использует колоночную архитектуру и многопоточность, что позволяет работать с большими объёмами данных значительно быстрее и с меньшим потреблением памяти.</p><p>Polars вдохновлена Pandas, но её API оптимизировано для производительности и удобства, а также даёт разработчику возможность писать цепочки ленивых вычислений, которые оптимизируются перед выполнением. Это делает её отличным инструментом для аналитиков, дата-инженеров и дата-сайентистов, которым нужно обрабатывать данные быстро.</p><h3>Какие задачи решает библиотека</h3><p>Polars явно есть, чем гордиться:</p><ul><li>Загрузка, очистка и преобразование больших датасетов;</li><li>Анализ данных с использованием цепочек преобразований;</li><li>Быстрая агрегация и группировка данных;</li><li>Ленивые вычисления: построение пайплайнов преобразования данных, которые выполняются только при вызове collect().</li><li>Обработка данных, которые не помещаются в память, за счёт эффективности и колоночной архитектуры.</li></ul><p>Если Pandas начинает притормаживаться на данных в несколько гигабайт, Polars обычно продолжает работать быстро, позволяя без боли обрабатывать большие CSV.</p><h3>Как пользоваться</h3><p>Установка:</p><p>Давайте загрузим данные и проведем базовые трансформации:</p><p>А вот и пример ленивых вычислений:</p><p>В чем особенность:</p><ul><li>pl.read_csv загружает данные сразу.</li><li>pl.scan_csv создаёт план вычислений для последующей оптимизации.</li><li>Используются выражения (pl.col, .with_columns, .agg), которые композируются без создания промежуточных копий, это ускоряет процесс.</li></ul><h3>Почему это меняет карьеру</h3><p>Polars меняет карьеру, потому что даёт преимущество в скорости и эффективности при работе с данными. Там, где Pandas уже не справляется, полярный медведь приходит на помощь.</p><p>Для <b>дата-инженеров</b> Polars полезен при построении ETL и пайплайнов обработки данных, где важна скорость и предсказуемое потребление ресурсов. Его можно использовать в продакшен-скриптах, для подготовки данных к ML и для автоматизации отчётности.</p><p>Для <b>дата-сайентистов </b>Polars даёт возможность анализировать больше данных за меньшее время, быстро итерировать гипотезы и ускорять исследования. Его API достаточно близок к Pandas, поэтому переход не требует месяцев переучивания.</p><p>Освоение Polars показывает работодателям, что ты не просто знаешь стандартные инструменты, но умеешь выбирать оптимальные решения для реальных задач, повышая эффективность работы команды. В эпоху роста данных это критично для любого Python-разработчика, работающего с аналитикой и машинным обучением.</p><h2>5. FastAPI</h2><p>FastAPI — современный фреймворк для создания API на Python, заточенный под скорость, асинхронность и валидацию данных из коробки. Он построен на Starlette и Pydantic, автоматически создаёт OpenAPI-документацию, поддерживает асинхронное программирование и позволяет писать производительные REST и WebSocket API с минимальным количеством кода.</p><p>Вместо долгой настройки, как у Flask или Django, в FastAPI многое готово изначально: удобная работа с запросами и ответами, декларативная валидация, документация Swagger, асинхронность и высокая производительность без лишних усилий.</p><h3>Какие задачи решает</h3><p>Задач, действительно, много:</p><ul><li>Быстрая разработка REST API для мобильных и веб-приложений;</li><li>Создание бэкенда для ML/DS моделей (деплой моделей в виде API);</li><li>Построение микросервисов с хорошей производительностью;</li><li>Реализация websocket-серверов и асинхронных API;</li><li>Подготовка внутренних инструментов или бэкендов для MVP.</li></ul><p>FastAPI помогает быстро запускать API и уверенно масштабировать его в полевых условиях. Это один из немногих фреймворков Python, который по скорости работы сопоставим с Node.js и Go.</p><h3>Как пользоваться</h3><p>Во-первых, нужно установить FastAPI и Uvicorn (используем ASGI-сервер для запуска):</p><p>Простейший API-пример с эндпоинтом GET /:</p><p>Запускаем сам сервер:</p><p>После запуска API будет доступен по адресу http://127.0.0.1:8000/. Автоматически доступна интерактивная документация Swagger по адресу http://127.0.0.1:8000/docs.</p><p>FastAPI поддерживает валидацию параметров запроса, тел запросов и путей прямо через типы Python. Например, простой эндпоинт с параметром:</p><p>При вызове http://127.0.0.1:8000/items/10?q=test FastAPI автоматически проверит, что item_id — это число, и распарсит q как строку.</p><h3>Почему это меняет карьеру</h3><p>FastAPI — билет в мир бэкенда, где скорость и чистота кода имеют довольно высокое значение. Для <b>Python-разработчика </b>это возможность быстро освоить создание API и микросервисов, не увязнув в громоздкой настройке, как в Django, и при этом получить систему, готовую к продакшену.</p><p>Для <b>ML-специалиста</b> FastAPI становится инструментом для деплоя моделей: можно обернуть пайплайн предсказаний в API, подключить авторизацию или логирование и получить работающий сервис за считанные дни.</p><p>Вообще умение быстро поднимать и поддерживать API — навык, который ценят в бигтехе и стартапах. На разработчиков, которые владеют FastAPI, часто равняются: они умеют превращать идеи бизнеса в работающие сервисы за минимальное время.</p><h2>6. Typer</h2><p>Typer — современная библиотека для создания CLI-приложений на Python с минимальным количеством кода и автоматической генерацией документации. Автор библиотеки — Себастьян Рамирес, создатель FastAPI.</p><p>Главная особенность Typer — использование type hints для автоматического парсинга аргументов командной строки. Вы получаете удобную и читаемую CLI с поддержкой автодополнения и цветного вывода за считанные минуты.</p><h3>Какие задачи решает библиотека</h3><p>Список задач такой:</p><ul><li>Создание CLI-утилит любого уровня сложности.</li><li>Быстрое прототипирование и упаковка Python-скриптов в удобные инструменты для продакшена.</li><li>Генерация подробной справки (--help) и автодополнения команд.</li><li>Облегченная поддержка и масштабирование CLI за счёт структуры и читаемого кода.</li><li>Организация CLI с подкомандами, вложенными аргументами и обработкой ошибок.</li></ul><p>Typer использует аннотацию типов и минимум шаблонного кода.</p><h3>Как пользоваться</h3><p>Установка:</p><p>Пример минимальной CLI:</p><p>Теперь можно запустить из консоли:</p><p>Результат будет такой: Привет, Алиса! Тебе 25 лет.</p><h3>Почему это меняет карьеру</h3><p>Typer меняет карьеру тем, что открывает путь к созданию удобных CLI-инструментов, которые автоматизируют рутину и повышают продуктивность.</p><p>С Typer можно быстро превращать свои Python-скрипты в надежные утилиты, которыми удобно пользоваться и другим разработчикам, и сотрудникам из других отделов. CLI-приложения часто становятся клеем инфраструктуры: они позволяют автоматизировать деплой, миграции БД, сбор данных, интеграцию с внешними API и локальную разработку.</p><p>Если вы <b>Data Scientist или ML-инженер</b>, Typer позволяет оборачивать пайплайны в CLI, которые легко запускать из Jenkins, Airflow или вручную. Если вы <b>DevOps или Backend-инженер</b>, можете создавать CLI для работы с инфраструктурой и сервисами без сложных зависимостей.</p><p>Кроме того, работа с Typer улучшает навык структурирования кода, понимание CLI, использования type hints и разработки инструментов, которые делают работу проще для других. А это, очевидно, ценится в любой команде и повышает востребованность специалиста.</p><h2>7. Rich</h2><p>Rich — библиотека Python для красивого форматирования и интерактивного отображения информации в терминале. С её помощью можно выводить цветные таблицы, маркдаун, прогресс-бары, подсвеченный синтаксис кода, деревья каталогов и логирование в понятной и привлекательной форме.</p><p>Rich создана для того, чтобы «оживить» консоль Python, сделать логи удобными для восприятия, а CLI-инструменты — профессионально выглядящими без лишних усилий. Это библиотека, которая улучшает и UX, и DX.</p><h3>Какие задачи решает</h3><p>Про красоту не забываем! Задачи следующие:</p><ul><li>Цветное и структурированное логирование, понятное при чтении логов в реальном времени.</li><li>Отображение прогресс-баров для долгих операций.</li><li>Вывод таблиц, деревьев каталогов, JSON прямо в терминале.</li><li>Подсветка синтаксиса кода для CLI-инструментов.</li><li>Создание CLI-интерфейсов, которые выглядят профессионально и современно.</li><li>Улучшение читаемости при отладке скриптов.</li></ul><p>С помощью Rich можно быстро сделать понятными даже сложные данные при отладке или демонстрации.</p><h3>Как пользоваться</h3><p>Установка Rich:</p><p>Для примера выведем таблицу с подсветкой в консоли:</p><p>В результате в терминале получится цветная таблица, которая выглядит понятно и презентабельно.</p><h3>Почему это меняет карьеру</h3><p>Rich — это библиотека, которая помогает быстро повысить качество любого CLI-инструмента или дев-опыт в команде. <b>Разработчик</b>, который использует Rich, делает свои инструменты удобными не только для себя, но и для коллег: логирование становится понятным, а отладка скриптов — наглядной.</p><p>Во многих стартапах и продвинутых командах важна скорость обратной связи при тестировании пайплайнов и автоматизаций, и Rich помогает выводить ключевую информацию максимально читаемо.</p><p>Кроме того, Rich позволяет быстро создавать CLI-интерфейсы, которые выглядят как продакшен-продукты, даже если это внутренние инструменты. Руководство будет радоваться и думать о вас как о крутом разрабе.</p><p>Для <b>дата-инженеров и разработчиков DevOps</b> Rich полезна при создании админ-утилит и при мониторинге пайплайнов, для <b>Python-разработчиков</b> — при создании библиотек и фреймворков с CLI.</p><h2>8. LangChain</h2><p>LangChain — фреймворк для создания приложений на базе LLM, например, GPT, Claude, Mistral, Gemini. Он позволяет строить цепочки обработки запросов, интегрировать LLM с данными и инструментами, добавлять память и управление состояниями, а также связывать работу модели с внешними API и базами знаний.</p><p>LangChain предоставляет удобный слой абстракции над вызовами LLM и ускоряет разработку чат-ботов, RAG-приложений, агентов с инструментами, систем анализа документов и других AI-сервисов.</p><h3>Какие задачи решает</h3><p>Список внушительный:</p><ul><li>Интеграция LLM в Python-приложения без необходимости писать тот самый клеевой код вручную.</li><li>Построение цепочек с последовательной обработкой сообщений, включая преобразования и вызовы внешних функций.</li><li>Добавление памяти в чат-боты для сохранения истории общения и контекста.</li><li>Использование агентов для динамического вызова инструментов (веб-поиск, базы данных, API).</li><li>Создание RAG-систем с интеграцией LLM и векторных БД.</li><li>Быстрая сборка прототипов LLM-приложений, которые можно развернуть в продакшен.</li></ul><h3>Как пользоваться</h3><p>Установка:</p><p>Создадим простую цепочку с чатом GPT:</p><p>Благодаря единым абстракциям, можно гибко комбинировать цепочки, память и вызов внешних инструментов, не усложняя код.</p><h3>Почему это меняет карьеру</h3><p>LangChain меняет карьеру, потому что открывает новый пласт Python-разработки в AI и LLM-инженерии, быстро превращая пользователя GPT в создателя полноценных AI-приложений. Вместо того чтобы писать хаотичный клеевой код, вы начинаете системно проектировать цепочки запросов, учитесь строить продуманные промпты и объединять их с инструментами, памятью и внешними API.</p><p>Работа с LangChain погружает в практическую LLM-инженерию: вы начинаете создавать RAG-приложения, которые умеют искать и анализировать данные перед генерацией ответа и строить агентов. Это востребовано в продуктах, где нужно подключать ИИ к базам знаний, автоматизировать задачи и разрабатывать интерактивные системы, которые реально используют модели в продакшене.</p><p>LangChain позволяет быстро собирать и запускать MVP AI-продуктов, что дает конкурентное преимущество при создании стартапов или внутренних сервисов. А ещё учит мыслить структурами и проектировать масштабируемую архитектуру LLM-приложений и видеть, как генеративный ИИ можно превратить в рабочий инструмент.</p><h2>9. SQLAlchemy</h2><p>SQLAlchemy — это мощная ORM и toolkit для работы с базами данных в Python, позволяющая писать SQL-запросы декларативно, создавать модели таблиц и управлять транзакциями в Python-коде без ручного написания SQL.</p><p>Библиотека даёт разработчику два уровня контроля:</p><ul><li>Core: низкоуровневая работа с SQL выражениями и соединениями;</li><li>ORM: высокоуровневая декларативная работа с моделями, классами и связями между таблицами.</li></ul><p>SQLAlchemy поддерживает PostgreSQL, MySQL, SQLite, Oracle и другие СУБД, давая единую абстракцию, без привязки к конкретному движку.</p><h3>Какие задачи решает</h3><p>Пул задач следующий:</p><ul><li>Описание таблиц в виде Python-классов и управление ими через сессии;</li><li>Создание, чтение, обновление и удаление данных;</li><li>Миграция SQL на декларативный стиль без потери гибкости;</li><li>Полный контроль над транзакциями и выполнением запросов;</li><li>Работа с асинхронными приложениями при создании FastAPI/Django-приложений;</li><li>Экранирование параметров, которое снижает вероятность SQL-инъекций и ошибок.</li></ul><h3>Как пользоваться</h3><p>Создадим минимальный пример для SQLite с таблицей пользователей:</p><p>Этот код создаёт базу example.db, таблицу users, добавляет туда одного пользователя и выводит всех пользователей в базе. При необходимости можно использовать SQLAlchemy Core для написания гибких запросов вручную, если нужно работать ближе к SQL.</p><h3>Почему это меняет карьеру</h3><p>SQLAlchemy меняет карьеру <b>Python-разработчика</b> тем, что даёт понимание системной работы с данными, архитектуры приложений и взаимодействия с реальными базами данных. Вы учитесь строить продуманные бэкенды, которые работают с транзакциями, миграциями, связями между таблицами и сложными выборками.</p><p>Знание SQLAlchemy открывает дорогу в мир API, микросервисов и продуктов, где требуется качественное управление данными и гибкая логика работы с БД. Работа с SQL теперь совсем не страшная.</p><h2>10. Seaborn</h2><p>Seaborn — библиотека для визуализации данных на Python, построенная поверх Matplotlib и упрощающая создание информативных и стильных графиков с минимальным количеством кода.</p><p>Она автоматически заботится о красивых стилях, цветах, разметке графиков, легендах и позволяет легко строить распределения, линейные графики, тепловые карты и другие визуализации.</p><p>Библиотека тесно интегрируется с Pandas DataFrame, позволяя использовать колонки данных напрямую для построения графиков, что делает её идеальной для EDA (разведочного анализа данных) и подготовки визуализаций для отчётов и презентаций.</p><h2>Какие задачи решает</h2><p>Визуализация безумно важна, особенно в контексте дата-аналитики. Seaborn отвечает за:</p><ul><li>Быстрое построение информативных графиков для анализа данных и поиска инсайтов;</li><li>Автоматическую обработку ошибок отображения и масштабирования, что экономит время;</li><li>Поддержку сложных визуализаций по типу ящиков с усами или тепловых карт без десятков строк кода;</li><li>Стилизацию графиков без ручных настроек Matplotlib;</li><li>Возможность добавлять статистические элементы (линию регрессии, KDE, распределение);</li><li>Интеграцию с Jupyter Notebook для интерактивного анализа данных.</li></ul><h3>Как пользоваться</h3><p>Допустим, у нас есть датасет с данными о чаевых:</p><p>В три строки мы получаем чистый и читаемый ящик с усами, показывающий, как счет за ужин распределяется по дням недели.</p><p>Для построения более сложных графиков можно использовать диаграмму рассеяния:</p><p>Тут мы добавляем цветовую кодировку по полу, чтобы увидеть зависимости между переменными.</p><h3>Почему это меняет карьеру</h3><p>Seaborn меняет карьеру, потому что даёт навык визуального анализа данных, что критично в современной аналитике и дата-инженерии. Умение быстро строить графики и видеть аномалии, распределения и взаимосвязи между переменными превращает работу с данными из слепого копания в числах в структурный анализ.</p><p>Использование Seaborn в Python-стеке помогает выделиться среди разработчиков, которые ограничиваются Pandas и текстовыми логами, ведь визуализация часто позволяет быстрее заметить закономерности и убедить команду или заказчика в правильности гипотезы.</p><p>Seaborn также учит пониманию данных через визуальные паттерны, что улучшает навыки построения моделей машинного обучения (так понятнее, какие признаки важны), и помогает создавать наглядные отчёты для продуктовых решений, где результат анализа нужно доносить до людей не из айти-индустрии.</p><p><i>А какими библиотеками пользуетесь вы? Делитесь в комментариях!</i></p>]]></content:encoded>
    </item>
    <item>
      <title>PostgreSQL: что нужно знать о счётчике транзакций</title>
      <link>https://tproger.ru/articles/postgresql--chto-nuzhno-znat-o-schyotchike-tranzakcij</link>
      <comments>https://tproger.ru/articles/postgresql--chto-nuzhno-znat-o-schyotchike-tranzakcij?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Postgres Professional]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/postgresql--chto-nuzhno-znat-o-schyotchike-tranzakcij</guid>
      <description><![CDATA[<p>Статья погружает в сложности счетчика транзакций PostgreSQL и MVCC в условиях высокой нагрузки. Разберитесь, почему 32-битные xid создают проблемы и как 64-битные идентификаторы транзакций решают их.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/postgresql--chto-nuzhno-znat-o-schyotchike-tranzakcij">PostgreSQL: что нужно знать о счётчике транзакций</a>»</p>]]></description>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 13 Jul 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Многие годы считалось, что PostgreSQL не подходит для систем с высокой нагрузкой. Но на практике всё чаще встречаются ситуации, когда даже крупные компании выбирают именно эту СУБД. В результате, всё больше внимания уделяется вопросам производительности и масштабируемости PostgreSQL. Один из таких вопросов — счётчик транзакций, о котором мы сегодня и поговорим.</p><h2>Что такое счётчик транзакций и зачем он нужен?</h2><p>PostgreSQL использует механизм многоверсионности (MVCC) благодаря которому читающие транзакции не блокируют пишущие, и наоборот. Каждая транзакция работает со своей версией данных, а доступ регулируется правилами видимости.</p><p>Чтобы понять, как функционирует MVCC, представьте, что у каждого пользователя базы есть свой «моментальный снимок» данных. Когда вы начинаете работать, вы видите состояние данных на этот конкретный момент времени. Изменения, которые делают другие пользователи, не влияют на ваш снимок, пока вы не завершите свою операцию и не начнете новую. Это позволяет нескольким пользователям одновременно читать и изменять данные, не мешая друг другу.</p><p>MVCC в PostgreSQL работает похожим образом:</p><ul><li>Каждая транзакция — это как отдельный пользователь, работающий с документом. Транзакция видит «снимок» базы данных на момент своего начала.</li><li>Когда транзакция изменяет данные, она не перезаписывает старые. Вместо этого создаётся новая версия изменённых строк.</li></ul><p>Каждая версия строки имеет специальные метки:</p><ul><li>xmin — идентификатор транзакции, которая создала версию.</li><li>xmax — идентификатор транзакции, которая удалила (или обновила) версию. Если строка ещё не удалена, xmax пустой.</li></ul><p>Когда транзакция читает данные, PostgreSQL определяет, какую версию строки ей показывать, на основе правил видимости:</p><ul><li>транзакция видит строки, созданные до её начала (xmin меньше её идентификатора), и не помеченные как удалённые (xmax пустой или больше её идентификатора);</li><li>транзакция видит строки, созданные ею самой;</li><li>транзакция не видит строки, созданные транзакциями, которые начались позже неё (xmin больше её идентификатора).</li></ul><p>Пример:</p><p>Допустим, у нас есть таблица users с данными:</p><p>1. Транзакция 1 (xid=100) начинается и читает таблицу  Она видит обе строки, потому что они были созданы до её начала, и xmax у них пустой.</p><p>2. Транзакция 2 (xid=105) начинается и обновляет возраст Alice на 31. PostgreSQL не перезаписывает строку Alice, а создаёт новую версию:</p><p>3. Обратите внимание, что у старой версии Alice xmax теперь равен 105 (идентификатор транзакции 2), а у новой версии xmin равен 105.</p><p>4. Транзакция 1 снова читает таблицу.  Она по-прежнему видит старую версию Alice (возраст 30), потому что новая версия была создана транзакцией, которая началась позже (105 &gt; 100), а старая помечена как удалённая транзакцией с большим номером.</p><p>5. Транзакция 2 фиксируется.</p><p>6. Транзакция 3 (xid=110) начинается и читает таблицу  Теперь она видит новую версию Alice (возраст 31), потому что транзакция 2, которая её создала, уже зафиксирована, и её xid меньше чем у транзакции 3.</p><p>Важно: номера транзакций (xid) не стоит сравнивать как обычные числа («больше» или «меньше»). Корректнее говорить «старше» или «младше». Дело в том, что номера транзакций сравниваются по модулю 232, образуя кольцо. Транзакции, отстающие от текущей на 231 назад, считаются «старше» («в прошлом»), а на 231 вперёд — «младше» («в будущем»).</p><p>Представьте себе круг:</p><ul><li>текущая транзакция — это точка на круге;</li><li>«прошлые» транзакции — это точки слева от текущей, если двигаться против часовой стрелки;</li><li>«будущие» транзакции — точки справа.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/115310/2025-07-04/f547fb58-a54c-404c-8852-6d91fd4a8aed.png" alt="" /></figure><p>Каждая запись в базе данных имеет служебные поля xmin и xmax. В xmin записывается номер транзакции, создавшей запись, а в xmax — номер транзакции, удалившей её. Учетом этих номеров и занимается счетчик транзакций.</p><h2>Как развивался счётчик транзакций</h2><p>До версии PostgreSQL 8.2 при достижении максимального значения счётчика транзакций (примерно 4 миллиарда) PostgreSQL просто «падал». Чтобы продолжить работу, нужно было сделать дамп базы данных и создать её заново.</p><p>В версии 8.2 появился механизм циклического перезапуска счётчика. Для этого в фоновом режиме запускается процесс очистки (VACUUM).</p><p>Как это работает:</p><ol><li><b>«Заморозка» старых транзакций</b>: Когда на VACUUM передаётся значение, что счётчик транзакций скоро переполнится, он начинает помечать старые транзакции специальным идентификатором FrozenTransactionId. По сути, VACUUM говорит: «Эти транзакции настолько старые, что мы считаем их замороженными. Мы всегда будем считать их старше любых других транзакций.»</li><li><b>Счётчик эпох</b>: Чтобы PostgreSQL знал, сколько раз счётчик уже «перезапускался», используется счётчик эпох. Каждый раз, когда счётчик транзакций доходит до конца и начинает заново, счётчик эпох увеличивается на единицу.</li><li><b>Циклический перезапуск:</b> После того как VACUUM «заморозит» старые транзакции, счётчик транзакций может безопасно начать считать заново с трёх. PostgreSQL теперь знает, что все транзакции с идентификатором FrozenTransactionId старше любых других транзакций, даже если их номера меньше.</li></ol><p>Это решило проблему «падения», но возникла новая: если VACUUM не успевает отработать вовремя, сервер может остановиться и потребовать запуска в монопольном режиме для очистки, что ведёт к простою.</p><h3>В чём же проблема?</h3><p>Сам по себе механизм счётчика транзакций работает хорошо. Проблема в том, что он создавался, когда 32-битное число (более 4 миллиардов) казалось огромным. Сейчас же, в системах с высокой нагрузкой (ретейл, крупные заводы, госучреждения), счётчик может оборачиваться раз в сутки.</p><p>Дополнительные сложности:</p><p>Среди служебных данных записи есть поле флагов. Для старых записей нужно периодически запускать VACUUM FREEZE, который помечает их как «замороженные» (FrozenTransactionId).</p><p>Для стабильной работы нужно, чтобы:</p><ul><li>разница между номером текущей транзакции и номером самой старой записи не превышала 2^32;</li><li>VACUUM FREEZE выполнялся до нарушения первого условия.</li></ul><p>В реальном мире это сложно:</p><ul><li>«долгие» транзакции мешают VACUUM FREEZE;</li><li>сложно определить, когда транзакция «долгая», а когда «зависшая»;</li><li>непонятно, когда бить тревогу из-за исчерпания идентификаторов;</li><li>администратор БД несёт ответственность за потери бизнеса из-за своих действий.</li></ul><p>Если вы можете остановить кластер БД, запустить его в монопольном режиме и подождать несколько часов, эта проблема вас не касается. Но в системах с высокими требованиями к доступности простой — недопустим.</p><p>Отдельно стоит упомянуть базы данных, в которые данные только добавляются (insert-only). В них VACUUM всё равно запускается для «заморозки» старых записей.</p><h2>Решение: 64-битные идентификаторы транзакций</h2><p>Казалось бы, простое решение — увеличить размер счётчика до 64 бит. Но это сложно:</p><ul><li>весь код PostgreSQL ожидает «видеть» 32-битные числа;</li><li>в каждом кортеже (записи) хранятся xmin и xmax. Увеличение их размера с 8 до 16 байт значительно увеличит размер базы.</li></ul><p>Мы в Postgres Professional разработали реализацию 64-битных идентификаторов транзакций (xid), увеличив их количество до 18 446 744 073 709 551 615 (264). Это решение используется во многих форках PostgreSQL. Проблема переполнения счётчика становится гипотетической (при высокой нагрузке 64-битный счётчик исчерпается примерно через 400 лет).</p><p>Патч с реализацией был предложен сообществу PostgreSQL, но пока не принят из-за его сложности. Однако многие разработчики форков PostgreSQL уже заявили о поддержке 64-битных xid в своих дистрибутивах.</p><p>Цель Postgres Professional  — не продвигать свой вариант как единственно верный, а привлечь внимание к проблеме и стимулировать сообщество к поиску оптимального решения. Первая часть удалась: идея получила внимание. Но внедрение таких изменений — долгий процесс. Рост нагрузок на СУБД во всём мире показывает важность этой проблемы.</p><p>Мы надеемся, что PostgreSQL сможет адаптироваться к растущим нагрузкам и укрепить свои позиции на рынке.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что по экологии? Сколько углеродного следа оставляет ваш код</title>
      <link>https://tproger.ru/articles/chto-po-ekologii--skolko-uglerodnogo-sleda-ostavlyaet-vaw-kod</link>
      <comments>https://tproger.ru/articles/chto-po-ekologii--skolko-uglerodnogo-sleda-ostavlyaet-vaw-kod?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-po-ekologii--skolko-uglerodnogo-sleda-ostavlyaet-vaw-kod</guid>
      <description><![CDATA[<p>Узнайте, сколько CO₂ генерирует ваш код в 2025 году и как снизить углеродный след в IT. Практические советы по оптимизации архитектуры, выбору «зеленых» технологий и реальные кейсы компаний. Экологичное программирование — новый тренд для разработчиков и бизнеса.
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-po-ekologii--skolko-uglerodnogo-sleda-ostavlyaet-vaw-kod">Что по экологии? Сколько углеродного следа оставляет ваш код</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Конференции]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Amazon]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[OpenAI]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Стартапы]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Сбер]]></category>
      <category><![CDATA[Дата-центр]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 10 Jul 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В 2025 году IT-индустрия потребляет больше энергии, чем крупная европейская страна  в 2010. <a href="https://www.iea.org/">По данным IEA</a> (International Energy Agency), дата-центры и телекоммуникационные сети уже отвечают за 3,7% глобальных выбросов CO₂ — это больше, чем производит авиация.</p><p>Казалось бы, код — это просто текст. Но каждый запрос к API, каждая компиляция и даже холостой цикл требуют энергии. Например, обучение GPT-4 в 2023 году «съело» столько же электричества, сколько 120 домохозяйств за год. А теперь представьте, что таких моделей тысячи, а серверов — миллионы.</p><p>Почему это важно? Во-первых, <a href="https://digital-strategy.ec.europa.eu/">регуляторы ужесточают требования</a>: в ЕС с 2025 года IT-компании обязаны раскрывать углеродный след своих продуктов. Во-вторых, инвесторы все чаще смотрят на ESG-рейтинги — показатели экологического и ответственного производства. В-третьих, оптимизация кода снижает затраты на инфраструктуру.</p><p>Эта статья — не манифест экоактивистов, а руководство для разработчиков, архитекторов и технических директоров компаний (СТО), которые стремятся более эффективные и экологичные проекты.</p><h2>Углеродный след кода: что скрывается за строчками</h2><p>Программное обеспечение — не виртуальный конструктор. Каждая операция требует электричества, а серверы, на которых работает код, часто питаются от невозобновимых источников энергии — например, угля и газа.</p><h3>Откуда берутся выбросы</h3><p>Когда мы говорим об углеродном следе ПО, важно понимать: код не существует в вакууме. Каждая строка, каждый запрос и каждая операция требуют физических ресурсов — электричества, серверного оборудования, систем охлаждения. В 2025 году эта цепочка стала еще сложнее из-за взрывного роста облачных вычислений и ИИ.</p><p>Прямые выбросы — это энергия, которую потребляют серверы при выполнении вашего кода. Например, один средний веб-сервер на AWS EC2 (тип t3.large) в год вырабатывает около 400 кг CO₂ — как небольшой автомобиль, проехавший 2000 км. При этом нагрузка на серверы постоянно растет: с 2020 по 2025 год энергопотребление дата-центров увеличилось на 35%.</p><p>Косвенные выбросы часто упускают из виду. Производство серверного оборудования — процесс крайне энергоемкий. Для создания одной только микросхемы памяти DDR5 требуется около 200 кВт⋅ч энергии — столько же, сколько средний холодильник потребляет за год. А после выхода оборудования из строя лишь 20% компонентов перерабатывается должным образом (<a href="https://globalewaste.org/">Global E-Waste Monitor 2024</a>).</p><p>Системы охлаждения — еще один скрытый источник выбросов. Современные дата-центры работают 24/7, и даже с использованием жидкостного охлаждения на поддержание температуры уходит до 40% всей потребляемой энергии. В жарких странах, ОАЭ или Сингапуре, этот показатель может достигать 50%.</p><p>Яркий пример — крупные языковые модели. Если в 2023 году обучение GPT-4 потребовало ~10 ГВт⋅ч (эквивалент годового потребления 120 домохозяйств), то к 2025 году из-за увеличения размеров моделей этот показатель вырос в 1,5 раза. Один запрос к такому ИИ теперь генерирует около 2 г CO₂ — как если бы вы проехали 10 метров на бензиновом автомобиле.</p><p>Но проблема не только в ИИ. Обычное веб-приложение с посещаемостью 100 000 пользователей в месяц может производить до 1 тонны CO₂ в год — и это без учета мобильных клиентов и API. При этом <a href="https://www.webpagetest.org/eco/">30% этой нагрузки приходится на неоптимизированный фронтенд</a>: тяжелые изображения, избыточные JavaScript-библиотеки и частые запросы к серверу.</p><p>Ситуацию усугубляет географический фактор. Дата-центр в Норвегии, где 98% энергии поступает от ГЭС, будет «чище», чем такой же центр в Польше, где угольные электростанции дают 70% энергии. <a href="https://app.electricitymaps.com/">Разница</a> в углеродном следе может быть 20-кратной для идентичных операций.</p><p>При этом стандарты измерения все еще остаются разрозненными. PUE (Power Usage Effectiveness), который используют Google и Microsoft, учитывает только эффективность инфраструктуры, но не источник энергии. Новый стандарт CUE (Carbon Usage Effectiveness), разработанный в 2024 году, уже включает эти данные, но его поддерживают менее 30% провайдеров.</p><h2>Где код тратит энергию впустую</h2><p>Некоторые части систем особенно вредны для экологии. Главные «пожиратели» ресурсов:</p><ul><li>Неоптимизированные алгоритмы. Сортировка пузырьком (O(n²)) на большом массиве данных может потреблять в 100 раз больше энергии, чем быстрая сортировка (O(n log n)).</li><li>Микросервисный хаос. Архитектура из сотен микросервисов увеличивает нагрузку на сеть. Каждый вызов API между сервисами — это дополнительные 0,5–1 Вт⋅ч.</li><li>Облачные провайдеры. Не все одинаково зеленые. AWS и Google используют 60–70% ВИЭ (возобновляемых источников энергии), но в Азии и Африке их дата-центры часто работают на угле.</li></ul><h3>Как измерить углеродный след</h3><p>В 2025 году появились инструменты, которые помогают оценить влияние кода:</p><ul><li>Cloud Carbon Footprint — анализирует выбросы AWS, GCP и Azure.</li><li>Scaphandre — мониторит энергопотребление серверов в реальном времени.</li><li>Greenframe.io — симулирует нагрузку на веб-приложение и считает CO₂.</li></ul><p>Климатические инициативы в IT больше не просто красивые слова в корпоративных отчетах. В 2025 году за неэффективный код можно получить не только порицание сообщества, но и вполне реальный штраф.</p><p>Европейский союз уже ввел санкции против пяти крупных SaaS-компаний за превышение углеродных квот, а Amazon Web Services выплатила 2,7 млн евро штрафа за неоптимизированные алгоритмы в своих сервисах.</p><h2>Как изменились подходы к разработке</h2><p>Эти тренды нацелены на долгосрочное действие и в перспективе должны полностью изменить текущую концепцию в разработке.</p><h3>Экологичный DevOps — новая реальность</h3><p>Современные системы автоматического масштабирования стали умнее. Kubernetes Horizontal Pod Autoscaler теперь учитывает не только нагрузку на CPU, но и текущий углеродный след дата-центра. Если в регионе пиковое потребление энергии и работают угольные электростанции, система сознательно ограничивает масштабирование.</p><p><a href="https://cloud.google.com/blog">Технология, разработанная Google</a> в партнерстве с WattTime, уже снижает выбросы CO₂ на 27-33% по сравнению с традиционным подходом.</p><p>CI/CD-цепочки тоже стали «зеленее». Вместо запуска полного набора тестов при каждом коммите, современные системы определяют, какие именно модули затронуты изменениями.</p><p><a href="https://carbonrunner.io/features/github-action-runners">GitHub Actions представил Carbon-Aware Runner</a>, который планирует выполнение задач на время максимальной доступности возобновляемой энергии в регионе. По данным Microsoft, это сокращает углеродный след тестирования на 40%.</p><h3>Языки программирования: война за эффективность</h3><p>Rust продолжает набирать популярность не только из-за безопасности, но и благодаря энергоэффективности. Тесты Benchmarks Game показывают, что один и тот же алгоритм обработки данных на Rust потребляет на 38-42% меньше энергии, чем на Python. В 2025 году Rust вошел в топ-5 языков для enterprise-решений, вытеснив Java в 17% крупных проектов.</p><p>Но настоящим открытием стал <a href="https://ziglang.org/documentation/master/">Zig </a>— язык, который сочетает производительность C с простотой синтаксиса. Его компилятор потребляет в 3 раза меньше ресурсов, чем LLVM-бэкенд Rust, что делает его идеальным выбором для встраиваемых систем.</p><h3>ИИ на грани: когда меньше значит лучше</h3><p>TinyML-революция набирает обороты. Современные нейросети для микроконтроллеров занимают менее 256 КБ памяти, но справляются с задачами, которые раньше требовали облачных вычислений.</p><p>Например, новые датчики Nest анализируют звук прямо на устройстве, определяя не только дым, но и тип возгорания. Это экономит до 150 МБ трафика в месяц на одно устройство.</p><p>На фронте больших языковых моделей тоже произошли изменения. Meta* выпустила LLaMA-3 Nano — модель с 500 млн параметров, которая работает на смартфоне и по качеству ответов не уступает GPT-3.5. Ее углеродный след при обучении в 1200 раз меньше, чем у GPT-4.</p><p><i>(*Компания запрещена в РФ)</i></p><h3>Новые правила игры: регуляторы и бизнес</h3><p>С января 2025 года в Евросоюзе действует Углеродный налог на цифровые продукты (Digital Carbon Border Tax). Теперь любое ПО, продающееся в ЕС, должно иметь сертификат углеродной эффективности.</p><p>Для крупных enterprise-решений максимально допустимый углеродный след составляет 500 г CO₂ на 1000 пользователей в месяц. Нарушители платят 7% от оборота продукта в регионе.</p><p>Венчурные фонды радикально изменили подход к инвестициям. <a href="https://www.pwc.com/gx/en/services/sustainability/publications.html">Согласно отчету PwC</a>, 43% фондов требуют ESG-отчетность перед заключением сделки, а 28% вообще не рассматривают стартапы без «зеленой» стратегии. В Кремниевой долине появился первый акселератор Carbon Neutral Startups, который дает бонусы в $50 000 проектам с нулевым углеродным следом.</p><p>Корпорации тоже не остались в стороне. <a href="https://www.microsoft.com/sustainability">Microsoft ввела внутренний углеродный налог</a> — теперь каждое подразделение платит $100 за каждую тонну CO₂, связанную с его продуктами. Эти деньги идут на развитие возобновляемой энергетики.</p><p>Но самое интересное происходит на рынке труда. Разработчики с навыками «зеленого» программирования получают на 15-20% больше предложений. Появилась появилась новая категория навыков — «Устойчивая разработка ПО», а спрос на таких специалистов вырос на 300% за последний год.</p><h2>Как писать «зеленый» код</h2><p>Каждая лишняя операция в коде — это не только миллисекунды процессорного времени, но и реальные граммы CO₂. В 2025 году энергоэффективность кода перестала быть теоретической концепцией и превратилась в конкретный навык, который влияет на карьеру разработчика. Рассмотрим три ключевых направления оптимизации.</p><h3>Оптимизация запросов к базе данных</h3><p>Типичный пример — использование SELECT * вместо явного перечисления полей. Когда приложение запрашивает все поля таблицы users (включая редко используемые avatar_blob или metadata_json), сервер БД тратит дополнительные ресурсы на чтение и передачу этих данных. В крупных системах с миллионами запросов в день это приводит к значительному перерасходу вычислительных ресурсов.</p><p>Современные ORM типа Prisma и Drizzle добавили автоматическую оптимизацию запросов. Теперь при использовании select() они анализируют, какие поля действительно нужны на клиенте, и генерируют оптимальный SQL. В тестах это снижает нагрузку на БД на 12-18%.</p><h3>Работа с циклами и алгоритмами</h3><p>Классическая ошибка — продолжать перебор массива после нахождения нужного элемента. В 2025 году статический анализатор кода в WebStorm и VS Code автоматически предупреждает о таких ситуациях. Особенно критично это для мобильных приложений: лишние итерации цикла на слабых устройствах увеличивают энергопотребление на 5-7%.</p><p>Новые версии JavaScript и TypeScript ввели оптимизированные методы для массивов. Например, array.findLast() работает в 1,5 раза эффективнее ручной реализации с циклом. Для сложных алгоритмов появились «зеленые» библиотеки вроде EcoCollections для Java, которые минимизируют энергопотребление при работе с структурами данных.</p><h3>Сжатие и передача данных</h3><p>Формат Brotli стал новым стандартом для API: он обеспечивает лучшее сжатие, чем gzip, особенно для JSON-ответов. Компания Cloudflare провела эксперимент: после перехода на новую версию Brotli нагрузка на их серверы снизилась на 18%, что эквивалентно годовому потреблению энергии 2000 домохозяйств.</p><p>Но сжатие — не панацея. Грамотное проектирование API может дать больший эффект. GraphQL-подход, где клиент запрашивает только нужные данные, в среднем почти вдвое уменьшает объем передаваемой информации по сравнению с REST. А технология Server-Sent Events (SSE) для реального времени потребляет в 3 раза меньше ресурсов, чем WebSockets, когда не нужна двусторонняя связь.</p><p>Современные фреймворки начали учитывать энергоэффективность. Next.js 15 <a href="https://nextjs.org/blog">представил «зеленый» режим компиляции</a>, который оптимизирует сборку под минимальное энергопотребление. В тестах это дало 8% экономии на процессоре при работе приложения. А Deno 2.0 автоматически кэширует зависимости на уровне ОС, сокращая число повторных загрузок.</p><p>Эти изменения кажутся мелкими, но в масштабах индустрии они имеют огромное значение. Если бы все репозитории на платформе применили базовые оптимизации, глобальное энергопотребление дата-центров сократилось бы на несколько процентов. Для отрасли, которая потребляет 700 ТВт⋅ч в год, это десятки миллионов долларов и тысячи тонн CO₂.</p><h2>Выбор технологий</h2><p>В 2025 году выбор стека технологий влияет не только на производительность, но и на экологичность проекта. Разберем ключевые аспекты, которые помогут снизить углеродный след вашего приложения.</p><h3>Языки программирования: баланс между скоростью и эффективностью</h3><p>Rust и Go продолжают доминировать в высоконагруженных системах. Тесты показывают, что веб-сервер на Rust потребляет на 35-40% меньше энергии при одинаковой нагрузке по сравнению с Node.js. Особенно заметна разница в облачных средах, где каждый ватт на счету.</p><p>C++ остается выбором для задач, где важна предсказуемая производительность. Новый стандарт C++26 добавил энергоэффективные режимы работы алгоритмов STL, что особенно важно для встраиваемых систем.</p><p>Python по-прежнему хорош для прототипирования, но в продакшене его лучше заменять на компилируемые языки. PyPy 8.0 сократил энергопотребление интерпретатора на 25%, но даже с этими улучшениями Python проигрывает Rust в 3-4 раза по эффективности.</p><h3>Базы данных: от малого к большему</h3><p>SQLite — идеальный выбор для небольших проектов и edge-устройств. Его новая версия 3.45 добавила режим «энергосбережения», который снижает потребление на 15% при фоновых операциях.</p><p><a href="https://www.postgresql.org/docs/17/release-17.html">PostgreSQL 17</a> сделал большой шаг в энергоэффективности. Функция автоматического партиционирования теперь учитывает не только производительность, но и энергопотребление. В тестах это дало 20% экономии на крупных аналитических запросах.</p><p>Для высоконагруженных систем появилась альтернатива — ScyllaDB 5.0. Эта Cassandra-совместимая СУБД потребляет втрое раза меньше энергии при аналогичной нагрузке, благодаря полному переписыванию на Rust.</p><h2>Кейсы: что работает, а что нет</h2><p>Российские компании тоже внедряют экологичные IT-решения. МТС разработала мобильное приложение, где пользователи получают бонусы за раздельный сбор мусора — их можно обменять на подписки или скидки. За первый год проект привлек 500 тысяч участников и сократил количество непереработанных отходов в регионах присутствия.</p><p>НИУ ВШЭ, совместно с Росприроднадзором, автоматизировал сбор экологической отчетности с помощью ИИ. Нейросеть анализирует данные с датчиков и заполняет формы вместо специалистов. Это сократило время обработки с 100 до 10 часов в месяц и уменьшило количество ошибок.</p><p>Некоторые архитектурные решения приносят больше вреда, чем пользы. Один московский стартап без необходимости разбил монолитную систему на 50 микросервисов — в результате затраты на инфраструктуру выросли в 3 раза, а углеродный след увеличился на 180%.</p><p>Проблемы возникают и на уровне зависимостей. История с left-pad повторилась в 2024 году, когда один npm-пакет потянул за собой 80 МБ ненужных библиотек. Теперь крупные компании проверяют каждую зависимость через Bundlephobia и устанавливают лимит на размер node_modules.</p><h2>Что нас ждет</h2><p>В 2025 году отрасль стоит на пороге радикальных изменений, которые перевернут наши представления о «зеленом» программировании.</p><p>Супероблака — следующий этап эволюции распределенных вычислений. В отличие от традиционных облачных провайдеров, эти системы автоматически переносят нагрузку между дата-центрами в зависимости от доступности возобновляемой энергии.</p><p><a href="https://cloud.google.com/sustainability">Google уже тестирует эту технологию</a> в Северной Европе: когда в Норвегии дует сильный ветер и ветряные электростанции работают на пике, система переносит вычисления именно туда. По предварительным оценкам, это снижает углеродный след на 18-22% по сравнению со статичным распределением.</p><p>Но настоящий прорыв ожидается в сегменте квантовых вычислений. Хотя современные квантовые компьютеры потребляют колоссальное количество энергии (система IBM Quantum System One требует около 25 кВт⋅ч для работы одного кубита), их потенциал для оптимизации классических алгоритмов огромен.</p><p>В 2024 году исследователи из ЦЕРНа <a href="https://www.nature.com/articles/s41534-024-00859-0">предложили квантовый алгоритм</a>, который сокращает время сложных расчетов в 1000 раз при той же точности. Когда такие решения станут массовыми (прогноз — 2028-2030 годы), энергопотребление дата-центров может сократиться на 30-40%.</p><p>Государственное регулирование становится строже. В 2025 году в силу вступает EU Digital Product Passport — требование указывать углеродный след для всего ПО, продающегося в Европе.</p><p>Компании, которые не смогут предоставить эти данные, столкнутся с дополнительными налогами до 7% от оборота. В ответ на это крупнейшие IT-корпорации создали Carbon Neutral Software Alliance — консорциум по разработке единых стандартов измерения.</p><p>Не отстает и аппаратная часть. Производители чипов переходят на новые техпроцессы: TSMC анонсировала 2-нм процесс, который на 30% энергоэффективнее предыдущего поколения. А стартапы вроде британской ZeroPoint Technologies разрабатывают память с нулевым энергопотреблением в режиме ожидания — технология может сократить энергопотребление серверов на 15%.</p><p><b>Но главный тренд </b>— децентрализация вычислений. Edge-устройства (от смартфонов до промышленных датчиков) становятся мощнее и берут на себя часть нагрузки. Например, новый алгоритм Apple для обработки фото на iPhone 16 выполняет 90% операций локально, а не в облаке. По оценкам компании, это экономит сотни тысяч тонн CO₂ в год только для пользователей в США.</p><p>Однако остаются и <b>проблемы</b>. Бум генеративного ИИ привел к взрывному росту энергопотребления: одна тренировка модели Gemini Ultra потребляет столько же энергии, сколько небольшой город за месяц. OpenAI и Anthropic уже работают над более эффективными архитектурами, но прорыва пока не случилось.</p><p>В ближайшие 3-5 лет нас ждет:</p><ul><li>массовый переход на углеродно-нейтральные дата-центры — к 2027 году их доля превысит 60%;</li><li>внедрение AI-оптимизаторов кода, которые автоматически сокращают энергопотребление;</li><li>появление «зеленых» рейтингов для приложений — аналог энергоэффективности для бытовой техники.</li></ul><p>Компании, внедрившие принципы устойчивого развития в IT, уже в 2025 году получают на больше инвестиций и быстрее проходят аудит регуляторов. Экологичность перестала быть затратой — теперь это конкурентное преимущество.</p><p>Технологии будущего уже здесь. Вопрос в том, насколько быстро мы сможем их адаптировать. Как сказал Дженсен Хуанг из NVIDIA на последней конференции GTC:</p><blockquote>«Следующее десятилетие определит, станет ли IT частью климатического решения или останется проблемой. Выбор за нами».</blockquote><h2>Итоги</h2><p>Экологичность в IT — не благотворительность и не актуальная повестка, а реальная экономия. Плюс работа на перспективу. Оптимизация кода снижает счета за облака и повышает производительность.</p><p>С чего начать? Начните с малого:</p><ol><li>Запустите аудит через Cloud Carbon Footprint.</li><li>Уберите «мусор» из зависимостей.</li><li>Выберите хостинг с ВИЭ.</li></ol><p>Как говорил Дональд Кнут, автор книги «Искусство программирования»:</p><blockquote>«Преждевременная оптимизация — корень всех зол. Но и запоздалая — тоже».</blockquote><p>В 2025 году это актуально как никогда.</p>]]></content:encoded>
    </item>
    <item>
      <title>Петабайты каждый день: как хранить и использовать данные с умом</title>
      <link>https://tproger.ru/articles/petabajty-kazhdyj-den--kak-hranit-i-ispolzovat-dannye-s-umom</link>
      <comments>https://tproger.ru/articles/petabajty-kazhdyj-den--kak-hranit-i-ispolzovat-dannye-s-umom?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/petabajty-kazhdyj-den--kak-hranit-i-ispolzovat-dannye-s-umom</guid>
      <description><![CDATA[<p> Как компаниям эффективно хранить и масштабировать big data? Разбираем решения с экспертом VK Cloud. </p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/petabajty-kazhdyj-den--kak-hranit-i-ispolzovat-dannye-s-umom">Петабайты каждый день: как хранить и использовать данные с умом</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Облачные технологии]]></category>
      <category><![CDATA[AMD]]></category>
      <category><![CDATA[CSR]]></category>
      <category><![CDATA[Дата-центр]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Jul 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Каждый день в мире генерируется более <a href="https://www.techbusinessnews.com.au/blog/402-74-million-terrabytes-of-data-is-created-every-day/">400 миллионов</a> терабайт данных. Возможно, стоило бы отпраздновать эту цифру, но компаниям все сложнее хранить такие объемы. С одной стороны, — это вопрос оптимизации стоимости. С другой, — удобства использования и масштабирования.</p><p>В этом материале вместе со Станиславом Погоржельским, технологическим евангелистом платформы VK Cloud, разберем особенности решений для хранения и работы с большими данными.</p><h2>Особенности локальных хранилищ</h2><p>Стоит держать в уме, что выбор таких решений не всегда зависит от архитектурных принципов и лучших практик, а чаще всего от наличия определенной экспертизы в компании. Проведем очную ставку трех основных моделей построения хранилищ.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-07-02/7eece396-17d8-49b4-8aca-522d466b3c85.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-07-02/5c60f581-5f7e-40e2-ac17-65eb3ad59714.png" alt="" /></figure><h3>Семь «грехов» локальных кластеров</h3><p>Теперь поговорим о том, какие неприятные особенности встречаются во время эксплуатации локальных кластеров.</p><h4>Структура данных и хаос</h4><p>В реальных системах данные редко бывают аккуратными. Вместо красивых таблиц разработчик часто сталкивается с миллионами мелких файлов по 1-2 Кб и, например, видео по несколько Гб. Такие крайности требуют противоположных стратегий хранения и кэширования.</p><p>Файловая система, не оптимизированная для работы с малыми файлами, быстро забивается inode'ами (переполнение файловых дескрипторов). Системы хранения начинают задыхаться не от общего объема, а от количества объектов, что критически влияет на производительность. Например, <a href="https://web.archive.org/web/20161101132116/http://engineering.spilgames.com/openstack-swift-lots-small-files/">известны случаи</a>, когда после миллиона объектов OpenStack Swift начинал терять метаданные, а в хранилищах висели призраки удаленных объектов.</p><h4>RAID — не универсальное спасение</h4><p>Настройка RAID-массивов кажется очевидным решением, но не все так однозначно:</p><ul><li>RAID 5 и 6 плохо переносят большие объемы из-за длительного времени восстановления.</li><li>RAID 10 требует удвоения или утроения объема хранения ради скорости и отказоустойчивости.</li><li>На петабайтных объемах пересборка массива после сбоя может занимать больше недели.</li></ul><h4>Поддержка архивов и ZIP-файлов</h4><p>Архивирование данных (например, с помощью ZIP) спасает место, но приводит к другим проблемам: невозможность выборочного доступа к отдельным файлам без полной распаковки, рост времени обработки запросов, сложность мониторинга целостности данных.</p><p>Массовая работа с архивами требует настройки кэширования и часто вынуждает строить параллельные системы для индексации содержимого архивов.</p><h4>Автоматизация мониторинга и ремонта</h4><p>Любая система хранения живет с постоянным риском деградации: умирают диски, выходят из строя контроллеры, падают сети. На уровне сотен и тысяч узлов мониторинг «вручную» невозможен: требуется автоматизированная оркестрация алертов, самовосстановление, динамическая миграция данных на здоровые узлы. Иначе разрастание локальных отказов перерастает в потерю данных.</p><h4>Шардирование данных: неизбежность и боль</h4><p>На больших объемах данных (более 250 Тб) приходится шардировать — разбивать на независимые логические части, чтобы сохранить производительность. Но с шардированием есть проблемы:</p><ul><li>усложняет маршрутизацию запросов;</li><li>увеличивает сложность восстановления данных при сбоях;</li><li>требует отдельных механизмов ребалансировки шардов при добавлении новых узлов.</li></ul><p>Более того, встроенные механизмы шардирования некоторых популярных СУБД (MongoDB, PostgreSQL с партиционированием) не рассчитаны на миллиарды записей и начинают деградировать.</p><h4>Проблемы метаданных</h4><p>Каждый файл и объект требуют метаданных: даты создания, размера, доступа, хеш-суммы. При росте числа объектов метаданные сами по себе становятся огромными: терабайты информации, требующие отдельного хранения, индексирования и защиты.</p><h4>Резервное копирование на практике</h4><p>Бэкап петабайта данных требует продуманной стратегии инкрементальных копий, дедупликации, постоянного тестирования восстановления. Локальное хранение больших объемов данных — это не про покупку железа и развертывание файлового сервера. Это бесконечная инженерная работа по балансировке между скоростью, надежностью, стоимостью и сложностью системы.</p><p>Хранение больших объемов обостряет вопросы производительности, резервного копирования и автоматизации мониторинга, где каждый аспект требует балансировки между скоростью, надежностью и сложностью ИТ-инфраструктуры.</p><h2>Облачные хранилища</h2><p>С локальными хранилищами разобрались, теперь рассмотрим технические особенности альтернативного решения.</p><h3>Гибкость и масштабируемость без ограничений</h3><p>В облаке увеличение объемов хранения происходит мгновенно:</p><ul><li>без ожидания закупки нового оборудования;</li><li>без сложного планирования миграций;</li><li>без перебоев в обслуживании приложений.</li></ul><p>Эксплуатация и разработчики могут динамически добавлять терабайты и петабайты данных в рамках одного API-запроса. Облачное хранилище предлагает готовое решение для масштабирования от стартапов до международного уровня компаний.</p><h3>Финансовая прозрачность и удобная модель оплаты</h3><p>Модель Pay-As-You-Go (оплата по факту использования) дает бизнесу и разработчикам:</p><ul><li>предсказуемость расходов;</li><li>возможность мгновенно адаптировать инфраструктуру под изменяющиеся требования;</li><li>отсутствие необходимости капитальных затрат на старте;</li><li>гибкость в выборе тарифов хранения (горячие, холодные, архивные данные).</li></ul><p>Такая прозрачная модель помогает экономить бюджет без потери качества сервиса.</p><h3>Надежность и отказоустойчивость «из коробки»</h3><p>S3-совместимый Object Storage обеспечивает высокую доступность данных благодаря:</p><ul><li>автоматической репликации данных в нескольких географических регионах;</li><li>встроенным механизмам самовосстановления данных;</li><li>резервированию оборудования на уровне дата-центров;</li><li>постоянному мониторингу целостности объектов.</li></ul><h3>Оптимизация работы с любыми типами данных</h3><p>Хранилище позволяет одинаково эффективно работать:</p><ul><li>с миллионами мелких файлов (фото, документы, логи);</li><li>с тяжелыми объектами (видео или архивами).</li></ul><p>Облачная платформа автоматически оптимизирует хранение и доступ, снижая латентность и ускоряя обработку даже при экстремальных нагрузках.</p><h3>Высокий уровень безопасности данных</h3><p>В облаке предоставляется комплексная защита данных с помощью:</p><ul><li>шифрования на стороне клиента и сервера;</li><li>гибкого управления правами доступа (ACL, IAM);</li><li>соответствия требованиям хранения ПДН и прочих стандартов безопасности;</li><li>автоматического обнаружения потенциальных уязвимостей.</li></ul><p>Безопасность данных обеспечивается на каждом уровне инфраструктуры и подтверждается регулярными внешними аудитами.</p><h3>Инструменты для разработчиков и автоматизации</h3><p>Хранение данных в облаке ориентировано на удобство интеграции и масштабирование за счет:</p><ul><li>полного набора API и SDK для популярных языков программирования;</li><li>готовых модулей для работы с данными в распределенных системах;</li><li>продвинутых средств мониторинга, алертинга и автоскейлинга;</li><li>поддержки DevOps практик через IaC-инструменты.</li></ul><p>Автоматизация всех процессов упрощает разработку и сопровождение проектов, значительно снижая риски человеческих ошибок.</p><h2>Опыт хранения больших данных</h2><p>Когда речь идет о масштабных системах хранения — таких как S3-совместимый сервис Object Storage на платформе VK Cloud, — производительность определяется не только скоростью сети и дисков. Ключевую роль играют архитектурные особенности приложений: как именно данные распределяются, обрабатываются и индексируются.</p><p>Особенно важно это в системах с огромным количеством объектов, где миллионы или миллиарды файлов разного размера постоянно создаются, обновляются и удаляются.</p><h3>Как измеряется производительность облачного хранилища</h3><p>Для реальной оценки производительности облачного хранилища важно замерять:</p><ul><li>Количество операций в секунду (RPS): сколько запросов на чтение/запись способна обработать система.</li><li>Среднюю и 99-ю персентиль задержек: критично для оценки качества обслуживания конечных пользователей.</li><li>Производительность на больших объемах объектов: важно не просто тестировать один файл, а моделировать реальную работу приложений с множеством параллельных операций.</li><li>Влияние мелких и крупных файлов: системы по-разному работают при миллионах маленьких объектов и гигабайтных видео.</li></ul><p>Практические сценарии измерений:</p><ul><li>многопоточная загрузка 100 миллионов объектов размером 1–10 КБ;</li><li>массовое чтение миллионов объектов через S3 API;</li><li>удаление больших объемов объектов для оценки работы сборки мусора;</li><li>сценарии с версионированием объектов, чтобы проверить нагрузку на метаданные.</li></ul><h3>Почему шардирование критически важно для облачного хранилища</h3><p>Правильная организация шардирования данных — один из ключевых факторов производительности больших хранилищ.</p><p><b>Что происходит без правильного шардирования:</b></p><ul><li>«Горячие» бакеты (S3-бакеты) с высокой нагрузкой становятся узким местом.</li><li>Распределение нагрузки по серверам становится неравномерным.</li><li>Метаданные начинают тормозить операции доступа.</li><li>Снижается общая масштабируемость системы.</li></ul><p><b>Реальная практика VK Cloud:</b></p><ul><li>Метаданные объектов распределяются по кластерам через шардирование по диапазонам ключей.</li><li>При превышении нагрузки шард автоматически расщепляется (split) для перераспределения нагрузки между нодами.</li><li>Для хранения метаданных используется Tarantool как высокоскоростная in-memory база данных, способная выдерживать сотни тысяч операций в секунду на один шард.</li></ul><p><b>Такой подход позволяет обеспечить:</b></p><ul><li>низкие задержки доступа даже при миллиардах объектов;</li><li>линейное масштабирование — добавление новых серверов дает реальный прирост пропускной способности;</li><li>быструю обработку как мелких, так и больших файлов без перегрузки одной ноды.</li></ul><p>С увеличением объема метаданных нагрузка на отдельные узлы или компоненты системы возрастает, что ограничивает масштабируемость и может снижать производительность при высоких требованиях к обработке данных.</p><h2>За что мы любим Tarantool</h2><p>Принцип работы СУБД Tarantool кардинально отличается от классических SQL-баз (PostgreSQL, MySQL) в хранилищах:</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-07-02/15133b4d-c1bc-4d7d-a09f-e86554a1d249.png" alt="" /></figure><p>Tarantool позволяет работать с облачным хранилищем на скорости, которую классические базы не способны обеспечить без радикальных усилий по оптимизации.</p><h2>Как правильно проектировать нагрузку на S3-совместимое облако</h2><p>Если вы проектируете высоконагруженную систему, важно:</p><ul><li>Использовать естественное шардирование ключей (например, вставлять случайные префиксы в имена объектов).</li><li>Ожидать миллионы объектов в бакете и строить приложения так, чтобы они не зависели от скорости листинга всех файлов.</li><li>Минимизировать количество операций массового удаления объектов — использовать batch-удаление через S3 API.</li><li>Понимать, что работа с метаданными так же важна, как и сама передача данных.</li></ul><p>Производительность облачного хранилища определяется не только сетью и железом, но и архитектурой работы с данными. Правильное шардирование, оптимизация структуры ключей и использование быстрых конечных СУБД — основа эффективных и масштабируемых сервисов.</p><h2>Заключение</h2><p>Работа с петабайтными объемами данных требует серьезного подхода к проектированию инфраструктуры. На этом пути локальные решения сталкиваются с проблемами масштабирования, отказоустойчивости, обновления оборудования и обеспечения безопасности. Управление инфраструктурой превращается в отдельный проект со своими ресурсами.</p><p>Облачное хранилище обеспечивает:</p><ul><li>автоматическое масштабирование объема хранения без потерь в производительности;</li><li>высокую доступность данных благодаря распределению по зонам отказа;</li><li>прозрачную модель оплаты — вы платите только за реально используемые ресурсы;</li><li>эффективную работу как с миллионами мелких файлов, так и с крупными объектами;</li><li>безопасность данных с помощью встроенного шифрования и управления доступом через IAM;</li><li>богатый инструментарий API для полной интеграции в любые архитектуры приложений.</li></ul><p>Облачные хранилища предоставляют возможность компаниям сосредоточиться на развитии своих продуктов и бизнес-логики, передав инфраструктурные задачи профессиональной облачной платформе.</p>]]></content:encoded>
    </item>
    <item>
      <title>5 инструментов, которые используют айтишные команды</title>
      <link>https://tproger.ru/articles/5-instrumentov--kotorye-ispolzuyut-ajtiwnye-komandy</link>
      <comments>https://tproger.ru/articles/5-instrumentov--kotorye-ispolzuyut-ajtiwnye-komandy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/5-instrumentov--kotorye-ispolzuyut-ajtiwnye-komandy</guid>
      <description><![CDATA[<p>Показываем, какими инструментами пользуются внутри айтишных команд и какие можно использовать для себя здесь и сейчас или внедрить в свою команду.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/5-instrumentov--kotorye-ispolzuyut-ajtiwnye-komandy">5 инструментов, которые используют айтишные команды</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Статистика]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Ruby on Rails]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Adobe]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 26 Jun 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В статье собрали 5 решений — от трекеров задач и онлайн-досок до комплексных платформ для управления проектами. Инструменты помогут закрывать горящие дедлайны, ускорять разработку и четко распределять задачи — все то, что используют в больших командах. Рассказываем, что делать с этими фичами и как их использовать.</p><h2>1. МояДоска</h2><p><a href="https://moyadoska.com/">«МояДоска»</a> — это российский SaaS-сервис для совместной работы и визуализации идей. У онлайн-доски бесконечный размер: это значит, что вы можете размещать сколько угодно элементов и никогда не упретесь в границу. Так, команды, преподаватели и креативные специалисты могут проводить брейнштормы, планирования, презентации и обучение в одном пространстве.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/4fe2215f-6b29-4d0c-a490-281b2d045ddc.jpeg" alt="" /></figure><h3>Что под капотом</h3><p>Фронт написан на React + PixiJS, а бэк — Node.js + PostgreSQL. Это обеспечивает быстрый и понятный интерфейс и стабильную работу даже при большом объёме объектов на доске. Команда выпускает обновления несколько раз в месяц, а о новинках можно узнать в <a href="https://t.me/moyadoska">Telegram-канале</a> сервиса. Например, в недавнем апдейте появилась возможность превратить фрейм в таблицу или тетрадь за пару кликов, а еще задать нужное число столбцов, колонок, толщину границ и цвет.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/0f1a8489-ffe3-4003-8ecc-09d25bbba3b3.png" alt="" /></figure><p><b>Из главных функций:</b></p><ul><li>Понятный интерфейс</li><li>Совместная работа в реальном времени</li><li>Привычные инструменты: фигуры, стрелки, стикеры, текст, загрузка файлов, маркер, карандаш</li><li>Обрезка фото прямо на доске, воспроизведение аудио, поддержка PDF</li><li>Гибкое управление доступом</li><li>Возможность повторного использования шаблонов</li><li>Поддержка фреймов и создание логичных пространств для разных задач</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/21a6ecbd-a6b5-40c9-ae19-71a85b919c46.png" alt="" /></figure><h3>Переезд на сервис</h3><p>«МояДоска» интегрируется в процессы на разных этапах, упрощая жизнь команде. Например, сама команда сервиса перешла с Miro на свою доску для стратегического планирования. С помощью стикеров и стрелок они построили дерево решений, чтобы лучше расставить приоритеты. А одно маркетинговое агентство перевело все документы и сессии планирования на доску, отказавшись от Google Docs и таблиц. Это ускорило принятие решений: сотрудники работали с данными в одном формате, точно собрались в одном кабинете перед маркерной доской.</p><h2>2. METEOR</h2><p><a href="https://u-meteor.ru">METEOR</a> — инструмент управления проектами. Это трекер задач с дашбордами, досками канбан, диаграммами Ганта и API, который работает в виде веб-приложения как в облаке, так и на своих серверах. Продукт создавался как универсальный центр управления задачами: он объединяет в себе все — от разработки и тестирования до маркетинга и поддержки. Сейчас его используют более 250 команд и свыше 2000 пользователей ежедневно.</p><h3>Что под капотом</h3><p>В основе — стек Ruby on Rails, React и TypeScript, PostgreSQL и Redis, плюс современная инфраструктура на Docker и Kubernetes.</p><p>Система разбита на микросервисы — за фоновую обработку, нотификации и работу с файлами отвечает отдельный функционал. Авторизация построена через OAuth 2.0 (Google, Yandex), а для аналитики используется Posthog и ELK-стек. Мониторинг реализован на Prometheus + Grafana. Обновления выходят каждую неделю, а обратная связь приходит разработчикам METEOR через Telegram-бот.</p><p><b>Вот главные функции:</b></p><ul><li>Гибкие доски задач (Kanban, Scrum) — 6 видов.</li><li>Списки задач с группировками и иерархией.</li><li>Автоматические отчеты (ежедневные/еженедельные сводки).</li><li>Умные напоминания (Telegram-бот, email).</li><li>Глубокая аналитика (время выполнения задач, загрузка команды).</li><li>Потоковая автоматизация процессов</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/60e0eb0a-c1b1-473b-b343-1c4fb1b3fbd6.png" alt="" /><figcaption>Упрощенная схема сущностей системы</figcaption></figure><p>METEOR — мощный инструмент для автоматизации процессов, с триггерами, серверными функциями и ИИ-аналитикой. Он позволяет гибко настраивать сложные операции.</p><p>Все данные анализируются, и внутри самого сервиса можно понять, как работает команда: кто загружен, сколько времени уходит на задачи, где стопперы в процессе.</p><p>Разработчики используют METEOR для линковки задач с pull-requests и контроля бэклога. Менеджеры получают отчеты автоматически и не тратят часы, чтобы собрать всю информацию вручную. QA ведут тест-кейсы и баги в удобных досках, а DevOps отслеживают инциденты и шаги деплоя. Даже HR подключаются — через систему проходят кандидаты и стажеры.</p><h3>Переезд на сервис</h3><p>После внедрения METEOR команды замечают, что продуктивность их работы сильно повышается:</p><ul><li>скорость выполнения задач увеличивается в среднем на 25% — благодаря автоматическим напоминаниям и чётким процессам;</li><li>количество потерянных задач снижается на 70% — исчезают хаотичные чаты и забытые письма;</li><li>на составление отчетов и сбор метрик уходит не 5 часов, а всего 30 минут в неделю;</li><li>а экономия времени — около 75 часов в месяц на команду из 10 человек.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/f3f086f0-5846-4a35-adba-dc4fbe17f1c0.png" alt="" /><figcaption>Карточка задачи</figcaption></figure><p>METEOR не просто помогает контролировать задачи — он становится частью операционного «ядра» команды, избавляя от хаоса, ускоряя работу и делая все немного спокойнее.</p><h2>3. Gitlife</h2><p><a href="https://gitlife.ru">GitLife</a> — это универсальная платформа для хостинга репозиториев и построения полного DevOps-процесса внутри компании. Разработана с прицелом на закрытые контуры, импортозамещение и гибкость — подходит как для современных Git-проектов, так и для инфраструктур, где все еще используется SVN.</p><p>Помимо самого Gitlife, разработчики делают Gitlife AI, в котором есть доступ к топовым ИИ-моделям и инструментам, чтобы разрабатывать ИИ-решения.</p><h3>Что под капотом</h3><p>Внутри Gitlife собраны модули для:</p><ul><li>Кода — репозитории, ветвление.</li><li>Задач — бэклоги, спринты, дашборды.</li><li>Документации — совместное редактирование документов, управление правами.</li><li>Аналитики — карты потока ценности, качество кода, метрики по инженерам.</li><li>Пайплайны — модуль «Конвейер» управляет сборками и CI/CD.</li></ul><p>Gitlife используется ИТ-отделами и R&amp;D-подразделениями в компаниях с высокими требованиями к информационной безопасности. Подходит как для небольших команд, так и для распределённых корпораций с десятками проектов.</p><p>Что решает:</p><ul><li>Безопасный и полностью локальный хостинг исходного кода (Git + SVN)</li><li>Управление задачами и CI/CD в одном месте</li><li>Централизованный доступ, права, аудиты и история изменений</li><li>Полная поддержка DevOps-процессов на российском ПО</li><li>Альтернатива GitHub, GitLab и Bitbucket в условиях ограниченного доступа и санкционных рисков</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/bb3f815f-ce07-4c9d-9243-7ace4b14d5ba.png" alt="" /><figcaption>Создание пайплайна</figcaption></figure><h3>Переезд на сервис</h3><p>Инструмент подходит практически всем командам — от инди-разработчиков до крупных проектов с множеством ролей. Например, гейм-девелопер может разрабатывать персональный проект и хранить код бесплатно, стартап — разрабатывать MVP, а крупный бизнес — управлять большими командами и проектами максимально безопасно.</p><h2>4. Cerebro</h2><p><a href="https://cerebrohq.com/ru/">Cerebro</a> — профессиональная система для совместной работы и управления проектами. Она помогает ставить задачи, планировать этапы, следить за выполнением, обмениваться файлами и комментировать их прямо в системе. Особенно полезна для команд, которые делают VFX, 3D, анимацию или дизайн — но при этом легко адаптируется и под другие команды.</p><p>Платформа охватывает полный цикл — от первых идей и планирования до комментирования финальных шотов (отдельных сцен или кадров в видео/анимации) и соблюдения дедлайнов. Такой подход помогает команде ускорить работу на 20%, сократить время на правки и держать весь процесс под контролем — от начала до сдачи проекта.</p><p>Cerebro подходит для команд от 1 до 1000+ человек с задачами на проекте от 1 до 10000+. Сервис работает с 2009 года, сейчас им пользуются более 400 команд в России и СНГ.</p><h3>Что под капотом</h3><p>Cerebro поддерживает десктоп (Windows, Mac и Linux), веб-версию и мобильное приложение, локальное, облачное и гибридное развертывание. Инструмент построен на клиент-серверной архитектуре — она гибкая, поэтому можно настраивать конфиги исходя из потребностей бизнеса.</p><p>Из технологий:</p><ul><li><b>Backend:</b> C, C++, Python, SQL</li><li><b>Frontend:</b> JS, TypeScript, ReactJS, Qt, PyQt</li><li><b>Мобильные клиенты:</b> React Native</li><li><b>БД: </b>PostgreSQL с проприетарными расширениями + SQLite</li><li><b>Файловое хранилище:</b> Cargador</li><li><b>Плагины: </b>Tentaculo (встраивается в производственные программы)</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/d51c709f-2b9c-4e0b-95c0-2b78d61f5c1e.png" alt="" /></figure><p>Cerebro покрывает весь пайплайн — от идеи до финала. Вот основные возможности сервиса:</p><ul><li>Множественные уровни вложенности задач — подходит для сложных иерархий продакшена</li><li>Планирование с помощью диаграммы Ганта и специального инструмента «План»</li><li>Канбан-доска для визуального контроля задач</li><li>Инструмент «Моё пространство» — для персонализированной фильтрации и отбора задач</li><li>Уровни доступа и ролевое управление</li><li>Расширенная статистика по проектам, командам, сотрудникам</li><li>Совместная работа над большими файлами (видео, изображения, 3D) — Mirada позволяет комментировать, делать подрисовки, оставлять голосовые заметки</li><li>Интеграция с пакетами Adobe, Autodesk и мессенджерами, возможность встраивать в любые пайплайны</li><li>Удобное подключение фрилансеров</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/5411ad9d-a74b-46ed-9774-61d60ff69885.png" alt="" /><figcaption>Навигатор и форум</figcaption></figure><h3>Переезд на сервис</h3><p>Обычно внедрение начинается еще на этапе препродакшена — во время разработки концепции и четкого плана действий. Затем система сопровождает проект на всех стадиях, вплоть до постпродакшена (финального тестирования и релиза), где она закрывает 80-100% задач. Cerebro позволяет собирать всё в одном месте: задачи, правки, сроки, бюджеты, загрузку сотрудников и статус проекта в целом.</p><p>После переезда снимается много рутинных задач: больше не нужно вручную назначать исполнителей, комментировать медиаконтент, передавать файлы между программами и так далее. В среднем проекты выполняются на 20% быстрее, без потери качества. В больших студиях объем выпускаемых шотов может вырасти до 20+ тысяч — это уже работает у других клиентов, среди которых СберМаркетинг, Sinners, Black Point и другие. Cerebro также помогает переехать с других такс-трекеров и систем для управления проектами.</p><h2>5. Replit Teams</h2><p><a href="https://replit.com/teams">Replit Teams</a> — это платформа для совместной разработки в реальном времени. По сути, это интегрированная IDE + git-репозиторий + система управления задачами — и все доступно через браузер. Подходит как для командной работы в стартапах, так и для образовательных проектов, хакатонов и небольших продуктовых команд.</p><p>А главная фишка — встроенный ИИ, к которому можно обращаться прямо во время написания кода. Инструмент разработан с акцентом на простоту входа, командную работу и быстрое прототипирование. Поддерживает более 50 языков программирования и позволяет запускать полноценные веб-приложения в облаке.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-26/70b00e25-9ec7-4858-911c-b2d7a181104e.png" alt="" /></figure><h3>Что под капотом</h3><p>Внутри Replit Teams есть интерфейсы для:</p><ul><li>Кода — редактор с автокомплитом, подсветкой синтаксиса, терминалом и интеграцией с Git.</li><li>Задач — встроенный таск-менеджер с распределением задач по участникам.</li><li>Общения — встроенные комментарии в коде, возможность ревью и обсуждений.</li><li>CI/DevOps — запуск и отладка приложений без настройки окружения.</li><li>Доступа — гибкие роли, приглашения по ссылке, настройки приватности.</li></ul><h3>Переезд на сервис</h3><p>Replit Teams позволяет моментально начать работу: не нужно ставить зависимости, конфигурировать CI или закупать сервера. Подходит как для быстрой прокачки навыков, так и для реальных командных проектов в продакшене.</p><p>Сейчас инструмент активно используют в стартапах — для быстрого MVP, парного программирования, хакатонов и удаленных командах — как замена локальным IDE и конфигурациям.</p><p>Рассказывайте в комментариях, какими сервисами пользуетесь вы.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как мы строим агрегатор финансовых продуктов в Казахстане: история Finance.kz</title>
      <link>https://tproger.ru/articles/kak-my-stroim-agregator-finansovyh-produktov-v-kazahstane--istoriya-finance-kz</link>
      <comments>https://tproger.ru/articles/kak-my-stroim-agregator-finansovyh-produktov-v-kazahstane--istoriya-finance-kz?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Жандос Байдильденов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-my-stroim-agregator-finansovyh-produktov-v-kazahstane--istoriya-finance-kz</guid>
      <description><![CDATA[<p>Как из обычного сайта-витрины вырастить финтех-продукт? Расскажу, как строится агрегатор финансовых продуктов в Казахстане.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-my-stroim-agregator-finansovyh-produktov-v-kazahstane--istoriya-finance-kz">Как мы строим агрегатор финансовых продуктов в Казахстане: история Finance.kz</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[SEO]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Техподдержка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 22 Jun 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Я — Жандос, руководитель проекта <a href="https://finance.kz">Finance.kz</a>. Последний год активно развиваем агрегатор финансовых продуктов в Казахстане, и за это время рынок изменился кардинально. Хочу поделиться опытом создания финтех-решения с нуля и рассказать, как мы конкурируем с зарубежными игроками за счёт глубокой локализации.</p><h2>Откуда началось: мой путь в финтех</h2><p>До Finance.kz я работал в казахстанских финтех-проектах — bai.kz и finbee.kz. Там понял, что рынок агрегаторов в Казахстане находится в зачаточном состоянии. Пользователи мучились, сравнивая предложения банков вручную, а сами финансовые организации не умели эффективно работать с цифровыми каналами привлечения клиентов.</p><p>Finance.kz существовал уже более 3 лет, но работал как классический сайт-витрина. Когда я пришёл в проект год назад, стало ясно: нужно полностью переосмыслить подход и создать технологическое решение нового поколения.</p><h2>Состояние рынка: от монополии к жёсткой конкуренции</h2><p>Казахстанский рынок агрегаторов финансовых продуктов переживает бум. Ещё два года назад здесь было 2-3 локальных игрока с простейшим функционалом. Сегодня ситуация кардинально изменилась — зашли зарубежные команды: vbr.kz, fintree.kz, moneypanda.com и другие.</p><p>Эти компании привозят готовые решения, которые хорошо работали в России или других рынках. На первый взгляд их продукты выглядят более зрелыми — красивые интерфейсы, отработанные воронки конверсии. Но у импортных решений есть критический недостаток: они плохо адаптированы под специфику казахстанского рынка.</p><h2>Технологические вызовы: интеграция с госсервисами и банками</h2><p>Главная боль при разработке агрегатора в Казахстане — это интеграции. В отличие от рынков СНГ, здесь нельзя обойтись простым партнёрским трафиком. Пользователи хотят получить продукт онлайн, полностью, без походов в офисы.</p><h3>API-интеграции с банками и МФО</h3><p>За год мы реализовали прямые API-интеграции с крупнейшими игроками рынка. Это означает, что пользователь может не просто сравнить условия кредитов, но и подать заявку, пройти скоринг и получить одобрение, не покидая наш сайт.</p><p>Техническая сложность — в разнородности API. Каждый банк использует собственные протоколы, форматы данных и методы аутентификации. Пришлось создать унифицированный слой-адаптер, который «переводит» наши запросы в формат, понятный конкретной финансовой организации.</p><h3>Интеграция с госорганами</h3><p>Finance.kz интегрируется с государственными сервисами eGov и Палаты предпринимателей (ПКБ). Это позволяет автоматически подтягивать справки о доходах, данные о трудоустройстве и другие документы, необходимые для получения кредита.</p><p>Работа с госAPI — отдельная история. Протоколы меняются, документация часто устаревает, а техподдержка работает в режиме «как получится». Но результат того стоит: время оформления кредита сокращается с нескольких дней до 15-30 минут.</p><h2>Архитектура продукта: ставка на микросервисы</h2><p>При проектировании архитектуры Finance.kz мы отказались от монолитного подхода в пользу микросервисов. Это решение диктовалось спецификой агрегатора — нам нужно было обеспечить высокую доступность при интеграции с десятками внешних систем.</p><h3>Backend</h3><p>Основные сервисы написаны на Node.js с использованием Express.js. Для работы с базами данных используем PostgreSQL для транзакционных данных и Redis для кэширования. Очереди сообщений реализованы через RabbitMQ — это критично для обработки заявок пользователей.</p><p>Отдельно выделили сервис интеграций, который отвечает за взаимодействие с внешними API. Он построен по принципу circuit breaker — если один из банков не отвечает, это не ломает работу всего агрегатора.</p><h3>Frontend</h3><p>Фронтенд построен на React с использованием Next.js для серверной отрисовки. Это важно для SEO — львиная доля трафика приходит из поисковых систем по запросам типа «кредит онлайн».</p><h2>Стратегия «единого окна»: от поиска до получения</h2><p>Наша главная идея — превратить агрегатор из витрины в полноценный финтех-сервис. Пользователь должен получить продукт полностью онлайн: от сравнения условий до перечисления денег на карту.</p><p>Для этого мы реализовали несколько ключевых функций:</p><ul><li>Умный подбор продуктов на основе данных пользователя и машинного обучения</li><li>Предварительный скоринг для оценки вероятности одобрения ещё до подачи заявки</li><li>Автоматическое заполнение анкет с подтягиванием данных из госсервисов</li><li>Отслеживание статуса заявки в реальном времени</li></ul><h2>Монетизация: CPS как основа устойчивого бизнеса</h2><p>Мы работаем по модели CPS (Cost Per Sale) — получаем комиссию только за успешно выданные продукты. Для кредитов это 2% от суммы, для микрозаймов — фиксированная сумма от 7 до 15 тысяч тенге.</p><p>Такая модель выгодна всем участникам: банки платят только за результат, пользователи получают продукт бесплатно, а мы мотивированы повышать качество трафика и конверсию.</p><h2>Конкурентные преимущества: локализация против красивых интерфейсов</h2><p>Главное отличие Finance.kz от зарубежных конкурентов — интеграция в казахстанскую финтех-экосистему. Пока они тратят месяцы на адаптацию готовых решений, мы изначально строили продукт под местную специфику.</p><h3>Что даёт локальный подход:</h3><ul><li>Знание рынка: мы понимаем особенности работы казахстанских банков и МФО</li><li>Связи с регуляторами: легче договариваться об интеграциях с госорганами</li><li>Техническая экспертиза: наша команда уже прошла путь интеграции с местными API</li><li>Гибкая настройка продукта под изменения законодательства и требований ЦБ</li></ul><h3>Результаты и метрики</h3><p>За год активного развития мы достигли:</p><ul><li>150 000 уникальных пользователей в месяц</li><li>Интеграция с 15+ финансовыми организациями</li><li>Конверсия заявка-выдача на уровне 35-40% (против 15-20% у конкурентов)</li><li>Средний чек по кредитам — 1,2 млн тенге, по микрозаймам — 85 тысяч</li></ul><h2>Планы на будущее: от агрегатора к экосистеме</h2><p>Ближайшие 1-2 года будут критичными для всего рынка. Мы видим несколько ключевых направлений развития:</p><h3>Расширение продуктовой линейки</h3><p>Планируем добавить страхование, депозиты и инвестиционные продукты. Цель — стать единой точкой входа для всех финансовых потребностей пользователя.</p><h3>Внедрение ИИ и машинного обучения</h3><p>Работаем над персонализацией предложений и предиктивной аналитикой. Хотим научиться предлагать продукты до того, как пользователь их осознанно найдет.</p><h3>Международная экспансия</h3><p>Рассматриваем возможность выхода на рынки Узбекистана и Кыргызстана. Наша технологическая платформа легко масштабируется на соседние рынки.</p><h3>Собственные финансовые продукты</h3><p>В долгосрочной перспективе планируем получить лицензию МФО и предлагать собственные займы наиболее качественным клиентам.</p><h2>Уроки и выводы</h2><p>Главный урок последнего года: в финтехе побеждает не тот, у кого красивее интерфейс, а тот, кто лучше решает реальные проблемы пользователей. Красивый дизайн можно скопировать за месяц, а на создание качественной технологической интеграции уходят годы.</p><p>Второй важный момент — команда решает всё. Мы собрали людей, которые понимают как технологии, так и специфику финансового рынка. Это даёт нам фору перед конкурентами, которые пытаются адаптировать готовые решения силами удалённых команд.</p><p>Рынок агрегаторов в Казахстане только формируется, и впереди ещё много интересных вызовов. Уверен, что следующие два года покажут, кто готов строить долгосрочный бизнес, а кто просто пытается заработать на хайпе.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как разработать простое приложение и тратить на него 2000$ в месяц</title>
      <link>https://tproger.ru/articles/kak-razrabotat-prostoe-prilozhenie-i-tratit-na-nego-2000--v-mesyac</link>
      <comments>https://tproger.ru/articles/kak-razrabotat-prostoe-prilozhenie-i-tratit-na-nego-2000--v-mesyac?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-razrabotat-prostoe-prilozhenie-i-tratit-na-nego-2000--v-mesyac</guid>
      <description><![CDATA[<p>Разработчик показывает, как из простого приложения сделать дорогостоящее — за счет трат на сервера, инфраструктуру и многое другое.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-razrabotat-prostoe-prilozhenie-i-tratit-na-nego-2000--v-mesyac">Как разработать простое приложение и тратить на него 2000$ в месяц</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[VPS]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 06 Jun 2025 12:31:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Да, из простого приложения можно создать такую архитектуру, которая будет стоить более $2000 в месяц. В этом <a href="https://www.youtube.com/watch?v=nYlv0I9Ips0">видео</a> разработчик показывает, как пошагово усложнять инфраструктуру простого приложения для задач, добавляя все больше и больше компонентов. А чтобы вам было проще сориентироваться — мы адаптировали его на русский.</p><h2>Этап 1: Простой MVP за $0</h2><p>Изначально нужно создать максимально простое приложение для управления задачами: веб-страница с несколькими категориями и возможностью добавлять таски. На фронте разработчик использует библиотеку Shad CN UI, а на бэке — Flask. Данные хранятся просто в словаре Python. Все приложение — это один файл. Оно запускается в Docker-контейнере через docker compose.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-06/b4963af4-3c83-4697-a8be-848850a1ee82.png" alt="" /></figure><p>Это MVP работает локально на компьютере разработчика и рассчитано на одного пользователя. Такой подход позволяет всё упростить, но при перезапуске контейнера все данные будут утеряны. Правда, чтобы получить прибыль, этого недостаточно.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-06/cced47f6-e8b2-40dd-a540-476a233e217e.png" alt="" /></figure><h2>Этап 2: Инфраструктура на $30</h2><p>Чтобы приложение стало более удобным и приближенным к продакшену, разраб добавляет несколько главных компонентов:</p><ul><li><b>База данных:</b> PostgreSQL.</li><li><b>Веб-сервер:</b> Nginx для проксирования запросов и избавления от портов.</li><li><b>Аутентификация: </b>авторизация через JWT и интерфейсы входа и регистрации на фронтенде.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-06/e903bb53-7168-4485-9d3a-a11f68015901.png" alt="" /></figure><p>Все эти компоненты подключаются к существующему приложению через docker-compose.yml. Благодаря этому теперь можно запускать приложение на localhost, а не по порту, и все будет работать как полноценное веб-приложение. Размещение такой системы на бесплатном облачном тарифе или VPS обойдётся в пределах 30 долларов.</p><h2>Этап 3: Допиливание до $100</h2><p>Разработчик добавляет допфункции:</p><ul><li><b>Уведомления по email:</b> вместо стороннего API — система очередей с RabbitMQ и воркером, который отправляет письма.</li><li><b>Обновления в реальном времени:</b> WebSocket’ы для синхронизации задач на разных устройствах.</li><li><b>Кэширование:</b> Redis для хранения данных в памяти, что значительно ускоряет работу.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-06/4a4ace77-7e6c-4e2f-b8a3-03943a57254a.png" alt="" /></figure><p>Также подключается Docker Build Cloud — сервис для параллельной сборки контейнеров и шаринга кеша между проектами. Это повышает производительность и ускоряет разработку.</p><p>Теперь в системе работает очередь заданий, кеш, WebSocket-сервер, SMTP и полноценная база данных. Все эти компоненты увеличивают инфраструктурные затраты до примерно $100 в месяц.</p><h2>Этап 4: Мониторинг и масштабирование за $500</h2><p>Разработчик внедряет:</p><ul><li><b>Логирование:</b> стек ELK (Elasticsearch, Logstash, Kibana).</li><li><b>Мониторинг:</b> Prometheus и Grafana.</li><li><b>Горизонтальное масштабирование:</b> добавляются реплики некоторых сервисов и балансировка нагрузки через Nginx.</li></ul><p>Эти инструменты позволяют отслеживать метрики, визуализировать логи, следить за состоянием приложений и быстро выявлять сбои. Инфраструктура становится ближе к корпоративному уровню. Стоимость такого комплекса достигает уже около 400–500 долларов в месяц.</p><h2>Этап 5: Целых $2000 долларов</h2><p>Разработчик решает перейти на Kubernetes и развернуть приложение в разных дата-центрах по всему миру. Для управления трафиком используется глобальный балансировщик нагрузки (например, Cloudflare). А чтобы все работало стабильно, внедряются:</p><ul><li>Postgres с репликацией в реальном времени,</li><li>Redis для быстрой отдачи данных.</li></ul><p>Сейчас без ИИ приложение уже не имеет смысла. Поэтому разработчик решает добавить серверлесс-функции с категоризацией задач, приоритетами и предложениями на основе поведения пользователей, а также с использованием обработки естественного языка для создания тасков. Также подключаются правовые ограничения — поддержка GDPR и CCPA.</p><p>Для мониторинга:</p><ul><li>Jaeger — для распределённой трассировки,</li><li>ELK Stack — для логов,</li><li>Grafana + PagerDuty — для алертов и инцидентов.</li></ul><p>Вишенка на торте — план восстановления после катастроф: бэкапы, автоматическое переключение на другие регионы и подготовка команды.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-06-06/399735e5-c8d1-4003-9ed2-91d9e5b83764.png" alt="" /></figure><p>Хотя вся система началась с одного Python-файла и простого UI, шаг за шагом разработчик добавлял в нее компоненты, которые делают её пригодной для реального продакшена: защита, масштабируемость, отказоустойчивость, мониторинг, кеширование и очереди. И оно вполне может стоить несколько сотен или даже тысяч долларов в месяц при развертывании в облаке.</p>]]></content:encoded>
    </item>
    <item>
      <title>Сломал ногу — выучил Python: как ИИ помог экс-консультанту стать программистом за 100 дней</title>
      <link>https://tproger.ru/news/slomal-nogu---vyuchil-python--kak-ii-pomog-eks-konsultantu-stat-programmistom-za-100-dnej</link>
      <comments>https://tproger.ru/news/slomal-nogu---vyuchil-python--kak-ii-pomog-eks-konsultantu-stat-programmistom-za-100-dnej?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/slomal-nogu---vyuchil-python--kak-ii-pomog-eks-konsultantu-stat-programmistom-za-100-dnej</guid>
      <description><![CDATA[<p>Экс-консультант стал программистом за 100 дней с помощью ChatGPT и Python — собрал портфолио, прошел собеседование и получил работу без курсов и Leetcode</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/slomal-nogu---vyuchil-python--kak-ii-pomog-eks-konsultantu-stat-programmistom-za-100-dnej">Сломал ногу — выучил Python: как ИИ помог экс-консультанту стать программистом за 100 дней</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 02 Jun 2025 18:09:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Эрик Леннрот, бывший консультант в Big Four, <a href="https://eriklonnroth.com/100-days/">стал программистом</a> всего за 100 дней — благодаря больничному, упорству и ChatGPT.</p><p>Все началось, когда 38-летний Эрик сломал лодыжку во время пробежки. Лежа дома, он увидел в соцсетях истории о том, как люди запускали SaaS-проекты за выходные с помощью ИИ. Это вдохновило его на третью попытку освоить программирование.</p><h2>Учеба без бюджета — только ИИ и бесплатные курсы</h2><p>Эрик решил не тратить ни копейки на курсы. Он выбрал Python как основной язык и прошел CS50 от Гарварда — сначала курс по Python, потом по веб-разработке.</p><p>С ИИ он работал как с личным наставником: писал псевдокод, просил ChatGPT раскритиковать его, затем вручную набирал код. Синтаксис — по запросу. Такой подход позволил быстрее понять концепции, а не просто запомнить команды.</p><p>Свой первый проект он сделал по мотивам Wordle — игру на угадывание слов он реализовал на Python под названием PyWordle.</p><p>Затем собрал полноценное веб-приложение Make My Meal Plan: генерация рецептов, списки покупок, TailwindCSS, Django, PostgreSQL, CI/CD и даже тестирование через Playwright — все своими руками за 150 часов. Проект включал 25 000 строк кода.</p><h2>Работа после 100 дней</h2><p>Через 3 месяца обучения он получил оффер. Без Leetcode, без алгоритмических задач — только благодаря портфолио. Его взяли на испытательный срок в консалтинговую компанию в Лондоне, чтобы он заменил Excel и устаревшие тулзы на автоматизированные пайплайны.</p><p>Эрик честно рассказал, что научился программировать за пару месяцев и активно использовал ИИ — и все равно его приняли.</p><p>По его словам, весь путь стоил $120 — подписки на Claude Pro и Cursor. Все остальное — бесплатные курсы и открытые материалы. Недавно он прошел испытательный срок, получил повышение и теперь работает с геоданными и статистикой, используя pandas и ArcGIS. Параллельно пишет Django-приложение для анализа населения и доходов в Великобритании.</p><h2>«Точно вовремя» вместо «на всякий случай»</h2><p>Эрик считает, что его история — отражение новой реальности: вместо долгих программ и формального образования — самостоятельное обучение под задачи, с фокусом на инициативу и реальные результаты. ИИ в этом — не костыль, а катализатор.</p>]]></content:encoded>
    </item>
    <item>
      <title>С помощью чего выучить SQL в 2025 году?</title>
      <link>https://tproger.ru/articles/s-pomoshhyu-chego-vyuchit-sql-v-2025-godu-</link>
      <comments>https://tproger.ru/articles/s-pomoshhyu-chego-vyuchit-sql-v-2025-godu-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Влад Полбенников]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/s-pomoshhyu-chego-vyuchit-sql-v-2025-godu-</guid>
      <description><![CDATA[<p>Как выучить SQL с нуля в 2025? Сравниваем 6 платформ: SYNC STUDY, SQL Academy, Karpov Courses и другие. Бесплатные и платные курсы, задачи из реальной аналитики, поддержка PostgreSQL. Советы по выбору для новичков и профессионалов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/s-pomoshhyu-chego-vyuchit-sql-v-2025-godu-">С помощью чего выучить SQL в 2025 году?</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Data Science]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 01 Jun 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>SQL остаётся ключевым инструментом для работы с данными. Даже базовые знания увеличивают шансы на трудоустройство в аналитику и Data Science. Но найти подходящий тренажёр или курс сложно: одни платформы слишком поверхностные, другие — дорогие, а третьи не дают практики в реальной среде.</p><h2>Как выучить SQL: ТОП-6 платформ для обучения</h2><p>Протестировав много ресурсов, я выбрал 6 лучших. Каждый подходит для разных целей: от тренажеров до подготовки к сложным собеседованиям.</p><p><b>Критерии оценки</b></p><ul><li>Контент: глубина тем (от SELECT до оптимизации запросов), задачи из реальной работы, подготовка к собеседованиям, поддержка сообщества.</li><li>Технические аспекты: мобильная версия, своя IDE, сертификат, адаптация под РФ, поддержка PostgreSQL.</li></ul><h3>SYNC STUDY</h3><p>Ссылка: <a href="https://sync.study/">SYNC STUDY</a></p><p>Для кого: Новички, профи и те, кто готовится к собеседованиям.</p><ul><li>Глубина погружения: Полный цикл — от основ (WHERE, JOIN) до оконных функций и создания витрин.</li><li>Собеседования: Отдельный модуль с кейсами из практики и с теоретическими вопросами с собеседований.</li><li>Практика: Задачи на расчет LTV, ABC-анализ, парсинг логов.</li><li>Техническая часть: Удобная мобильная версия, своя IDE. Полная адаптация под РФ.</li></ul><ul><li>Решения воспроизводятся в реальной среде PostgreSQL.</li></ul><p>Минусы:</p><ul><li>Поддержка в процессе прохождения: отсутствует.</li><li>Сертификат по окончании курса: нет.</li></ul><h3>SQL Academy</h3><p>Ссылка: <a href="https://sql-academy.org/ru">SQL Academy</a></p><p>Для кого: Новички и практикующие разработчики.</p><ul><li>Глубина погружения: От простых запросов до триггеров и оптимизации. Подробные примеры из e-commerce.</li><li>Собеседования: Нет отдельного раздела, но есть задачи уровня FAANG.</li><li>Практика: Симулятор с интерактивными заданиями (например, расчет Retention Rate).</li><li>Поддержка: Форум, где можно обсудить решение.</li><li>Техническая часть: Своя IDE, работает на мобильных. Сертификат — после финального экзамена.</li><li>Бесплатный доступ.</li></ul><p>Минус: Мало информации по работе с большими данными (например, партицирование).</p><h3>Karpov Courses</h3><p>Ссылка: <a href="https://karpov.courses/simulator-sql">Karpov Courses</a></p><p>Для кого: Новички в IT, менеджеры, аналитики, дата-сайентисты и все, кто хочет освоить SQL и продуктовую аналитику с нуля.</p><ul><li>Глубина погружения: Акцент на практику — от основ SQL до продвинутых тем (оконные функции, объединения) и решения реальных продуктовых задач.</li><li>Собеседования: Кейсы из собесов Альфа-Банка, Сбера, Ozon.</li><li>Практика: 150+ SQL-задач на симуляторе. Работа над кейсом аналитика сервиса доставки: расчет бизнес-метрик, анализ данных, проверка гипотез.</li><li>Поддержка: Доступ к чату сообщества для общения и вопросов.</li><li>Техническая часть: IDE с подключением к реальной PostgreSQL и инструмент для визуализации Redash.</li></ul><ul><li>Бесплатный доступ ко всем материалам, симулятору и инфраструктуре.</li></ul><h3>SQL-ex.ru</h3><p>Ссылка: <a href="https://sql-ex.ru/">SQL-ex.ru</a></p><p>Для кого: Для тех, кто любит учиться через решение задач.</p><ul><li>Глубина погружения: Более 500 задач — от простых SELECT до хранимых процедур.</li><li>Собеседования: Нет.</li><li>Практика: Олимпиадные задания (например, расчет скользящего среднего без оконных функций).</li><li>Поддержка: Форум с энтузиастами.</li><li>Техническая часть: Устаревший интерфейс, нет мобильной версии.</li></ul><p>Минус: Теория подается фрагментарно.</p><h3>SQLZoo</h3><p>Ссылка: <a href="https://sqlzoo.net/wiki/SQL_Tutorial">SQLZoo</a></p><p>Для кого: Новички, которые хотят попробовать SQL бесплатно.</p><ul><li>Глубина погружения: Базовый уровень + JOIN, подзапросы.</li><li>Собеседования: Нет.</li><li>Практика: Интерактивные задачи с автоматической проверкой.</li><li>Поддержка: Нет сообщества.</li><li>Техническая часть: Работает на мобильных, своя IDE.</li></ul><p>Минус: Нет продвинутых тем (CTE, оптимизация).</p><h3>Stepik</h3><p>Ссылка: <a href="https://stepik.org/catalog/42">Курсы на Stepik</a></p><p>Для кого: Для системного изучения с нуля.</p><ul><li>Глубина погружения: Полный курс с видеоуроками — от основ до анализа в Python.</li><li>Собеседования: Нет.</li><li>Практика: Задачи на анализ реальных датасетов (например, Airbnb).</li><li>Поддержка: Обсуждения к каждому уроку.</li><li>Техническая часть: Поддержка PostgreSQL, сертификат.</li></ul><p>Минус: Мало задач на оконные функции.</p><h2>Итог: Какую платформу выбрать?</h2><ul><li>Для новичков: SQL Academy (бесплатно) или Stepik (структурный курс).</li><li>Для подготовки к собеседованиям: SYNC STUDY или Karpov Courses (бесплатно).</li><li>Для углубленного изучения: Karpov Courses (аналитика) или SQL-ex.ru (практика).</li><li>Для мобильного обучения: SYNC STUDY или SQLZoo.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Ошибки, которые можно избежать в SQL: грабли начинающего аналитика</title>
      <link>https://tproger.ru/articles/owibki--kotorye-mozhno-izbezhat-v-sql--grabli-nachinayushhego-analitika</link>
      <comments>https://tproger.ru/articles/owibki--kotorye-mozhno-izbezhat-v-sql--grabli-nachinayushhego-analitika?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алёна Select*]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/owibki--kotorye-mozhno-izbezhat-v-sql--grabli-nachinayushhego-analitika</guid>
      <description><![CDATA[<p>Эта статья — ваш чеклист по самым распространённым ошибкам в SQL: с примерами, пояснениями и советами, как не попасть в ловушку из-за забытого WHERE или неправильного JOIN.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/owibki--kotorye-mozhno-izbezhat-v-sql--grabli-nachinayushhego-analitika">Ошибки, которые можно избежать в SQL: грабли начинающего аналитика</a>»</p>]]></description>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 18 May 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>SQL — мощный инструмент, но неправильное использование даже простых операторов может привести к неверной аналитике. В этой статье — основные ошибки, которые совершают новички. Каждую разберём с использованием примеров на PostgreSQL.</p><h2>Какие бывают ошибки в SQL</h2><p>Ошибки в SQL можно условно разделить на несколько категорий:</p><ol><li><b>Синтаксические ошибки.</b> Это ошибки в написании SQL-кода: пропущенные запятые, неверные ключевые слова, неправильный порядок конструкции. Они чаще всего ловятся самим движком базы при попытке выполнить запрос.</li><li><b>Логические ошибки.</b> Самые коварные. Код выполняется, но результат не тот. Например, неверный фильтр, JOIN по неправильному полю, перепутанный порядок WHERE и HAVING или лишний DISTINCT. Эти ошибки особенно опасны в аналитике, потому что могут привести к неверным бизнес-решениям.</li><li><b>Ошибки работы с NULL.</b> NULL — это отдельная категория значений в SQL, и она требует особого внимания. Сравнение через = и != с NULL не работает так, как многие ожидают. Здесь нужны IS NULL и IS NOT NULL.</li><li><b>Ошибки при работе с JOIN. </b>Отсутствие условия соединения, неправильный тип соединения (INNER вместо LEFT, или наоборот), дублирование строк из-за некорректного связывания — всё это может нарушить итоговую выборку.</li><li><b>Ошибки производительности.</b> Использование SELECT * в больших таблицах, отсутствие индексов на полях фильтрации, тяжёлые подзапросы и вложенные SELECT’ы там, где можно обойтись CTE или JOIN — всё это тормозит выполнение и грузит сервер.</li><li><b>Ошибки доступа.</b> Запрос к несуществующей таблице, попытка обращения к колонке с опечаткой, отсутствие прав на SELECT/INSERT — это технические ошибки, но тоже распространённые. Часто возникают при смене окружения (dev → prod, другой пользователь и т.д.).</li></ol><p>Перейдем к примерам распространенных ошибок.</p><h2>Синтаксическая ошибка с некорректным GROUP BY</h2><p>Ошибка возникает, если указать в SELECT столбцы, которые не попадают ни в агрегатную функцию, ни в GROUP BY.</p><p>Ошибочный запрос, который выдаст ошибку “ERROR: column “sales.product” должен присутствовать в предложении GROUP BY или использоваться в агрегатной функции:</p><p>Исправленный запрос:</p><h2>Логическая ошибка при использовании DISTINCT с агрегатной функцией без GROUP BY</h2><p>Комбинация DISTINCT и агрегатных функций, таких как SUM, AVG, COUNT, без явного указания GROUP BY, вводит SQL в замешательство. Запрос неясен: нужно ли агрегировать по customer_id, или просто выбрать уникальные строки? SQL требует однозначности — все неагрегированные поля в SELECT должны быть указаны в GROUP BY. Иначе возникает ошибка выполнения или, что хуже, некорректный результат.</p><p>Ошибочный запрос:</p><p>Результатом будет:</p><p>ERROR: column “sales.customer_id” must appear in the GROUP BY clause or be used in an aggregate function</p><p>Исправленный запрос:</p><h2>Ошибка при использовании JOIN с несовместимыми типами данных</h2><p>При соединении таблиц через поля с разными типами данных (INTEGER, TEXT, UUID, и т. д.) база данных может не только вернуть некорректные результаты, но и вовсе не выполнить соединение. Особенно это критично, если соединение происходит по полям с разной длиной или форматом — ошибки при этом могут быть скрытыми и долго не обнаруживаться.</p><p>Ошибочный запрос:</p><p>Тут order_id и customer_id имеют разные типы данных.</p><p>Исправленный запрос:</p><h2>Удаление данных из таблицы без WHERE</h2><p>Это классика жанра: забыть WHERE в DELETE — всё равно что взять и нажать «Удалить всё», и подтвердить. Вместо удаления пары строк исчезает вся таблица. Особенно больно, если это прод и нет бэкапа. Один неосторожный DELETE, и ваша база превращается в чистый лист.</p><p>Ошибочный запрос, который удалит все строки из таблицы:</p><p>Исправленный запрос:</p><h2>Ошибка работы с NULL при сравнении через =</h2><p>NULL в SQL — это не просто «пусто», а «неизвестно». А с неизвестным нельзя сравнивать напрямую. Условие amount = NULL никогда не даст TRUE, потому что результат сравнения с NULL — всегда NULL, то есть «неизвестно». Поэтому такой запрос не вернёт ни одной строки, даже если NULL в колонке есть. Для проверки нужно использовать IS NULL и IS NOT NULL.</p><p>Ошибочный запрос, который не выдаст ни одной строки:</p><p>Исправленный запрос:</p><h2>Ошибка с JOIN без условий соединения</h2><p>Забыть ON в JOIN — всё равно что сказать базе: «Соедини всё со всем, как хочешь». В первом случае вы получите синтаксическую ошибку, а во втором — декартово произведение: каждая строка из первой таблицы будет соединена с каждой строкой из второй. Это быстро превращает обычный запрос в лавину данных и боль для сервера (и аналитика).</p><p>Ошибочный запрос с синтаксической ошибкой:</p><p>Ошибочный запрос с декартовым произведением:</p><p>Исправленный запрос:</p><h2>Неоправданное использование подзапросов</h2><p>Подзапросы внутри SELECT могут выглядеть удобно, но часто создают лишнюю нагрузку. Каждый подзапрос выполняется отдельно для каждой строки — а это значит больше вычислений, больше времени и меньше масштабируемости. Там, где можно использовать JOIN, лучше так и сделать: это быстрее и понятнее.</p><p>Ошибочный запрос:</p><p>Исправленный запрос:</p><h2>Ошибка производительности при выборе всех строк с SELECT *</h2><p>Можно воспринимать эту ошибку как «принеси мне всё из холодильника, хотя я хотел только яблоко». Такой запрос тянет все колонки, включая те, которые не нужны. Это замедляет выполнение, особенно при работе с большими таблицами, и мешает оптимизатору строить эффективный план.</p><p>Ошибочный запрос:</p><p>Исправленный запрос:</p><h2>Отсутствие WHERE и LIMIT при больших данных в таблице</h2><p>Без WHERE и LIMIT вы загружаете всю таблицу — даже если вам нужно 5 строк. Это всё равно что выгружать весь архив почты за 10 лет, чтобы найти одно письмо. Такой запрос сильно нагружает базу, тормозит интерфейс и может привести к таймаутам или сбоям.</p><p>Ошибочный запрос:</p><p>Исправленный запрос:</p><h2>Неэффективное использование OR</h2><p>Запросы с множеством OR выглядят безобидно, но могут мешать оптимизатору построить эффективный план выполнения. Особенно в больших таблицах это замедляет работу. Использование IN делает запрос компактнее, читаемее и зачастую быстрее.</p><p>Ошибочный запрос:</p><p>Исправленный запрос:</p><h2>Заключение</h2><p>Большинство ошибок новичков — это результат непонимания порядка выполнения SQL-запроса. Разбирайте, в какой момент работает WHERE, когда применяется GROUP BY, и когда можно использовать алиасы. Лучше медленно, но правильно, чем быстро и с багами. SQL прощает мало, но учит быстро — особенно если смотреть на результаты собственных запросов внимательно.</p><p>Не бойтесь экспериментировать, но всегда проверяйте себя: читайте, что именно возвращает ваш запрос, и задавайте себе вопрос: «А это точно то, что я хотел(а) получить?» Чем раньше вы привыкнете анализировать не только код, но и его поведение, тем быстрее исчезнет ощущение, что SQL — это какая-то магия. На самом деле, это просто строгое, но честное ремесло.</p><p>Еще больше полезных материалов в моем TG-канале. Подписывайтесь и читайте контент <a href="https://t.me/+yuO3oSXyXQQ5OWNi">по ссылке</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как работает Sharding в базах данных?</title>
      <link>https://tproger.ru/articles/kak-rabotaet-sharding-v-bazah-dannyh-</link>
      <comments>https://tproger.ru/articles/kak-rabotaet-sharding-v-bazah-dannyh-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Владислав Устинов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-rabotaet-sharding-v-bazah-dannyh-</guid>
      <description><![CDATA[<p>Что такое Sharding. Показываем, как работает шардинг в базах данных. Рассматриваем пошаговую инструкцию и основные нюансы ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-rabotaet-sharding-v-bazah-dannyh-">Как работает Sharding в базах данных?</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[NoSQL]]></category>
      <category><![CDATA[Дата-центр]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 15 May 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда данных становится слишком много для одного сервера, на помощь приходит шардинг — способ разбить базу на части и разложить их по разным машинам. Это помогает масштабироваться, ускоряет запросы и снижает нагрузку. Но вместе с плюсами шардинг приносит и новые сложности: как искать данные, как проводить транзакции между серверами, как считать агрегаты. Сегодня разбираемся, как всё устроено, какие бывают подходы к шардингу и что нужно учесть при его внедрении.</p><h2>Как работает database sharding</h2><p>Database sharding (шардирование базы данных) — это техника горизонтального масштабирования, при которой большая база разделяется на несколько частей. Их называют шардами. Эти шарды распределяются по другим серверам и связываются в одну систему. Рассмотрим подробнее.</p><h3>Принцип: разбиение данных на независимые сегменты (шарды)</h3><p>Каждый шард работает как отдельная независимая база данных. Ключевым элементом здесь выступает ключ шардирования (shard key). Это правила, которые определяют, в какой именно шард попадёт конкретная строка данных.</p><p>Например, мы можем задать правило: если у нас есть user_id и его значение меньше тысячи, то данные попадают в шард 1, если значение больше тысячи, то в шард 2.</p><p>Главная цель такого разделения — добиться независимости шардов. В идеале запрос, касающийся данных одного пользователя (или одного документа, заказа и т. д.), должен обрабатываться только одним шардом.</p><p>Так, мы можем параллельно обрабатывать много запросов и увеличивать пропускную способность системы.</p><h3>Общая архитектура: клиент — роутер — шард</h3><p>Чтобы приложение могло понять, в какой шард отправить запрос, нужна особая архитектура.</p><p><b>Клиент</b>: Программа на стороне пользователя, которая отправляет стандартный запрос к базе данных (например, SELECT * FROM users WHERE user_id = 123).</p><p><b>Маршрутизатор запросов</b> или роутер (Query Router): Это что-то вроде посредника между клиентом и шардом, который выполняет роль диспетчера. Он принимает запрос, при помощи sharding ключа определяет, что это за данные, в какой шард и с какой целью их надо отправить. Далее он отправляет запрос на нужный шард.</p><p><b>Шард (Shard)</b>: Получает запрос, выполняет и возвращает результат обратно маршрутизатору, который затем передаёт его клиенту.</p><p>Благодаря такой архитектуре мы можем «скрыть» database sharding на стороне клиента и обеспечить централизованное управление запросами. Не надо сильно заморачиваться с кодом и архитектурой приложений, ведь вся логика будет на серверах.</p><h3>Основные компоненты: шард, маршрутизатор, реплика-сеты</h3><p>Мы уже рассмотрели, что такое шарды и маршрутизаторы, теперь обратим внимание на реплика-сеты. Это сервера с копией данных шардов. Если главный сервер шарда выходит из строя, одна из реплик автоматически берёт на себя его роль. Так, мы можем повысить отказоустойчивость нашей системы.</p><p>Ещё в этой схеме обычно применяют серверы конфигурации. Это отдельный компонент, который хранит метаданные о шардах. Он содержит информацию о том, какие диапазоны ключей или хеши какому шарду соответствуют. Маршрутизаторы периодически обращаются к серверам конфигурации, чтобы получить актуальную карту распределения данных и лучше понять, в какой шард направить тот или иной запрос.</p><h2>Виды шардинга</h2><p>Существует много вариантов, как разбить базу данных на шарды. Этот выбор будет зависеть от множества факторов: структуры данных, типичных запросов, требований к производительности и сложности управления. Разберём основные виды шардинга.</p><h3>Горизонтальный sharding (по строкам): самый популярный</h3><p>При горизонтальном шардинге мы «нарезаем» нашу базу данных по строкам. Допустим, у нас таблица с клиентами. Мы задаём диапазон ключу шардирования с user_id от 1 до 1 000 000. Данные в этом диапазоне, построчно будут храниться в шадре 1. Если user_id попадает в диапазон от 1 000 001 до 2 000 000, то эти данные отправляем на шадр 2. И так далее.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-30/ced7c0e7-fcbb-4f28-870b-91682a38f689.png" alt="Что такое Sharding" /><figcaption>Горизонтальный шардинг</figcaption></figure><p>Благодаря этому способу мы можем равномерно распределять данные, и нам будет проще масштабировать систему при помощи создания новых шадров и добавления серверов.</p><p>Горизонтальный sharding — идеальный вариант, когда основная проблема — это огромное количество строк в таблицах и высокая нагрузка на чтение/запись.</p><h3>Вертикальный шардинг (по столбцам): разделение по функциональности</h3><p>Если горизонтальный шардинг режет таблицу поперёк (по строкам), то вертикальный — вдоль, разделяя столбцы. Таблица делится на несколько с меньшим количеством столбцов. Обычно они группируются по частоте использования или по смысловой нагрузке. Например, в таблице юзеров можно выделить часто запрашиваемые user_id, username, email в одну таблицу, а редко используемые — biography, preferences, last_login_details — в другую.</p><p>Это полезно, когда у таблицы очень много столбцов или когда группы столбцов имеют совершенно разные паттерны доступа. Мы можем улучшить производительность запросов, так как они работают с таблицами меньшей ширины.</p><h3>Directory-based sharding: использование хеш-таблицы маршрутов</h3><p>При горизонтальном и вертикальном шардинге маршрутизатор часто сам, при помощи специальных функций, определяет, какие данные в какой шадр отправить. Это не всегда удобно. При таком подходе мало гибкости. Поэтому был придуман вид шардинга, который опирается на хеш-таблицы и называется directory-based. Его суть в том, что мы создаём централизованный каталог, который связывает наши ключи шардирования и шарды.</p><p>Вот пример того, как это работает:</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-30/8dc151d5-591c-4a6c-8564-898afc26aaa1.png" alt="Как работает шардинг в базах данных" /><figcaption>Directory-based sharding</figcaption></figure><ul><li>Клиентское приложение отправляет запрос (например, получить данные для order_id = 98765).</li><li>Маршрутизатор запросов перехватывает его.</li><li>Маршрутизатор обращается к каталогу: с запросом, где найти order_id = 98765.</li><li>Каталог ищет в своей таблице соответствий правило, под которое подпадает order_id = 98765. Для быстрого поиска он часто использует эффективные структуры данных, такие как хеш-таблицы или B-деревья (это внутренняя деталь реализации самого каталога).</li><li>Допустим, каталог находит правило «Диапазон order_id 90000-99999 → Shard-3» и сообщает это маршрутизатору.</li><li>Маршрутизатор перенаправляет исходный запрос на Shard-3.</li></ul><p>При таком подходе удобнее перемещать данные между шардами, изолировать их и менять логику.</p><h3>Range-based sharding: разбиение по диапазонам значений</h3><p>По сути, это тот же горизонтальный sharding с разбиением данных на кусочки по строкам при помощи диапазонов.</p><p>Администратор системы (или автоматизированный инструмент) определяет границы диапазонов для ключа шардинга. Маршрутизатор получает запрос, смотрит на значение этого ключа и сравнивает его с известными диапазонами, чтобы определить целевой шард.</p><p>Этот способ простой, логичный и отлично подходит для работы с данными за определённый период. Но у него есть проблема. Допустим, мы запустили форум и проводим шардирование по трём ключам:</p><ul><li>id от 1 до 1000 — шард 1;</li><li>id от 1001 до 2000— шард 2;</li><li>id от 2001 до 3000 — шард 3.</li></ul><p>Когда пользователи начнут регистрироваться, у нас будет активен шард 1, потом шард 2. Далее вся нагрузка перейдёт на шард 3. Они не будут одновременно равномерно работать. Это может стать проблемой при оптимизации.</p><h3>Hash-based sharding: равномерное распределение по хешу ключа</h3><p>Этот подход помогает добиться максимально равномерного распределения нагрузки по всем шардам. Работает следующим образом:</p><p><b>Берём значение ключа</b> для конкретной строки данных (например, user_id = 2001).</p><p><b>Применяем к нему хеш-функцию</b>. Хеш-функция (например, MD5, SHA-1, MurmurHash) — это алгоритм, который превращает входные данные (наш user_id) в строку или число фиксированной длины (хэш), которое выглядит почти случайно. Даже небольшое изменение на входе (например, user_id = 2001 и user_id = 2002) обычно даёт совершенно разные хеши.</p><p><b>Вычисляем номер шарда</b>. Чаще всего делим значение хеша на количество шардов и берём остаток от деления. Например, 548291 % 3 = 2. Далее в зависимости от остатка распределяем данные по шардам. Значение с остатком 2 пойдёт в шард 2, если остаток 1, то в шард 1 и так далее.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-30/bb6c10d3-0c7a-4499-ab9a-11d2d3c34be0.jpg" alt="Что такое Sharding" /><figcaption>Hash-based sharding</figcaption></figure><p>Так мы получаем более равномерное распределение данных. Но из минусов — в такой базе сложно обрабатывать диапазоны и добавлять новые шарды в систему.</p><h2>Примеры реализации</h2><h3>MongoDB: встроенная поддержка шардинга</h3><p>MongoDB — это NoSQL база данных, которая была разработана с закосом на горизонтальное масштабирование. То есть она адаптирована к тому, чтобы работать на нескольких серверах и расширять это число по мере необходимости. Поэтому sharding здесь доступен из коробки, нам не надо заморачиваться со внешними расширениями.</p><p>Рассмотрим пример, как настроить sharding и работать с ним:</p><ul><li>sh.addShard() — добавляем сервер в кластер как шард. MongoDB понимает, что может использовать этот сервер для хранения части данных.</li><li>use socialApp; sh.enableSharding("socialApp") — переключаемся на базу данных «socialApp». При помощи команды sh.enableSharding() разрешаем шардинг в этой БД.</li><li>sh.shardCollection("socialApp.users", { "user_id": 1 }) — применяем sharding к коллекции users. Мы указываем полное имя коллекции (socialApp.users) и ключ шарда ({ "user_id": 1 }). Цифра 1 означает, что мы используем шардинг по диапазонам. Эти диапазоны не нужно задавать вручную, MongoDB определяет их самостоятельно.</li><li>db.users.insertMany([...]) — вставляем данные в коллекцию users. MongoDB автоматически определяет, на какой шард поместить каждого пользователя.</li><li>db.users.findOne({ user_id: 1 }) — запрашиваем данные пользователя user_id = 1. Mongos сам определит, на каком шарде они находятся.</li></ul><h3>PostgreSQL + Citus</h3><p>В PostgreSQL нет поддержки встроенного шардинга, поэтому приходится устанавливать на сервер Citus. Это популярное расширение, которое как раз добавляет возможности горизонтального масштабирования и шардинга. Оно превращает кластер стандартных серверов PostgreSQL в распределённую базу данных.</p><p>Посмотрим на пример использования SQL-команд для настройки шардинга с помощью Citus:</p><ul><li>CREATE EXTENSION citus; — активируем Citus в текущей базе данных.</li><li>CREATE TABLE app_logs (...) — создаём таблицу app_logs на узле-координаторе точно так же, как создали бы обычную таблицу в PostgreSQL.</li><li>SELECT create_distributed_table('app_logs', 'service_name'); — при помощи этой команды включаем sharding. Citus понимает, что таблицу app_logs нужно распределить по рабочим узлам, используя поле service_name как ключ шардинга. Citus по умолчанию применяет Hash-based sharding, то есть, равномерно распределяет по шардам при помощи хеш-функций.</li><li>INSERT INTO app_logs — добавляем данные логов. Citus перехватывает запрос, вычисляет хеш от значения service_name для каждой строки и распределяет данные по шардам.</li><li>SELECT ... FROM app_logs — запрашиваем данные. Если фильтруем по service_name (как в первом SELECT), Citus направит запрос на нужный шард.</li></ul><h3>MySQL + Vitess</h3><p>MySQL — ещё одна система управления базами данных, у которой по умолчанию нет поддержки шардинга. Ситуацию спасает Vitess. Это система кластеризации баз данных — что-то вроде сторонней платформы, которая помогает организовать работу в рамках кластера.</p><p>Vitess вместо прямых команд для шардинга определяет его правила в отдельном JSON-файле, который называется VSchema (Vitess Schema).</p><p>Допустим, у нас есть база данных commerce. Вот как она выглядит в виде кода:</p><p>А вот так она выглядит в виде таблицы:</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-30/1dd751fd-aa6e-49f1-9883-6431fa53b08f.png" alt="Как работает шардинг в базах данных" /><figcaption>Пример структуры базы данных</figcaption></figure><p>В базе данных есть таблица orders, её мы и хотим шардировать по customer_id при помощи хеширования (hash-based sharding).</p><p>Файл VSchema (vschema.json) может выглядеть примерно так:</p><ul><li>"sharded": true — указываем, что база данных шардирована.</li><li>"vindexes" — определяем hash_index типа hash, который будет использовать хеш-функцию для распределения.</li><li>"tables" — описываются правила для конкретных таблиц.</li><li>"orders" — настраиваем таблицу orders.</li><li>"column_vindexes" — определяем, какой столбец является ключом ("column": "customer_id") и какой vindex ("name": "hash_customer_id") использовать для него.</li></ul><h2>Проблемы шардирования</h2><h3>Перераспределение шардов (resharding)</h3><p>Со временем может потребоваться изменить количество шардов или способ разделения данных. Например, добавить серверы для увеличения мощности или изменить ключ шардирования. Этот процесс называется решардингом.</p><p>При решардинге часто приходится перегонять большие объёмы данных между серверами. Если используется хеш-шардинг, и мы меняем количество шардов, то пересчитываются ключи, по которым распределяются данные.</p><p>Например, раньше у нас было 4 шарда. Мы брали user_id, например 9, делили на 4 и получали остаток — 1. Значит, данные шли на шард номер 1. После масштабирования стало 5 шардов, и 9 % 5 = 4 — теперь те же данные должны храниться на шардe 4.</p><p>Такое перемещение затратно по ресурсам: грузит сеть, диски, может занять часы или даже дни. Иногда для этого приходится останавливать запись, что делает процесс ещё рискованнее.</p><h3>Неравномерная нагрузка (hot shards)</h3><p>Вспомним вид шардирования Range-based sharding. Это когда мы разбиваем данные по диапазонам. У нас был пример выше с форумом и шардингом user_id:</p><ul><li>id от 1 до 1000 — шард 1;</li><li>id от 1001 до 2000— шард 2;</li><li>id от 2001 до 3000 — шард 3.</li></ul><p>Мы столкнулись с проблемой, что шард 1 и шард 2 после завершения диапазонов простаивали, а вся новая нагрузка приходилась на шард 3.</p><p>Такую проблему называют горячим шардом (hot shards). Производительность всей системы начинает зависеть от самого загруженного шарда. Преимущества шардирования снижаются.</p><p>Чтобы этого избежать, приходится либо более въедливо продумывать ключи шардирования, либо вручную разделять слишком нагруженный шард.</p><h3>Сложности с глобальными транзакциями и агрегациями</h3><p>Допустим, нужно перевести деньги со счёта А на счёт Б — операция состоит из двух шагов: списание и зачисление. Транзакция позволяет объединить их в единое целое: либо всё выполнится, либо ничего. Это защищает от потери данных и ошибок. В классических базах данных за это отвечают принципы ACID — они гарантируют надёжность в пределах одного сервера.</p><p>Но если счёт А находится на одном шарде, а счёт Б — на другом, стандартная транзакция не сработает. Между независимыми серверами нельзя просто так обеспечить ACID-гарантии. Для этого нужны сложные и медленные механизмы координации, например двухфазный коммит (2PC). Либо приходится идти на компромисс и использовать eventual consistency — когда данные приходят в согласованное состояние с небольшой задержкой. Например, деньги уже списались, но ещё не зачислились.</p><p>Аналогичная проблема и с агрегациями: посчитать сумму продаж или число пользователей уже не получится одной SQL-командой. Каждый шард сначала считает свою часть, а потом результат нужно собрать и объединить — это требует дополнительной координации и может усложниться при фильтрации или группировках.</p><h3>Сложность управления и мониторинга</h3><p>Шардированный кластер — это распределённая система, управлять которой сложнее, чем одним сервером.</p><p><b>Больше компонентов</b>: Вместо одной базы данных появляется множество шардов (часто с репликами), маршрутизаторы запросов, серверы конфигурации. Всё это нужно настраивать, обновлять и обслуживать.</p><p><b>Мониторинг</b>: Требуется отслеживать состояние каждого шарда, равномерность распределения нагрузки, задержки в сети, работу маршрутизаторов. Нужны более сложные инструменты мониторинга.</p><p><b>Отладка</b>: Найти источник проблемы в распределённой системе сложнее. Ошибка может быть где угодно: в приложении, маршрутизаторе, на одном из шардов или в сети.</p><p><b>Резервное копирование</b>: Создание согласованных резервных копий и восстановление данных со множеством независимых шардов требует более сложных процедур.</p><h2>Когда стоит применять Sharding</h2><h3>Рост объёма данных и нагрузок</h3><p>Sharding стоит применять, если БД сильно разрослась, хранить её на одном сервере становится сложно и дорого. Серверу приходится обрабатывать много данных, и поэтому увеличивается время отклика.</p><p>Иногда серверу приходится одновременно читать и записывать слишком много запросов. Система становится перегруженной, пользователи замечают задержки и нестабильную работу. Здесь тоже поможет sharding.</p><h3>Не справляется один сервер/реплика</h3><p>Допустим, у нас один сервер и он не справляется с запросами и большими данными. Конечно, мы можем заняться вертикальным масштабированием, поставить CPU производительнее, добавить больше ОЗУ и так далее. Однако у этого подхода есть ограничения. Во-первых, каким бы мощным ни был бы сервер, он со временем упрётся в потолок своей производительности. Во-вторых, иногда дешевле купить несколько новых серверов помощнее, чем прокачивать старый. Поэтому создание кластера и распределение в нём нагрузки при помощи шардинга — часто более выигрышное решение, чем один сервер.</p><h3>Потребность в геораспределённости или отказоустойчивости</h3><p>Если пользователи находятся в разных частях света, то деление данных и хранение ближе к ним может ускорить работу приложения. Мы можем при помощи шардинга размещать данные в разных дата-центрах, ближе к определённым группам пользователей. Например, так делает Youtube. Компания размещает свои сервера в разных странах, чтобы видео прогружались быстрее и в более высоком качестве.</p><p>Мы можем хранить все данные и обрабатывать запросы на одном сервере и сделать его реплику с копией данных. Если этот сервер падает, то его заменяет реплика. Но что, если эта реплика тоже упадёт? Тогда нам и помогает sharding с репликацией. В случае сбоев отвалятся только отдельные серверы с некоторыми наборами данных. Конечно, здесь тоже, в теории, можно положить весь кластер, включая реплики, но сделать это сложнее.</p><p>Шардирование — полезный инструмент при работе с СУБД. А узнать про большее число подобных инструментов можно в нашем <a href="https://t.me/+qUpIFTBINgJkOGJi">телеграм канале</a>!</p>]]></content:encoded>
    </item>
    <item>
      <title>Большой гайд по инструментам для разработчиков от Tproger: фреймворки, базы, AI и DevOps в одной подборке</title>
      <link>https://tproger.ru/articles/bolwoj-gajd-po-instrumentam-dlya-razrabotchikov-ot-tproger--frejmvorki--bazy--ai-i-devops-v-odnoj-podborke</link>
      <comments>https://tproger.ru/articles/bolwoj-gajd-po-instrumentam-dlya-razrabotchikov-ot-tproger--frejmvorki--bazy--ai-i-devops-v-odnoj-podborke?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/bolwoj-gajd-po-instrumentam-dlya-razrabotchikov-ot-tproger--frejmvorki--bazy--ai-i-devops-v-odnoj-podborke</guid>
      <description><![CDATA[<p>Подборка топовых инструментов и технологий для разработчиков: от Elixir и DevOps-платформ до no-code, AI-инструментов и новых фреймворков.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/bolwoj-gajd-po-instrumentam-dlya-razrabotchikov-ot-tproger--frejmvorki--bazy--ai-i-devops-v-odnoj-podborke">Большой гайд по инструментам для разработчиков от Tproger: фреймворки, базы, AI и DevOps в одной подборке</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Функциональное программирование]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 04 May 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Мы собрали для вас огромную подборку наших статей про самые полезные инструменты, технологии и практики.
Если вы хотите работать быстрее, чище и с кайфом — сохраняйте себе этот гайд, чтобы не искать потом по всему интернету. Внутри — топовые фреймворки, AI-помощники, базы данных, лайфхаки и советы от практиков.</p><h2>Основные инструменты и технологии</h2><p>Статьи, с которых стоит начать, если хочется обновить стек или разобраться в новых подходах:</p><p><a href="https://tproger.ru/articles/top-60-luchwih-instrumentov-dlya-razrabotki-po-v-2025">ТОП 60 лучших инструментов для разработки ПО в 2025</a> — Собрали шестьдесят лучших инструментов для разработки программного обеспечения в 2025 году. От трекеров и редакторов до библиотек и фреймворков.</p><p><a href="https://tproger.ru/articles/top-11-trendov--kotorye-nuzhny-ajtiwniku-v-2025-godu">Топ 11 трендов, которые нужны айтишнику в 2025 году</a> — Представляем одиннадцать ключевых трендов в IT, которые будут актуальны в 2025 году. Краткий гид по технологиям, которые будут на слуху.</p><p><a href="https://tproger.ru/articles/obzor-populyarnyh-frejmvorkov-dlya-veb-razrabotki">Фреймворки, меняющие игру: выбираем идеальный инструмент для ваших веб-проектов</a> — Обзор современных веб-фреймворков, которые могут изменить подход к разработке ваших проектов.</p><p><a href="https://tproger.ru/articles/instrumenty-i-frejmvorki-qa--kotorye--ne--nuzhno-znat">Инструменты и фреймворки QA, которые (не) нужно знать</a> — о том, что реально используется в тестировании.</p><p><a href="https://tproger.ru/articles/chto-izuchat-nachinashhemu-razrabotchiku-na-c-">Что изучать начинающему разработчику на C#</a> — рассматриваем  языки, среды и подходы, которые пригодятся новичкам. Рекомендуем, с чего начать изучение C# и какие темы освоить в первую очередь.</p><p><a href="https://tproger.ru/articles/reactjs-na-izi--chto-realno-nuzhno-znat-frontend-razrabotchiku-v-2025-godu">ReactJS на изи: что реально нужно знать фронтенд-разработчику в 2025 году</a> — Краткий гайд по ключевым знаниям и навыкам, необходимым для работы с ReactJS в 2025 году.</p><h2>Базы, API, DevOps и CI/CD</h2><p>Набор инструментов и практик, которые помогут масштабироваться и не выгорать:</p><p><a href="https://tproger.ru/articles/top-10-instrumentov-devops--kotorye-uprostyat-vawu-zhizn-i-izbavyat-ot-nochnyh-relizov">Топ-10 инструментов DevOps, которые упростят вашу жизнь и избавят от ночных релизов</a> — must-have решения для DevOps-команд.</p><p><a href="https://tproger.ru/articles/postgresql-vs--clickhouse-vs--duckdb--kakuyu-opensors-bazu-vybrat-dlya-analitiki-v-2025-godu-">PostgreSQL vs. ClickHouse vs. DuckDB: какую опенсорс базу выбрать для аналитики в 2025 году?</a> — Сравниваем три популярные опенсорс СУБД для аналитики: возможности, производительность и кейсы использования.</p><p><a href="https://tproger.ru/articles/10-api--kotorye-sokratyat-vam-nedeli-razrabotki">Семь API, которые сократят вам недели разработки</a> — Подборка решений, которые можно быстро внедрить.</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/kak-avtomatizirovat-prostye-zadachi-s-pomoshhyu-skriptov-">Как автоматизировать простые задачи с помощью скриптов?</a> — Гайд по быстрой автоматизации без боли.</p><p><a href="https://tproger.ru/articles/luchwie-praktiki-dlya-raboty-s-komandnoj-strokoj">Лучшие практики для работы с командной строкой</a> — Рассказываем, что такое командная строка. Рассматриваем пошаговую инструкцию по использованию.</p><h2>AI-инструменты и нейросети</h2><p>Что может помочь вам уже сейчас — от подсказок до генерации кода:</p><p><a href="https://tproger.ru/articles/top-5-ii-instrumentov-dlya-programmistov-v-2025">Топ-5 ИИ-инструментов для программистов в 2025 году</a> — Самые полезные AI-ассистенты по мнению редакции.</p><p><a href="https://tproger.ru/articles/deepseek-ili-claude--kakaya-nejroset-napiwet-kod--za-kotoryj-ne-stydno-">DeepSeek или Claude: какая нейросеть напишет код, за который не стыдно?</a> — Сравниваем возможности нейросетей DeepSeek и Claude в контексте генерации качественного кода.</p><p><a href="https://tproger.ru/articles/edge-ai--kak-rabotayut-nejroseti-na-ustrojstvah-s-ogranichennymi-resursami">Edge AI: как работают нейросети на устройствах с ограниченными ресурсами</a> — Объясняем, как нейросети работают на устройствах с ограниченными ресурсами и где это применимо.</p><p><a href="https://tproger.ru/articles/10-sposobov-zarabotat-na-iskusstvennom-intellekte-v-2025">10 способов заработать на искусственном интеллекте в 2025</a> — Рассказываем о десяти способах монетизации искусственного интеллекта в 2025 году.</p><h2>Утилиты, лайфхаки и неожиданно полезные штуки</h2><p>То, что экономит время, силы и нервы:</p><p><a href="https://tproger.ru/articles/sobral-11-sajtov--ekonomyashhih-vremya--kotorye-nuzhny-kazhdomu-razrabotchiku">11 сайтов, экономящих время, которые нужны каждому разработчику</a> — Подборка must-have ресурсов.</p><p><a href="https://tproger.ru/articles/luchwie-biblioteki-dlya-animacij-na-react">7 библиотек для анимаций на React</a> — Обзор популярных библиотек для создания анимаций в React: от простых эффектов до сложных переходов.</p><p><a href="https://tproger.ru/articles/30-samyh-poleznyh-bibliotek-python-dlya-veb-razrabotki-v-2024-godu">30 самых полезных библиотек Python для веб-разработки в 2024 году</a>  — Подборка тридцати полезных библиотек Python, которые пригодятся веб-разработчикам в 2025 году.</p><p><a href="https://tproger.ru/articles/7-programm-dlya-wifrovaniya-dannyh">7 программ для шифрования данных</a> —  Базовая кибер-гигиена для всех, кто работает с пользовательскими данными.</p><p><a href="https://tproger.ru/articles/top-samyh-poleznyh-magicheskih-komand-dlya-zavsegdataev-colab">Топ самых полезных магических команд для завсегдатаев Colab</a> — Рассказываем, как использовать магические команды в Colab, чтобы ускорить работу с данными и кодом.</p><p><a href="https://tproger.ru/articles/otkryvaem-cikl-statej-etl-dlya-zooparka-botov">5 ETL для обработки данных из Python-ботов</a> — Представляем пять ETL-инструментов, которые помогут автоматизировать сбор, трансформацию и загрузку данных от Python-ботов</p><p><a href="https://tproger.ru/articles/rabota-s-excel-gde-on-primenyaetsya-chem-polezen-i-gde-osvoit-etot-navyk-erid-ljn8klxkn">Работа с Excel: где он применяется, чем полезен и где освоить этот навык</a> — Объясняем, где и как используется Excel, почему он важен для аналитиков и где научиться работать с ним.</p><h2>Немного философии</h2><p>Когда хочется не просто выбрать инструмент, а понять, зачем он вам нужен:</p><p><a href="https://tproger.ru/articles/yazyk-elixir-i-funkcionalnoe-programmirovanie--chto-eto-za-zver-i-pochemu-on-horow-dlya-otkazoustojchivyh-sistem">Язык Elixir и функциональное программирование: что это за зверь и почему он хорош для отказоустойчивых систем</a> — Знакомим пользователей с Elixir и его применением.</p><p><a href="https://tproger.ru/articles/pochemu-mikroservisy-ne-nuzhny--antihajpovyj-razbor">Почему микросервисы не нужны: антихайповый разбор</a> — Анализируем случаи, когда микросервисная архитектура может быть излишней и неэффективной.</p><p><a href="https://tproger.ru/articles/10-luchwih-platform-dlya-sozdaniya-prilozhenij-bez-edinoj-strochki-koda">10 лучших платформ для создания приложений без единой строчки кода</a> — Обзор десяти лучших no-code платформ, позволяющих создавать приложения без программирования.</p><p>Скорее пользуйтесь нашим гайдом и читайте предыдущие. Вот, например, по <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/bolwoj-gajd-po-react-ot-tproger--topovye-stati-i-instrumenty">React</a>.</p><p>Кстати! Забрать все самые топовые нейронки для айтишников можно в нашем <a href="https://tprg.ru/LN8a">большом гайде с 70+ ИИ-инструментами </a></p>]]></content:encoded>
    </item>
    <item>
      <title>PostgreSQL vs. ClickHouse vs. DuckDB: какую опенсорс базу выбрать для аналитики в 2025 году?</title>
      <link>https://tproger.ru/articles/postgresql-vs--clickhouse-vs--duckdb--kakuyu-opensors-bazu-vybrat-dlya-analitiki-v-2025-godu-</link>
      <comments>https://tproger.ru/articles/postgresql-vs--clickhouse-vs--duckdb--kakuyu-opensors-bazu-vybrat-dlya-analitiki-v-2025-godu-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Владислав Устинов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/postgresql-vs--clickhouse-vs--duckdb--kakuyu-opensors-bazu-vybrat-dlya-analitiki-v-2025-godu-</guid>
      <description><![CDATA[<p>В этой статье сравним и разберём опенсорные СУБД для задач, связанных с аналитикой, на понятном для новичков языке.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/postgresql-vs--clickhouse-vs--duckdb--kakuyu-opensors-bazu-vybrat-dlya-analitiki-v-2025-godu-">PostgreSQL vs. ClickHouse vs. DuckDB: какую опенсорс базу выбрать для аналитики в 2025 году?</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 15 Apr 2025 10:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>В 2025 году выбор правильной открытой базы данных для аналитики становится критически важным для успеха любого проекта. PostgreSQL, ClickHouse и DuckDB — три лидера в этой области. PostgreSQL славится своей надежностью и гибкостью, ClickHouse — высокопроизводительными аналитическими возможностями, а DuckDB — простотой использования и интеграции. Сегодня мы рассмотрим, какая из этих баз данных лучше всего подойдет для аналитиков в текущем году.</p><h2>PostgreSQL: Универсальная объектно-реляционная СУБД</h2><p>PostgreSQL — объектно-реляционная СУБД (система управления базами данных). Термин реляционная означает, что мы записываем данные в виде взаимосвязанных таблиц со строгой схемой. В этой схеме у нас есть столбцы и ячейки, где занесены значения определённого типа: строки, числа, даты. Прямо как в Excel.</p><p>«Объектность» PostgreSQL заключается в том, что в качестве значений мы можем записывать не только числа, строки, даты, но и сложно структурированные данные, например, JSON или XML файлы. Ещё здесь есть наследование, мы можем создавать дочерние таблицы, которые повторяют структуру и данные родительских. Другая фишка PostgreSQL — пользовательские типы. В нём допускается прописывать свои типы данных и работать с ними. По логике это немного напоминает ООП с классами, объектами и наследованием.</p><p>Есть возможность писать свои функции для обработки данных, подключать сторонние библиотеки, причём делать это на разных языках. В общем, с расширяемостью и гибкостью здесь всё очень неплохо.</p><p>PostgreSQL используют в интернет-магазинах, финансовых системах, банковских и геопространственных приложениях, системах управления контентом в блогах, социальных сетях и аналитике. Это универсальный гибкий инструмент.</p><p>Вишенка на торте — PostgreSQL доступен с открытым исходным кодом. Его можно установить, не заморачиваясь с лицензиями и оплатой, настроить под себя и пользоваться.</p><h2>ClickHouse: Скорость и аналитика от Яндекса</h2><p>ClickHouse родился в стенах Яндекса в середине 2000-х. Изначально это была внутренняя разработка для Яндекс.Метрики — чтобы быстро обрабатывать миллиарды событий, подсчитывать статистику и выдавать отчёты, не теряя в скорости. В 2016 году разработку опубликовали на GitHub с опенсорс лицензией.</p><p>Особенность ClickHouse заключается в его колоночно-ориентированной архитектуре. Традиционные СУБД работают с данными построчно. Это значит, что каждая строка — как бы отдельная сущность с данными.</p><p>Допустим, нам надо считать данные с одного столбца. Классические СУБД пойдут искать ячейки столбца по строкам, вместо того, чтобы выбрать этот столбец.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-09/5154a022-f01e-47bc-a8b3-6fb0fc41dea3.jpg" alt="" /><figcaption>Пример логики работы строковой СУБД</figcaption></figure><p>ClickHouse спроектирован иначе. Он хранит данные в столбцах, а не в строках. Благодаря этому в задачах с аналитикой, нам не надо считывать все строки, чтобы добраться до конкретной ячейки в столбце. Мы считываем меньше ячеек, тратим меньше ресурсов и получаем большую производительность.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-09/f3031a64-68a7-4bac-900d-0895bd51cd86.jpg" alt="" /><figcaption>Пример логики работы колоночной СУБД</figcaption></figure><p>ClickHouse поддерживает векторизацию. Это значит, что он нарезает БД (базу данных) на векторы — отдельные куски. СУБД сразу обрабатывает весь кусок целиком, вместо того чтобы по очереди заниматься каждой ячейкой. Здесь есть Simd-оптимизация — технология, которая позволяет процессору выполнять операции сразу над несколькими элементами данных параллельно.</p><p>Благодаря колоночной архитектуре и хорошей оптимизации ClickHouse быстро работает с данными. Его применяют в аналитике Uber, Bloomberg, Google, Netflix, VK, Avito, Т-банк, ну и, конечно же, Яндекс.</p><h2>DuckDB: Локальная аналитика</h2><p>DuckDB — ещё одна СУБД с открытым исходным кодом. Как и ClickHouse использует колоночную архитектуру, векторизацию и Simd-оптимизацию. Благодаря этому, хорошо справляется с аналитическими задачами.</p><p>Главная фишка DuckDB в том, что он предназначен для работы на стороне клиента и оптимизирован под обычные ПК и ноутбуки. DuckDB популярен среди аналитиков, которые работают с данными локально, например, через Python или R. Его можно подключить как библиотеку и работать с данными внутри проекта.</p><h2>Сравнение возможностей СУБД</h2><h3>Производительность в тестах</h3><p>Для <a href="https://benchmark.clickhouse.com/">сравнения </a>я использовал <a href="https://benchmark.clickhouse.com/">ClickBench</a>. Это набор данных с тестами для разных СУБД, весом более 70 гб и количеством около 100 млн строк.</p><p>В качестве оборудования выбрал c6a.4xlarge. Здесь 32 гб. ОЗУ, 16-ядерный процессор и диск объёмом 500 гб.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-09/8b471ba3-6e69-43e7-aa02-d25826208226.png" alt="" /><figcaption>Результаты тестов</figcaption></figure><p>Тест предполагает, что СУБД обрабатывает данные при помощи 42 запросов. Cold Run — обработка некэшированных данных, Hot Run — работа с кэшированными данными, Storage Size — сжатие в гигибайтах (1 Гиб ≈ 1.073 Гб).</p><p>DuckDB оказался самым шустрым в тесте Cold Run, он обрабатывает некэшированные данные за 372 секунды, тогда как у ClickHouse 470 сек., а у PostgreSQL 937 сек.</p><p>Однако, ClickHouse оказывается быстрее в тесте Hot Run — когда данные в кэше. У него 372 сек., тогда как у DuckDB 470 сек. а у PostgreSQL всё те же 937 сек.</p><p>Также ClickHouse лучше всех работает с памятью. Он смог сжать 70 гб. данных до 13.48 гибибайт. На втором месте DuckDB, у него 22.03 Гиб. PostgreSQL не только не сжал данные, но и раздул их до 99.18 Гиб (примерно 106 гб). Возможно, ClickHouse и DuckDB проще сжимать информацию, так как у них колоночный подход к работе с данными, ведь в столбце повторяющиеся значения могут встречаться чаще, чем в строке. Увеличение объёма данных в PostgreSQL возможно вызвано тем, что СУБД наплодило много метатегов к данным.</p><p>В общем, PostgreSQL сильно уступает в производительности ClickHouse и DuckDB. С памятью работает тоже хуже.</p><h3>Масштабируемость систем</h3><h4>PostgreSQL — хороший вариант для вертикального масштабирования</h4><p>Отлично подходит для вертикального масштабирования. Это значит, что если у нас увеличивается нагрузка и сервер уже не вывозит, то мы можем просто его прокачать: купить побольше ОЗУ, диск, процессор помощнее. Либо можно купить другой более мощный сервер и перенести данные на него.</p><p>Такова особенность классических реляционных моделей, они изначально проектировались с учётом вертикальной масштабируемости.</p><p>Обратная сторона — проблемы с горизонтальным масштабированием. Это когда мы покупаем несколько серверов послабее, распределяем между ними нагрузку и создаём кластер. Чтобы такое провернуть, понадобится дополнительная настройка через инструменты вроде Citus или Pgpool.</p><h4>ClickHouse масштабируется вертикально и горизонтально</h4><p>Тоже хорошо подходит для вертикального масштабирования, как и PostgreSQL. Однако он также поддерживает шадрирование и репликацию. Шадрирование означает, что  ClickHouse может нарезать базу данных на кусочки и распределять эти кусочки между разными узлами. Репликация означает, что СУБД может копировать их на другие сервера в кластере.</p><p>Благодаря этому ClickHouse также хорошо подходит и для горизонтального масштабирования, когда нагрузка распределена на несколько серверов. Но есть нюанс. Здесь может быть задержка при синхронизации между узлами и сложности с изоляцией транзакций.</p><h4>DuckDB — только вертикальное масштабирование на обычных ПК и ноутбуках</h4><p>Мы можем установить DuckDB на обычный ПК и прокачивать компьютер сколько угодно. В этом плане с вертикальным масштабированием никаких проблем нет. Но вот создать кластер и масштабировать горизонтально не получится, так как СУБД предназначена для индивидуального локального использования.</p><h3>Экосистема и удобство использования</h3><p><b>PostgreSQL </b>выделяется своей зрелой экосистемой. Он кроссплатформенный, можно установить на Windows, MacOS, Linux, Docker. После установки необходима небольшая настройка под свои задачи.</p><p>Мы можем управлять СУБД через графический интерфейс pgAdmin.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-09/1fce6f0f-5d47-4104-92b5-cd2eaf57968d.png" alt="" /><figcaption>Интерфейс Postgresql</figcaption></figure><p>Он поддерживает создание и редактирование объектов, просмотр структуры, визуализацию схемы. Для этого даже необязательно вводить SQL запросы, хотя это тоже можно. Также есть консольный клиент psql.</p><p>PostgreSQL поддерживает интеграцию с BI системами, например, Tableau, Metabase, Power BI, и расширения наподобие PostGIS и TimescaleDB.</p><p>У PostgreSQL всё хорошо с расширяемостью, мы вправе писать свои функции, индексы, подключать сторонние модули. Здесь можно писать код не только на SQL, но и на Python, C, C++, Java, JS, Rubi, R, Lua.</p><p>Документация — одна из лучших, а сообщество активно помогает на форумах и конференциях. Однако для аналитики нужна оптимизация, импорт больших данных может быть медленным.</p><p><b>ClickHouse </b>ориентирован на аналитику больших данных в реальном времени, что отражается в его экосистеме. Поддерживает установку на Windows, MacOS, Linux, Docker.</p><p>ClickHouse готов к работе «из коробки» для аналитических задач. Можно ничего не настраивать и сразу создать таблицу, но при условии, что СУБД будет работать только на одном устройстве. Если мы собираемся запустить ClickHouse на кластере, то придётся немного повозиться с настройками шадринга и репликации. Есть поддержка как SQL, так и других языков, но только через клиентские библиотеки.</p><p>Документация подробная, но сообщество меньше, чем у PostgreSQL. Разных наворотов тоже меньше, поэтому ClickHouse больше про минимализм. Есть много вариантов графических интерфейсов от сторонних разработчиков.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-09/7d7fe2cd-fe50-4481-9c5f-ee806bb9bae5.png" alt="" /><figcaption>Сторонний интерфейс agx</figcaption></figure><p>Например, на изображении интерфейс <a href="https://github.com/agnosticeng/agx/tree/main">agx</a>.</p><p>DuckDB можно установить на Windows, MacOS, Linux. Установка напоминает подключение библиотеки к проекту. Просто пишем команду pip install duckdb для Python или install.packages("duckdb") для R и всё установлено локально, без сервера. Поддерживает и другие языки через клиентские библиотеки.</p><p>Он разработан с акцентом на простоту и локальное использование, поэтому здесь можно сразу начать работу, без настройки.</p><p>В марте 2025 года у DuckDB появился свой графический интерфейс. В нём тоже можно писать SQL запросы, смотреть результаты и организовывать проекты в виде блокнотов.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-04-09/c4e05f6f-0653-48c3-a2b0-1126f16b524d.png" alt="" /><figcaption>Интерфейс DuckDB</figcaption></figure><p>Также есть интерфейсы от сторонних разработчиков и консольный клиент.</p><h3>Поддержка транзакций (ACID)</h3><p>ACID — это набор свойств, которые обеспечивают надёжность транзакций в базах данных:</p><ul><li><b>Atomicity (Атомарность)</b>: Все операции в транзакции выполняются полностью, или ни одна из них не выполняется. Если что-то идёт не так, изменения откатываются.</li><li><b>Consistency (Согласованность)</b>: После каждой транзакции база данных остаётся в согласованном состоянии, соблюдая все ограничения (например, уникальность ключей, внешние ключи).</li><li><b>Isolation (Изоляция)</b>: Транзакции изолированы друг от друга, то есть незавершённые транзакции не видны другим.</li><li><b>Durability (Долговечность)</b>: После завершения транзакции все изменения сохраняются, даже в случае сбоя системы.</li></ul><p>ACID особенно важен для OLTP — обработки транзакций в реальном времени. Такие транзакции есть, например, в банковских системах, где требуется строгая согласованность и надёжность. В аналитических сценариях (OLAP) требования к ACID могут быть менее строгими, так как приоритет отдаётся скорости и масштабируемости.</p><p><b>PostgreSQL </b>изначально разработан для OLTP-нагрузок, где транзакционность критически важна. Он полностью поддерживает ACID, но в ущерб скорости обработки данных, что может снижать производительность в аналитических задачах.</p><p><b>ClickHouse </b>жертвует полной поддержкой ACID ради скорости и масштабируемости. Это делает его идеальной СУБД для аналитических задач, но ограничивает использование в OLTP-сценариях.</p><p>Колоночная архитектура позволяет быстро считывать и обрабатывать данные, но вот чтобы их добавлять, изменять, удалять нужно взаимодействовать со строками.</p><p>Когда мы изменяем или удаляем данные, у нас создаётся новая строка, но старая никуда не девается, а просто помечается как изменённая или удалённая. В конце, при слиянии, ClickHouse всё же в фоне удаляет устаревшие данные, но из-за особенностей движка у нас есть промежуточное состояние, когда одновременно есть и старые, и новые строки. Это нарушает принципы атомарности и согласованности. Если представить, что ClickHouse отвечал бы за операции с оплатой в интернет-магазине, мы могли получить ситуацию, когда 2 пользователя купили один товар.</p><p><b>DuckDB</b> балансирует между скоростью (для OLAP) и частичной поддержкой ACID (для надёжности). Он поддерживает транзакции, но с ограничениями. Например, СУБД не может работать сразу с несколькими пользователями, что делает её подходящей для одиночной аналитики, но не для OLTP.</p><p>Из-за колоночной архитектуры здесь также, как и в ClickHouse есть сложности в плане поддержки атомарности.</p><h2>Какую СУБД выбрать для аналитики</h2><p>Выбирая между PostgreSQL, ClickHouse и DuckDB надо определиться, что важнее: транзакционная надёжность, аналитическая скорость или локальная простота.</p><h3>PostgreSQL: для небольших данных и универсальности</h3><p>PostgreSQL подойдёт для аналитики не сильно больших данных, например, в интернет-магазине, при условии, что это не маркетплейс размером с OZON. Это особенно хороший вариант для проектов, где нужна гибкость или поддержка транзакций по стандарту ACID.</p><h3>ClickHouse: для больших данных в реальном времени</h3><p>ClickHouse хороший вариант для аналитиков данных и дата-инженеров, которые работают с большим потоком информации в реальном времени. Идеальный вариант для веб-аналитики. Например, здесь можно анализировать лог сайта с большим числом строк. Но не подойдёт, если нужны ACID транзакции. Быстро читает и обрабатывает данные, но медленно их изменяет, создаёт и удаляет.</p><h3>DuckDB: для локальной аналитики на ноутбуке</h3><p>Подойдёт дата-сайентистам и аналитикам, работающим локально, без настройки сервера. Однако DuckDB не годится для больших объёмов данных, его не получится развернуть на кластере, про поддержку ACID тоже можно забыть.</p><blockquote><b>PostgreSQL </b>отлично подходит для транзакционных приложений, особенно когда нет особенно высоких требований по масштабируемости или скорости. Когда они появляются, нужно будет искать более сложные решения.<br /><br />Кстати, для ИИ-приложений, в частности, для Retrieval-Augmented Generation (RAG), pg_vector для PostgreSQL — довольно популярное стартовое решение.<br /><br />Если нужна «просто СУБД» — PostgreSQL отличное решение «по умолчанию».<br /><br /><b>ClickHouse </b>— хороший выбор для быстрой аналитики. Например, чтобы строить отчёты и графики в BI-инструментах. Популярная также комбинация PostgreSQL и ClickHouse как лидеров в своих нишах. В этой комбинации PostgreSQL отвечает за исходную обработку данных в приложении, затем передаёт данные в ClickHouse, который поддерживает последующую аналитику.<br /><br />Для более специфических задач — ultra-low latency, потоковая обработка данных, комбинированные решения — могут потребоваться другие, более сложные инструменты. Примеры: CockroachDB, YugabyteDB (оба — распределённые версии PostgreSQL), Apache Ignite (для ultra-low latency SQL и транзакции), Apache Druid (для быстрой аналитики).<br /><br /><b>DuckDB </b>— скорее нишевый инструмент для data scientists и data engineers. Например, он подходит для обработки больших объёмов данных в скриптах на Python, когда это нужно сделать локально. Если вы разрабатываете приложения, то, скорее всего, вам DuckDB не нужен.<br /><br />Я много лет разрабатываю распределённые базы данных (GridGain и Apache Ignite). Помог запустить множество систем, использовавших PostgreSQL и ClickHouse, или заменял их своим продуктом.<br />PostgreSQL — отличный продукт, очень гибкий. Но, чтобы раскрыть его потенциал нужна или очень сильная команда, или хороший внешний вендор, поэтому у Postgres Professional всё хорошо. Большинству компаний для нетиповых задач, особенно low-latency/real-time, проще найти альтернативное решение.<br /><br />ClickHouse классно делает ровно одну вещь — быстро обрабатывает SQL запросы на больших данных. Им не решить все задачи аналитики в компании — долгосрочное хранение, трансформация данных и многое другое нужно будет решать другими инструментами.</blockquote><blockquote>PostgreSQL, ClickHouse и DuckDB — три очень разные системы, каждая со своей логикой и зоной применения. Тут не про «что лучше», а скорее — «что подойдёт именно под вашу задачу».<br /><br /><b>PostgreSQL<br /><br /></b>Это универсальный инструмент. Если не знаете, с чего начать — скорее всего, начинать стоит с него. Он хорошо справляется с большинством типовых задач: хранение данных, транзакции, запросы, индексы, API. Работает стабильно, предсказуемо, и его знают почти все разработчики. Проблемы начинаются, когда данных становится очень много, особенно если есть тяжёлые аналитические запросы — тогда он уже не так эффективен. Масштабируется скорее вертикально, и не всегда удобно тюнить для сложной аналитики.<br /><br /><b>ClickHouse<br /><br /></b>Если у вас огромные объёмы данных и вы хотите быстро гонять по ним аналитику — это ваш инструмент. СУБД для чтения, не для транзакций. Отлично показывает себя в задачах мониторинга, логирования, аналитики в реальном времени. Очень быстрая, но требует больше внимания: настроек, понимания архитектуры, знание её ограничений (например, с JOIN'ами и транзакциями). Это уже не «поставил и работает», тут придётся повозиться.<br /><br /><b>DuckDB<br /><br /></b>Это интересный новичок — очень лёгкая, быстрая аналитическая СУБД, которая отлично работает локально, особенно в связке с Python или Jupyter. Я бы назвал её «SQLite для дата-сайентистов». Не требует сервера, можно просто подключить к CSV, Parquet или Pandas DataFrame и писать SQL-запросы. Для быстрого анализа данных — идеально. В продакшене пока использовать её с осторожностью, но для локальной аналитики — инструмент номер один.<br /><br /><b>Когда что выбирать?<br /><br /></b>Если вы делаете обычное приложение — PostgreSQL. ClickHouse — лучший выбор для аналитики в реальном времени, дашбордов, логирования, мониторинга, и других сценариев с интенсивными SELECT-запросами. DuckDB — отличный выбор для дата-сайентистов, аналитиков и быстрой локальной аналитики. Особенно хорош в ситуациях, когда нужно быстро что-то «пощупать» без подъёма инфраструктуры.</blockquote><p>AI, ML, нейросети, аналитика — это явно твоя тема. Поэтому скорее ждем в нашем <a href="https://t.me/+qUpIFTBINgJkOGJi">тг-канале</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как понять партиционирование: DWH для гуманитариев</title>
      <link>https://tproger.ru/articles/kak-ponyat-particionirovanie--dwh-dlya-gumanitariev</link>
      <comments>https://tproger.ru/articles/kak-ponyat-particionirovanie--dwh-dlya-gumanitariev?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ponyat-particionirovanie--dwh-dlya-gumanitariev</guid>
      <description><![CDATA[<p>Вместе с Никитой Егоровым, ведущим аналитиком в МТС Диджитал, объясняем принципы партиционирования простыми аналогиями, сравниваем с шардированием, разбираем стратегии разбиения данных и популярные инструменты (PostgreSQL, BigQuery, ClickHouse). 
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ponyat-particionirovanie--dwh-dlya-gumanitariev">Как понять партиционирование: DWH для гуманитариев</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Apr 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В современном мире данные — основной ресурс для принятия решений. Компании хранят терабайты информации, которая ежедневно используется в аналитике, прогнозировании и отчетности. Однако без правильной организации данных даже самые мощные системы начинают тормозить, а запросы выполняются слишком долго.</p><p>Одна из ключевых технологий, позволяющих ускорить обработку данных, —  партиционирование. Многие аналитики, не обладая техническим бэкграундом, воспринимают это как сложный термин, хотя на самом деле принцип достаточно прост. Вместе с Никитой Егоровым, ведущим дата-аналитиком в МТС Диджитал и автором тг-канала <a href="https://t.me/data_analysis_it">Дата аналитикс</a>, мы разберемся, что такое партиционирование, чем оно отличается от шардирования, как правильно его применять и какие инструменты помогают работать с ним эффективнее.</p><h2>Что такое партиционирование и зачем оно нужно?</h2><p>Партиционирование — это разбиение больших таблиц на более мелкие части для ускорения запросов.</p><p>Представьте себе большой архив документов. Если все бумаги хранятся в одной стопке, найти нужный документ будет сложно и долго. Если же разложить их по папкам —  например, по годам или отделам —  поиск займет секунды.</p><p>Также работают базы данных: если таблицы слишком большие, система затрачивает много ресурсов на поиск нужной информации. Партиционирование позволяет хранить данные в отдельных «папках», сканируя только необходимые части, а не всю таблицу.</p><p>Даже если аналитик не пишет SQL-запросы вручную, понимание партиционирования помогает:</p><ul><li>Ускорять работу отчетов — база данных обрабатывает только нужные данные, а не весь массив (данные за последний месяц, а не за 10 лет).</li><li>Эффективно взаимодействовать с инженерами DWH — осознанные запросы помогают оптимизировать хранилище.</li><li>Избегать «тяжелых» запросов — если таблицы не разбиты на партиции, отчеты могут выполняться слишком долго.</li></ul><h3>Партиционирование и шардирование: в чем разница?</h3><p>Партиционирование часто путают с шардированием, хотя это разные вещи:</p><ul><li>Партиционирование — разбиение данных внутри одной базы. Например, таблица с продажами разделяется по месяцам.</li><li>Шардирование — распределение данных по разным серверам. Например, пользователи из Европы хранятся в одной базе, из Азии — в другой.</li></ul><p>Обе технологии помогают ускорить обработку данных, но работают на разных уровнях.</p><h2>Как партиционирование помогает ускорить запросы?</h2><p>Неправильное партиционирование может замедлить работу, вместо того чтобы ее ускорить. Ошибкой будет, например, разбиение данных по регионам, если все запросы фильтруются по датам. В этом случае система все равно будет сканировать всю таблицу, не получая преимущества от партиционирования.</p><p>Принцип эффективного партиционирования прост: <b>чем меньше данных нужно обработать </b>—<b> тем быстрее работает запрос</b>.</p><p>Если таблица разбита по датам, то запрос:</p><p>будет читать только нужную партицию, а не всю таблицу.</p><h2>Основные стратегии партиционирования</h2><ul><li>По дате — самый популярный вариант для логов и транзакций;</li><li>По регионам — когда данные имеют географическую привязку;</li><li>По ID (например, user_id) — если важно равномерное распределение нагрузки.</li></ul><p>Универсальный код для партиционирования<b>:</b></p><h2>Какие инструменты помогают работать с партиционированием?</h2><p>Спойлер: в топе будет BigQuery — там партиции настраиваются в пару кликов, а Google сам подсказывает, как оптимизировать запросы.</p><p>Но мы все равно расскажем о популярных решениях, которые сделают жизнь аналитиков проще.</p><h3>PostgreSQL: Ручное партиционирование через PARTITION BY</h3><p>Шаг 1: Создание партиционированной таблицы</p><p>Шаг 2: Создание партиций</p><p>Шаг 3: Вставка данных (автоматически попадают в нужную партицию)</p><p>Шаг 4: Чтение данных (автоматический pruning)</p><p>Особенности PostgreSQL:</p><ul><li>Требует явного создания партиций;</li><li>Поддерживает RANGE, LIST, HASH партиционирование;</li><li>Можно добавлять/удалять партиции динамически (ALTER TABLE ... DETACH PARTITION).</li></ul><p>Здесь же надо сказать, что оконные ранжирующие функции, которые содержат операцию PARTITION BY для получения ранга записи, это немного другое, но при выполнении запроса налету.</p><h3>BigQuery: Автоматическое партиционирование</h3><p>Создадим партиционированную таблицу:</p><p>Особенности BigQuery:</p><ul><li>Автоматическое управление партициями (не нужно создавать вручную);</li><li>Лимит — 4000 партиций на таблицу;</li><li>Кластеризация (дополнительная оптимизация) через CLUSTER BY region.</li></ul><h3>ClickHouse: Продвинутое партиционирование через PARTITION BY</h3><p>Шаг 1: Создание партиционированной таблицы</p><p>Шаг 2: Вставка данных</p><p>Шаг 3: Чтение с pruning</p><p>Особенности ClickHouse:</p><ul><li>Гибкие ключи партиционирования (включая выражения);</li><li>Оптимизация под аналитические запросы (высокая скорость);</li><li>Ручное управление партициями (ALTER TABLE sales DROP PARTITION '202305').</li></ul><p><b>Итоговые рекомендации: </b></p><p>PostgreSQL: Выбирайте для OLTP-систем, где важно ручное управление.</p><p>BigQuery: Идеален для аналитики в GCP (минимум настроек).</p><p>ClickHouse: Лучший выбор для высоконагруженных аналитических запросов.</p><h2>Заключение</h2><p>Партиционирование — один из ключевых инструментов, позволяющих оптимизировать работу с данными. Оно помогает значительно ускорить выполнение запросов, снизить нагрузку на базу данных и улучшить производительность аналитических отчетов.</p><p>Главное, что нужно запомнить:</p><ul><li>Партиционирование — разбиение данных в одной базе, шардирование — распределение данных по разным серверам.</li><li>Выбор стратегии партиционирования зависит от типа данных и запросов: чаще всего используется разбиение по дате.</li><li>Разные DWH используют разные механизмы: PostgreSQL требует ручной настройки, BigQuery делает все автоматически, а ClickHouse дает максимальную гибкость.</li></ul><p>Бонус: Если видите, что запрос тормозит, спросите инженера: «Эта таблица партицирована? Можно добавить партицию по моему фильтру?», — и вас сразу запомнят как продвинутого аналитика</p>]]></content:encoded>
    </item>
    <item>
      <title>Зачем разработчику знать SQL, если есть NoSQL? Разбираемся на примерах</title>
      <link>https://tproger.ru/articles/zachem-razrabotchiku-znat-sql--esli-est-nosql--razbiraemsya-na-primerah</link>
      <comments>https://tproger.ru/articles/zachem-razrabotchiku-znat-sql--esli-est-nosql--razbiraemsya-na-primerah?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Владислав Устинов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/zachem-razrabotchiku-znat-sql--esli-est-nosql--razbiraemsya-na-primerah</guid>
      <description><![CDATA[<p> Зачем разработчику знать SQL, если есть NoSQL. Показываем основные отличия SQL и NoSQL. Рассматриваем пошаговую инструкцию и важные особенности ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/zachem-razrabotchiku-znat-sql--esli-est-nosql--razbiraemsya-na-primerah">Зачем разработчику знать SQL, если есть NoSQL? Разбираемся на примерах</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[NoSQL]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Mar 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Ключевые отличия SQL и NoSQL</h2><h3>Структура данных: реляционные таблицы vs. Документо-ориентированные, графовые, ключ-значение базы</h3><p>SQL — язык запросов, с помощью которого мы можем обращаться к реляционным базам данных и манипулировать ими. Они имеют строгую структуру и отношения, логика их схемы напоминает таблицу или несколько связанных таблиц.</p><p>Рассмотрим пример таблицы ниже:</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-03-12/a2ede9fc-5a44-48c8-8cb4-d49eae7761b6.jpg" alt="Зачем разработчику знать SQL" /><figcaption>Пример таблицы Excel</figcaption></figure><p>Это таблица excel, в которую занесены данные о различных персонажах. В ней мы можем фильтровать данные, искать их, сортировать содержимое, писать значения с разными типами, обращаться к данным во внешних таблицах. При помощи запросов SQL возможно всё то же самое в реляционной базе.</p><p>Давайте создадим нашу таблицу при помощи SQL:</p><p>Командой CREATE TABLE создаём таблицу, которую называем «Персонажи». В скобках прописываем название столбцов, напротив указываем тип данных, который здесь будет храниться. Например, VARCHAR(50) — это текст до 50 символов, DATE — дата, INT — число. PRIMARY KEY — первичный ключ строки. Он нужен, чтобы у каждой строки таблицы был свой уникальный номер.</p><p>Далее заполним нашу таблицу при помощи команды INSERT INTO Персонажи VALUES:</p><p>Заполняем значениями в кавычках, через запятую. Запятые отделяют столбцы друг от друга.</p><p>А теперь добавим ещё одного персонажа и отфильтруем значения по столбцу «Фильм_Сериал»:</p><p>Команда INSERT INTO добавляет нового персонажа в уже существующую базу.</p><p>В скобках после INSERT INTO мы перечисляем столбцы, которые хотим заполнить. VALUES — значения для этих столбцов.</p><p>Эта команда выбирает все столбцы в таблице «Персонажи», проверяя, что новое значение добавилось.</p><p>Далее проводим фильтрацию по сериалу: «Игра престолов»:</p><ul><li>SELECT — выбирает данные из столбцов.</li><li>После SELECTпишем, какие именно столбцы хотим видеть (не всё, а только эти шесть).</li><li>FROM Персонажи — указываем таблицу, из которой берём данные.</li><li>WHERE Фильм_Сериал — выбираем столбец, по которому будем искать данные.</li></ul><p>В результате получим вот такие данные:</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-03-12/5ed2fec8-f939-4ba5-8297-ef5226c7c0c6.jpg" alt="Зачем разработчику знать SQL" /><figcaption>Визуализация вывода</figcaption></figure><p>NoSQL в сравнении с SQL не просто другой язык, а целая философия организации базы данных. Никаких строгих таблиц — всё зависит от того, с чем работаем. В NoSQL есть много видов данных, под каждый из них существуют свои системы управления базами данных (СУБД). Вот основные из них:</p><p><b>Документо-ориентированные базы (MongoDB):</b> данные лежат в виде документов, похожих на JSON, но это не совсем он, а BSON. Различия кроются в том, что это его бинарная версия.</p><p>Пример:</p><p>Слева в кавычках мы пишем название наших полей, например, «Персонаж». Далее через двоеточие указываем значение (тоже в кавычках) и заканчиваем запись для поля запятой. Всё это внутри фигурных скобок.</p><p><b>Ключ-значение (Redis):</b> это тип NoSQL баз данных, где информация хранится в виде пар «ключ-значение», как в словаре: ключ — уникальный идентификатор, значение — любые данные, связанные с ним. Например, запись Джона Сноу будет выглядеть так:</p><p>Внутри фигурных скобок прописываем ключ в кавычках. Далее через двоеточие пишем значение. Отделяем поля между собой при помощи запятой.</p><p><b>Графовые базы (Neo4j):</b> здесь данные — это узлы.</p><p>CREATE (Джон:Персонаж {имя: "Джон Сноу", дом: "Старк"});</p><p>Создаётся узел с меткой Персонаж, который представляет Джона Сноу. Узел имеет два свойства: имя со значением «Джон Сноу» и дом со значением «Старк». Переменная Джон — временное имя для ссылки на узел.</p><p>CREATE (Тирион:Персонаж {имя: "Тирион Ланнистер", дом: "Ланнистер"});</p><p>Далее создаётся ещё один узел с меткой Персонаж, представляющий Тириона Ланнистера. У него тоже два свойства: имя — «Тирион Ланнистер» и дом — «Ланнистер». Переменная Тирион позволяет ссылаться на этот узел.</p><p>CREATE (Джон)-[:ЛАЙК]-&gt;(Тирион);</p><p>Затем появляется направленная связь (ребро) между узлами Джон и Тирион. Она имеет тип ЛАЙК и указывает, что Джон «лайкает» Тириона. Скобки () обозначают узлы, а [:ЛАЙК] со стрелкой -&gt; показывает направление отношения.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-03-12/f97cfff4-8608-4b0f-ba06-7ce5198da147.jpg" alt="Зачем разработчику знать SQL" /><figcaption>Пример визуализации графа из кода</figcaption></figure><h3>Гибкость схемы SQL против NoSQL: строгая схема vs динамическая структура</h3><p>Представьте, что у нас есть база данных с персонажами из фильмов и сериалов — огромная таблица на миллион строк. Теперь мы решили добавить в неё нестандартную запись: включить в список реальную историческую личность, а заодно создать новый столбец «факты», чтобы указать, чем личность запомнилась. Сделать это можно при помощи команды CREATE, но есть проблема.</p><p>Дело в том, что если мы создадим новый столбец в большой базе данных и запишем туда значение только для одного персонажа, то остальные строки в столбце для других примут значение null. И это не очень удобно, так как большое количество null усложняет запросы и может запутать разработчика при обработке данных.</p><p>В этом фундаментальное различие SQL и NoSQL. Первый плохо подходит для работы с неструктурированными данными.</p><p>В NoSQL мы можем при помощи MongoDB прописать значение только для одного персонажа, не трогая других:</p><p>Сравните данные Илона Маска и Сайтамы, у них есть различия в схеме.</p><p>Для такой записи в SQL нам пришлось бы добавлять поле «Чем известен» для всех персонажей в базе. Другие бы тогда получили значение null:</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2025-03-12/e9f5f43b-ae55-41bf-a58c-bf1807d5c9bc.jpg" alt="Зачем разработчику знать SQL" /></figure><p>Из-за строгой схемы надо заранее продумывать логику структуры. Если база данных уже большая и её логику надо поменять, это чревато неудобствами.</p><p>У NoSQL, в отличие от SQL, нет строгой схемы, благодаря этому он отлично подходит для работы с плохо структурированными данными.</p><h2>Транзакции в SQL и NoSQL: ACID (SQL) vs. BASE (NoSQL)</h2><p>Транзакция — набор тех операций, которые либо выполняются полностью, либо не выполняются совсем. Представим перевод денег: снимаем 500 рублей с нашего счёта и отправляем их на другой. Если что-то сломается на полпути, транзакция либо отменится, либо завершит оба шага. В базах данных транзакции нужны, чтобы данные оставались надёжными. Рассмотрим основные различия транзакций SQL и NoSQL.</p><h3>ACID (SQL)</h3><p>SQL-базы данных работают по принципу ACID-транзакций, что гарантирует стабильность и предсказуемость работы с данными. Этот набор правил включает атомарность, согласованность, изоляцию и долговечность.</p><p><b>Атомарность (Atomicity)</b> — транзакция выполняется как единое целое. Если хоть одна операция внутри неё не удалась, всё отменяется. Например, если при переводе денег сервер внезапно отключился, система откатит изменения, и средства не исчезнут.</p><p><b>Согласованность (Consistency) </b>— данные всегда соответствуют правилам базы. Если на счёте 80$, а мы пытаемся перевести 100$, система просто не даст выполнить такую операцию.</p><p><b>Изоляция (Isolation) </b>— параллельные транзакции не мешают друг другу. Пока одна выполняется, другая видит только конечный результат. Например, если один процесс переводит 100$ со счёта A на счёт B, а другой в этот момент проверяет баланс, он увидит либо старое состояние, либо уже обновлённое, но никогда промежуточное.</p><p><b>Долговечность (Durability) </b>— завершённая транзакция остаётся в базе навсегда, даже в случае сбоя. Если мы пополнили счёт на 100$, эта информация будет сохранена, независимо от того, что произойдёт с сервером после.</p><h3>BASE (NoSQL)</h3><p>BASE-модель, которую используют NoSQL-базы данных, строится на трех принципах: базовая доступность, мягкое состояние и конечная согласованность. В отличие от строгих ACID-правил, здесь делается упор на скорость и масштабируемость, даже если это временно снижает точность данных.</p><p><b>Базовая доступность (Basically Available)</b> — система всегда отвечает на запросы, даже если часть данных ещё не синхронизирована. Например, ставя лайк, мы сразу видим его, даже если информация ещё не дошла до сервера.</p><p><b>Мягкое состояние (Soft State)</b> — данные могут временно быть несогласованными. Ради высокой доступности система допускает, что информация изменяется без нашего участия. Например, когда у нового видео на YouTube лайков больше, чем просмотров — это результат того, что одни данные обновились быстрее других.</p><p><b>Конечная согласованность (Eventual Consistency) </b>— если систему оставить в покое, она сама «додумает» и согласует данные между всеми узлами. Допустим, у поста 50 лайков, но у разных пользователей отображаются разные числа: кто-то видит 49, кто-то 53. Через некоторое время система синхронизируется, и у всех будет одинаковое значение.</p><p>BASE-жизнь — это про скорость и гибкость. Главное, чтобы данные в итоге сошлись, а не были идеальными в каждый момент времени.</p><h2>Масштабируемость: вертикальное (SQL) vs горизонтальное (NoSQL) масштабирование</h2><h3>Вертикальное масштабирование (SQL)</h3><p>Реляционные базы данных изначально проектировались для работы на одном сервере (или кластере серверов) с использованием строгой структуры данных (таблицы, строки, столбцы) и поддержки ACID-транзакций.</p><p>Если наше «железо» не справляется с обработкой реляционной базы, то проще его прокачать, например, установить больше памяти, либо купить новый сервер помощнее и перенести на него данные. При таком масштабировании мы как бы гонимся вверх, стараемся получить больше памяти и производительное «железо».</p><p>Конечно, можем купить второй сервер или кластер серверов и распределить на них часть нагрузки, но это будет сложно из-за архитектуры реляционных баз.</p><h3>Горизонтальное масштабирование (NoSQL)</h3><p>При горизонтальном масштабировании мы докупаем дополнительные сервера и распределяем между ними нагрузку. NoSQL базы данных изначально проектировались для работы на множестве серверов. Здесь не нужна строгая схема хранения данных, и они лучше оптимизированы для работы с большим объёмом информации.</p><p>Благодаря этому мы можем распределять нагрузку NoSQL среди множества серверов. Это значит, что если нам не хватает производительности, то можно просто докупить новые устройства.</p><p>Вертикальное масштабирование здесь тоже возможно, но оно часто дороже, хуже подходит для больших баз данных и, в целом, менее удобно из-за архитектуры NoSQL.</p><blockquote>Первое и главное преимущество SQL — строгая структура данных и операций. У базы есть контракт, который ты обязан соблюдать при добавлении, изменении или запросе данных. Правило простое: «Либо всё, либо откат». Второе преимущество — мощный и популярный язык запросов. Сложные аналитические задачи ему по плечу. Уверен, реляционные БД будущего будут опираться на опыт SQL.<br /><br />Строгая структура — одновременно и ограничение. Добавление полей или связей может стать проблемой при реализации на клиенте. Второй момент — горизонтальное масштабирование. Реляционные базы данных очень сложно масштабировать горизонтально. Ты не можешь просто подключить ещё один кластер и продолжать спокойно существовать. Есть ещё определённые проблемы с производительностью, если между объектами существует много связей.<br /><br />Плюсы NoSQL в гибкости, лёгкости масштабирования, высокой производительности при больших нагрузках и разнообразии предметно-ориентированных решений. Например, Redis — для кеширования, Firebase — для реалтайм-обновлений и так далее. Структуру данных можно менять на лету, идеально для проектов с частыми изменениями структуры данных.<br /><br />Минусы в том, что у многих NoSQL свои системы команд и запросов — их приходится учить. Также есть сложности с консистентностью данных.</blockquote><h2>Где использовать SQL и NoSQL</h2><h3>Сценарии, где SQL незаменим</h3><p>SQL хорош там, где важны точность, структура и сложные взаимосвязи данных.</p><h4>Финансовые и банковские системы</h4><p>Здесь цена любой ошибки — чьи-то деньги, поэтому важна точность. Транзакции по стандарту ACID гарантируют, что деньги не потеряются при сбоях. Связь между счетами, клиентами и операциями проще строить через реляционные базы данных.</p><p>Примеры систем: PostgreSQL, Oracle Database, Microsoft SQL Server.</p><h4>Аналитика и сложные запросы</h4><p>В аналитике нужно регулярно вытаскивать данные из таблиц и строить зависимости. В SQL есть операторы JOIN, GROUP BY и оконные функции, которые решают задачи, наподобие расчёта среднего чека за квартал, в пару строк.</p><p>Примеры систем: MySQL, Snowflake, Google BigQuery.</p><h4>Работа с отчётами и BI-системами</h4><p>Данные для бизнеса — это таблицы, сводки, графики. SQL легко интегрируется с инструментами вроде Power BI или Tableau. Строгая схема помогает избежать путаницы в метриках.</p><p>Примеры систем: PostgreSQL, SQL Server, Redshift.</p><h4>Логирование и аудит данных</h4><p>В этой сфере важно понимать, кто, что и когда изменил. Реляционные базы фиксируют историю изменений с точными связями. Триггеры и индексы ускоряют поиск по логам.</p><p>Примеры систем: SQLite, PostgreSQL, MariaDB.</p><h4>Управление складом и инвентаризацией</h4><p>Данные о товарах, поставках и остатках связаны между собой. Реляционная модель идеально описывает такие структуры. Запросы вроде «что заканчивается на складе» пишутся быстро и понятно.</p><p>Примеры систем: MySQL, Oracle Database.</p><h3>Где NoSQL работает лучше?</h3><p>NoSQL — это про скорость, гибкость и масштабирование. Там, где SQL требует строгих рамок, NoSQL даёт свободу и справляется с хаосом больших данных. Вот сценарии, где он выигрывает:</p><h4>Высоконагруженные системы и real-time сервисы</h4><p>Допустим, у нас стриминговый сервис, здесь миллионы запросов в секунду, а задержки недопустимы. Горизонтальное масштабирование размазывает нагрузку по серверам. Данные отправляются быстро, без сложных JOIN’ов.</p><p>Примеры систем: Cassandra, MongoDB, DynamoDB.</p><h4>Гибкие структуры данных и работа с JSON</h4><p>В реальной жизни данные далеко не всегда приходят в виде строгой схемы. У кого-то может быть указан email, у кого-то его нет, но есть телефон. Поэтому для работы с такой информацией лучше подходят документо-ориентированные базы, которые хранят JSON или BSON без строгой структуры. Если мы добавим новое поле, такая база не сломается.</p><p>Примеры систем: MongoDB, CouchDB, Firebase.</p><h4>Графовые базы для рекомендаций и соцсетей</h4><p>Иногда связи между объектами важнее самих данных. Графовые базы строят сети вроде «друзья друзей» или «похожие товары» за доли секунды. SQL для этой задачи медленнее.</p><p>Примеры систем: Neo4j, ArangoDB, OrientDB.</p><h2>Почему SQL и NoSQL нужно знать вместе?</h2><p>SQL даёт точность и структуру, данные в NoSQL — это про скорость и гибкость. В реальных проектах их часто используют вместе, чтобы закрыть слабые места друг друга.</p><h3>Примеры гибридных архитектур: SQL и NoSQL в одном проекте</h3><h4>Работа с каталогами товаров, запросами и системой рекомендаций в интернет-магазинах</h4><p>Представим интернет-магазин: каталог товаров и заказы лежат в SQL — там важны связи и точность. А рекомендации «похожие товары» или история просмотров — в NoSQL, чтобы быстро отдавать данные и не мучиться со схемой.</p><p>Например, PostgreSQL хранит данные о клиентах и транзакциях, а MongoDB — отзывы и пользовательские профили. Всё в одном проекте, каждый инструмент на своём месте.</p><h4>Кеширование запросов с помощью Redis и SQL</h4><p>SQL силён в сложных запросах, но в больших базах может тормозить. А если у нас есть операция, которая предполагает повторный подсчёт? Это будет долго. Здесь выручает Redis, NoSQL-база типа «ключ-значение».</p><p>Представим аналитику продаж: SQL вычисляет «топ-10 товаров за месяц» Готовый список сохраняем в Redis. Теперь, когда нам нужен этот топ, данные тянутся из Redis за миллисекунды, нам не надо заново проводить вычисления в SQL.</p><h4>Использование NoSQL для логов, SQL — для отчётности</h4><p>Логи — это поток данных: миллионы записей, структура не всегда предсказуема. NoSQL вроде Cassandra или MongoDB «переваривает» их без проблем благодаря скорости записи и горизонтальному масштабированию. А потом из этого хаоса SQL, например, MySQL, вытягивает нужное для отчётов: «сколько ошибок за день» или «кто чаще ломает систему». NoSQL собирает сырые данные, SQL их структурирует.</p><h2>Стоит ли учить SQL? Мнение экспертов</h2><p>Мы решили спросить у экспертов, что бы они посоветовали молодым разработчикам изучать в первую очередь, SQL или NoSQL. Делимся мнениями:</p><blockquote>Мой совет — начинайте с SQL. Вот почему:<br /><br />1) База знаний. SQL учит вас основам работы с данными — как их хранить и извлекать. Это фундамент, который пригодится в любом проекте, даже если вы потом перейдёте на NoSQL.<br /><br />2) Широкое применение. SQL встречается повсюду — от стартапов до банков. Знание SQL сразу даёт вам больше шансов найти работу или понять, что происходит в существующем проекте.<br /><br />Но это не значит, что NoSQL можно просто игнорировать. После SQL я бы рекомендовал изучить хотя бы одну NoSQL базу — например, Redis или MongoDB. Современные проекты часто требуют гибкости и скорости, которые дают NoSQL системы. Зная обе технологии, вы сможете выбирать инструмент под задачу, а не подстраиваться под то, что знаете.</blockquote><blockquote>Первым делом нужно освоить SQL. Это фундаментальный навык, который необходим в любой сфере, связанной с данными. Знание реляционных баз помогает понять, как правильно структурировать данные, оптимизировать запросы и обеспечивать их целостность. Независимо от того, с какой технологией будет иметь дело разработчик в будущем, понимание SQL даст ему прочную основу.<br /><br />После освоения SQL я бы рекомендовал изучить и NoSQL. Важно понимать, какие задачи он решает, какие бывают типы нереляционных баз и в каких случаях их применение оправдано. Даже если специалист в своей работе чаще использует SQL, знание NoSQL поможет ему грамотно проектировать архитектуру и принимать взвешенные технологические решения.</blockquote><blockquote>Не существует как такового единого NoSQL как системы управления базы данных, зачастую это очень сильно различающийся набор решений, поэтому стоит начать с SQL, для разных СУБД он довольно мало отличается синтаксически. SQL — это фундамент. NoSQL даст более полное понимание того, как можно работать с базами данных. Можно отметить, что в SQL добавляются фичи NoSql и наоборот.</blockquote><p>SQL и NoSQL желательно знать вместе. Как видно исходя из комментариев экспертов и примеров, SQL — первый ключ к базам данных, NoSQL — второй, для более сложных сценариев.</p>]]></content:encoded>
    </item>
    <item>
      <title>Хакеры взломали Минфин США с помощью Unicode. Как это вообще стало возможным?</title>
      <link>https://tproger.ru/news/hakery-vzlomali-minfin-swa-s-pomoshhyu-unicode--kak-eto-voobshhe-stalo-vozmozhnym-</link>
      <comments>https://tproger.ru/news/hakery-vzlomali-minfin-swa-s-pomoshhyu-unicode--kak-eto-voobshhe-stalo-vozmozhnym-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/hakery-vzlomali-minfin-swa-s-pomoshhyu-unicode--kak-eto-voobshhe-stalo-vozmozhnym-</guid>
      <description><![CDATA[<p>Китайские хакеры взломали Минфин США через уязвимость PostgreSQL, связанную с Unicode. SQL-инъекция оставалась незамеченной 9 лет и позволила атакующим захватить контроль над сервером</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/hakery-vzlomali-minfin-swa-s-pomoshhyu-unicode--kak-eto-voobshhe-stalo-vozmozhnym-">Хакеры взломали Минфин США с помощью Unicode. Как это вообще стало возможным?</a>»</p>]]></description>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Unicode]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 14 Mar 2025 06:52:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>30 декабря, пока большинство людей готовилось к встрече Нового года, Министерство финансов США столкнулось с куда менее праздничным событием — <b>китайские хакеры проникли в их системы</b>.</p><p>Согласно уведомлению, направленному в Конгресс, за атакой стояла <b>группировка, спонсируемая государством</b> (Advanced Persistent Threat, APT).</p><p>Однако самым удивительным стало то, <b>каким именно способом взломщики проникли в защищённые серверы</b>: всё <a href="https://slamdunksoftware.substack.com/p/hidden-messages-in-emojis-and-hacking?r=3d42d">произошло</a> <b>из-за SQL-инъекции, связанной с особенностями Unicode в PostgreSQL</b>.</p><h2>SQL-инъекция в PostgreSQL, которая оставалась незамеченной 9 лет</h2><p>Критическая уязвимость была найдена в <b>программе управления привилегированным доступом (PAM) от компании BeyondTrust</b>, которая использовала PostgreSQL.</p><p>Проблема заключалась в функции pg_escape_string, отвечающей за экранирование пользовательского ввода, и её вызове внутри PostgreSQL-библиотеки libpq.</p><p>Хакеры использовали <b>два байта (c0 27)</b>, которые PostgreSQL ошибочно интерпретировал как часть валидного Unicode-символа. В результате этот механизм позволил атакующим внедрить <b>неэкранированный одиночный апостроф ('), открывший путь для SQL-инъекции</b>.</p><p>Этот апостроф позволил хакерам <b>захватить контроль над psql (CLI-интерфейсом PostgreSQL)</b>, а оттуда <b>использовать команду</b> \! <b>для выполнения произвольного кода</b> на серверах Минфина США.</p><h2>Как такую уязвимость могли не заметить?</h2><p>SQL-инъекции — одна из <b>старейших и самых известных атак</b>, которую разбирают в каждом учебнике по кибербезопасности. Однако эта конкретная уязвимость:</p><ol><li><b>Скрывалась на уровне Unicode</b> — у PostgreSQL не было встроенной валидации корректности Unicode-символов в PQescapeStringInternal.</li><li><b>Не представляла угрозы, пока не использовалась в командной строке psql</b> — а это не самый частый сценарий.</li><li><b>Оставалась незамеченной более 9 лет</b> в одном из самых популярных open-source проектов.</li></ol><p>Теперь, после раскрытия проблемы, PostgreSQL выпустил обновление, исправляющее баг в pg_utf_mblen.</p><h2>Выводы: строки сложны, Unicode ещё сложнее</h2><p>Эта история ещё раз доказывает, что <b>обработка строк и кодировки — источник огромного количества неожиданных уязвимостей</b>.</p><p>Простая ошибка в обработке Unicode могла оставить PostgreSQL уязвимым на протяжении почти десятилетия.</p><p>И напоследок забавный факт: <b>вы можете стать владельцем собственного символа Unicode</b> — например, Buffalo Wild Wings уже «усыновили» эмодзи 🍗, а бейсбольная команда Oakland A’s владеет ⚾, 🐘 и 🌳.</p>]]></content:encoded>
    </item>
    <item>
      <title>MultiDirectory: российская альтернатива Active Directory с 2FA, SSO и совместимостью с AD</title>
      <link>https://tproger.ru/articles/multidirectory-rossijskaya-alternativa-active-directory-s-2fa-sso-i-sovmestimostyu-s-ad</link>
      <comments>https://tproger.ru/articles/multidirectory-rossijskaya-alternativa-active-directory-s-2fa-sso-i-sovmestimostyu-s-ad?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/multidirectory-rossijskaya-alternativa-active-directory-s-2fa-sso-i-sovmestimostyu-s-ad</guid>
      <description><![CDATA[<p>MultiDirectory от компании МУЛЬТИФАКТОР — современная служба каталогов для централизованного хранения данных и управления информацией о пользователях, группах и сетевых ресурсах. Она помогает российским компаниям администрировать инфраструктуру с помощью удобных инструментов и гибких механизмов для поиска и фильтрации данных. Рассказываем об особенностях и функционале MultiDirectory.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/multidirectory-rossijskaya-alternativa-active-directory-s-2fa-sso-i-sovmestimostyu-s-ad">MultiDirectory: российская альтернатива Active Directory с 2FA, SSO и совместимостью с AD</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[LDAP]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 03 Mar 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>К корпоративным сетям подключены тысячи пользователей и устройств, и без служб каталогов у сотрудников будут теряться доступы к серверам и сервисам, а права не будут выдаваться в принципе. Самая популярная служба LDAP-каталогов на рынке — Microsoft Active Directory. Она долго оставалась стандартом, но из-за ограничений на зарубежное ПО многим компаниям приходится искать альтернативу, плюс она использует устаревшие протоколы, которые небезопасны.</p><p>MultiDirectory, разработанная компанией МУЛЬТИФАКТОР — российская служба каталогов с открытым кодом, в которой используется тот же набор атрибутов, что и в AD — это упрощает интеграцию с различными системами. Она поддерживает Kerberos, LDAP, SSO, двухфакторную аутентификацию и легко интегрируется с текущей IT-инфраструктурой. В статье расскажем:</p><ul><li>чем служба каталогов MultiDirectory отличается от AD и других систем;</li><li>как она помогает управлять доступами и безопасностью в корпоративной сети;</li><li>какие функции упрощают администрирование и защиту данных.</li></ul><h2>Что такое службы каталогов и как они работают</h2><p>Служба каталогов — это база данных пользователей, групп и устройств, которая управляет их доступами в корпоративной сети. Учетные данные сотрудников хранятся централизованно, поэтому админам не нужно вручную раздавать права каждому сотруднику и следить, кто к чему подключается. Система автоматически проверяет учетные данные и позволяет администраторам управлять доступом к сервисам, добавляя пользователей в нужные группы. А уже сами сервисы, опираясь на эти группы, выдают пользователям нужные права.</p><p>Сотрудник входит в систему — служба каталогов проверяет его логин и пароль. Для этого используются протоколы аутентификации, такие как LDAP или Kerberos. MultiDirectory поддерживает Kerberos, поэтому пользователям не нужно вводить пароли повторно: система автоматически подтверждает их личность.</p><p>Вся эта информация хранится в иерархической или реляционной структуре, которая организована по объектам: пользователи, группы, устройства и так далее. Когда администратор меняет пароль пользователя в службе каталогов, это затрагивает все системы, которые используют каталог для аутентификации через LDAP или Kerberos, но при этом изменения в сами системы не вносятся. Пользователь также может самостоятельно сменить пароль через программу, в которой он работает, а она сама отправит запрос в каталог и обновит данные через протокол LDAP или Kerberos.</p><p>А если какой-то сервер выйдет из строя, в службах каталогов используется механизм репликации: копии базы данных хранятся на нескольких серверах — так данные будут доступны всегда. Плюс система автоматически переключится на резервный сервер, и пользователи этого даже не заметят.</p><h2>Какие есть службы каталогов</h2><p>Вот наиболее популярные решения:</p><ul><li>Microsoft Active Directory. Он интегрируется с Windows Server и поддерживает протокол LDAP и механизм доменов.</li><li>OpenLDAP. Он используется в UNIX- и Linux-системах, подходит для опенсорсных систем. Но это только реализация LDAP — у него нет встроенного Kerberos, DNS, DHCP и так далее.</li><li>Apache Directory. Java-реализация службы каталогов, поддерживающая LDAP и другие протоколы, часто используется в кроссплатформенных средах.</li></ul><p>Зарубежные Open-Source-решения не поддерживаются официально либо требуют значительных затрат на локальную интеграцию и поддержку — это создаёт дополнительные риски для бизнеса.</p><p>В моменте, когда компании ищут замену Active Directory, они сталкиваются с проблемами:</p><ul><li>Не все решения поддерживают 2FA для Kerberos и совместимы с текущей инфраструктурой.</li><li>Сложный перенос учётных записей пользователей.</li><li>Не хватает встроенной двухфакторной аутентификации.</li></ul><p>MultiDirectory имитирует работу AD, поэтому системы, в которых раньше была AD, можно перенастроить на MultiDirectory без изменений в работе — они будут думать, что всё так же работают с AD.</p><h2>Основные технические характеристики MultiDirectory</h2><p>MultiDirectory работает по трёхзвенной архитектуре: сервер каталогов, репликация данных и система аутентификации. Это позволяет масштабировать систему без простоев, автоматически синхронизировать данные между серверами и минимизировать риски отказов.</p><p>Опенсорсный исходный код MultiDirectory написан на Python — это дает возможность гибкой настройки и контроля на отсутствие закладок. Код можно бесплатно использовать и предлагать исправления. Развёртывание происходит через Docker, что упрощает установку: система запускается на любом сервере с поддержкой контейнеров, без сложных зависимостей и долгой настройки.</p><p>Более того, в отличие от обычных служб каталогов, MultiDirectory хранит данные в базе Postgres. Поэтому репликация и бэкапирование настраиваются через саму СУБД или внешние инструменты, а не самой службой каталогов.</p><h2>Функциональные возможности и простая миграция</h2><p>MultiDirectory позволяет плавно «переехать» с Active Directory, а еще в ней есть поддержка 2FA, SSO и централизованное управление учетными записями. Рассказываем об этих функциях ниже.</p><h3>Централизованное управление учётными записями</h3><p>Администраторы могут управлять учётными записями пользователей и правами через открытый API или вручную с помощью понятного веб-интерфейса. Также у них есть возможность создавать, изменять и удалять учётки и разграничивать права пользователей.</p><p>Доступ пользователей настраивается через группы и роли:</p><ul><li>Domain Admins — администраторы с полными правами</li><li>Read Only — пользователи, которые могут только просматривать данные</li><li>Domain Users — пользователи, у которых есть доступ только к своим учетным записям</li></ul><h3>Надежность, безопасность и 2FA</h3><p>Хэши паролей хранятся в базе данных. А если нужно дополнительное шифрование, можно воспользоваться наложенными средствами защиты или встроенными функциями PostgreSQL. Для аутентификации используется Kerberos — протокол, реализация которого не предполагает передачу пароля по каналам связи. Это обеспечивает гораздо более высокий уровень безопасности по сравнению с тем же NTLM.</p><p>Двухфакторная аутентификация в MultiDirectory работает для нескольких интерфейсов: Admin API, LDAP и Kerberos. Каждый из них может быть защищен с помощью 2FA, а правила его использования настраиваются через политики безопасности.</p><ol><li>Admin API (HTTP) поддерживает OTP или Push-уведомления.</li><li>LDAP также работает с OTP или Push.</li><li>Kerberos поддерживает только Push.</li></ol><p>Если аутентификация происходит через Kerberos, после успешного подтверждения система выдает пользователю тикет доступа.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2025-02-25/90e556de-e79b-4652-a25e-9e9929b9bef1.png" alt="" /></figure><p>2FA снижает риск компрометации аккаунтов, даже если основной пароль утёк.</p><p>MULTIFACTOR — 2FA-система того же разработчика — интегрирована с MultiDirectory, поэтому настройка двухфакторной аутентификации не требует установки дополнительных адаптеров.</p><h3>Режим Bypass</h3><p>Если облачный сервис MULTIFACTOR временно недоступен, в MultiDirectory автоматически включается режим Bypass. В зависимости от настроек можно разрешить или запретить вход в систему без 2FA.</p><p>Настройки режима позволяют:</p><ul><li>Разрешить вход без 2FA в случае сбоя, чтобы бизнес-процессы не останавливались.</li><li>Полностью запретить авторизацию при отсутствии двухфакторной проверки — если безопасность важнее доступности.</li></ul><h3>Поддержка DNS</h3><p>MultiDirectory интегрируется с Bind9 и позволяет управлять всеми типами записей зоны через веб-интерфейс. При настройке DNS автоматически создаются необходимые записи для Kerberos и LDAP.</p><h3>Быстрая авторизация с Single Sign-On (SSO)</h3><p>Технология единого входа (SSO) позволяет пользователям вводить пароль только один раз — дальше система автоматически авторизует их в корпоративной почте, CRM, облачных сервисах и других внутренних приложениях.</p><p>В чем плюсы:</p><ul><li>Сотрудники не тратят время на постоянный ввод паролей.</li><li>IT-отделу не приходится восстанавливать доступ к забытым учетным записям.</li><li>Снижается риск утечек паролей.</li></ul><h2>Заключение</h2><p>MultiDirectory — это российская альтернатива AD с поддержкой 2FA, SSO и централизованного управления.</p><p>Задачи, которые решает MultiDirectory:</p><ul><li>централизованное управление учетными записями, компьютерами группами;</li><li>единая точка идентификации, аутентификации и авторизации;</li><li>поддержка современных стандартов безопасности;</li><li>управление DNS-записями через Bind9</li><li>гибкая интеграция с внешними системами.</li></ul><p>Продукт уже работает в корпоративных средах, а в 2025 году разработчики планируют регистрацию в реестре отечественного ПО и выпуск Enterprise-версии с расширенными возможностями. В ней появятся:</p><ul><li>поддержка доверия доменов;</li><li>дополнительные методы защиты;</li><li>DHCP-сервер;</li><li>гранулированная настройка доступа;</li><li>делегирование полномочий;</li><li>интерфейс для логов;</li><li>журнал событий;</li><li>и многое другое.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Рефакторинг запросов: как ускорить работу API без переписывания всего кода</title>
      <link>https://tproger.ru/articles/refaktoring-zaprosov--kak-uskorit-rabotu-api-bez-perepisyvaniya-vsego-koda</link>
      <comments>https://tproger.ru/articles/refaktoring-zaprosov--kak-uskorit-rabotu-api-bez-perepisyvaniya-vsego-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/refaktoring-zaprosov--kak-uskorit-rabotu-api-bez-perepisyvaniya-vsego-koda</guid>
      <description><![CDATA[<p>Рефакторинг запросов. Показываем, как ускорить работу API без переписывания всего кода. Рассматриваем пошаговую инструкцию и основные нюансы ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/refaktoring-zaprosov--kak-uskorit-rabotu-api-bez-perepisyvaniya-vsego-koda">Рефакторинг запросов: как ускорить работу API без переписывания всего кода</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 24 Feb 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>API тормозит, а переписывать код с нуля — не вариант? Рефакторинг запросов поможет ускорить работу без радикальных изменений. Разбираем, как оптимизировать API, сокращая задержки и снижая нагрузку на сервер, не разваливая всю систему.</p><h2>Анализируем производительность API</h2><p>Прежде чем ускорять API, нужно понять, что именно замедляет его работу. Для этого оцениваем ключевые метрики:</p><ul><li>Время отклика — сколько времени проходит от запроса до получения ответа.</li><li>Нагрузка на сервер — сколько ресурсов потребляет API при обработке запросов.</li><li>Частота ошибок — как часто сервер возвращает некорректные ответы.</li></ul><p>Отслеживать эти показатели помогают инструменты вроде Postman, New Relic и APM-систем. Они визуализируют данные, автоматизируют тестирование и позволяют находить проблемы в режиме реального времени.</p><h3>Postman</h3><p>Используется для ручного тестирования запросов. Postman показывает время отклика и ошибки. Также через него удобно тестировать сценарии работы API.</p><p>Инструмент удобен тем, что поддерживает коллекции запросов. Это упрощает тестирование сложных цепочек операций во время рефакторинга. Можно интегрировать Newman для автоматизации тестов и анализа метрик на регулярной основе.</p><p><a href="https://tproger.ru/articles/gajd-po-rabote-s-postman">Большой гайд по работе с Postman API Platform</a></p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/bec33c5a-fa3c-4888-af85-885ece3d6f85.jpg" alt="" /><figcaption>Интерфейс Postman</figcaption></figure><h3>New Relic</h3><p>Платформа для мониторинга производительности приложений. Можно отслеживать время обработки API-запросов, статистику по операциям, загрузку системы.</p><p>New Relic показывает распределение времени выполнения между сервером, БД и внешними сервисами, что помогает в рефакторинге разных частей системы.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/732eea24-d64a-4e3b-9585-f2e4f23e2f75.png" alt="" /><figcaption>Интерфейс New Relic</figcaption></figure><h3>APM-системы</h3><p>Инструменты Datadog, AppDynamics или Dynatrace сохраняют данные о том, как работает API. Через них можно смотреть трассировку запросов, выявлять проблемы с медленными вызовами или зависимостями от внешних систем.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/55c2a216-1a7c-46c9-b19a-3324bc9a9493.jpg" alt="" /><figcaption>Трасса в Datadog</figcaption></figure><h3>Ищем узкие места в запросах</h3><p>Для выявления проблемных фрагментов кода необходимо посмотреть, как API реагирует на разные нагрузки, и как распределяется время обработки запроса.</p><p>Поиск состоит из 7 этапов:</p><ul><li><b>Анализ общей картины</b>. С помощью APM-систем и логирования нужно выделить самые медленные запросы.</li><li><b>Локализация длинных операций</b>. В одном запросе может быть несколько узких мест (тяжелый SQL-запрос, внешний API-вызов).</li><li><b>Поиск запросов с высокой частотой вызовов</b>. Например, запросы к слою авторизации или ручки API, к которым обращаются массово при каждом действии пользователя.</li><li><b>Проверка ошибок</b>. Ошибки приводят к дополнительной нагрузке: например, если клиент совершает повторные запросы после тайм-аута.</li><li><b>Анализ распределения нагрузки</b>. Если одни эндпоинты перегружены трафиком, а другие используются редко, в рамках рефакторинга нужно сбалансировать нагрузку. Например, добавить серверы только под обработку горячих эндпоинтов.</li><li><b>Тестирование в условиях пиковой нагрузки</b>. Стресс-тест средствами JMeter поможет выявить проблемы, скрытые в условиях обычного трафика.</li><li><b>Анализ зависимостей API</b>. Замедленная работа внешнего сервиса увеличивает время отклика для каждого запроса. Через Jaeger или Zipkin можно посмотреть цепочку зависимостей.</li><li><b>Локализация длинных операций</b>. В одном запросе может быть несколько узких мест (тяжелый SQL-запрос, внешний API-вызов).</li></ul><h2>Оптимизация запросов к базе данных</h2><p>Уменьшить время отклика API без переписывания кода можно за счёт оптимизации работы с БД. Один из ключевых инструментов — <a href="https://tproger.ru/articles/indeksy-v-postgresql">индексы</a>. Они ускоряют поиск данных, снижая нагрузку на сервер.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/2e25a089-667a-4002-9967-66601f996cfa.jpg" alt="" /><figcaption>B-Tree индекс PostgreSQL</figcaption></figure><p>Что индексировать в первую очередь:</p><ul><li>Поля, используемые в WHERE, JOIN, ORDER BY, GROUP BY. Например, если запросы часто фильтруют по email, имеет смысл добавить индекс.</li></ul><ul><li>Запросы с несколькими условиями фильтрации — их лучше оптимизировать составными индексами. Важно, чтобы порядок полей соответствовал порядку в SQL-запросах.</li></ul><ul><li>Только те данные, где индексация действительно ускорит поиск. Например, индекс для gender (male/female) не даст прироста скорости.</li></ul><p>Лишние индексы замедляют операции записи, их нужно удалять. В PostgreSQL они могут пересекаться, но при дублировании  замедляют запросы. Вместо нескольких отдельных индексов эффективнее использовать составные.</p><h3>Агрегация и выбор только необходимых полей</h3><p>Обработка бесполезных данных увеличивает объем передаваемой информации, замедляет чтение и создает нагрузку на сеть.</p><p>Например, команда SELECT * выбирает все колонки таблицы, включая неиспользуемые. Вместо SELECT * FROM users следует указывать целевые поля: SELECT id, name, email FROM users.</p><p>Если к запросу добавлены ненужные JOIN-ы, группировки или сортировки, в рамках рефакторинга нужно постараться избавиться от них. Избыточные операции на стороне БД рекомендуется переносить в бизнес-логику приложения.</p><p>Снизить объем данных можно за счет COUNT, SUM, AVG, MAX, MIN — эти функции возвращают обобщенные записи вместо отдельных значений. Частичную обработку данных можно выполнять на стороне БД. Например, в PostgreSQL есть встроенные функции по типу JSON_AGG.</p><h3>Пагинация и лимиты в запросах</h3><p>API, работающие со списками пользователей и транзакциями, обязательно должны использовать пагинацию. Лимит на объем возвращаемых записей предотвращает перегрузку серверов и клиента.</p><p>Самое простое решение — во время рефакторинга ограничить количество строк с помощью LIMIT или FETCH FIRST. Например, вместо загрузки всех пользователей SELECT id, name FROM users LIMIT 30 вернет только первые 30 строк.</p><p>Еще можно использовать постраничную выборку (комбинацию LIMIT и OFFSET):</p><p>Если производительность упала, значит офсет слишком большой. В таких случаях лучше перейти на модель курсоров.</p><p>Пагинация с курсорами заменяет OFFSET значением последнего взятого элемента. Например, вместо LIMIT 20 OFFSET 100 можно использовать запрос:</p><p>Чтобы пагинация работала корректно, всегда нужно использовать явный ORDER BY.</p><p><a href="https://tproger.ru/articles/realizuem-paginaciju-v-go-ispolzuja-postgresql">Пагинация на Go в PostgreSQL</a></p><h2>Кэширование</h2><p>Количество запросов к серверу можно сократить, если сохранять часто запрашиваемые данные. Это называется <b>кэшированием</b>. Рефакторинг кэширования уменьшает нагрузку на сервер, снижает время отклика API.</p><p>Рассмотрим инструменты для кэширования.</p><h3>Redis</h3><p>Подходит для серверного и распределенного кэширования. Поддерживает TTL, работу со списками, хэшами и включение репликации для отказоустойчивости. Для интеграции доступны библиотеки и клиенты — ioredis для Node.js или StackExchange.Redis для .NET.</p><p><a href="https://tproger.ru/articles/kak-ispolzovat-redis-dlya-kewirovaniya-i-ocheredej-v-veb-prilozheniyah">Как использовать Redis для кэширования и очередей в веб-приложениях</a></p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/a5b5085d-4c58-45f0-b8f7-b27fcd78ad85.jpg" alt="" /><figcaption>Схема работы Redis, данные хранятся в оперативной памяти сервера</figcaption></figure><p>Рефакторинг кэширования повысит производительность сервиса:</p><ul><li>если API возвращает неизменяемые или редко изменяющиеся данные,</li><li>если часть запросов к БД выполняется кратно дольше остальных.</li></ul><p>Например, в Redis можно сохранять список активных пользователей:</p><h3>Memcached</h3><p>Применяется для уменьшения нагрузки на базу данных и работы с временными данными. Memcached менее функционален, чем Redis, но более эффективен для сценариев, где не требуется сложная логика или постоянное хранилище.</p><p><a href="https://tproger.ru/articles/kak-ispolzovat-servery-redis-i-memcached-dlya-kewirovaniya">Как использовать серверы Redis и Memcached для кэширования</a></p><h3>Виды кэша</h3><p>Выбор типа кэширования зависит от архитектуры API и характера данных.</p><ul><li>Клиентский кэш — данные хранятся на стороне клиента. Например, браузеры загружают страницу дольше в первый раз, но затем мгновенно извлекают её из кэша.</li><li>Серверный кэш — данные сохраняются на сервере или в промежуточном хранилище (Redis, Memcached). Это снижает нагрузку на базу данных: повторные запросы возвращаются из кэша, а не пересчитываются заново.</li><li>Распределённый кэш — данные кэшируются в нескольких узлах для масштабирования и высокой доступности. Например, Redis в режиме кластера помогает организовать кэширование в микросервисной архитектуре.</li></ul><h2>Уменьшение объема передаваемых данных</h2><p>Скорость API зависит от объема данных, передаваемых между клиентом и сервером.</p><h3>Оптимизация формата ответа: JSON vs Protobuf</h3><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/d023e3be-de47-4800-9eed-c034b97920c4.jpg" alt="" /><figcaption>Сравнение JSON и Protobuf</figcaption></figure><p>Формат <b>JSON </b>популярен из-за читаемости и универсальной поддержки большинством языков программирования. Он менее эффективен по сравнению с бинарными форматами. JSON занимает больше места из-за текстового представления структур и значений.</p><p><b>Protobuf </b>(Protocol Buffers) —  бинарный формат, разработанный Google. Он компактен, быстрее сериализуется и занимает меньше места по сравнению с JSON. В формате Protobuf каждый элемент закодирован с минимальным количеством байтов.</p><p>Переход на Protobuf может потребовать изменений в клиентах API, поэтому такая оптимизация выполняется на этапе, когда остальные методы снижения объема данных себя исчерпали.</p><h3>Удаление избыточных данных и компрессия</h3><p>Часто API отправляет больше данных, чем реально нужно клиенту. Это лишний сетевой трафик и задержки:</p><ul><li>Удаление ненужных полей — ограничение выборки данных на стороне сервера: используются выборочные запросы к БД, настройка сериализаторов или фильтрация на уровне представлений.</li><li>Сжатие Gzip — уменьшение размера текстовых данных (JSON, XML) на 70–90%, не требуя изменений в API. Включается на уровне Nginx, Apache или через middleware. Клиенты автоматически распаковывают такие ответы, сохраняя прозрачность процесса.</li></ul><h3>Версионирование API</h3><p>Клиенты обычно нуждаются в данных разного объема. Вместо универсального ответа для всех пользователей рекомендуется разработать несколько версий API.</p><p>Новые версии должны отправлять клиентам упрощенные данные или предлагать другую модель представления без модификации существующих запросов.</p><p>Упрощение достигается через фильтрацию полей на стороне сервера с использованием сериализаторов или форматов ответа. Например, через GraphQL можно сделать так, чтобы клиенты напрямую запрашивали только необходимые поля.</p><p>Чтобы не произошло одновременного отказа у клиентов на старых версиях API, можно временно поддерживать несколько версий. Со временем старую версию нужно объявить устаревшей и отключить.</p><h2>Параллелизация и объединение запросов</h2><p>Оптимизировать API можно за счет рефакторинга batch-запросов. Они объединяют несколько запросов в один — количество обращений между клиентом и сервером сокращается.</p><p>Клиенты отправляют массив запросов, сервер обрабатывает их и возвращает всего один ответ.</p><p>Batch-запросы дают прирост к производительности, когда клиент ожидает получение или обновление нескольких независимых ресурсов.</p><p>Например, мобильное приложение может запрашивать информацию о пользователе и связанных с ним объектах (сообщения, уведомления) за один вызов.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/c893e38f-6031-4a2a-a861-b911798ce759.jpg" alt="" /><figcaption>Схематичное изображение batch-запросов</figcaption></figure><p>Если API поддерживает вложенные запросы, клиент может запрашивать связанные данные одним вызовом. Пример на GraphQL:</p><h3>Асинхронные операции</h3><p>API после рефакторинга будет работать быстрее, если выполнять запросы независимо друг от друга. Сервер может распределять выполнение независимых операций по асинхронным потокам.</p><p>Например, при обработке одного запроса API может обратиться к нескольким подсистемам, отправить синхронные запросы в базу данных и внешние API, параллельно собирая результаты.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/d1a8d43e-6ba2-4c84-866f-caae7301910a.jpg" alt="" /><figcaption>Принцип работы асинхронного API</figcaption></figure><p>Для асинхронных операций часто используются очереди сообщений RabbitMQ или Apache Kafka.</p><h2>Оптимизация на уровне серверной логики</h2><p>Обработку запросов можно откладывать до момента, когда данные действительно понадобятся. Это полезно при работе с запросами, где связанная информация не требуется или используется не полностью. Такое поведение называется <b>lazy loading</b> (ленивая загрузка).</p><p>Загружать связанные данные можно заранее в одном запросе, чтобы сократить количество запросов к БД. Такой принцип работы API называется <b>eager loading</b> (стремительная загрузка). Используется в случаях, когда известно, что все связанные данные понадобятся в ходе операции.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-02-14/56dd35a2-1b7c-437e-b796-cc3ef56b2ea0.jpg" alt="" /></figure><p><b>Lazy loading</b> подходит, если только небольшая связка данных используется в каждом запросе.</p><p><b>Eager loading</b> лучше применять, когда количество запросов к БД критично или весь объем данных необходим для выполнения операции.</p><h3>Очереди для обработки задач в фоне</h3><p>Вместо выполнения тяжелых задач в реальном времени, сервер может добавлять их в очередь, чтобы они обрабатывались фоновыми воркерами.</p><p>Очереди используются для задач, не влияющих на основной ответ клиенту:</p><ul><li>отправка писем,</li><li>формирование отчетов,</li><li>обновление статистики,</li><li>построение индексов,</li><li>обработка данных.</li></ul><p>При поступлении запроса API выполняет только основные операции (валидацию данных или запись в базу), после чего создает задачу в очереди. Процессы выполняются в отдельной среде, не влияя на основной поток обработки запросов.</p><h3>Разделение сложных операций на этапы</h3><p>Комплексные операции, например, генерации отчетов, можно разделить на сбор данных из базы, их обработку и финальное преобразование. Каждый шаг выполняется независимо, а результаты промежуточных операций сохраняются для последующего использования.</p><p>Вместо последовательного выполнения всех шагов, задачу можно поручить системе планировщиков или pipeline в <a href="https://tproger.ru/articles/kak-nastroit-i-ispolzovat-jenkins-dlya-avtomatizacii-processov">Jenkins</a>. Каждый этап становится в очередь и выполняется отдельным процессом.</p><h2>Мониторинг и тестирование</h2><p>После рефакторинга хочется быть уверенным в стабильности API, выявить возможные проблемы и оценить эффективность оптимизаций. Процесс включает:</p><ul><li>нагрузочное тестирование,</li><li>сравнение метрик до и после рефакторинга,</li><li>автоматизацию наблюдения за состоянием API.</li></ul><p>Нагрузочное тестирование определяет, как API справляется с возрастающей нагрузкой. Оно выявляет точки перегрузки. Инструменты для стресс-теста API: Apache JMeter, Gatling.</p><p>На основе результатов нагрузочного тестирования можно проанализировать, насколько рефакторинг улучшил производительность API. В сборе метрик помогут APM-инструменты.</p><p><b>Если показатели значительно улучшились, поздравляем, рефакторинг удался. </b></p><p>Автоматизация мониторинга повышает надежность API и предотвращает проблемы до их масштабного проявления. Инструменты для поддержания производительности в реальном времени: Prometheus + Grafana, Datadog.</p><h2>Что запомнить</h2><ul><li>Производительность API оценивается с помощью метрик: времени отклика, нагрузки на сервер и частоты ошибок.</li><li>Для мониторинга API используются инструменты Postman, New Relic и APM-системы, которые выявляют узкие места системы.</li><li>Оптимизация запросов к базе данных включает индексацию, удаление избыточных операций и выбор только необходимых полей. Для работы с большими объемами данных используется пагинация с применением LIMIT, OFFSET или курсоров.</li><li>Кэширование снижает нагрузку на сервер, сохраняя востребованные данные локально.</li><li>Уменьшение объема передаваемых данных достигается за счет перехода с JSON на Protobuf, компрессии Gzip и фильтрации полей.</li><li>Для сокращения числа запросов к API применяются batch-запросы.</li><li>Асинхронная обработка операций с помощью очередей RabbitMQ или Kafka ускоряет время отклика API для клиентов.</li><li>Очереди для фоновой обработки задач снижают нагрузку на основной поток запросов.</li><li>Нагрузочное тестирование помогает оценить улучшения после рефакторинга.</li><li>Автоматизация мониторинга предотвращает проблемы API до их критического проявления.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Go-разработчик 2025: что нужно знать на каждом грейде</title>
      <link>https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde</link>
      <comments>https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Danil Dinko]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde</guid>
      <description><![CDATA[<p>Даниил Динько, тимлид в компании-лидере в международном кибербезе и эксперт Эйч Навыки, собрал стартер-паки для Go-разработчика каждого уровня.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde">Go-разработчик 2025: что нужно знать на каждом грейде</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Feb 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Грейды — штука абстрактная, поскольку у каждой компании есть свое мнение на этот счет. Для одних ты можешь быть джуном+, а для других — сильным сеньором. Тем не менее, можно однозначно наметить общие тренды в требованиях по индустрии.</p><p>Я — <a href="https://h.careers/curators/daniil-dinko?utm_source=tg_bot&amp;utm_medium=rassilka&amp;utm_campaign=161024">Даниил Динько</a>, веду свой личный <a href="https://t.me/thestrikemch">телеграм-канал</a>, где рассказываю о себе, об IT и о Golang. Также являюсь экспертом и спикером в компании <a href="https://h.careers/skills?utm_source=site_tproger&amp;utm_medium=article">Эйч Навыки</a>, TeamLeadом в компании-лидере в международном кибербезе, ex. старшим разработчиком в Ozon Tech. Вместе разбираемся, что объединяет Go-разрабов каждого грейда.</p><p>А почитать о том, как сейчас стать Go-разрабом, можно в предыдущей <a href="https://tproger.ru/articles/kak-sejchas-stat-go-razrabotchikom-s-nulya--vse-puti">статье</a>.</p><h2>Навык собеседований vs. навык работы</h2><p>Для начала важно разделять два понятия: навык прохождения собеседований и навык работы. Интервью длится 3-4 часа — этого невероятно мало, чтобы прочувствовать весь ваш кругозор в бою, поэтому индустрия использует стандартные задачи-заглушки. У большинства компаний такие задачи примерно про одно и то же, поэтому сейчас не редка ситуация, когда на собеседовании ваш реальный грейд на единицу или полторы выше реального — как раз потому, что такие заглушки отскакивают от зубов.</p><ul><li><b>Что это значит для кандидата:</b> в такой ситуации можно быстрее вырасти в реальном навыке работы, потому что через навык собеседований вы получаете грейд. Эти задачи не даются просто так на позиции, которая соответствует навыку реальной работы. Так, в стрессовой ситуации вы максимально выравниваетесь за короткий срок.</li><li><b>Что это значит для компании:</b> для работодателя это плохо, поскольку  определить грейд —  еще сложнее. И есть шанс нанять кандидата, на которого потратят больше денег, чем он теоретически может принести.</li></ul><p>Теперь разберем, что требуется от Go-разработчиков на каждом уровне.</p><h2>Что нужно с точки зрения навыка собеседований</h2><p>Сейчас интервью стали гораздо жестче: конкуренция растет, а требования к кандидатам повышаются.</p><p>Дисклеймер: не обязательно знать все из списка ниже — в нем представлено максимальное количество навыков и верхняя граница знаний по грейду. Поэтому если вы что-то не знаете, это отличный способ понять, что наверстывать.</p><h3>Грейд: Junior</h3><p>Сейчас на рынке Go очень много джунов — он перегрет, и попасть в компанию без коммерческого опыта будет крайне сложно. Более того, от начинающих разработчиков ждут немало знаний и навыков. О них — ниже.</p><h4>Углубленное знание Go</h4><ul><li>Уметь абстрактно рассказать про очереди в планировщике.</li><li>Знать про мапу под капотом: как устроено хеширование, коллизии и разрешение конфликтов.</li><li>Уметь решать задачи по concurrency на относительно базовом уровне (воркер пул) и на слайсы</li><li>Понимать принципы работы горутин и каналов.</li></ul><h4>Базы данных</h4><ul><li>Знать виды баз данных и рассказать про максимальное количество юзкейсов из опыта с разными типами данных.</li><li>Знать индексы и ACID и уметь их базово  писать.</li><li>Знать SQL, уметь составлять схемы и идейно понимать, как работают самые известные базы —  PostgreSQL, ClickHouse.</li><li>Понимать репликацию и шардирование</li></ul><h4>Системный дизайн</h4><p>Да-да, теперь даже джуну нужно иметь абстрактное понимание сисдиза:</p><ul><li>Монолит vs. микросервисы: знать плюсы и минусы каждой архитектуры.</li><li>Знать варианты коммуникаций между сервисами (брокеры сообщений, REST API, gRPC).</li></ul><h4>Алгосы и Computer Science</h4><ul><li>Уметь решать медиум-задачки на LeetCode. Фокус при этом на задачах со слайсами, деревьями и графами.</li><li>В Computer Science — знать про устройство Linux, планировщик, потоки/процессы, а еще про устройство сети — OSI, TCP/IP, протоколы и т.д.</li></ul><p>Также  в некоторых компаниях сейчас ко всему этому требуют еще и знание Kubernetes.</p><p>Вот <a href="https://miro.com/app/board/uXjVLGihxYs=/">здесь</a> собрал дорожную карту, как влиться в IT на примере Go. Из полезных ссылок:</p><ol><li><a href="https://www.youtube.com/watch?v=eQPfHdiz_KI">Один из лучших курсов по Go на Youtube</a></li><li><a href="https://www.youtube.com/watch?v=d6BtxBKhQoc&amp;t=3178s">Крутой урок по системному дизайну</a></li><li><a href="https://www.youtube.com/watch?v=ZTJcaP4G4JM">Все про каналы в Go</a></li></ol><p>А <a href="https://miro.com/app/board/uXjVLIldoLE=/">здесь</a> можно посмотреть, как джуну стать мидлом.</p><h3>Грейд: Middle</h3><p>Схема примерно такая же, как и с джунами, правда, знать все нужно гораздо глубже.</p><h4>Go</h4><ul><li>Знать планировщик на уровне того, какая структура данных используется в локальных очередях.</li><li>В слайсах — уметь решать задачи со срезом по capacity, плюс более уверенное решение кейсов по concurrency.</li></ul><h4>Базы данных</h4><ul><li>MVCC,</li><li>Проблема разбухания индексов,</li><li>Селективность,</li><li>Шардирование на уровне реальных решений основной проблемы решардинга — Consistent Hash,</li><li>Реприликация и паттерн Raft.</li></ul><p>А еще важно уметь писать нормальные индексы и эффективные SQL запросы. Плюс ожидается, что у вас будет больше юзкейсов работы с разными типами баз данных.</p><h4>Сисдиз</h4><p>Нужно знать про паттерны межсервисного взаимодействия: Saga, Transactional Outbox, Circuit Breaker. На мидла могут уже спокойно давать практические задачи на внедрение каких-то идейных дизайнерских штук, например, идемпотентности.</p><h4>Алгосы и Computer Science</h4><p>Здесь они играют меньшую роль. Главное — показать коммерческий опыт, рассказать о кейсах и блеснуть знаниями в Go, базах и проектировании.</p><h3>Грейд: Senior</h3><p>Сеньоры — моя любимая тема, самый абстрактный и спорный грейд. Здесь требуется все то же, что и на мидла, но знания должны быть еще более глубокие. Вот примерный список:</p><h4>Go</h4><p>Нужно знать библиотеку Reflection со всякими приколами, которые могут ускорить concurrency. Также разбираться в аренах памяти и планировщике.</p><h4>Сисдиз</h4><p>В паттернах межсетевого взаимодействия история с обычным рассказом не пройдет — юзкейсы здесь must-have. Поэтому важно уметь проходить System Design-интервью — собирать функциональные и нефункциональные требования, считать нагрузку, проектировать на разных уровнях абстракции, углубляться и решать проблемы в своей же архитектуре. Это сложно, и без хотя бы косвенного соприкосновения с проектированием, будет непросто. Поэтому в качестве совета — стремитесь максимально участвовать на архитектурных сессиях и грумингах, будучи мидлом.</p><h4>Базы данных</h4><p>Будет круто знать, как под капотом реализован, например, PostgreSQL: как он поднимает что-то в буфер, как хранит данные на диске, что такое чекпоинты и бэкапы и как реализована MVCC.</p><p>В случае с ClickHouse лучше верхнеуровнево понимать LSM-дерево, а с ElasticSearch — инвертированные индексы.</p><h4>Алгосы и Computer Science</h4><p>Алгоритмы уже почти не играют роли в большинстве компаний, а Computer Science требуется примерно на том же уровне, что и на джуна. Единственное — в Linux могут чуть капнуть.</p><p>Также в зависимости от компании могут требовать углубленные знания в DevOps, но мы про это говорить не будем — не самый частый кейс. Однако базовое понимание того, как что развернуть, какие могут быть проблемы и как их решить идейно, должно быть.</p><p>Мне часто на трансляциях говорят: «Зачем мне знать планировщик или уметь решать сложные задачи по concurrency? Когда мне это пригодится в работе?». Действительно, на эффективность в решении рабочих задач это влияет незначительно, но все же это особенность собеседований (подробнее можно посмотреть <a href="https://t.me/thestrikemch/68">здесь</a>):</p><ul><li><b>Собес ≠ работа. </b>Принято считать, что знания, требуемые на собеседовании, пригодятся в работе — это не так. За несколько часов невозможно полностью оценить кандидата, поэтому интервью строятся на проверке общих знаний и концепций.</li><li><b>Почему спрашивают про планировщик?</b> Банально узнают софты.</li><li><b>Жесткая конкуренция. </b>Все просто: знание — сила.</li></ul><h2>Что нужно с точки зрения реальной работы</h2><p>На мой взгляд, самое важное, помимо знания технологий — прокаченные софт-скиллы. И наработать их можно только с опытом.</p><ul><li><b>Грейд Junior.</b> Нужно уметь делать максимально базовые задачи. Например, добавить поле или прокинуть фича-флаг. Или же при курировании и ревью быть мотивированными. Этого достаточно. Да, как бы грустно это ни звучало, здесь по классике предполагается, что тебе нельзя доверить что-то серьезное без сторонней помощи.</li><li><b>Грейд Middle.</b> Относительно безболезненно брать на себя полноценные части продукта в зону ответственности, фича-лидить. Здесь предполагается, что ты можешь действовать относительно самостоятельно, приходя с вопросами лишь иногда. Тут уже желательно участвовать в каких-либо технических обсуждениях.</li><li><b>Грейд Senior.</b> Здесь нужно разрабатывать фичи любого уровня сложности под ключ. Тебе достаточно предоставить бизнес-требования, сходить с ними по командам с экспертизой. Затем спроектировать качественную архитектуру, которая развалится с минимальной вероятностью, самому реализовать и принести лиду  таску в Done. Здесь также важно менторить сотрудников, активнейшим образом участвовать на грумингах и любых других технических созвонах.</li></ul><p>Конкуренция растет, требования становятся все жестче, поэтому самое главное — постоянное развитие. Учитесь, ходите на собеседования, участвуйте в грумингах и обсуждениях. И помните, что навык проходить интервью и реальная работа — разные вещи, но без них никуда.</p>]]></content:encoded>
    </item>
    <item>
      <title>Это БАЗА (данных): Как подключиться и выполнить запрос?</title>
      <link>https://tproger.ru/articles/kak-podklyuchitsya-k-baze-dannyh-i-vypolnit-zapros-</link>
      <comments>https://tproger.ru/articles/kak-podklyuchitsya-k-baze-dannyh-i-vypolnit-zapros-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Елизавета Малышева]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-podklyuchitsya-k-baze-dannyh-i-vypolnit-zapros-</guid>
      <description><![CDATA[<p>Как подключиться к базе данных. Показываем основные запросы к базам данных. Рассматриваем пошаговую инструкцию по использованию ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-podklyuchitsya-k-baze-dannyh-i-vypolnit-zapros-">Это БАЗА (данных): Как подключиться и выполнить запрос?</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[NoSQL]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 16 Jan 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Хотите заплатить хакерам $15 миллионов за свои данные?</p><p>Это не шутка. Именно<a href="https://www.interfax.ru/world/920813"> такую сумму</a> заплатила американская сеть казино Caesars Entertainment злоумышленникам, которые увели их БД.</p><p>База данных ––  самое ценное, что есть у каждой компании. Именно в ней хранится вся чувствительная и важная для бизнеса информация. В этой статье расскажем, какие есть базы данных и как правильно с ними работать: подключаться и делать запросы.</p><h2>Такие разные базы данных</h2><p>Базы данных — основной инструмент программирования. БД хранят важную информацию о пользователях и позволяют этой информацией управлять.</p><p>Они делятся на два основных типа: реляционные и нереляционные.</p><p><b>Реляционная база</b> — как большой шкаф с ящиками. У каждого своя подпись, и в нём лежат только определенные вещи по порядку. Например, один ящик для носков, второй для шапок, третий –– для носовых платков.</p><p>Все очень аккуратно, ничего не теряется, но если нужно что-то изменить, например, носки переложить в ящик с платками –– будет не так-то просто.</p><p>Чтобы делать запросы к реляционной базе, нужно использовать язык SQL. А обрабатывать эти запросы будет СУБД –– система управления базами данных. Простыми словами –– штука, которая помогает вам управлять самой базой. Что-то из шкафа вытащить, кого-то в него спрятать.</p><p><b>Нереляционная база данных</b> — как огромная коробка, куда можно складывать всё, что угодно и как угодно. Это удобно, но для системы с чёткой структурой не подойдёт.</p><p>Какой тип БД выбрать для проекта –– зависит от целей компании, размера и особенностей бизнеса. Разберём каждый тип.</p><h2>Реляционные базы данных (SQL)</h2><p>Реляционные базы –– таблицы, где данные организованы в строки и столбцы. У каждой таблицы строгая схема, которая определяет типы данных и их взаимосвязь. Реляционные базы используются для приложений, где важны точность и согласованность информации.</p><p>Посмотрим на конкретные примеры.</p><h3>MySQL</h3><p>Очень популярная база с открытым исходным кодом. Она надежная, удобная и быстрая. MySQL часто используют для веб-приложений. Например,  Airbnb, Netflix и Uber.</p><p>Её любят, потому что у неё качественная и подробная документация, а также большое сообщество.</p><h3>PostgreSQL</h3><p>Мощная и универсальная реляционная база данных, которая предлагает расширенные возможности. Среди них —  работа с JSON, хранение массивов и поддержка пользовательских типов данных. Это делает PostgreSQL гибким инструментом для решения самых разнообразных задач.</p><p>СУБД используется в сложных приложениях, где важны высокая надежность и гибкий функционал.</p><h3>SQLite</h3><p>Эта однофайловая СУБД мало весит и не требует сервера для работы. Она идеально подходит для небольших приложений, мобильных устройств и тестирования.</p><p>Если нужно будет что-то куда-то переносить –– процесс пойдёт быстро. За эту простоту SQLite и любят.</p><h2>Нереляционные базы</h2><p>Нереляционные базы данных подходят для работы с большими объемами, которые могут быть неструктурированными или слабо структурированными.</p><p>В отличие от реляционных, у этих баз нет строгой схемы, что делает их гибкими и удобными для многих современных приложений.</p><p>Разберём самые популярные варианты нереляционных баз.</p><h3>MongoDB</h3><p>NoSQL-база данных, которая хранит данные в формате JSON, обеспечивает гибкость и простоту работы. MongoDB часто используется в приложениях, требующих динамической структуры данных, а также в учебных и небольших проектах благодаря своей доступности и лёгкости освоения.</p><h3>Redis</h3><p>Высокопроизводительная база данных, оптимизированная для минимизации задержек при доступе к данным. Идеально подходит для кэширования, управления сессиями, обработки очередей сообщений и других задач, требующих мгновенного отклика.</p><h2>В чём разница между базами данных</h2><p>Выбор базы данных — долгосрочное решение, от которого зависит эффективность работы вашего приложения. Давайте подробнее разберём различия между реляционными и нереляционными базами данных, чтобы помочь вам сделать осознанный и правильный выбор.</p><p>Структура данных</p><figure><img src="https://media.tproger.ru/user-uploads/105990/2025-01-10/0da24965-ccd4-4f79-b395-82f484763ae0.png" alt="" /></figure><p>Масштабируемость</p><figure><img src="https://media.tproger.ru/user-uploads/105990/2025-01-10/30f9658d-daa5-46b7-932f-0e7772881a03.png" alt="" /></figure><p>Скорость и производительность</p><figure><img src="https://media.tproger.ru/user-uploads/105990/2025-01-10/05f69730-26ff-4f9c-ba20-044a59df6d02.png" alt="" /></figure><p>Выбор зависит от потребностей проекта: для сложных транзакционных систем с жесткой структурой данных лучше использовать реляционные базы, а для гибких, масштабируемых приложений с неструктурированными данными — нереляционные.</p><p>Для работы с базами данных важно уметь выполнять ключевые операции: извлечение, добавление, обновление и удаление данных. Разберём, что такое SQL-запросы и как выполнение этих операций отличается в реляционных и нереляционных базах данных.</p><h2>Подключаемся к MySQL</h2><p>Для реляционных баз данных используются стандартные операции:</p><ul><li>SELECT — получить данные;</li><li>INSERT — добавить новые данные;</li><li>UPDATE — обновить существующие данные;</li><li>DELETE — удалить данные.</li></ul><p>Поработаем с ними на примере MySQL. Представим, что у нас есть база с пользователями нашего блога. Чтобы поработать с ней, нужно настроить соединение с программой. Разберём этот процесс шаг за шагом.</p><h3>Шаг 1. Устанавливаем библиотеку</h3><p>Для работы с MySQL в Python нам понадобится библиотека mysql-connector-python.</p><p>Дла этого напишем команду в терминале:</p><p>С помощью неё можно подключиться к базе, отправлять к ней запросы и обрабатывать результаты этих запросов.</p><h3>Шаг 2. Настраиваем подключение</h3><p>Чтобы подключиться к базе данных MySQL, необходимо знать её параметры:</p><ul><li>Хост: адрес сервера, где находится база данных. Это может быть localhost;</li><li>Порт: номер порта для подключения. По умолчанию для MySQL — 3306-й порт;</li><li>Пользователь: имя пользователя, который имеет доступ к базе;</li><li>Пароль: пароль для этого пользователя;</li><li>Имя базы данных: конкретная база, с которой вы хотите работать.</li></ul><p>Как это может выглядеть:</p><ul><li>Хост: localhost</li><li>Порт: 3306</li><li>Пользователь: root</li><li>Пароль: “”</li><li>Имя базы данных: test_db</li></ul><h3>Шаг 3. Подключаемся к базе данных</h3><p>Теперь создадим программу, которая установит соединение с MySQL.</p><h4>Что тут происходит:</h4><ol><li>Импорт нужных библиотек: mysql.connector — это основной модуль для работы с MySQL в Python. Error — класс для обработки ошибок;</li><li>Настройка подключения: Используем метод mysql.connector.connect, в который передаются параметры: host, user, password и database. Это наши настройки для базы данных;</li><li>Проверка подключения:Метод is_connected() из переменной connection проверяет, удалось ли установить соединение;</li><li>Выполнение запросов:Создаём курсор для выполнения SQL-запросов с помощью connection.cursor(). После этого можно делать запросы к базе. Выбираем конкретную базу, получаем все данные, добавляем в неё сущность, а затем удаляем её. Последний запрос — получение одного конкретного юзера;</li><li>Закрытие соединения:Закрываем соединение с помощью метода connection.close() для того, чтобы избежать утечек ресурсов и проблем с безопасностью.</li></ol><p>Вы также можете обернуть код в try-except, чтобы отловить непредвиденные ошибки и не уронить сервер.</p><p>С помощью этого подхода можно быстро настроить подключение к MySQL и начать работу с базой данных в Python-проекте.</p><h2>Подключаемся к MongoDB</h2><p>Для нереляционных баз используем NoSQL-запросы. Функционал такой же: добавление, удаление, изменение и получение данных. А выглядят они по-другому. Посмотрим на примере MongoDB.</p><p>Для работы с MongoDB в Python используется библиотека pymongo. Разберём, как настроить соединение, выбрать базу данных и выполнить простой запрос.</p><h3>Шаг 1. Устанавливаем библиотеку</h3><p>Для начала установим библиотеку pymongo на своём компьютере. Введём команду в терминал:</p><h3>Шаг 2. Настраиваем подключение</h3><p>Чтобы подключиться к MongoDB, нужно знать параметры базы:</p><ul><li>Хост: адрес сервера;</li><li>Порт: порт, на котором работает MongoDB. По умолчанию — 27017;</li><li>Имя базы данных: название базы, которую вы хотите использовать;</li></ul><p>MongoDB автоматически создаст базу данных, если она не существует.</p><p>Пример настроенной базы:</p><ul><li>Хост: localhost</li><li>Порт: 27017</li><li>Имя базы данных: test_db</li></ul><h3>Шаг 3. Подключаемся и выполняем запрос</h3><p>Нам нужно подключиться к базе данных MongoDB, добавить, удалить и получить данные коллекции:</p><p>Разберём подробнее:</p><ol><li>Импорт библиотеки: Используем MongoClient из библиотеки pymongo, чтобы создать подключение к базе;</li><li>Создание подключения: Используем данные хоста и порта, где запущен MongoDB;</li><li>Выбор базы данных и коллекции: Выбираем нужную базу данных. В нашем случае –– test_db. Если базы нет, MongoDB создаст её при добавлении первого документа;</li><li>Добавление документа: Добавляем новый документ с пользователем с помощью insert_one(). А также выводим в консоль информацию о добавленном пользователе;</li><li>Удаление. Удаляем юзера и проверяем, получилось ли. Если нет, в консоли увидим запись, что такого юзера не существует;</li><li>Выполнение запроса: Ищем только что добавленный документ методом find_one() и проверяем, нашли ли. Тут то же самое: если юзера нет, то в консоли мы это увидим;</li><li>Закрытие подключения: Закрываем вызов через client.close() и оповещаем самих себя в консоли.</li></ol><p>Вы могли заметить, что мы везде заканчиваем код закрытием соединения. Это важно по нескольким причинам:</p><ol><li>Подключение к базе данных –– ресурсы сервера и клиента. Если соединение не закрыть, ресурсы останутся занятыми. Значит, их нельзя будет использовать для более нужных вещей;</li><li>Неиспользуемые открытые соединения приводят к утечкам памяти;</li><li>Открытое соединение может стать уязвимостью для атак, несанкционированного доступа или SQL-инъекций.</li></ol><p>В этом фрагменте кода реализовано то же самое, но с улучшениями. Мы обернули его в блок try-except, чтобы защитить сервер от ошибок и предотвратить его аварийное завершение работы.</p><p>В этой статье мы лишь поверхностно коснулись темы баз данных. Если у вас ещё нет лишних денег на выкуп своих данных, рекомендуем инвестировать время в изучение основ и тонкостей работы с БД.</p><p>Качественно спроектированная база данных не только повысит эффективность и прибыльность бизнеса, но и защитит его от серьёзных рисков. Кроме того, вы значительно прокачаете свои навыки программирования.</p><p>Удачи в разработке и безопасности ваших данных! 🚀</p>]]></content:encoded>
    </item>
    <item>
      <title>PostgreSQL стал лучшей СУБД 2024 года</title>
      <link>https://tproger.ru/news/--postgresql-stal-luchwej-subd-2024-goda</link>
      <comments>https://tproger.ru/news/--postgresql-stal-luchwej-subd-2024-goda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--postgresql-stal-luchwej-subd-2024-goda</guid>
      <description><![CDATA[<p>PostgreSQL признана лучшей СУБД 2024 года по рейтингу DB-Engines благодаря стабильности, производительности и новым возможностям в версии 17</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--postgresql-stal-luchwej-subd-2024-goda">PostgreSQL стал лучшей СУБД 2024 года</a>»</p>]]></description>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 15 Jan 2025 05:30:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рейтинг DB-Engines вновь <a href="https://db-engines.com/en/blog_post/109">признал</a> <b>PostgreSQL</b> лучшей СУБД года — она сохраняет свой титул уже второй год подряд.</p><p>При этом PostgreSQL уже занимал первое место в 2017, 2018, 2019 и 2023 годах. Среди 423 систем, мониторящихся DB-Engines, PostgreSQL показала наибольший прирост популярности за 2024 год.</p><p>На втором месте расположилась Snowflake, а третье заняли продукты Microsoft — <b>Azure SQL Database</b> и <b>SQL Server</b>.</p><h2>Почему PostgreSQL остаётся лидером?</h2><p>История PostgreSQL начинается почти 35 лет назад с системы Postgres. С тех пор она эволюционировала, став одной из самых современных и стабильных систем управления базами данных.</p><p>В 2024 году PostgreSQL представила новую версию — <b>PostgreSQL 17</b>, которая включила:</p><ul><li>Улучшения производительности.</li><li>Расширенные опции репликации.</li><li>Дополнительные функциональные возможности для разработчиков.</li></ul><h2>Конкуренты: Snowflake и Microsoft</h2><h2>Snowflake</h2><p>Snowflake — облачная СУБД, которая активно набирает популярность благодаря уникальной архитектуре разделения хранения и вычислений. Среди её преимуществ:</p><ul><li>Поддержка мультиоблачных сред.</li><li>Возможности обмена данными между различными системами.</li></ul><p>Эти особенности сделали Snowflake популярным выбором для компаний, работающих с облачными хранилищами данных.</p><h2>Microsoft</h2><p>Продукты Microsoft, такие как Azure SQL Database и SQL Server, продолжают удерживать высокие позиции благодаря:</p><ul><li>ИИ для оптимизации производительности.</li><li>Поддержке гибридных сценариев между локальными и облачными средами.</li><li>Передовым решениям и широкому спектру возможностей для управления данными.</li></ul><h2>Как определяется победитель?</h2><p>DB-Engines оценивает популярность СУБД на основе роста интереса к системе за год. Этот рост включает в себя:</p><ul><li>Количество упоминаний в вакансиях.</li><li>Упоминания в профессиональных профилях.</li><li>Цитаты в сети.</li></ul><p>Для определения СУБД года используется разница в популярности между январём 2024 и январём 2025 года, что позволяет объективно оценить рост без перекоса в сторону менее известных систем.</p>]]></content:encoded>
    </item>
    <item>
      <title>Развитие PostgreSQL и вклад российских разработчиков</title>
      <link>https://tproger.ru/articles/razvitie-postgresql-i-vklad-rossijskih-razrabotchikov</link>
      <comments>https://tproger.ru/articles/razvitie-postgresql-i-vklad-rossijskih-razrabotchikov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/razvitie-postgresql-i-vklad-rossijskih-razrabotchikov</guid>
      <description><![CDATA[<p>PostgreSQL, одна из самых популярных в мире систем управления базами данных с открытым исходным кодом, активно развивается благодаря совместным усилиям международного сообщества разработчиков, тестировщиков и энтузиастов. </p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/razvitie-postgresql-i-vklad-rossijskih-razrabotchikov">Развитие PostgreSQL и вклад российских разработчиков</a>»</p>]]></description>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 12 Dec 2024 10:39:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>PostgreSQL, одна из самых популярных в мире
систем управления базами данных с
открытым исходным кодом, активно
развивается  благодаря совместным
усилиям международного сообщества
разработчиков, тестировщиков и
энтузиастов. Недавно вышла 17-я версия
продукта, которая  привнесла множество
улучшений, нововведений и исправлений,
сделавших  PostgreSQL еще более надежной и
функциональной, способной на равных
конкурировать с коммерческими продуктами
от ведущих мировых ИТ-корпораций.</p><p>Международное
сообщество PostgreSQL является одним из
самых активных и сплоченных в мире
OpenSource-проектов. Выход
каждой новой  версии — это итог кропотливой
работы множества участников. Как <a href="https://speakerdeck.com/clairegiordano/whats-in-a-postgres-major-release-an-analysis-of-contributions-in-the-v17-timeframe-claire-giordano-pgconf-eu-2024">рассказала</a> на проходившей в октябре в Афинах
европейской конференции PostgreSQL
Клэр Джордано, руководитель группы
разработчиков открытого исходного кода
Postgres в компании Microsoft,
в период создания 17 версии было отправлено
2 680 коммитов от 232 авторов кода и
документации со всего мира. Сообщество
активно растет и развивается, в том
числе и за счет появления новых участников,
среди которых — как разработчики форков
свободной СУБД, так и создатели
всевозможных полезных утилит и дополнений
для нее. Более 35 тысяч сообщений в
рассылке pgsql-hackers за период разработки
свидетельствуют о динамичном обсуждении
и решении сложных технических задач.</p><h2>Вклад в кодовую базу</h2><p>Большая часть отправленных коммитов в
исходный код PostgreSQL 17 были небольшими
по объему изменений. Так, 316 коммитов не
изменили ни одной строки кода, 636 коммитов
затронули от 2 до 10 строк, и только 70
коммитов изменили более одной тысячи
строк кода. Временной промежуток между
первым обсуждением в рассылке и
непосредственным коммитом варьировался:
220 коммитов были осуществлены в тот же
день, 476 коммитов — в течение недели, а
некоторые идеи ждали реализации более
пяти лет. Разработка новой версии
включала как исправления старого кода,
так и добавление новых функций.
Примечательно, что были удалены или
изменены около 150 строк кода, включенных
еще в Postgres95, одну из первых версий, что
свидетельствует о постоянном обновлении
и модернизации системы.</p><p>Российские разработчики
играют значительную роль в развитии
PostgreSQL. В числе уже упомянутых 232 авторов
кода фигурировали 17 россиян. Среди них
сотрудники компаний «Яндекс», Postgres
Pro и других, а также
независимые программисты. Для сравнения,
граждан Китая среди авторов кода всего
13 человек, а индийцев – только 7. Участие
российских компаний также высоко ценится
сообществом, о чем упомянула Клэр
Джордано.</p><h2>Открытость и дружелюбие</h2><p>Клэр Джордано также отметила, что
сообщество PostgreSQL признано одним из
самых открытых и дружелюбных. В нем
действуют различные программы менторства,
например, очень популярен сервер
PostgreSQL Hacker Mentoring, где опытные разработчики
помогают новым участникам освоиться и
внести свой вклад. Крупные компании
также активно поддерживают PostgreSQL,
спонсируя мероприятия и способствуя
развитию сообщества. Так, в 13 организациях
трудятся 30 коммитеров PostgreSQL.</p><h2>Активность в комьюнити</h2><p>Сообщество PostgreSQL активно организует и
участвует в различных мероприятиях,
направленных на обмен знаниями, развитие
навыков и укрепление связей между
пользователями и разработчиками базы
данных PostgreSQL. Это некомерческие
мероприятия, в основе которых лежат
принципы уважительного отношения друг
к другу, сотрудничества, инклюзивности,
открытости, а также конструктивной
критики.</p><p>Ежегодно проводятся международные
конференции, такие как PGConf и PGCon, где
эксперты делятся опытом, представляют
новые разработки и обсуждают актуальные
темы в области PostgreSQL. Во многих странах
организуются региональные конференции
и встречи. Эти события позволяют локальным
сообществам обмениваться знаниями на
родном языке и учитывать специфические
региональные потребности.</p><p>Что касается
России и Белоруссии, то здесь также
проводятся региональные мероприятия
под эгидой сообщества — PG BootCamp.
Они уже проводились в Москве, Минске и
Казани. Это важно, как для российского
и белорусского, так и для мирового
комьюнити. Несмотря на тот факт, что
рынок наших двух стран частично отрезан
от западной экономики, в Postgres-сообществе
идет интенсивный обмен идеями, мнениями
и видением подходов по дальнейшему
технологическому развитию одной из
самых популярных в мире СУБД. А для
России плюс также состоит в том, что в
связи с уходом западных вендоров, таких
как Oracle и Microsoft,
отечественные игроки получили отличный
шанс занять достойное место на рынке.</p><figure><img src="https://media.tproger.ru/user-uploads/110070/2024-12-12/7ecf9943-45ec-4727-be40-13e3305c0729.png" alt="" /></figure><p>Отечественных разработчиков на
международных  мероприятиях слушают и
слышат. В период разработки PostgreSQL
17 было проведено 29 официальных мероприятий,
в которых приняли участие 397 спикеров
из 39 стран, в том числе 11 человек из
России.</p><figure><img src="https://media.tproger.ru/user-uploads/110070/2024-12-12/b7a711ef-028a-4eef-8150-3e46bc48c2f0.png" alt="" /></figure><p>В каких компаниях работают 437 спикеров,
выступавших на международных мероприятиях
во время работы над Postgres
17? Большая часть экспертов трудится в
ИТ-гигантах, таких как AWS
и Microsoft. В то же время из
российских компаний наибольшую активность
показала «Тантор Лабс» с долей в 1%.
Это немало, учитывая что 2/5 приходится
на именитые мировые компании, а 3/5 всех
спикеров суммарно занимают ровно тот
же 1%.</p><figure><img src="https://media.tproger.ru/user-uploads/110070/2024-12-12/590d7841-ab4f-4cb7-b1a1-d854cd620d18.png" alt="" /></figure><p>Такой процент участия в мероприятиях
включает как международные конференции
и встречи, так и PG BootCamp
Russia.</p><p>На конференции звучали доклады по самым разным темам: оптимизация запросов с помощью
pg_stat_advisor, аудит безопасности PostgreSQL,
работа с планировщиком, векторная
обработка данных (с приростом
производительности до 64 раз) и анонимизация
данных с помощью pg_anon.</p><p>Итак, PostgreSQL — это
результат слаженной работы международного
сообщества. Важно
отметить открытость и положительное
отношение в этом сообществе к российским
программистам и инженерам, включая
признание их опыта, заслуг и экспертизы.
К сожалению, даже в мире OpenSource
такое наблюдается далеко не всегда.
Достаточно вспомнить недавний скандал
с отлучением россиян от разработки
Linux Kernel.
Поэтому вдвойне отрадно, что коммьюнити
по достоинству оценивает вклад наших
соотечественников не только в развитие
функциональности новых версий, но и в
укрепление позиций PostgreSQL как одной из
ведущих систем управления базами данных
в мире.</p>]]></content:encoded>
    </item>
  </channel>
</rss>