Инженерный контур 1С. Часть 3 - Анализ потребления памяти рабочими процессами: локализация утечек и стабилизация кластера 1С | infolimp.ru

Инженерный контур 1С. Часть 3 - Анализ потребления памяти рабочими процессами: локализация утечек и стабилизация кластера 1С

5 сентября 2026 · infolimp.ru

Исследование динамики распределения оперативной памяти рабочих процессов rphost платформы «1С:Предприятие 8.3» в среде Linux. Дифференциация метрик RSS, VIRT и Private Dirty, разграничение штатного сессионного кэширования и деструктивных утечек памяти в алгоритмах BSL, автоматический сбор дампов при превышении пороговых значений, конфигурирование профилей безопасности кластера и systemd slices для защиты от OOM Killer.

Об иллюстративном кейсе. Сквозной пример «Торговый контур» в этой статье - обобщённый собирательный сценарий, а не описание конкретной компании или проекта. Цифры и симптомы типичны для нагруженных инсталляций 1С:ERP/КА с СУБД PostgreSQL на Linux и приведены для наглядности инженерных решений, а не как отчёт о конкретном внедрении.

Контекст и аудитория


В чём проблема

1. Физика потребления памяти в runtime 1С: дифференциация RSS, VIRT и Private Dirty

Для объективного анализа поведения рабочих процессов rphost необходимо разграничивать метрики виртуальной памяти, регистрируемые ядром Linux:

  1. Размер виртуальной памяти (VIRT / VmSize): Полный объем виртуального адресного пространства, зарезервированного процессом. Включает исполняемый код, разделяемые библиотеки, все отображенные файлы (memory-mapped files) и незадействованные страницы виртуальной кучи, для которых еще не выделены физические фреймы.
  2. Резидентный размер в памяти (RSS / VmRSS): Объем страниц оперативной памяти, фактически находящихся в физической RAM. Однако метрика RSS не отражает реальной изолированной нагрузки процесса, так как включает разделяемые между процессами страницы библиотек (Shared_Clean и Shared_Dirty).
  3. Private Dirty Memory (монопольно модифицированная память): Наиболее критичный показатель для рабочего процесса 1С. Это страницы анонимной памяти (куча, структуры объектов, кэши метаданных), которые выделены исключительно данным процессом rphost, модифицированы им и не могут быть освобождены ядром без сброса в swap или уничтожения процесса.
+-----------------------------------------------------------------------------+
|             Виртуальное адресное пространство процесса rphost (VIRT)        |
|                                (до 128+ ГБ)                                 |
+--------------------------+--------------------------------------------------+
|    Фактическая RAM (RSS) |   Зарезервировано, но не выделено в физической   |
|         (16–45 ГБ)       |               памяти (VIRT - RSS)                |
+-------------+------------+--------------------------------------------------+
|   Shared    |                     Private Memory                            |
|   (2–3 ГБ)  +-------------------------------+-------------------------------+
| Библиотеки, |     Private Clean (~1 ГБ)     |     Private Dirty (15–40 ГБ)  |
| read-only   | Отображения исполняемых кодов,| Анонимная куча процесса:      |
| отображения | немодифицированные страницы   | кэши 1С, ТаблицыЗначений,     |
|             |                               | внутренние структуры glibc    |
+-------------+-------------------------------+-------------------------------+

2. Фрагментация виртуальной памяти стандартного аллокатора glibc (ptmalloc)

Стандартная библиотека Си (glibc), используемая в дистрибутивах Ubuntu и Astra Linux, содержит аллокатор памяти ptmalloc3. Для исключения конкуренции за блокировки при параллельном выделении памяти потоками данный аллокатор памяти создает пулы - арены (arenas): - На 64-битной архитектуре аллокатор памяти создает до $8 \times N_{\text{CPU}}$ изолированных арен. - На сервере «Торгового контура» с 32 vCPU каждый рабочий процесс rphost, порождающий десятки системных потоков под клиентские сеансы и обработчики пулов соединений, создает до 256 изолированных арен памяти. - Каждая арена резервирует в виртуальном адресном пространстве блок размером 64 МБ через системный вызов mmap().

