Антон Дорошкевич | проводник в мире 1С и СУБД – Telegram
Антон Дорошкевич | проводник в мире 1С и СУБД
10.7K subscribers
28 photos
15 links
Только интересные технические подробности, кейсы, тесты, а также анонсы выступлений на мероприятиях
Никакой "воды" и рекламы

Вся информация в этом канале - это моё личное мнение и не является официальной позицией вендоров и рекомендациями к действиям
Download Telegram
🗓 Выступления на конференциях в ближайшие пару месяцев

11-12 Сентября, Hackathon в ИнфоСофт, Новосибирск, Было круто!
▫️27-28 Сентября - Партнёрский семинар 1С, Москва
▫️29 Сентября - PGConf.СПб 2025, Санкт-Петербург
▫️09-12 Октября - Infostart Tech Event 2025, Санкт-Петербург
▫️17-19 Октября - Merge.Baltic, Калининград/Светлогорск
▫️24 Октября - Жёлтая конфа, Москва

Не знаю почему для организаторов не существует в году месяцев кроме Сентября и Октября 😁
Please open Telegram to view this post
VIEW IN TELEGRAM
😁28👍12🔥11
🔤🔤🔤 Когда Dump базы PostgreSQL при восстановлении может содержать данные на гораздо ранний период чем вы ожидали?

Сразу оговорюсь - dump это крайне надёжный и очень гибкий способ создания резервных копий!

Но, есть нюансы...

Рекомендуемая в том числе и мной схема организации резервного копирования:
▫️Мастер
▫️Реплика для отказоустойчивости
▫️Реплика для резервных копий

Соответственно резервные копии, например с помощью утилиты pg_dump (а в PostgreSQL есть ещё и другие способы сделать backup) рекомендуется делать с "Реплики для резервного копирования".
Так как dump это длительная транзакция, а длительные транзакции для PostgreSQL это плохой сценарий для мастера приводящий к блокировке работы autovacuum (процесс автоочистки "мёртвых" строк).
Помимо этого dump это ещё и достаточно большая нагрузка на диски, что так же не зачем мастеру, его работа пользователей обслуживать, а не ит-шные хотелки 😁

Итак, осознавая зачем и почему мы прилежно делаем dump-ы с реплики и считаем что всё хорошо. В целом оно так и есть при одном условии:
❗️Если реплика не отстаёт от мастера

Давайте на цифрах:
▫️Время на мастере - 12:00:00
▫️Время на которое реплика уже "проиграла" в себя данные - 11:59:59.389
▫️Время старта dump с реплики - 12:00:00
В этом случае всё прекрасно, делаем dump, и при восстановлении данные в базе будут на 11:59:59.389. так как dump консистентен на начало транзакции.

Теперь другой сценарий:
▫️Время на мастере - 13:00:00
▫️Время на которое реплика уже "проиграла" в себя данные - 11:59:59.389
▫️Время старта dump с реплики - 13:00:00
❗️В этом случае при восстановлении данные в базе будут на 11:59:59.389 и это неожиданно! Ведь мы то думали что они будут на момент старта dump-а 13:00:00!

Как такое произошло?
Всё дело в отставании реплики, оно на момент старта dump-а составило чуть более 1 часа.

Откуда может взяться отставание?
Дело в том, что в отличии от мастера, реплика однопоточная и ничего не знает о версиях, номерах транзакций и т.д., очень нужных вещей для мастера и совершенно бесполезных для реплики.
И если на реплики идёт транзакция, то "проигрывание" данные в базу останавливается (начинается накопление WAL - журнала предзаписи), "проигрывание" продолжится как только транзакция будет завершена. И так до следующей транзакции.
И как ни странно, этой первой транзакцией может легко оказаться наш первый dump, который просто длился более 1 часа

Второй вариант отставания - это чисто "железное" отставание, когда не справляется сеть между мастером и репликой. В этом случае на реплику просто не поступили ещё WAL-ы с мастера и ей нечего записать в базу.

Как получить отставание реплики от мастера?
Для этого есть специальное представление pg_stat_replication

select replay_lag from pg_stat_replication


Вернёт нам отставание реплики от мастера. например 00:00:00.003122

Но отставание как мы выше поняли может быть 2х типов (на самом деле больше, но это уже экзотика), получить отставание, которое обосновано не транзакциями на реплике, а сетью можно тем же представлением:

select wtite_lag from pg_stat_replication


❗️Что с этим со всем делать?

1. Следить за отставанием реплик
2. Иметь более одной реплики от мастера
3. Использовать другие средства резервного копирования (pg_basebackup, probackup и ещё штук 10 вариантов открытого ПО)
4. При крайней необходимости сделать dump с мастера, он всегда будет содержать данные на момент начала dump-а
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27🔥12👏31
🔤🔤🔤 PostgreSQL, symlink, неожиданность с репликацией и бэкапами

Есть довольная распространённая практика переноса каталога Журнала предзаписи транзакций (WAL) на другой диск, что даже рекомендуется разработчиками Postgres и звучит эта рекомендация так:
Имеет смысл размещать WAL на другом диске, отличном от того, где находятся основные файлы базы данных. Для этого можно переместить каталог pg_wal в другое место (разумеется, когда сервер остановлен) и создать символическую ссылку из исходного места на перемещённый каталог.

И тут всё хорошо. Действительно в Postgres нет настройки расположения каталога pg_wal и его перенос решается через создание символической ссылки на каталог (symlink).

По всей видимости лёгкость, понятность и распространённость такого подхода повлияла на то что Администраторы СУБД либо Системные администраторы помимо каталога pg_wal так же этим способом переносят и другие каталоги Postgres.

