Нормальные герои всегда идут в обход
Айболит 66
Думаю, что многие встречались с необъяснимым поведением компонентов 1С, подсистем ОС, драйверов, СУБД которое видно в трассировке, но трассировка не отвечала на главный вопрос - почему? Т.е. по документации должно работать, но не работает.
Несмотря на все более возрастающее движение за системы с открытым кодом, всегда есть что-то, к чему нет исходников, либо нет компетенций, ресурсов в них разбираться. Ну даже если Вы найдете причину в открытом коде – скажем, PostgreSQL, чтобы это исправить, нужны хорошие навыки и компетенции. И все дороги, получается, ведут по пути Workaround (обходной путь), поскольку решение службы поддержки ждать дольше.
Более тяжелым случаем являются ограничения платформы (например, ограничения 1С при горизонтальном масштабировании, см.: Язык мой враг мой), которые тоже приходится обходить.
В английском закрепился термин, и ему посвящена статься в Wiki , где его связывают с анти-паттерном
Надо сказать. Workaround не обязательно костыль, или заплата, но он всегда несет в себе какие-то минусы – ведь мы действуем обходным путем
Термины не возникают на пустом месте – значит, сложилась предыстория, приемы, методы, которые нужно было как то назвать. Например, названия трюков на вейкборде Ollie, Wake to wake и т.д… это ниточка, за которой тянется техника, подводящие упражнения и многое другое.
Умение создавать workaround жизненно важно для систем,
- У которых маленькие технологические окна. Например наша, где роботы работают почти круглосуточно 1C Методика похудения 100% и с высокой нагрузкой.
- Устаревшие системы, которые сняты с поддержки
- Системы с высокой нагрузкой, использующие горизонтальное масштабирование, где проявляются эффекты бутылочных горлышек.
- Системы крупных вендоров, где не будет мгновенной реакции службы поддержки (Конечно, Вы можете попробовать расширенную поддержку 1С Корп, но руководство будет смотреть на Вас, а не на поддержку 1С 😉 )
- Я надеюсь, в комментариях добавят еще интересные кейсы
Разберем методы создания Workaround на реальных историях. Предлагаемая классификация методов наверняка неполная, и в комментариях к статье добавят много нового.
История №1. Как MS SQL случайным образом отключал соединения 1С (актуально и сейчас)
Все началось с жалоб пользователей на ошибки сверки с Backoffice при закрытии дня. Анализ показал, что некоторые фоновые задания, применяющиеся при расчетах с горизонтальным масштабированием, завершались некорректно. Надо заметить, что 1С сейчас хранит историю только по 1000 последних фоновых заданий, и мы создали расширенное логгирование в конфигурации для отслеживания таких ситуаций. Подробнее о проблеме можно посмотреть тут Язык мой Враг мой.
В 1С проблему можно локализовать анализом тех. журнала, а там заметили следующее
16:42.3540-0,SCOM,2,process=rphost,t:clientID=2352,Func='setSrcProcessName(MyDB, MyDB)'
16:42.4481-0,EXCP,2,process=rphost,p:processName= MyDB,t:clientID=2352,t:applicationName=BackgroundJob,t:connectID=14847,Exception=DataBaseException,Descr='Ошибка СУБД:
Microsoft SQL Server Native Client 11.0: TCP Provider: An existing connection was forcibly closed by the remote host.
HRESULT=80004005, HRESULT=80004005, SQLSrvr: SQLSTATE=08001, state=1, Severity=10, native=10054, line=0
Удивительно – но MS SQL сам отключает коннекты «случайным образом»? Анализ логов MS SQL \Операционной системы ничего не дал, в какие то критические режимы MS SQL не входил.
Выхода было два, либо копать глубже с трассировкой на уровне стека TCP и MS SQL Profiler, либо задать вопрос Google – возможно, он не даст прямое решение, но какую то идею.
К счастью. Google сразу вывел на статью Microsoft TLS connection forcibly closed, где была описана ошибка в TLS протоколах и Workaround для нашей версии Windows – отключить TLS_DHE_* в групповых политиках.
В данном случае workaround сделан по принципу
Не работает – измени окружение
Поскольку проблемные методы шифрования были убраны из политик и оставлены работающие – окружение 1С – MS SQL сервер изменилось.
У кого-то возникнет вопрос – а как действовать, если Google не вывел на прямой ответ?
Многие бросаются ставить все возможные патчи - ковровой бомбардировкой на ОС, SQL Server, 1С. Мне не нравится этот метод, поскольку они могут привести к другим проблемам, если длительно не выдержаны и протестированы на резервном контуре\контуре тестирования. Кроме того, в рассматриваемом случае патчи есть только для новых ОС
В рассматриваемом случае можно еще больше локализовать проблему – ведь ошибка TCP провайдера не означает, что проблема на транспортном уровне модели OSI. Нужно проверять еще прикладной, представления, сеансовый. В документации по ошибке есть пример network traсe, который позволяет ее выявить и, судя по всему, это сделано O Wire Shark и придется привлечь системных администраторов.
Если повезет, можно быстро понять, что дело на уровне шифрования TLS, но если нет возможности заниматься анализом, можно поступить по другому.
В нашем случае ошибка регистрируется периодически для фоновых заданий при взаимодействии сервера приложений 1С и SQL сервера и вредит она фоновым заданиям
Вариант 1. А что, если сделать повторный запуск фоновых заданий в 1С, если оно не доработало? В целом это нормальный вариант, который повысит выживаемость 1С в нестабильной среде при любых таких плавающих проблемах. Такой подход называется
Не работает - Измени подсистему и ее поведение
Вариант 2. Перенастроить кластер 1С на сервер с MS SQL и включить Shared memory protocol. Радикальная смена стека протоколов поможет обойти проблему по пути «Не работает – измени окружение». Да на нагрузка на оборудование возрастет, но зато прикладные проблемы уйдут
Сделав обходной путь можно спокойно докапываться до сути проблемы на резервном кластере.
Для крупных систем наличие резервного дублирующего контура жизненно необходимо чтобы
- тестировать все патчи и обновления
- воспроизводить, исследовать, взаимодействовать со службой поддержки по таким проблемам
- подготовить среду, где эти проблемы не возникают (напр новая операционная система, новый набор патчей и т.д.)
История №2. Как ускорить запись в регистр сведений 1С? Почти Антипаттерн, пока 1С не исправит
При использовании горизонтального масштабирования на уровне кластера 1С можно создать множество параллельных задач, которые постят движения в регистры, импортируют операции, и можно даже параллельно считать статьи баланса. Однако узким местом в 1С является запись в регистры (подробнее изложено в статье Язык мой Враг мой).
Допустим, нам нужно импортировать операции, по которым 6 миллионов изменений за день, а уникальных операций около миллиона в день. Изменения поступают по шине RabbitMQ
Построим регистры СУУ_АгрегированнаяСделкаКП (Индексы по измерениям , поле Удалено, Дата)
СУУ_НеобязательныеРеквизитыДляАгрегированныхОпераций (Индексы по измерениям)
С импортом новых операций проблем не возникнет, их можно записывать в регистры сведений сразу набором по 1000 шт за один раз с распараллеливанием.
Но если мы захотим обновить 1000 операций , то это можно сделать только по отдельным ИдИсхСистемы - поскольку фильтр отбора по измерений 1С работает только на равенство везде, т.е. получим 1000 отдельных вызовов .Записать()
Метаданные типа Документ еще хуже – документы можно записывать по одному, а не несколько в крупном DML.
Даже если эти записи распараллелены на 40 потоков – SQL сервер будет под атакой тысяч небольших DML операций со всеми вытекающими для производительности.
Добавлю, что при обновлении нужно решать проблему правильной записи версий, чтобы версия 1 не записалась поверх версии 2
Как укрупнить DML в таких условиях, если хочется остаться в рамках 1С?
Изменить свое отношение к проблеме, решай другую проблему
Обновление большого количества операций, имеющих изменения, это затратная по производительности задача даже если использовать конструкции типа Merge в SQL, ведь приходится обновлять не только таблицы, но и индексы.
Но ведь можно ничего не обновлять, а писать сразу версии! Сделаем регистры сведений периодическими и будем писать версии (версия в стандартном поле Период)! Главное, чтобы версия была одинакова и у реквизитов, и у операций. Поле Период по факту будет временем начала записи пакета из 1000 операций\необязательных реквизитов
Да, усложнится отбор операций для последующей обработки - ведь нам нужно отбирать последние версии операций и соединять их при необходимости с последними версиями необязательных реквизитов. Но зато мы можем организовать импорт максимально быстро в данном окружении.
Анонс: Эффективное написание запросов в этом случае тема отдельной статьи.
1С и в этом случае добавляет барьеров в виде неэффективных соединений с временными таблицами (подробно тут: 1С Миссия невыполнима. Общие реквизиты разделители против временных таблиц), но в целом задача решается просто изменением подхода к проблеме.
Хочется еще быстрее – тогда пишите в регистр сведений напрямую, минуя 1С , но это уже другая история.
История №3. Как рабочий процесс 1С терял контекст драйвера Oracle
Дело было в 2014 году , мы активно распараллеливали фоновыми заданиями задачи импорта. Появилась задача импортировать операции с базы на Oracle в 1С, обращение к серверу Oracle шло с использованием драйвера Oracle12c, на сервере приложений. В процессе эксплуатации начали регистрироваться сбои. Текст ошибки не помню, но суть была в потере контекста для определения параметров Oracle_home, причем периодически, а не постоянно.
Замечу, для драйверов Microsoft для Oracle ничего подобного не наблюдалось, но по разным причинам нужно было использовать родной драйвер Oracle
Тут сложно было сказать, кто виноват - 1С или Oracle, но было ясно, что более глубокая трассировка вряд ли приведет к решению, а общение со службой поддержки затянется. Поэтому применили принцип
Не работает - Измени подсистему и ее поведение
Подсистема работы с внешними источниками в 1С тогда еще была с ограниченным функционалом, поэтому использовали ADODB
Сначала была попытка соединиться правильно, но если не удавалось, создавали Ole вызов клиента 1С на сервере из фонового задания, и уже через Ole брали данные. Обходной вариант выглядел так (код сократил для удобочитаемости)
ADOConnection = СУУ_СоздатьОбъектАДО(ИДВызова, "ADODB.Connection");
Если ADOConnection = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
ОбъектОЛЕ = Неопределено;
СоединениеУстановлено = Ложь;
// установка соединения
Попытка
ADOConnection.Open(СтрокаСоединения);
СоединениеУстановлено = Истина;
Исключение
// Ошибка
КонецПопытки;
Если НЕ СоединениеУстановлено Тогда
// сюда дойдем, если при подключении через родной объект ADODB.Connection произошла ошибка
// на ORACLE x64 + 1С x64 + Windows x64 есть ошибка - после какого-то количества успешных подключений возникает ошибка.
//решение проблемы не найден. есть только обход:
//если соединение не установилось из конкретно этой базы в серверном режиме, то нужно получить соединение
//из клиента 1С, который всегда x32
//для этого написана микро-конфа с тремя экспортными методами:
//ADOConnectionObj();
//ADOCommandObj();
//ADORecordsetObj();
//фишка - если получили Connection таким образом, то и Command нужно тоже получить из 32-х разрядного клиента,
//иначе будет ошибка на этом моменте: Command.ActiveConnection = ADOConnection;
ОбъектОЛЕ = Неопределено;
Попытка
ОбъектОЛЕ = Новый COMобъект("V82.Application");
ОбъектОЛЕ.Visible=Ложь;
ОбъектОЛЕ.Connect("File=""C:\1C\ComSrv""; Usr="""";Pwd="""";");
ОбъектОЛЕ.Visible=Ложь;
СоединениеОЛЕ = Истина;
Исключение
//Сообщаем об ошибке
УничтожитьОбъектАДО(ADOConnection);
УничтожитьОбъектОЛЕ(ОбъектОЛЕ);
Возврат Неопределено;
КонецПопытки;
Некрасиво получается, а что делать?
Не работает – убери подсистему из окружения
Более красивый вариант – создать DBLink с Oracle на MSSQL сервере, где находилась база 1С , и обращаться уже к DBlink, используя только драйвера Microsoft, так в принципе можно сделать более универсальным код работы с внешними СУБД. Минус – слишком много слоев и сложный маршрут по сети (1С сервер – MS Sql сервер – Oracle сервер).
История №4 из Java
Я не эксперт в Java, но писал небольшие приложения для склеивания 1С с различными шинами, приложениями, для администрирования СУБД и т.д. Ведь когда что-то в 1С невозможно, проще найти это в мире Java и интегрировать.
При попытке написать приложение с использованием JSF + Glassfish обнаружил, что связка категорически не хочет работать даже с Hello word, см. тут: Мой наивный вопрос на StackOverflow
Я не смог найти рецептов, понять причину проблемы, и пришлось решить сменой сервера приложений Glassfish на Payara. Да, вот так радикально. Вообще качество решений на Java это тема отдельной статьи. Количество конкурирующих решений размывает качество тестирования на конечных потребителях. И после этого начинаешь очень ценить порядок и предсказуемость в платформе 1С.
Присоединяйтесь к нашему телеграм каналу. Очень интересно будет увидеть в комментариях случаи и решения не укладывающиеся в данную классификацию и другие методы создания Workaround.