Механизм возникновения эффекта раздувания (Memory Bloat): 1. Поток A в арене 1 выделяет временную выборку данных на 50 МБ. 2. Поток B в арене 2 запрашивает блок памяти на 10 МБ. 3. Поток A завершает операцию и освобождает 50 МБ через стандартный вызов free(). 4. Внутренний механизм ptmalloc не возвращает эти страницы операционной системе (вызов ядра brk или madvise с флагом MADV_DONTNEED), если освобожденные адреса не находятся на верхней границе непрерывного сегмента кучи либо если размер фрагментов недостаточен для схлопывания страницы (4 КБ). Память остается закэшированной внутри арены 1 для будущих аллокаций потока A. 5. При этом поток B или вновь стартовавший поток C не могут переиспользовать свободную память арены 1 и запрашивают новые страницы у ядра в рамках арены 2 или арены 3. 6. В результате возникает тяжелая фрагментация виртуальной памяти: рабочий процесс физически удерживает десятки гигабайт в RSS, хотя реальный объем полезных прикладных данных может не превышать 4–6 ГБ.

Арена 1 (Поток 1): [ Занято 4 КБ ][ Свободно 60 МБ ][ Занято 4 КБ ] --> Нельзя вернуть ОС!
Арена 2 (Поток 2): [ Свободно 30 МБ ][ Занято 32 КБ ]               --> Нельзя вернуть ОС!
Арена 3 (Поток 3): [ Запрос 50 МБ ] --> Аллокатор запрашивает новые физические страницы у Linux!

3. Антипаттерны прикладного кода, приводящие к скачкам потребления памяти

Помимо особенностей системного аллокатора, прогрессирующая утечка памяти провоцируется дефектами архитектуры прикладных конфигураций: - Накопление контекста в объектах с длительным жизненным циклом: Неконтролируемое сохранение больших массивов структур в модулях с признаком ПовторноеИспользованиеВозвращаемыхЗначений (на время сеанса), накопление параметров сеанса без принудительной очистки после выполнения фоновых процедур. - Неоптимальная материализация выборок данных (ТаблицаЗначений): Выгрузка сотен тысяч записей из базы данных в оперативную память сервера («Выгрузить()») для программной фильтрации или перебора вместо выполнения группировок и расчетов на стороне СУБД средствами SQL/SDBL. - Длительно живущие контексты фоновых заданий: Запуск регламентных заданий пакетной обработки (например, проведение 50 000 чеков или начисление резервов), выполняющих всю обработку в рамках единой транзакции без периодической фиксации порций и освобождения промежуточных переменных. - Утечки в нативных внешних компонентах (Native API / COM): Использование динамических библиотек сторонних интеграций (драйверы терминалов сбора данных, криптографические провайдеры электронной подписи, генераторы PDF-документов), написанных на C/C++ с нарушением управления жизненным циклом динамической памяти (пропуск free() / delete).

4. Недостатки практики регулярных ночных перезапусков кластера

Административное решение проблемы через регулярный ночной перезапуск служб 1С в cron обладает критическими недостатками: - Уничтожение прогретых кэшей: Сброс серверного кэша метаданных, кэша скомпилированных модулей и кэша прав пользователей. - Утренний эффект «холодного старта»: При массовом входе 350 сотрудников в 08:30 утра сервер тратит колоссальные ресурсы CPU и ввода-вывода на первичное чтение метаданных из конфигурации и их компиляцию в память, провоцируя лавинообразный рост времени ожидания (CPU Spike до 100%, деградация открытия форм документов до 30–45 секунд). - Маскирование дефектов: Перезапуск скрывает архитектурные утечки памяти, не позволяя инженерам локализовать проблемный прикладной код до тех пор, пока рост нагрузки не приведет к падению сервера прямо в середине рабочего дня.