А тут нас ждёт очень интересная проблема...
Дело в том, что утилита pg_basebackup с помощью которой создаются резервные копии кластера PostgreSQL и реплики (для них создание резервной копии кластера это первый шаг создания) не учитывает символические ссылки.

Что в итоге мы можем получить:
Допустим что установили Postgres и он по умолчанию создал каталог с базой данный в /var/lib/postgres/data.
Далее мы создали в нём базу ERP (пока пустую) её OID пусть будет 358924. Соответсвенно все данные этой базы будут у нас располагаться в каталоге /var/lib/postgres/data/base/358924

Заранее зная что база будет большой, админы выделили место под базу в каталоге /data, а место под wal в каталоге /wal_data
Опираясь на опыт переноса каталог pg_wal:
▫️Останавливаем postgres
▫️Переносим каталог var/lib/postgres/data/pg_wal в /wal_data/pg_wal
▫️Делаем symlink между этими каталогами

❗️Переносим каталог var/lib/postgres/data/base/358924 в /data/358924 (каталог нашей ERP)
▫️Делаем symlink между этими каталогами

Стартуем postgres - всё работает!!!

Казалось бы, что может пойти не так? 😁

Рассказываю:
Как правильные админы, после создания мастера мы делаем реплику
Утилитой pg_basebackup заливаем данные с мастера на реплику.

Стартуем реплику и тоже всё стартует и работает!!!
И даже когда мы начнём заливать в базу ERP данные - они послушно побегут на реплику, так как передаются посредством трансляции WAL.

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

❗️Мы запускаем pg_basebackup. она выполняется, вот только копия не содержит нашу базу ERP.
Поскольку база на мастере располагается в каталоге с символической ссылкой и вместо данных, утилита в бэкап кластера скопирует просто пустой каталог /358924.
❗️Тоже самое нас ждёт при попытке создать новую реплику.
Она создастся, но вот только без базы ERP.

Как же правильно вынести какую-то базу или несколько баз, а может и все сразу в другое место?

Для этого необходимо использовать Таблиные пространства (tablespace)
Т.е. в нашем сценарии мы должны были сначала создать табличное пространство
CREATE TABLESPACE erp_data LOCATION '/data'

а затем создать базу ERP уже в этом табличном пространстве
CREATE DATABASE ERP WITH OWNER = postgres ENCODING = 'UTF8' TABLESPACE = erp_data


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

1. Заново инициализировать кластер Postgres через Initdb указав в качестве расположения каталог /data
2. Переопределить табличное пространство по умолчанию в конфигурационном файле postgresql.conf переопределив параметр default_tablespace = '/data'

❗️Будьте очень осторожны с символическими ссылками не смотря на то, что это очень удобный и быстрый инструмент!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥34👍133
1️⃣🔤 Сколько реально сеансов можно запустить на одной пользовательской лицензии?

Согласно документации:
Вариант расходования лицензии - Лицензия получена клиентским приложением на локальном компьютере, Программная/Аппаратная - На компьютер

"Под термином «на компьютер» понимается следующее: если лицензия получена в варианте «на компьютер», то на компьютере, получившим лицензию, допускается запуск произвольного количества клиентских приложений, работающих с произвольным количеством информационных баз."

Для нас тут важно слово "произвольное".
Обычно это понимается как бесконечное, но на практике это не так.

Часто проводя нагрузочное тестирование не только фоновыми операциями, но и реальными запусками клиентских приложений 1С было обнаружено что ограничение всё таки есть,

Потом этот факт подтвердился на партнёрском форуме, у кого есть доступ, почитайте: https://partners.v8.1c.ru/forum/message/2241411

❗️Итак, в реальности ограничение равно 256 запускам приложений (Конфигуратор, Толстый клиент, Тонкий клиент).
Для некоторых сценариев это очень важное недокументированное ограничение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43🔥156
1️⃣🔤 + 🔤🔤🔤 Когда реструктуризация 2.0 или перенос базы между СУБД через ibcmd replicate может завершиться с ошибкой при том что всё работает штатно?

Представьте, запустили вы реструктуризацию своей любимой 1С-ки через оптимизированный механизм реструктуризации 2.0 , всё идёт хорошо и вдруг получаем ошибку обрыва соединения, реструктуризация прерывается и достаточно сложно вернуть базу в начальное состояние без восстановления на резервную копию ДО реструктуризации (а резервные копии же у вас есть всегда!?).

Такая же ситуация может произойти и когда идёт репликация базы между СУБД с помощью утилиты ibcmd replicate...

Причём ошибка может звучать либо очень странно - что-то там про таймаут либо в случае ibcmd будет просто сообщение что репликация завершилась с ошибкой.

❗️Главная особенность именно этой ошибки, что она происходит по истечении более чем ДВУХ часов!

Что за волшебные 2 часа и что вообще происходит?

В операционных системах Windows и почти во всех Linux есть ограничение на ожидание последнего пакета, отправленного по сети.
По прошествии этого времени соединение помечается как требующее проверки, затем несколько раз проверяется и если проверки закончились неудачно. то оно разрывается.

А с чего это вдруг система решила что прошло уже 2 часа?
Это будет в том случае, если мы натолкнулись на создание огромного индекса .т.е. команду CREATE INDEX.
Эта команда вернёт обратно утилите своё состояние только по завершению создания индекса, т.е. это одна транзакция., а не несколько (единиц, десятков, сотен, тысяч и т.д.) как в случае когда мы заполняем таблицы данным при реструктуризации или репликации.

