Свёртка, которая не лечит. Часть 4: финал
База данных - HighLoad оптимизация
Часть 4. Финал: сервер, который уронила свёртка, коды-призраки и честное «было / стало»
Это последняя часть цикла. В первой базу собрались сворачивать, потому что «слишком большая», а замеры показали, что ни одна причина нагрузки не связана с объёмом. Во второй мы прошли по музею накопленного за годы. В третьей — по живым боям на площадке. Осталось рассказать, чем закончилась история со свёрткой, — и посчитать, что изменилось на самом деле.
1. Свёртка, которая уронила сервер
Свёртку довели до этапа догрузки: свёрнутая копия начала забирать из рабочей базы изменения, накопившиеся за время работ.
В пятницу утром рабочий процесс сервера 1С впервые упал по памяти. В субботу он перезапускался семь раз. В воскресенье — восемнадцать за четырнадцать часов. И каждый раз выбрасывал из базы всех, кто в ней работал, — по три-четыре десятка сеансов за раз.
Причиной оказался один запрос. Свёрнутая копия попросила у рабочей базы «список объектов» по архиву протоколов обмена с ветеринарной системой — той самой таблице из третьей части: больше 43 миллионов записей, около 180 гигабайт. Попросила все поля сразу и без порций, хотя из ответа нужна была одна колонка ссылок.
Рабочая база честно пыталась выполнить запрос целиком. Один вызов разгонялся до 206–217 гигабайт памяти при лимите кластера около 204 — и кластер убивал процесс. Ошибку нигде не перехватывали: запись в очереди обмена так и оставалась «получена», и при следующем запуске всё повторялось с начала. Плюс три повтора через десять секунд — для надёжности.
А на том же рабочем процессе жили ещё три базы, включая бухгалтерию и зарплату. Поэтому падали все четыре сразу.
Это как попросить архивариуса принести одну справку — а он, не дослушав, тащит к столу весь архив. Падает на лестнице, встаёт и идёт за архивом снова. Восемнадцать раз за воскресенье.
Нашли по технологическому журналу 1С: три дня, около 450 мегабайт логов, разбор скриптом. Ошибки памяти, пик памяти каждого вызова, события перезапуска процесса — и 347 выполнений одного и того же запроса к одной и той же таблице, от двух до 83 минут каждое.
Остановили просто: отключили регламентное задание отправки объектов. Механизм догрузки исправили, обмен перезапустили — на момент написания перезапусков больше не было.
Урок здесь не про свёртку как таковую. Сбой, который никто не ловит, превращается в бесконечный повтор. А запрос «дай всё» к таблице в десятки миллионов строк — мина, даже если по замыслу из неё нужна одна колонка.
2. Домино
Падение сервера — это не только выброшенные из базы люди. Оно задело то, что вообще не имело отношения к свёртке.
Обработка маркировки работала так: сначала помечала каждый код «использован» — отдельной записью, — а документ с этими кодами записывала уже в конце. Сервер падал посередине — и коды оставались помеченными, а документа не было.
За два дня так повисло около полутора тысяч кодов. Продать продукцию с ними было нельзя: по учёту коды числились использованными, а документа, в котором их использовали, не существовало.
Коды вернули в оборот, а для обработки подготовили правку: пометка кодов и запись документа — в одной транзакции. Сбой на любом шаге откатывает всё целиком, и повторный запуск подбирает те же коды заново. Это строже прежнего: если не удалось пометить один код, откатывается весь документ. Зато не остаётся ни повисших кодов, ни документа с недобором.
Правило старое, но работает только когда его соблюдают: всё, что должно случиться вместе, должно быть в одной транзакции.
3. Подчёркивание, которое искало чужие коды
Ещё одна мина в маркировке досталась от прежних разработчиков. Её мы обезвредили в самом начале работ — но рассказать о ней стоит.
Жалоба звучала так: коды маркировки печатаются со скоростью несколько кодов в минуту. При партиях в сотни и тысячи единиц это означало остановку линии.
Технологический журнал показал запрос, который на каждый код искал его в справочнике штрихкодов — двести с лишним миллионов строк. Поиск был написан через ПОДОБНО. А серийный номер кода маркировки — смесь букв, цифр и спецсимволов, среди которых встречаются подчёркивание и процент. Для ПОДОБНО подчёркивание означает «любой символ», а процент — «что угодно». Поиск одного конкретного кода превращался в просмотр всех кодов этого товара: 41 секунда на код и больше 700 ложных совпадений — тормоза, мусор и риск взять чужой код вместо нужного.
Точный поиск находил тот же код мгновенно. ПОДОБНО заменили на точное сравнение — и печать из «нескольких кодов в минуту» стала мгновенной.
Рядом жила вторая ловушка того же рода. Строки в запросах 1С сравниваются без учёта регистра букв, а коды маркировки регистр различают. Два разных кода, которые отличаются только большой и маленькой буквой, для базы — одно и то же значение. Прежние разработчики отсеивали таких «двойников» по последним пяти символам — и это работало, пока двойники не начали отличаться раньше.
Чем больше кодов копилось в пуле, тем чаще новый код совпадал со старым. По одному продукту их набралось почти 900 тысяч, и около 6–7% новых кодов находили себе «близнеца». Форма показывала 1 213 кодов вместо загруженных 1 300. Коды при этом не терялись — их недосчитывал служебный регистр, но выглядело это как пропажа.
Создание кодов при печати теперь сравнивает точно. Общий модуль, через который идёт ещё полсотни вызовов, — в очереди.
Код маркировки — не строка для поиска «похожего», а точный ключ. Сравнивать его нужно точно.
4. Операция на каждую строку
Ещё одно наследство прежних автоматизаторов — в обмене с ветеринарной системой. Обмен шёл около двух часов, за день — больше трёх тысяч документов.
Замер показал: на 677 реализаций за день приходилось 3 820 исходящих транспортных операций — в среднем больше пяти на документ, у отдельных — по двадцать. Обработка логиста шла циклом по строкам реализации и на каждую строку создавала свою транспортную операцию. А каждая операция — это отдельный документ, отдельное проведение и отдельный запрос в ветеринарную систему.
При этом типовой механизм умеет собирать строки в одну операцию — по перевозчику, накладной, получателю и условиям хранения, — а сама ветеринарная система принимает несколько поставок одним запросом. Механизм был, его просто обходили.
Обработку перевели на типовую группировку. Свести всё к одной операции на реализацию не дали особенности учёта, но и так в тот же тип дня вместо примерно 4 000 документов стало около 900 — почти в пять раз меньше. Обмен стал быстрее в три–пять раз.
Был и бонус. При переносе логики обработки в общий модуль убрали пустую «Попытку» — блок, который молча глотал любую ошибку. И сразу всплыло: у логистов давно не было прав на один из справочников, запрос падал, а пустая «Попытка» это скрывала. Часть функций обработки у них не работала никогда — просто никто об этом не знал. Права поправили.
5. Свёртка, которая сработала
Свёртка при этом — нормальный инструмент, если применять её точечно. Летом мы сами свернули один регистр прямо в рабочей базе.
С 2024 года в регистр заказов на производство перестал записываться приход, а расход шёл как прежде. Закрытые заказы так и висели в остатках: 67 993 заказа, хотя активных было полтора десятка. И каждый выпуск продукции переписывал этот раздутый слой итогов под блокировкой — до 363 секунд на проведение и сотни конфликтов блокировок.
Закрытые заказы обнулили, запись прихода починили — и в первый же день 94 выпуска прошли без единого таймаута. Без проекта, без копий базы и без переноса данных.
Свернуть нужно ровно то, что мешает. А чтобы понять, что мешает, нужны замеры.
Было / стало
Ниже — только то, что подтверждено замерами или журналом работ. Всё — на той же базе и на том же сервере.
| Что | Было | Стало |
|---|---|---|
| Остатки ветеринарной системы | ручной запрос на пять с лишним часов | обмен за пару минут |
| Проведение выпуска продукции | до 363 с, сотни конфликтов блокировок | ноль таймаутов |
| Ночной цикл обмена и маркировки | к 5 утра, в тяжёлые ночи — к 10 | в среднем к 3 утра |
| Открытие документа маркировки | минуты | около секунды |
| Печать кодов маркировки | несколько кодов в минуту | мгновенно |
| Документы обмена с ветеринарной системой | около 4 000 в день | около 900 в день |
| Падения сервера по памяти из-за журнала маркировки | были | не повторялись |
| Журнал транзакций SQL Server | 456 ГБ | 1 ГБ |
| Ночное обслуживание статистики | очередь в 15 тысяч объектов, не разбиралась никогда | 664 объекта за 17 секунд |
И честно — что не сделано. Ночное задание маркировки по-прежнему идёт 38–97 минут. Перепроведение цепочки документов при выпуске спроектировано, но ещё не внедрено. Обмен с бухгалтерией ждёт своей очереди. Найти причину и починить её — два разных этапа, и между ними иногда проходят месяцы.
Вместо послесловия
Всё началось с диагноза «база слишком большая — надо резать». Почти всё, что реально мешало, лечилось на той же базе и на том же железе: индексом, настройкой, исправленным отбором, одной транзакцией вместо многих. Размер при этом остался прежним.
Свёртка — инструмент, а не диагноз. Сначала замеры, потом решения.
А что вы проверяете первым делом, когда слышите «база слишком большая»?
Случай обезличен, отдельные детали обобщены. Оценки — мнение автора по результатам замеров, а не оценка свёртки как метода или исполнителей в целом.
Технические подробности для коллег
Падения по памяти при догрузке свёрнутой копии. Признаки в технологическом журнале: исключения «Превышен максимальный расход памяти сервера за один вызов» и «Недостаточно памяти для получения результата запроса», большой MemoryPeak у события CALL, в журнале менеджера кластера — Memory exceeded temporary allowed limit и перезапуск процесса по памяти. Механизм: принимающая сторона формировала запрос со всеми полями таблицы, отбор брался только из правил выборки (нет правила — нет условий), отправляющая сторона выполняла Запрос.Выполнить() целиком и делила результат на пакеты уже после выполнения. Исключение в цикле очереди не обрабатывалось, статус записи не менялся — отсюда повтор при каждом запуске. Что должно быть: выбирать только ссылку, порциями (ПЕРВЫЕ N + условие «ссылка больше последней»), ловить исключение, писать его в журнал ошибок обмена и менять статус записи. Отдельно: несколько баз на одном рабочем процессе означают, что падение из-за одной роняет все — тяжёлые базы стоит разводить по отдельным процессам.
Повисшие коды маркировки. Пометка «использован» каждой записью отдельно (НаборЗаписей.Записать() в цикле) и запись документа после цикла — классическое окно неконсистентности. Перенос цикла и записи документа в одну транзакцию закрывает окно, но меняет поведение при ошибке: после исключения внутри транзакции платформа не даёт её зафиксировать («в данной транзакции уже происходили ошибки»), поэтому схема «не удалось — пропустить и идти дальше» внутри транзакции невозможна; ошибка одного кода = откат всего документа и повторный запуск.
ПОДОБНО и спецсимволы. В шаблоне ПОДОБНО символы _, %, [, ], ^ — служебные. Для поиска точного значения — =; если нужен именно шаблон — экранирование через СПЕЦСИМВОЛ. Строковые сравнения в запросах идут по регистронезависимой сортировке СУБД, поэтому для кодов маркировки надёжнее сравнение по хешу кода (SHA-256 различает регистр и не содержит спецсимволов) или точная проверка строки в коде после выборки.
Транспортные операции ветеринарной системы. Типовой обмен умеет переиспользовать документ транспортной операции по ключу «перевозчик — способ хранения — накладная — грузополучатель — грузоотправитель», а запрос оформления исходящих документов в ветеринарную систему принимает несколько поставок сразу. Создание операции в цикле по строкам реализации обходит и то и другое. При укрупнении следите за идентификатором строки: он должен быть сквозным в пределах документа, иначе упаковки привяжутся не к тем позициям.
Мини-свёртка регистра. Регистр остатков, в который годами не писался приход, раздувает таблицу итогов; каждое проведение по нему перезаписывает итоги под блокировкой. Лечение: исправить запись движений, обнулить остатки закрытых объектов документом-корректировкой, пересчитать итоги.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.