Архитектура решения

Для обеспечения долговременной стабильности разработан трехуровневый контур контроля и балансировки памяти:

1. Инфраструктурный уровень: jemalloc и systemd

Замена стандартного аллокатора на jemalloc кардинально меняет управление виртуальной памятью: - Разделение аллокаций по размерным классам (Size Classes): jemalloc квантует запросы памяти на малые (small), большие (large) и огромные (huge). Это предотвращает взаимную фрагментацию мелких прикладных структур и крупных массивов данных. - Агрессивный возврат страниц (Purging / Decay): Вместо удержания страниц в аренах jemalloc использует механизм экспоненциального затухания (decay-based purging), вызывая madvise(MADV_DONTNEED) для неиспользуемых страниц физической памяти. - Встроенное профилирование аллокаций (prof:true): Возможность сохранения точных дампов кучи с трассировкой стека вызовов функций ядра платформы без деградации производительности.

2. Платформенный уровень: математическая модель лимитов кластера

Кластер серверов «1С:Предприятие 8.3» обладает встроенным механизмом контроля памяти рабочих процессов. Если рабочий процесс rphost превышает объем max-memory-size непрерывно в течение времени max-memory-time-limit, менеджер кластера rmngr: 1. Помечает текущий процесс rphost как неактивный (приостанавливает назначение новых соединений). 2. Запускает новый резервный рабочий процесс rphost. 3. Все новые клиентские сеансы и вызовы направляются на новый чистый процесс. 4. Существующие сеансы на старом процессе плавно завершают свои текущие серверные вызовы; по мере завершения вызовов сеансы прозрачно переключаются на новый процесс. 5. После полного завершения активных вызовов старый процесс rphost корректно освобождает все ресурсы и завершается.

Математический расчет конфигурации памяти

Для хоста «Торгового контура» с общим объемом оперативной памяти $\text{RAM}_{\text{total}} = 128\text{ ГБ}$:

Общий баланс памяти описывается уравнением: $$\text{RAM}{\text{total}} \ge \text{RAM}{\text{OS}} + \text{RAM}{\text{Reserve}} + \sum{i=1}^{N_{\text{rphost}}} \text{Limit}_{\text{process}}$$

Где: - $\text{RAM}{\text{OS}} = 8\text{ ГБ}$ - резерв для ядра Linux, системных демонов, страничного кэша ввода-вывода (I/O page cache); - $\text{RAM}{\text{Reserve}} = 24\text{ ГБ}$ - страховочный буфер для предотвращения срабатывания OOM Killer в момент параллельного запуска новых процессов rphost при ротации (когда старый процесс еще не завершился, а новый уже набирает кэш); - Доступный бюджет под рабочие процессы: $$\text{RAM}{\text{workers}} = 128 - 8 - 24 = 96\text{ ГБ}$$ - Для обслуживания 350 сеансов и интенсивных фоновых задач оптимальное количество рабочих процессов $N{\text{rphost}} = 5$ (в среднем 70 сеансов на процесс, что гарантирует высокую утилизацию ядер CPU без деградации блокировок внутренних структур сессий). - Предельный допустимый объем памяти одного рабочего процесса (max-memory-size): $$\text{Limit}{\text{process}} = \frac{\text{RAM}{\text{workers}}}{N_{\text{rphost}} + 1} = \frac{96}{6} = 16\text{ ГБ} = 17\,179\,869\,184\text{ байт}$$ (Коэффициент $N_{\text{rphost}} + 1$ учитывает нахождение одного дополнительного процесса в стадии плавной ротации). - Временной лимит превышения (max-memory-time-limit): $$\text{Time}{\text{limit}} = 60\text{ секунд}$$ Данный интервал позволяет процессу кратковременно превысить порог для выполнения разовой тяжелой транзакции (например, построение отчета за квартал) и самостоятельно освободить память без инициирования ротации. - Лимит превышения за один вызов (excessive-memory-allocation-time-limit): $$\text{Time}{\text{excessive}} = 30\text{ секунд}$$ Защита от аномальных запросов, единовременно захватывающих память гигабайтами.