Повлиять на скорость создания индекса достаточно сложно, хотя можно, и как это сделать в PostgreSQL расскажу в следующий раз.
А вот повлиять на поведение системы, чтобы она не прерывала такое соединение можно достаточно просто.

Для Linux:
▫️sysctl net.ipv4.tcp_keepalive_time узнаём какой сейчас стоит таймаут, обычно ответ будет 7200
▫️Если он меньше чем нам нужно, то устанавливаем новое значение в секундах, которое заведомо больше нашего времени создания индекса sysctl -w net.ipv4.tcp_keepalive_time=14400 в секундах!
▫️Если мы хотим установить этот параметр так чтобы он подтянулся и после перезагрузки, то нужно в файле /etc/sysctl.conf добавить строчку: net.ipv4.tcp_keepalive_time = 14400

Для Windows:
▫️В разделе реестра
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

создаём параметр DWORD с именем KeepAliveTime и значением 14400000 в миллисекундах!
▫️Перезагружаем систему

Какое время необходимо вам для создания индекса конечно нужно смотреть в логах СУБД заранее настроив их на сбор длительных запросов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥51👍144🤔1
1️⃣🔤 Как сделать так, чтобы при добавлении http-сервиса даже в расширение не нужно было переопубликовывать базу на веб-сервере?

Большинство из нас привыкло, что при изменении состава публикуемых web или http сервисов нужно заново публиковать базу на веб-сервере чтобы новшества заработали.

При этом файл default.vrd выглядит очень большим и сложным:

<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/buh"
ib="Srvr=&quot;server1c:1541&quot;;Ref=&quot;buh&quot;;">
<standardOdata enable="false"
reuseSessions="autouse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
<ws>
<point name="AccHRMDataTransfer"
alias="AccHRMDataTransfer.1cws"
enable="true"
reuseSessions="dontuse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
<point name="EnterpriseDataExchange_1_0_1_1"
alias="EnterpriseDataExchange_1_0_1_1.1cws"
enable="true"
reuseSessions="dontuse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
<point name="EnterpriseDataUpload_1_0_1_1"
alias="EnterpriseDataUpload_1_0_1_1.1cws"
enable="true"
reuseSessions="dontuse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
...


Но если внимательно прочитать ИТС, то можно обнаружить что для работы всех возможных сервисов публикации, в том числе и тех, которые в расширениях, достаточно сделать вот такой файл default.vrd:
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/buh"
ib="Srvr=server1c:1541;Ref=buh;"
<ws pointEnableCommon="true"
publishExtensionsByDefault="true"/>
<httpServices publishExtensionsByDefault="true"/>
<standardOdata enable="true"
reuseSessions="autouse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
<analytics enable="true"/>
</point>


❗️Помимо того что это просто красиво, такая настройка позволяет ничего не переопубликовывать при добавлении нового web или http-сервиса, всё сразу работает!

Так зачем же тогда Платформа 1С делает такую развёрнутую публикацию?
Ответ достаточно прост - чтобы была возможность что-то исключить из публикации, например какому-то одному или нескольким сервисам установить значение enable="false" либо наоборот, запретив всё разрешить только некоторые
  <httpServices publishByDefault="false"
publishExtensionsByDefault="false">
<service name="ПолучениеЗаказовПоAPI"
rootUrl="Marketplace_API"
enable="true"
reuseSessions="autouse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
</httpServices>
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥55👍119👏7
1️⃣🔤 + 🔤🔤🔤 Запись не найдена в менеджере имён базы данных

Достаточно редкая, но очень "противная" и непонятная ошибка.
Что только не делают чтобы её убрать:
▫️Удаляют базу с кластера 1С и регистрируют заново.
▫️Добавляют базу в другой кластер 1С.
▫️Останавливают службу 1С с очисткой сеансовых данных.

Все эти способы почти никогда не помогают.

❗️Что было замечено?
▫️Эта ошибка практически в 100% случаев возникает только с базами PostgreSQL.
▫️Так же практически всегда она возникает после того как базу восстановили из дампа с помощью pg_restore.

Давайте разбираться в чём же проблема? Неужели виновата "православная" СУБД?

Проблема в том, что по умолчанию pg_restore НЕ УДАЛЯЕТ базу перед восстановлением в неё дампа.
Т.е. в восстановленной базе есть "ошмётки" от старой базы и новые данные из дампа.

Именно это и приводит к появлению ошибки "Запись не найдена в менеджере имён базы данных".

Почему ошибка не всегда и не у всех?
Потому что если вы восстанавливаете базу в её же "старый вариант", то возможно вам повезёт и платформа не обнаружит нарушений в своих системных данных и всё будет работать.

Как сделать так чтобы ошибка возникла с вероятностью 99%?
▫️На СУБД не должно быть нашей базы test.
▫️Добавить базу в кластере 1С с установленной галкой "Создать в случае отсутствия".
▫️Восстановить дамп в эту базу, причём дамп сливался с базы с названием отличным от test.

В отличии от PostgreSQL, MS SQL наоборот всегда УДАЛЯТ базу, СОЗДАЁТ заново пустую и в неё уже восстанавливает резервную копию - поэтому при использованию MS SQL этой ошибки и не возникает.

Как же правильно восстанавливать/обновлять существующую базу 1С на PostgreSQL?
❗️Вариант 1 (универсальный):
▫️Удалить базу с кластера 1С
▫️Удалить базу с СУБД PostgreSQL
▫️Создать пустую базу 1С на PostgreSQL скриптом (пример для PG 17):

