Мы перенесли базу 1С на 276 ГБ с Windows и MS SQL на Ubuntu и PostgreSQL. Главная неприятность оказалась не там, где её ждут: она вообще не про Linux. А вот восемь ловушек, которые встретились по дороге, про Linux ровно настолько, что каждая стоила отдельного часа. Ни одной из них нет в чек-листах, которые я читал перед началом.
Сначала о том, чего НЕ случилось
В прошлой статье я разбирал, почему у нас четыре раза подряд молча вставал перенос на PostgreSQL. Виноваты были невидимые символы: библиотека ICU, через которую сравниваются строки в типах mchar и mvarchar, схлопывает Unicode-совместимые формы. Неразрывный пробел равен обычному, № равно No. MS SQL считает такие строки разными, PostgreSQL одинаковыми, уникальный индекс не строится.
Первое, что я сделал на Linux-стенде, это прогнал те же опыты заново. Ожидал разницы: другая операционная система, другая сборка ICU, другая локаль.
SELECT ('a b')::mvarchar = ('a' || chr(160) || 'b')::mvarchar AS nbsp_vs_space; -- true SELECT ('No5')::mvarchar = (chr(8470) || '5')::mvarchar AS numero_vs_No; -- true SELECT ('ABC')::mvarchar = ('abc')::mvarchar AS case_insensitive; -- true SELECT (chr(1077))::mvarchar = (chr(1105))::mvarchar AS e_vs_yo; -- false
Ответы совпали с Windows дословно, все четыре.
Вывод, который мне самому не нравился, но он честный: главная проверка перед переездом не имеет отношения к операционной системе. Она про ICU, а ICU одинаков и там, и там. Кто уходит только с MS SQL на PostgreSQL, оставаясь на Windows, получает ровно ту же беду.
Приятная деталь: е и ё ICU различает. У ё нет совместимого разложения, это самостоятельная буква, а не форма. Правило именно про формы NFKD, а не «про похожие символы».
Ловушка 1. Флаг виртуализации врёт
Начал со стенда. Посмотрел, можно ли поднять виртуальную машину, и увидел:
VirtualizationFirmwareEnabled : False
Сделал вывод: виртуализация выключена в BIOS, нужен физический доступ к машине и перезагрузка. Написал об этом как о блокере.
Вывод был неверный. Этот флаг показывает ложь ровно тогда, когда гипервизор уже загружен: Windows в таком случае смотрит на прошивку из-под него и честного ответа дать не может. Правильный признак другой:
(Get-CimInstance Win32_ComputerSystem).HypervisorPresent # правда (Get-CimInstance Win32_Processor).VirtualizationFirmwareEnabled # врёт при живом гипервизоре
HypervisorPresent был True с самого начала. Понадобилось только включить роль Hyper-V и перезагрузиться, машина вернулась за минуту.
Ловушка 2. Процессы из удалённой сессии умирают вместе с ней
Запустил скачивание установочного образа на стенде через Start-Process внутри Invoke-Command. Скачивание оборвалось на 166,9 МБ ровно в момент закрытия сессии WinRM.
Лечится планировщиком задач: там владелец процесса служба, а не сессия.
$act = New-ScheduledTaskAction -Execute 'curl.exe' -Argument '-L -s -o "файл" "url"' $pr = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName 'download' -Action $act -Principal $pr -Settings $st Start-ScheduledTask -TaskName 'download'
Тонкость, из-за которой я не сразу понял закономерность: сам перенос ibcmd в похожей ситуации выживал. Разница в том, что он запускался с ключом ожидания внутри живой сессии, а не отсоединённым. Правило простое: если процесс должен пережить закрытие сессии, запускать его надо не из неё.
Ловушка 3. Автоустановка Ubuntu всё равно спрашивает согласия
Подготовил автоматическую установку: образ с конфигурацией на томе с меткой cidata, всё по документации. Машина загрузилась, в консоли видно, как отработали все шаги применения конфигурации. И следом:
Confirmation is required to continue. Add "autoinstall" to your kernel command line to avoid this Continue with autoinstall? (yes|no)
Конфигурация с тома считается недоверенной: установщик её применяет, но диск без живого «yes» не размечает. Чтобы этого не было, слово autoinstall должно стоять в командной строке ядра, а туда без правки загрузчика в консоли не попасть.
Ловушка 4. Клавиатура Hyper-V возвращает успех и ничего не вводит
Консоль виртуальной машины автоматизируется через WMI, и это спасло установку. Экран забирается методом GetVirtualSystemThumbnailImage: он отдаёт сырые пиксели, которые собираются в картинку. Без него я бы гадал, почему процессор простаивает и диск не растёт.
А вот с вводом вышло интереснее:
| Метод | Итог |
|---|---|
Msvm_Keyboard.TypeText('yes') |
код возврата 0, символы не дошли, приглашение повторилось |
TypeKey посимвольно (0x59 0x45 0x53, затем 0x0D) |
сработало, установка пошла |
Нулевой код возврата у TypeText означает «вызов принят», а не «текст введён». Верить надо экрану, а не коду возврата.
Ловушка 5. Ubuntu отдаёт логическому тому сотню гигабайт из семисот
Установка прошла, захожу, смотрю диск:
/dev/mapper/ubuntu--vg-ubuntu--lv 98G 7.3G 86G 8% /
Девяносто восемь гигабайт при виртуальном диске в семьсот. Установщик создаёт том на сотню, остальное оставляет свободным в группе томов. Узнали бы мы об этом на середине переноса базы в триста гигабайт.
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv sudo resize2fs /dev/ubuntu-vg/ubuntu-lv # стало 686 ГБ
Отсюда пункт в предполётную проверку: смотреть не размер диска, а размер файловой системы под каталогом данных. Это разные числа.
Ловушка 6. Кластер молча создаётся с английской локалью
Вот эта, на мой взгляд, самая опасная из восьми, потому что не проявляется сразу.
Пакет PostgreSQL инициализирует кластер сам, при установке. Локаль берёт системную, а на свежей Ubuntu это en_US.UTF-8. Русской базе нужна ru_RU.UTF-8, иначе сортировка строк пойдёт по другим правилам. Обнаруживается это не в день переезда, а через месяц, когда кто-то заметит странный порядок в отчёте.
Пробую задать локаль явно и получаю:
initdb: error: too many command-line arguments (first is "--locale=ru_RU.UTF-8")
Оболочка pg-setup initdb аргументы в initdb не пробрасывает. Локаль берётся из окружения, а sudo окружение вычищает. Рабочий вызов:
sudo locale-gen ru_RU.UTF-8
sudo systemctl stop postgrespro-1c-17
sudo rm -rf /var/lib/pgpro/1c-17/data
sudo env LANG=ru_RU.UTF-8 LC_ALL=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 LC_CTYPE=ru_RU.UTF-8 \
/opt/pgpro/1c-17/bin/pg-setup initdb --tune=1c
Переинициализация уничтожает данные. Делать это надо до того, как база приехала, и это единственный момент, когда локаль ещё можно поменять дёшево.
Ловушка 7. Расширения, которые не расширения
Мелочь, но время съела. Проверяю, подключены ли online_analyze и plantuner, которые рекомендуют для 1С:
ERROR: расширение "online_analyze" отсутствует DETAIL: Не удалось открыть управляющий файл расширения ".../online_analyze.control"
При этом параметр plantuner.fix_empty_table в конфигурации живой и работает. Разгадка: они подключаются библиотеками через shared_preload_libraries, а не через CREATE EXTENSION. Искать их в pg_extension бессмысленно, смотреть надо в pg_settings.
Ловушка 8. Автотюнер ставит work_mem 512 МБ при 250 соединениях
У сборки PostgreSQL для 1С есть режим автонастройки --tune=1c. Вот что он выставил на машине с 6 ГБ памяти:
| Параметр | Значение |
|---|---|
shared_buffers |
1,4 ГБ |
work_mem |
512 МБ |
max_connections |
250 |
effective_cache_size |
4,3 ГБ |
maintenance_work_mem |
370 МБ |
max_locks_per_transaction |
256 |
work_mem выделяется на каждую сортировку в каждом сеансе. Двести пятьдесят соединений по 512 МБ это теоретические 128 гигабайт на машине, где их шесть. Автотюнер считает по объёму памяти, но со связкой с max_connections не сверяется.
Это тот случай, когда рекомендация вендора вредна, и сказать об этом надо прямо. В предполётную проверку пошёл отдельный пункт: произведение work_mem на max_connections против физической памяти, с вердиктом «чинить», если оно больше половины.
Проверил сервер под 1С и нашёл ноль шрифтов
Когда кластер поехал, я прогнал по серверу проверку, которую сам же и написал в предполётный чек-лист. Ожидал увидеть «нет Arial и Times». Увидел другое:
Сам чек-лист собран в обработку: Проверка базы данных перед миграцией на PostgreSQL. Для переезда с Windows на Linux там отдельный сценарий «СУБД и ОС» - он проверяет ровно то, обо что спотыкаются в этой статье: внешние компоненты без сборки под Linux, шрифты в макетах, тома хранения файлов с незаполненным Linux-путём, Windows-пути в константах и список регламентных заданий для просмотра глазами.
L1_FONTS_TOTAL=0 L1_FONT=Arial;found=0 L1_FONT=Times New Roman;found=0 L1_FONT=Calibri;found=0 ... и так все шесть
Не «нет нужных шрифтов», а нет ни одного. В минимальной установке Ubuntu Server нет даже fontconfig. Печатные формы там не разъедутся, они просто не отрисуются.
Заодно та же проверка показала, что системная локаль осталась английской:
L1_LOCALE=LANG=en_US.UTF-8;LC_COLLATE="en_US.UTF-8";...
А кластер PostgreSQL я поднял с ru_RU.UTF-8. Это два разных места, и починка одного не чинит другое. Хорошая иллюстрация к тому, почему проверок должно быть много и почему они должны быть отдельными.
Учётная запись и лимиты, кстати, тоже оказались в состоянии «как поставилось»: ulimit -n равен 1024 при рекомендованных для 1С 65536, vm.swappiness шестьдесят при рекомендованных единицах, huge pages в режиме madvise вместо never. Ничего из этого не мешает поставить сервер, и всё это вылезет под нагрузкой, когда люди уже работают.
Про память, и почему цифра в конфиге ничего не значит
Отдельная история, которая стоила двух сорванных прогонов и хорошо иллюстрирует, чем стенд отличается от продуктива.
Перенос дважды упал с ошибкой:
Ошибка СУБД: Microsoft OLE DB Driver for SQL Server: Недостаточно свободной памяти в буферном пуле. native=802
Первая мысль: у SQL Server мало памяти, подниму лимит. Поднял с 3 до 6 ГБ. Упало снова. Полез смотреть, что происходит на самом деле:
SELECT (SELECT CAST(value_in_use AS int) FROM sys.configurations WHERE name = 'max server memory (MB)') AS max_mem_setting, (SELECT CAST(cntr_value/1024 AS int) FROM sys.dm_os_performance_counters WHERE counter_name = 'Target Server Memory (KB)') AS target_mb, (SELECT process_physical_memory_low FROM sys.dm_os_process_memory) AS low_flag;
max_mem_setting target_mb low_flag 6144 290 1
Настройка разрешает шесть гигабайт, а SQL Server сам держит цель на 290 мегабайтах и не снимает флаг нехватки памяти. Потому что брать их неоткуда: на хосте виртуальная машина, рабочий стол и суммарно 10,8 ГБ рабочих наборов при 15,8 физических.
Поднятие настройки было пустым действием. Цифра в конфиге это разрешение, а не память в наличии, и SQL Server честно от неё отказывается, когда операционная система сигналит о дефиците. Помогло другое: ужать виртуальную машину, снизить shared_buffers на приёмнике и уменьшить порцию переноса с 10 000 строк до 1000. Ошибка 802 возникает на конкретном запросе памяти, и уменьшение порции бьёт по причине, а не по симптому.
Итог переноса на Linux
| Показатель | Значение |
|---|---|
| Время переноса | 3 часа 30 минут (209,9 мин, код возврата 0) |
| Размер на Linux | 300,19 ГБ |
| Таблиц | 4470 |
| Индексов | 10 623, из них уникальных 9111 |
| Невалидных индексов | 0 |
Те же цифры я снял днём раньше с переноса на Windows-PostgreSQL. Они совпали до единицы: 4470 таблиц, 10 623 индекса, 9111 уникальных, 300 ГБ. Две разные операционные системы дали структурно идентичный результат, и это, пожалуй, лучший аргумент в пользу того, что выбор ОС для самого переезда вторичен.
По времени сравнение некорректное, и я это скажу прямо, чтобы не вводить в заблуждение: Windows-прогон занял 2 часа 28 минут, Linux - 3 часа 30. Но условия были разные. После двух падений по памяти я снизил параллельность до одного потока и уменьшил порцию с 10 000 строк до 1000, а целевая машина получила 2,5 ГБ памяти вместо шести. Медленнее оказался не Linux, а моя осторожность.
А вот это я не ожидал: таблицы растут неравномерно
База в целом выросла на 8,9 процента. Но когда я сравнил таблицы поимённо, средняя цифра рассыпалась:
| Таблица | MS SQL | PostgreSQL | Отношение |
|---|---|---|---|
_AccRgED14402X1 |
11,17 ГБ | 39,92 ГБ | ×3,6 |
_AccRg14374X1 |
13,84 ГБ | 30,91 ГБ | ×2,2 |
_Document229X1 |
9,20 ГБ | 14,74 ГБ | ×1,6 |
_InfoRg7855X1 |
47,38 ГБ | 44,47 ГБ | ×0,94 |
Регистры бухгалтерии распухли в два-три раза, а самая большая таблица базы даже немного усохла. Плюс девять процентов это средняя температура по больнице, и планировать место по ней опасно: если у вас нагруженная бухгалтерия с движениями по счетам, разнесёт именно её.
Почему так, я до конца не проверял, и врать не буду. Правдоподобное объяснение: у PostgreSQL заголовок строки 24 байта против 7 у MS SQL, и на узких таблицах регистров бухгалтерии, где строк десятки миллионов, а полезных данных в строке мало, эта разница множится. Плюс индексы там занимают больше самих данных. Проверяемая гипотеза, но проверять её надо отдельно.
Практический вывод от этого не зависит: смотрите на свои топ-таблицы, а не на общий размер базы. Список даёт любой скрипт вроде того, что я приводил в прошлой статье.
Что я об этом думаю
Если свести восемь ловушек к одному, получится так: почти каждая была не отказом, а молчанием. Флаг виртуализации не соврал грубо, он ответил на другой вопрос. Скачивание не выдало ошибку, оно просто остановилось. Клавиатура вернула успех и ничего не сделала. Кластер не пожаловался на локаль, он взял ту, что нашёл. Автотюнер не предупредил про соединения, он посчитал по памяти.
Поэтому единственный работающий приём, который я вынес из этого переезда, звучит скучно: после каждого шага проверять результат независимым способом. Не «команда отработала без ошибки», а «диск действительно того размера», «локаль действительно русская», «текст действительно введён». На стенде это стоит минут. В окне переключения, когда база лежит, а люди ждут, это стоит совсем других денег.
И повторю главное из первой статьи, потому что оно от операционной системы не зависит: прогоните проверку на невидимые символы. Шесть минут на копии, и вы избавились от риска, который срывает перенос молча и на любой платформе.
Проверка, о которой речь, собрана в обработку: Проверка базы данных перед миграцией на PostgreSQL. Сценарий «СУБД и ОС» закрывает ровно то, о чём эта статья: внешние компоненты без сборки под Linux, шрифты макетов, тома хранения с незаполненным Linux-путём, Windows-пути в константах.
Другие наши инструменты диагностики 1С:
- Карта объёмов базы 1С - из чего состоит база и куда ушли гигабайты.
- Чек-ап СУБД под 1С - правильно ли СУБД настроена под платформу.
- Трансформатор SQL в 1С - что на самом деле делает конкретный запрос.
- Оптимизатор временных таблиц - как переписать то, что нашли.
Вступайте в нашу телеграмм-группу Инфостарт