Пошаговая реализация

Шаг 1: Конфигурирование системного окружения Linux (systemd override и jemalloc)

  1. Установите системную библиотеку аллокатора jemalloc и утилиты отладки: ```bash # Для Ubuntu 22.04 LTS: sudo apt-get update && sudo apt-get install -y libjemalloc2 libjemalloc-dev gdb pigz

# Для Astra Linux 1.7: sudo apt-get install -y libjemalloc2 libjemalloc-dev gdb pigz ```

  1. Создайте каталог переопределения конфигурации systemd для службы сервера 1С: bash SERVICE_NAME="srv1cv8-8.3.24.1667@default.service" sudo mkdir -p "/etc/systemd/system/${SERVICE_NAME}.d"

  2. Разверните файл конфигурации /etc/systemd/system/${SERVICE_NAME}.d/override.conf: ```ini [Service] # 1. Ограничение арен памяти в glibc (стабилизация VIRT при откате на ptmalloc) Environment="MALLOC_ARENA_MAX=4"

# 2. Подключение jemalloc через механизм предварительной загрузки библиотек Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"

# 3. Настройка параметров профилирования и сброса страниц jemalloc Environment="MALLOC_CONF=prof:true,prof_leak:true,lg_prof_sample:19,lg_prof_interval:30,prof_prefix=/var/log/1c/dumps/jeprof"

# 4. Лимиты системных ресурсов ядра Linux LimitNOFILE=131072 LimitCORE=infinity TasksMax=16384

# 5. Защита процессов 1С от аварийной ликвидации OOM Killer OOMScoreAdjust=-500 ```

  1. Примените конфигурацию и выполните перезапуск службы в регламентное технологическое окно: bash sudo systemctl daemon-reload sudo systemctl restart "${SERVICE_NAME}"

  2. Проверьте факт загрузки jemalloc в адресное пространство процесса rphost: bash RPHOST_PID=$(pgrep -f "rphost" | head -n 1) cat /proc/${RPHOST_PID}/maps | grep -E "libjemalloc|libc"


Шаг 2: Применение параметров управления памятью в кластере 1С через rac

Для применения рассчитанных лимитов используется консольная утилита администрирования rac. Запустите скрипт artifacts/rac/cluster-memory-tuning.sh либо выполните команды вручную:

# Определение идентификатора кластера
CLUSTER_ID=$(rac cluster list 127.0.0.1:1545 | awk '$1 == "cluster" {print $3}')

# Применение лимитов памяти кластера
rac cluster update \
    --cluster="${CLUSTER_ID}" \
    --cluster-user="cluster_admin" \
    --cluster-pwd="AdminSecurePassword" \
    --max-memory-size=17179869184 \
    --max-memory-time-limit=60 \
    --excessive-memory-allocation-time-limit=30 \
    --kill-problem-processes=yes \
    127.0.0.1:1545

Проверка зарегистрированных параметров:

rac cluster info --cluster="${CLUSTER_ID}" --cluster-user="cluster_admin" --cluster-pwd="AdminSecurePassword" 127.0.0.1:1545 \
  | grep -E 'max-memory|kill-problem'

Вывод команды:

max-memory-size                         : 17179869184
max-memory-time-limit                   : 60
excessive-memory-allocation-time-limit  : 30
kill-problem-processes                  : yes

Шаг 3: Настройка телеметрии памяти в Технологическом Журнале и аналитика в ClickHouse