CREATE DATABASE test
WITH
OWNER = postgres
ENCODING = 'UTF8'
LC_COLLATE = 'ru_RU.UTF-8'
LC_CTYPE = 'ru_RU.UTF-8'
ICU_LOCALE = 'ru-RU'
LOCALE_PROVIDER = 'icu'
TABLESPACE = pg_default
CONNECTION LIMIT = -1
IS_TEMPLATE = False;


▫️Восстановить дамп через pg_restore в базу test
▫️Добавить базу в кластер 1С

❗️Вариант 2:
▫️Удалить базу с кластера 1С
▫️Восстановить дамп через pg_restore в базу с тем названием, которое было у оригинальной базы с которой делался дам с параметрами --clean --create
▫️Добавить базу в кластер 1С

❗️Небольшая, но важная особенность:
С параметром --create база, заданная параметром -d, применяется только для подключения и выполнения начальных команд DROP DATABASE и CREATE DATABASE. Все данные восстанавливаются в базу данных, имя которой записано в архиве.

❗️Так же обратите внимание что во всех вариантах при восстановлении базы на уровне СУБД (не перезаливкой dt) необходимо удалять базу с кластера 1С и добавлять заново. Так как кластер 1С не в курсе что ему подсунули новую базу и вся система кэширования в итоге оказывается проблемой, а не помощником.
Эта особенность не зависит от того какую СУБД использовать PostgreSQL или MS SQL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥409👍8😱1🤬1
До встречи на Инфостарте!
Расскажу новое и интересное)
👍57🔥365
🔤🔤🔤 Временные таблицы в postgresql.

Ни для кого не секрет что с одной стороны запросы 1С все буквально сотканы из временных таблиц.
С другой стороны, именно работа с временными таблицами является ахилесовой пятой postgresql.
За последние несколько лет сделано очень много оптимизаций и изменений, касающихся работы с времеными таблицами как со стороны Платформы 1с так и со стороны postgres.

Но недавно нагрузочные тесты показали еще один интересный момент, про который сегодня расскажу.

Все мы знаем, что временные таблицы сеанса postgres размещаются в оперативной памяти, пока не исчерпают обьем, указанный в параметре temp_buffers.
И конечно есть соблазн купить много оперативной памяти и выкрутить этот параметр в бОльшую сторону.
Например вместо рекомендуемых 128-256МБ поставить 2ГБ.
И конечно же ожидать от этого только плюсы и увеличение скорости работы с временными таблицами.

Оказалось что при достаточно больших значениях temp_buffers, 1ГБ и более (но как и при любом тесте многое зависит от железа и эта цифра может быть как больше так и меньше), удаление временной таблицы из памяти занимает достаточно продолжительное время.
Это происходит из-за того что при работе с памятью системе нужно последовательно пройти все страницы и освободить их, при размере временной таблицы в 1ГБ таких проходов около 0.5 млн.

В итоге пришли в неожиданному выводу, что эффективнее наоборот уменьшить temp_buffers, но при этом вынести табличное пространство для временных таблиц на диск в оперативной памяти (RAM-диск, tmpfs).
Так как удаление файла размером в 1ГБ это очень быстрая файловая операция, а не последовательный проход страниц.

Как же вынести временные таблицы в отдельное табличное пространство?

За это отвечает параметр в postgresql.conf - temp_tablespaces

Итого, нам нужно смонтировать каталог в tmpfs, дать на него права пользователю и группе postgres и указать его абсолютный путь в параметре temp_tablespaces.

Только будьте внимательны!
Размер каталога должен соответствовать профилю вашей нагрузки.

Тут проще всего ориентироваться на статистику максимального размера занимаемого места временными таблицами.
К сожалению именно такого разреза статистики в postgresql нет, но зато это знает операционная система.
Просто выносим временные таблицы в отдельное табличное пространство на диске, где работаем сейчас.
И ставим размер свободного или занятого места на этом диске на мониторинг в вашей системе мониторинга.
Ждём релевантный для вашего профиля нагрузки период и смотрим там максимальный показатель занятого места.
Прибавляем к нему 20-30% и именно столько нам нужно будет выделить место в оперативной памяти для уверенности в том что его хватит.

Опять же, это справедливо для случая когда мы не меняем параметр temp_buffers. Если же мы его уменьшаем, то таблиц на диске будет еще больше и вам нужна новая статистика для определения необходимого объема.

Это особенно актуально в системах, где вы часто видите запрос drop temptable, который длится более 1 сек.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥53👍123
1️⃣🔤 Очень странное поведение после обновления платформы

При давно отработанной процедуре обновления платформы 1с, при переходе на 27 версию достаточно часто стали получать прямо таки неадекватное поведение системы при в общем-то штатной работе и отсутствием обшибок в ТехЖурнале.

Что за процедура?
Для Windows:
▫️Устанавливаем новую версию на сервер, снимая галку "установить как службу"
▫️Правим реестр ОС с указанием нового каталога исполняемых файлов службы Агент сервера 1с
▫️В технологическое окно:
- удаляем все сеансы
- останавливаем службу
- дожидаемся остановки всех процессов rphost, rmngr, ragent
- запускаем службу

Для Linux всё тоже самое, только вместо реестра заменяем симлинк файла службы на новый

Заходим в 1С и всё работает, по крайней мере так было последние несколько лет стабильно.

Но при обновлении именно на 27 версию начались чудеса: странные ошибки как на картинке, исчезновение кнопок у платформенных форм, ругань на отсутсвие каких-то очень странных файлов по странным путям и т.д.
При этом в ТехЖурнале тишь да благодать...

В ходе попыток найти решение было обнаружено что причиной такого поведения является каталог сеансовых данных.
В нем странным образом переставали создаваться файлы и структуры каталогов, хотя с правами у пользователя всё хорошо.

В итоге система стабилизировалась только после полной очистки каталога C:\Program Files\1cv8\srvinfo\reg_1541\snccntx

Да, в чек-листе от 1С в примере скрипта по остановке службы 1С всегда была строка: DEL /Q /F /S %CNTX_PATH%\snccntx*
НО:
Во-первых - ктож вообще читает инструкции? 😁
Во-вторых - давно уже обходилось обновление без этого действия, но вот опять 😄

❗️Если вы столкнулись с очень странными сообщениями платформы, то перезапустите службу 1С с очисткой сеансовых данных и не забудьте это сделать при обновлении версии платформы!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63🔥252🙏1
Мой первый опыт в подкастах

https://vkvideo.ru/video-227129566_456239066

Спасибо Сергею Сыпачеву за приглашение и атмосферу!)
🔥49👍19👏7🎉3
1️⃣🔤 Как понять какой кластер обслуживают какие процессы "сервера лицензирования"

Очень частой практикой является выделение отдельного сервера 1С с ролью "Сервер программного лицензирования" и подключения к нему многих серверов/кластеров 1С.
Это очень удобно, просто и гибко, так как можно запустить несколько служб с разной версией платформы 1С и тем самым обеспечить всех лицензиями как серверными так и клиентскими.

Но, затем встаёт вопрос - а как понять кого обслуживает наш сервер лицензирования?

Вспоминать и бежать по всем кластерам/серверам 1С и смотреть состав рабочих серверов и их ТНФ? - очень долго и ненадёжно, так как можем просто забыть что-то.
Вести какую-то табличку? - она точно устареет и будет неактуальной.
Видеть всё где-то в одном месте? - классно, но пока такого инструмента нет (ждём 8.5.2).

❗️Сейчас же у нас всё таки есть возможность узнать какие кластера 1С обслуживает наш сервер лицензирования, а именно:

Для Windows:
▫️Открываем Диспетчер задач на сервере лицензирования - вкладка "подробности"
▫️Правой кнопкой мыши по имени любого столбца - Выбрать столбцы
▫️Ставим галку "Командная строка". Теперь у нас в Подробностях появился столбец с отображением Командной строки приложения
▫️Ищем процессы rmngr и rphost отсортировав список по колонке "Имя"

В командной строке мы видим надпись "-reghost SERVER1C-2" - это и есть имя сервера к которому в кластер его службы 1С был добавлен наш сервер лицензирования.

Для Linux - инструмент htop, в остальном всё точно так же.

Таким образом мы видим факт обслуживания, что является объективной информацией.

На примере из скриншота видно что SERVER1C обслуживает помимо самого себя (на нём есть кластер с базами) ещё и сервер SERVER1C-2.
Идём на SERVER1C-2 и видим что там server1c является сервером лицензирования.

❗️Но по хорошему нам недостаточно просто знать, надо ещё и гарантировать что конкретные (обычно серверные) лицензии должны быть заняты только конкретными серверами 1С.

Давайте рассмотрим сценарий где у нас на сервере лицензирования помимо клиентской лицензии на 100 пользователей есть ДВЕ серверные лицензии.
Одна для сервера прода, вторая для сервера разработки, а клиентские лицензии общие.
И нам нужно гарантировать что никто случайно не сможет создать ещё один сервер 1С и занять нашу лицензию для прода.