Разверните профиль сбора логов artifacts/1c/logcfg-memory.xml в каталоге /etc/1cv8/logcfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <log location="/var/log/1c/logs/memory" history="4">
    <!-- Срезы суммарного потребления памяти процессами -->
    <event>
      <eq property="name" value="MEM"/>
    </event>

    <!-- Серверные вызовы CALL с расходом оперативной памяти от 50 МБ -->
    <event>
      <eq property="name" value="CALL"/>
      <ge property="Memory" value="52428800"/>
    </event>

    <!-- Вызовы с пиковым потреблением свыше 100 МБ -->
    <event>
      <eq property="name" value="CALL"/>
      <ge property="MemoryPeak" value="104857600"/>
    </event>

    <!-- Длительные тяжелые запросы SDBL -->
    <event>
      <eq property="name" value="SDBL"/>
      <ge property="duration" value="3000000"/>
    </event>

    <!-- Системные исключения Out Of Memory -->
    <event>
      <eq property="name" value="EXCP"/>
      <like property="descr" value="*памят*"/>
    </event>
    <event>
      <eq property="name" value="EXCP"/>
      <like property="descr" value="*memory*"/>
    </event>
    <event>
      <eq property="name" value="EXCPCNTX"/>
    </event>

    <property name="all"/>
  </log>
</config>

Анализ инцидентов утечек через ClickHouse

Сформированные события Технологического Журнала передаются агентом Vector в ClickHouse. Для выявления виновников утечек выполняются аналитические SQL-запросы:

-- Топ-10 контекстов прикладного кода, выделяющих максимальный объем оперативной памяти за один вызов
SELECT
    Context AS application_context,
    count() AS calls_count,
    round(avg(Memory) / 1024 / 1024, 2) AS avg_allocated_mb,
    round(max(MemoryPeak) / 1024 / 1024, 2) AS max_peak_mb,
    round(sum(Memory) / 1024 / 1024 / 1024, 2) AS total_allocated_gb
FROM default.tech_log_events
WHERE event = 'CALL'
  AND Memory >= 52428800
  AND timestamp >= now() - INTERVAL 12 HOUR
GROUP BY Context
ORDER BY total_allocated_gb DESC
LIMIT 10;

Пример обнаруженного инцидента прикладного кода:

application_context: Обработка.ИнтеграцияСкладыМаркетплейс.МодульОбъекта : 412 : Выборка = Запрос.Выполнить().Выгрузить();
calls_count:         142
avg_allocated_mb:    312.45
max_peak_mb:         1240.18
total_allocated_gb:  44.36

Анализ выявил, что разработчик интеграционного модуля выполнял полную выгрузку остатков по всем складам в ТаблицуЗначений без фильтрации по номенклатуре, удерживая сотни мегабайт в сессионной памяти на каждый входящий HTTP-запрос.


Шаг 4: Расследование критических инцидентов и снятие неразрушающего дампа памяти

В случае выявления зависшего или аномально деградировавшего процесса rphost для детального исследования структур памяти применяется скрипт artifacts/scripts/capture-dump.sh:

  1. Предварительная проверка свободного дискового пространства: Скрипт оценивает VmRSS процесса и требует наличия свободного места на накопителе в объеме не менее $130\%$ от размера памяти процесса.
  2. Изоляция в кластере: Через интерфейс rac процесс переводится в статус --enable=no, прекращая прием новых вызовов.
  3. Генерация дампа: Вызывается утилита gcore -o /var/log/1c/dumps/rphost_<pid> <pid>.
  4. Фоновое сжатие: Дамп архивируется многопоточным компрессором pigz с низким классом приоритета ввода-вывода (ionice -c 3 nice -n 19), исключая влияние на дисковую подсистему продуктивного контура.
# Вызов снятия дампа процесса PID=14285:
sudo bash articles/03-rphost-memory/artifacts/scripts/capture-dump.sh \
    -p 14285 \
    -c "${CLUSTER_ID}" \
    -u "cluster_admin" \
    -w "AdminSecurePassword"