Это тоже можно реализовать:
▫️На сервере лицензирования запускаем ДВЕ службы 1С на разных портах ( прод -1540, 1541, 1560-1591, разработка (2540, 2541, 2560-2591) и под разными пользователями (прод - user1cprod, разработка - user1cdev)
▫️Ограничиваем Сетевым экраном доступ по портам на сервер лицензирования только с сервера прода и сервера разработки
▫️На файл программной серверной лицензии для прода ставим запрет для пользователя user1cdev и разрешение для user1cprod
▫️На файл программной серверной лицензии для разработки наоборот ставим запрет для пользователя user1cprod и разрешение для user1cdev
▫️На файл программной клиентской лицензии разрешение для user1cdev и для user1cprod
▫️На каждой службе сервера прода и разработки задать РАЗНЫХ администраторов сервера в консоли администрирования
▫️На каждой службе сервера лицензирования задать соответствующих администраторов сервера в консоли администрирования

Таким образом мы ограничим на уровне сети и знания логинов/паролей администраторов сервера 1С сценарий, когда на любой машине в локальной сети устанавливается серверная часть платформы и в созданный по умолчанию кластер добавляется наш сервер лицензирования.
А в момент долгого (более 20 минут) отсутствия одного из серверов (прод или разработки) сервер лицензирования высвободит их лицензию и отдаст неизвестному серверу по его требованию. И мы получим проблемы с работой нужных серверов.
Внутри сервера лицензирования мы с помощью прав на файлы сделали так чтобы службы разработки не смогла занять файл прода и наоборот.

❗️Нужен именно комплекс мер, а не что-то одно.
Тогда вероятность случайного/умышленного "угона" лицензии на другой кластер будет крайне мала.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42🔥155
1️⃣🔤 "Падение" кластера 1С из-за лицензии разработчика

Недавно в рамках РКЛ разбирали очень интересную ситуацию.

Кластер 1С состоит из трёх серверов:
▫️Server1 - Центральный сервер (ТНФ отсутствуют)
▫️Server2 - Рабочий сервер (ТНФ: Клиентские соединения - Авто, Для всех - Не назначать)
▫️ServerLic - Рабочий сервер (ТНФ: Сервис лицензирования - Назначать, Для всех - Не назначать). На этом сервере активированы обе серверные лицензии 1С (для Server1 и Server2) и какое-то количество клиентских лицензий 1С.

Ожидаемое поведение кластера 1С:
Клиентские соединения равномерно (по производительности серверов 1С) распределяются по серверам 1С.

❗️Всё именно так и работало долго и успешно, но в один "прекрасный" момент соединения перестали назначаться на Server2 и все пользователи работали только на Server1

В консоли администрирования было видно что рабочий процесс Server2 не имел лицензии.
Сначала казалось что проблема именно в этом, было идея что серверную лицензию Server2 занял какой-то другой кластер.
Подробно я разбирал это здесь: https://news.1rj.ru/str/explorer1c/21
Анализ показал что это не так и лицензию никто не занимает.

Ок, решили тогда попробовать удалить Server2 из кластера и добавить заново...
Вот тут то мы и получили ошибку со скриншота,
Ошибка регистрации рабочего сервера в кластере:
Ошибка операции администрирования
Лицензия для разработчиков позволяет использовать только один рабочий в кластере...


Казалось бы - фигня делов, сейчас исправим! Мы же знаем где хранятся файлы программных лицензий!

Не тут то было, ни в одном из каталогов хранения программных лицензий никаких лицензий разработчиков не оказалось.
Поиск файлов по всей системе по маске *.lic выдал только 3 файла на сервере ServerLic:
▫️Серверная лицензия для Server1
▫️Серверная лицензия для Server2
▫️Клиентская лицензия на 500 пользователей

Что делать когда предыдущий опыт не помогает?
ВЕРНО! Читать ИТС!!!
Но и там не оказалось ничего про то где и как хранится лицензия для разработчиков...

Опытным путём, а именно пересобиранием кластера было выяснено что лицензия разработчика активирована именно на Server2.

❗️В итоге попробовали на Server2 переименовать каталог reg_1541 (каталог кластера 1С) и о чудо всё заработало, кластер собрался без ошибок!

Пошли выяснять дальше, оказалось что лицензия разработчика хранится в каталоге сеансовых данных сервера 1С. Достаточно почистить этот каталог и проблема вместе с лицензией разработчика исчезает.
Это было очень неожиданно!

❗️И теперь самое важное: пока не просматривается сценария защиты на уровне платформы от этого, так как активировать лицензию можно не только из Конфигуратора, но и из пользовательского режима...
Достаточно при активации просто выбрать в пункте "Дополнительно" сервер кластера 1С.

❗️❗️❗️Что мы можем сделать чтобы всё таки уменьшить вероятность:
▫️Закрыть доступ по TCP опубликовав базу по https и настроить сетевой экран на серверах 1С на запрет доступа по портам 1540,1541,1560-1591 (по умолчанию) всем кроме серверов 1С кластера 1С и web-сервера с публикацией 1С.
▫️Написать и применить расширение, блокирующее пункт в меню "Получение лицензии".
▫️Остаётся конфигуратор - тут только знание, что не надо на продовых кластерах и базах пытаться активировать лицензию разработчика.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥40👍18😱42🤔1
1️⃣🔤 Во время выполнения действия была потеряна связь с сервером...

Достаточно давно, периодически (естественно почти не подтверждаемая на тестах) как у наших клиентов РКЛ так и у клиентов нашего Облака стала возникать ошибка как на скриншоте.
Причём возникает она просто при работе клиента с 1С ни с того ни с сего.

В результате попыток понять что-же это за проблема было обнаружено два момента:
▫️Ошибка возникает только при работе с базами по http/https, по TCP всё хорошо
▫️Ошибка возникает только если обращение к базе 1С идёт через NGINX, если работать напрямую с apache/iis, то всё хорошо

Ок, определили что с NGINX что-то не так.
Но как всегда, до этого же всё работало!)))
Поэтому сильно хочется начать поиски ключа там где светло, а не там где потерял ключ...

Включаем лог ошибок в NGINX
в файл nginx.conf вверху добавляем строку:
error_log /var/log/nginx/error.log error;
nginx -t (проверить корректность настройки)
nginx -s reload (перечитываем настройки)


В лог ошибок во время получения ошибки пользователем в 1С фиксируется запись:
[error] 3408371#3408371: *954123377 upstream timed out (110: Connection timed out) while reading response header from upstream, client:


Т.е. у нас срабатывает таймаут чтения ответа от проксируемого сервера...

Ок, идём на итс и смотрим какие настройки таймаутов рекомендует 1С и там видим рекомендацию:

proxy_read_timeout 300s;


Но проблема в том, что у нас в настройках уже есть этот параметр и более того он выставлен в значение 3600s, что больше чем рекомендуемое в 20 раз.

Ок, может мы чего-то не понимаем, ставим 300s.
Ситуация поменялась, но уже в части другого.
Ошибок у пользователей осталось как было, а вот других записей в лог ошибок NGINX резко прибавилось:

connect() failed (110: Connection timed out) while connecting to upstream, client:


Вернули параметр в 3600s, всё стало как прежде.

Ну и если честно, то тут прям взяли грех на душу и посчитали что во всём виновато обновление на платформу 1С 8.3.27, так как вроде бы обращения пользователей коррелируют с временем обновления.

Проблема в том. что ошибка практически не повторялась на тесте, а откатить прод. где она есть на предыдущие версии платформы 1С уже было невозможно из-за требований конфигураций 1С...

Так в расстройстве прошло какое-то время, но червячок всё таки грыз понемногу - что ну не может такого быть!)))

Поиск в интернете по ошибке "upstream timed out (110: Connection timed out) while reading response header from upstream," всё равно приводил к параметру proxy_read_timeout, что нам не помогало...

И только в одном из форумов был намёк "попробуйте установить значение параметра "proxy_send_timeout" в больше чем по умолчанию (60s)

Ну когда ничего не остаётся надо идти читать документацию)))
▫️proxy_read_timeout - Задаёт таймаут при чтении ответа проксированного сервера.
▫️proxy_send_timeout - Задаёт таймаут при передаче запроса проксированному серверу

Ну и опять же, вроде мы не тупим - ошибка "while reading response header from upstream" как раз про чтение ответа, а это параметр proxy_read_timeout.
Опять тупик...

С другой стороны, вроде бы нам ничего не мешает установить и значение параметра proxy_send_timeout в 3600s.

Делаем, и вуаля!!!
Ошибки исчезли!

Вот так разное описание параметра в документации и реакции сервера на этот параметр в логе привело в нескольким неделям блужданий в темноте...

❗️Так что если у вас наблюдается ошибка потери связи и при этом у вас есть NGINX, то попробуйте установить параметр proxy_send_timeout в значение 3600s.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥69👍342🎉2
Коллеги, привет!
Я никуда не исчез, но меня свалила сильная простуда и температура под 40...
Как только поправлю этот баг в своей платформе обязательно продолжим))

Всем крепкого здоровья!
69🙏53😱13🔥4😢4
Всем привет!

Возможно вы заметили статус A+ у канала.
Это означает что канал прошёл проверку РКН!

Теперь канал есть и в MAXe https://max.ru/explorer1c

Присоединяйтесь!)
🔥53👍14👎12😁7🤔2
🔤🔤🔤 Резервное копирование в PostgreSQL и его мифы

Достаточно часто во время обучения корпоративных заказчиков особенностям эксплуатации PostgreSQL сталкиваюсь с одними и теми же заблуждениями...
Ну что ж, буду понемногу опрозрачивать эту тему.

Заблуждение № 1:
Резервная копия PostgreSQL будет настоящей только если выгнать всех пользователей из базы 1С и заблокировать базу.

Заблуждение № 2:
Резервное копирование PostgreSQL это только Dump.

Заблуждение № 3:
Резервное копирование PostgreSQL это только весь сервер с помощью basebackup, а базу отдельно забэкапить невозможно.

Заблуждение № 4:
Резервная копия PostgreSQL не имеет обратной совместимости, т.е. копия сделанная на версии 14 не сможет быть восстановлена на версии 15 и новее (сейчас есть уже 18).

Заблуждение № 5:
Резервная копия PostgreSQL может быть только полной и не умеет делать дифференциальные или инкрементные копии.

Как обстоят дела на самом деле:
Резервная копия (бэкап) субд PostgreSQL является что ни на есть настоящей и консистентной даже если сделана во время работы базы и не требует ни отсутствия пользователей в 1С ни блокировки базы.
В отличии от MS SQL где есть только один вид резервного копирования, PostgreSQL имеет два основных вида:
▫️PG_Dump
▫️PG_BaseBackup

В чём их особенности:
PG_Dump - это логическое чтение всех данных со всех таблиц базы данных.
В следствии этого копия созданная утилитой pg_dump консистентна на начало копирования (в отличии от MS SQL, резервная копия которого консистентна на момент окончания копирования).
Так же pg_dump поскольку является по факту просто запросом select с выводом в файл имеет много гибких настроек.
Можно исключить определенные таблицы из копии (очень полезно при создании копии для среды разработки и тестирования, например можно выкинуть иэ бэкапа таблицу истории данных или версионирования данных)
Так же dump не содержит индексов, а содержит только команды их создания. Из-за этого бэкап сделанный с помощью dump занимает намного меньше места чем копия созданная на СУБД MS SQL, которая как раз таки содержит и индексы.
Копия созданная утилитой pg_dump имеет обратную совместимость, т.е. нет никаких проблем в том чтобы создать копию на версии 14 и восстановить её на версии 17.
Единственный нюанс состоит в том, что использовать утилиту восстановления pg_restore нужно в этом случае именно версии 17.

Это ещё не всё про pg_dump)))
Формат резервной копии этой утилиты может быть трёх видов:
▫️-Fp - plain
▫️-Fc - custom
▫️-Fd - directory

Plain - просто текстовый формат, выходной файл будет состоять из команд insert.
Особенность в том что этот формат однопоточный, НО можно немного схитрить и отправить результат команды не в файл, а в поток, а этот поток уже многопоточно сжать через pigz для windows или любого аналога для Linux и тем самым кратно ускорить создание резервной копии | c:\util\pigz\pigz.exe -p4
Плюсы - квазимногопоточность создания бэкапа
Минусы - восстановление только в один поток и предварительно необходимо распаковать файл резервной копии

Custom - это встроенный формат бэкапа, сжимается на лету
Плюсы - многопоточное восстановление. Не требует предварительной распаковки
Минусы - однопоточное создание бэкапа

Directory - бэкап на уровне каталога.
Особенность - гарантированно выполняется только на заблокированной базе, если же базу не блокировать, то возможно что система затребует блокировку таблицы, которую ещё не забэкапили и тогда pg_dump прервёт свою работу по ошибке.
Плюсы - многопоточное создание и восстановление. Не требует предварительной распаковки
Минусы - гарантированное выполнение только на заблокированной базе.

Особенности любых резервных копий, создаваемых через pg_dump:
Только полное резервное копирование, никаких дифференциальных и инкрементальных копий.
После восстановления из резервной копии необходимо выполнить операцию обновления статистики, благо в PostgreSQL она очень быстрая.
Проверки на валидность файла резервной копии не существует, контролировать нужно именно отсутствие ошибок при работе pg_dump.