Анализ полученного дампа в gdb:

# Загрузка дампа в отладчик с указанием бинарного файла rphost
gdb /opt/1cv8/x86_64/8.3.24.1667/rphost /var/log/1c/dumps/rphost_14285_20260905_024500.core.14285

# Получение сводки по всем потокам:
(gdb) thread apply all bt
# Оценка распределения аллокаций памяти:
(gdb) info proc mappings

Проверка результата и метрики

После внедрения трехуровневого контура контроля памяти в продуктивном контуре «Торговый контур» была собрана сравнительная телеметрия за 30 дней непрерывной промышленной эксплуатации:

Сравнительная таблица эксплуатационных показателей

Метрика стабильности и производительности Исходное состояние (glibc ptmalloc, без лимитов) Целевое состояние (jemalloc + rac лимиты + ТЖ) Динамика изменений
Аварийные завершения rphost по OOM Killer 2–3 инцидента в неделю 0 инцидентов за 30 дней Полная ликвидация аварий
Принудительные перезапуски служб кластера 2 раза в сутки (в 03:00 и 13:30) 0 перезапусков (аптайм > 60 суток) Отказ от cron-рестартов
Среднее потребление RAM процессом rphost Рост с 8 до 45+ ГБ (неконтролируемый) Стабилизация на уровне 9–14 ГБ Снижение пиков на 68%
Максимальный объем VIRT одного процесса До 148 ГБ (фрагментация арен) Не более 22 ГБ Сокращение на 85%
Время утреннего холодного старта (08:30) 35–50 секунд (прогрев метаданных) < 1.2 секунды (кэши сохранены) Ускорение в 30 раз
Время отклика HTTP-сервисов (p95) 4.8 секунды (деградация из-за сборок мусора) 0.38 секунды Ускорение в 12.6 раз
Доля сеансов, потерявших соединение До 15% пользователей в неделю 0.00% Полная непрерывность сессий

Динамика утилизации оперативной памяти сервера (128 ГБ RAM)

Память
(ГБ)
 50 --+                                         [ Исходное состояние: OOM Crash ]
 45 --+                +----------+                 +-----------+ (OOM Killer)
 40 --+               ++          ++               ++
 35 --+              ++   Cron      ++            ++
 30 --+             ++   Рестарт     ++          ++
 25 --+            ++    (13:30)      ++        ++
 20 --+-----------++-------------------+-------++-----------------------------
 16 --+- - - - - -|- - - - - - - - - - - - - - -|- - - - - - [ Порог max-memory-size ]
 14 --+           |   +---+   +---+             |   +---+   +---+
 10 --+ +---------+---+   +---+   +-------------+---+   +---+   +- [ jemalloc: Стабильно ]
  5 --+ |
  0 --+-+-------+-------+-------+-------+-------+-------+-------+-------+-------> Время
       08:00   10:00   12:00   14:00   16:00   18:00   20:00   22:00   24:00

Риски и ограничения

При внедрении механизмов управления памятью инженерная группа обязана учитывать следующие критические риски:

1. Трэшинг рабочих процессов при заниженном лимите max-memory-size

2. Блокировка потоков процесса утилитой gcore на продуктивном сервере

3. Бинарная совместимость и поддержка альтернативных аллокаторов


Итоги

Расширение «НОПик» для 1С — встраиваемый коннектор к внешнему AI с интеллектуальным поиском по базе. Задавайте вопросы обычными словами - AI сам найдёт нужное. 45 дней бесплатно.

Попробовать НОПик →
Знаете ответ на такие вопросы не хуже автора статьи? Пройдите бесплатную анонимную проверку уровня на infolimp.ru - 3 практических задачи, 15 минут, публичный токен-профиль, который можно показать работодателю или заказчику. Без регистрации по почте.

Проверить свой уровень бесплатно →