Про особенности, плюсы и минусы pg_basebackup расскажу в следующий раз.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍53🔥269🤔1
🔤🔤🔤 Резервное копирование в PostgreSQL и его мифы часть 2

В этой части поговорим про другой вид резервного копирования в PostgreSQL. а именно про pg_basebackup

Главное отличие от pg_dump состоит в том, что pg_basebackup это резервная копия всего сервера, а не отдельной базы.

Процесс создания резервной копии включает 3 этапа:
▫️Выполнение контрольной точки
▫️Копирование журналов транзакций (WAL)
▫️Копирование самих данных (каталог сервера СУБД)

Последние 2 этапа идут параллельно, и копирование журнала транзакций заканчивается сразу после того как закончилось копирование самих данных.
Таким образом резервная копия консистентна на момент окончания процедуры копирования.
Резервная копия pg_basebackup всегда идёт в 1 поток и содержит как данные так и индексы, так как является по факту копией каталога.
Резервная копия pg_basebackup не имеет обратной совместимости, т.е. копия созданная на версии 15 будет работать только с версией 15.

Начиная с 17-ой версии PostgreSQL pg_basebackup может быть как полным так и инкрементом.
Причём снятие инкремента сделано таким образом, что необходимо вручную указать от какой копии делать инкремент. Таким образом мы можем формировать как инкрементные копии от последней копии, так и дифференциальные копии от полной копии, выстраивая таким образом ваши сценарии резервного копирования.

Процесса восстановления из полной резервной копии pg_basebackup не существует, это просто сервер PostgreSQL готовый к старту и чтобы восстановить резервную копию достаточно стартануть СУБД с указанием каталога: pg_ctl start -D /backup/full_copy

Процесс же восстановления из полной копии плюс набор инкрементных включает в себя сначала сборку каталога кластера и затем уже старт PostgreSQL в этом каталоге: pg_combinebackup /backup/full1 /backup/inc1 -o backup/full_combined и затем уже старт: pg_ctl start -D /backup/full_copy

Как снять инкремент:
▫️В postgresql.conf установить wal_level =replica или logical, summarize_wal = on
▫️Также указать wal_summary_keep_time в минутах (по умолчанию 10 дней) - это параметр, отвечающий за то какой глубины вы сможете снимать копии
▫️Создаём полную копию pg_basebackup -D /backup/full1 (в каталоге копии помимо самой копии появится файл backup_manifest, содержащий информацию и контрольные суммы по всем файлам)
▫️Содаём инкремент указывая от какой копии этот инкремент pg_basebackup -D /backup/inc1 -i /backup/full1/backup_manifest

Так же в 17-ой версии появился инструмент проверки резервной копии: pg_verifybackup /backup/full1, НО процедура контроля, выполняемая утилитой pg_verifybackup не включает в себя все проверки, которые будет выполнять сервер, если его запустить с этой копией данных

Помимо "ванильных" средств резервного копирования существует так же несколько вариантов платных и бесплатных ПО со своими плюсами и особенностями.
Чуть позже расскажу про pgpro_backup. так как мы и используем именно это ПО и знаем как оно работает не по наслышке.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥35👍65😱1
1️⃣🔤 После старта сервера 1С стартуют все регламенты...

❗️Достаточно часто встречаюсь с непониманием ситуации - почему после старта службы 1С стартуют все регламенты в базе, хотя у нас же настроено расписание?

▫️Во-первых, - не надо перезапускать сервера 1С, это очень нехорошая практика... Настройте перезапуск рабочих процессов - этого достаточно для стабильной работы Лучшей в мире платформы 1С!

▫️Во-вторых, - почему-же после запуска сервер запускает регламенты 1С?
Причина в том, что сервер 1С "помнит" когда последний раз запускал регламент в оперативной памяти менеджера кластера (rmngr).
Дата окончания у всех заданий - <не определено> (скриншот 1)

Но тут возникает следующий вопрос: почему стартует задание с расписанием "каждый день; с 5:25:23 один раз в день" (скриншот 2). когда сейчас только час ночи?

Когда в расписании указано только Время начала и при этом регламентное никогда не выполнялось по мнению менеджера кластера, то сервер запустит этот регламент неважно настало это время или нет!

Та же самая ситуация будет в кластере с двумя центральными серверами и уровнем отказоустойчивости = 0 при выходе одного из них из строя (а именно на нём был сервис заданий).
В этом случае вам необходимо установить уровень отказоустойчивости = 1 и тогда информация о Дате окончания будет синхронизироваться между обоими серверами и всё будет хорошо.

Если же вы хотите чётко определить время запуска регламента, то помимо Времени начало в расписании необходимо задать Время окончания (не путать с Завершать после - это совсем другой параметр).

Итак, зададим нашему регламенту расписание "каждый день; с 5:25:23 по 5:25:30 один раз в день" (скриншот 3).
И вот только в этом случае, даже при старте сервера в час ночи, наш регламент стартанёт ТОЛЬКО в промежутке 7 секунд с 5:25:23 до 5:25:30.

Посмотрите расписания регламентов в своих базах и настройте его правильно согласно бизнес-логике.
Конечно периодические регламенты (раз в 30 минут, 30 сек и т.д.) так настраивать нет смысла.

Выдержка из итс: В механизме расписаний существует соглашение, что если какой-то элемент расписания не указан, то он не участвует в создании расписания. Например, если мы не указали дату окончания, то расписание будет выполняться неограниченно долго. Также, если мы не указали дату начала, то расписание будет выполняться от текущего момента. Расписание не будет выполняться до даты начала, и после даты окончания расписания.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍40🔥286😱4😁1