0. zhichkin 486 20.05.19 09:40 Сейчас в теме

Альтернативная стратегия управления блокировками

Данная публикация освещает одну из альтернативных стратегий блокирования данных на уровне MS SQL Server, которая недоступна средствами 1С, но может быть весьма полезной. Разбирается практический пример.

Перейти к публикации

Комментарии
Избранное Подписка Сортировка: Древо
1. YPermitin 2976 20.05.19 14:23 Сейчас в теме
(0) темы про SQL Server на ИС всегда хорошо :)

+

Тема интересная. А за репо на GitHub отдельный плюс)
botokash; acanta; +2 Ответить
2. ifal 286 21.05.19 08:34 Сейчас в теме
Вам бы отдельной статьей оформить описание вашего инструмента, не каждый долистает до конца и просто не заметит, на мой взгляд вещь с большим потенциалом. Особенно если хотите, чтобы кто-нибудь присоединился к разработке.
bugtester; wowik; +2 Ответить
4. zhichkin 486 21.05.19 11:14 Сейчас в теме
(2) Согласен. Как раз готовлю такую статью. Скорее всего их будет несколько.
3. Dach 271 21.05.19 09:34 Сейчас в теме
Спасибо за интересный материал!

"Все значения статуса обновлены, кроме записи, которая до сих пор заблокирована транзакцией № 1.

Наша задача выполнена =)"

А как узнать в этом же контексте, какая запись обновлена не была? Это можно как-то сделать? Может эти данные где-то хранятся? Типа статистики какой-нибудь. Хотелось бы понять, на каких записях мы не смогли обновиться, получить их и закэшировать куда-нибудь. Или только потом делать Select с проверкой на нужные условия, как в примере?

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

Мы похожим образом сделали. У нас все строки, которые отвалились на блокировках - запоминаются в специальный кэш, а из него уже циклами добавляются до тех пор, пока все-таки не добавятся (не более N проходов). Тут вся соль в том, что надо в таких системах дробить крупные и длинные транзакции на более мелкие и короткие.
5. zhichkin 486 21.05.19 11:38 Сейчас в теме
(3) До начала выполнения запроса у Вас есть ссылки, на номенклатуру например, или какой-то отбор. В предложении OUTPUT можно вернуть значения этих ссылок - это то, что обновилось. Осталось вычесть это из того что было до отправки запроса.

По правде говоря, на продакшене я бы реализовал задачу резервирования, описанную в статье, на очередях. Очередью можно сделать таблицу SQL. Вот отличная статья по этому поводу: https://rusanu.com/2010/03/26/using-tables-as-queues/ В какой-то степени, если я правильно понял суть, Вы именно это и реализовали, но назвали "специальный кэш".
6. Dach 271 21.05.19 11:55 Сейчас в теме
(5) Именно так. Товар, который не удалось "поставить на резерв" по причине ожидания на управляемой блокировке 1С - падает в "очередь", откуда затем система (в конце алгоритма) несколько раз повторно пытается обработать его тем же самым способом (рекурсивный вызов).

Алгоритм рабочий, но ожидание на блокировке - это же какое-то время (причем довольно длительное, зависит от настройки базы). А вот с помощью хинта READPAST как оказывается - можно эту проблему решить... И это выглядит очень заманчиво с точки зрения повышения пропускной способности системы на предмет большего резервирования товаров за единицу времени. Правда, блокировка остатков накладывается же на стороне ORM, то есть 1С, объектом БлокировкаДанных... То есть, это же не совсем объектная блокировка, о которых Вы ведете речь в статье. Как на стороне СУБД при выполнении прямого запроса понять, что данный набор измерений регистра (Склад+Номенклатура+...+...) действительно заблокирован? Есть над чем подумать, одним словом.
7. zhichkin 486 21.05.19 16:46 Сейчас в теме
(6) Хочу немного уточнить кое что:
ORM - это то, что "укладывает" объекты в памяти в реляционную базу данных.
БлокировкаДанных - это объект в памяти сервера 1С. Он ничего не блокирует на уровне СУБД.
На уровне СУБД блокировка выполняется в момент НаборЗаписей.Записать() - это ORM.

У Вас по сути реализована работа с очередью в памяти (in-memory queue). Тут есть такой нюанс при работе с объектами в памяти - они могут потеряться при "падении" или "зависании", например, фонового задания, в котором всё это, вероятно, работает. Если это имеет значение, то нужно подумать о реализации сохраняемых очередей (persistent queue). Об этом я писал в прошлом моём сообщении.

Узнать какие блокировки наложены в момент выполнения запроса нельзя. Я думаю, что без этого можно обойтись. Это вопрос реализации.

Если очень хочется узнать кто и что блокирует до выполнения запроса, то в SQL Server можно посмотреть сюда sys.dm_tran_locks
8. Dach 271 21.05.19 17:52 Сейчас в теме
(7) очередь у нас как раз сохраняется - это регистр сведений. Суть не в том, сохраняется ли очередь или нет. Товар в очередь падает только в том случае, если его на первом проходе цикла добавления в резерв - не удалось добавить (по причине тайм-аута на управляемой блокировке 1С - кто-то другой уже добавляет в этот момент этот же товар).

"ORM - это то, что "укладывает" объекты в памяти в реляционную базу данных.
БлокировкаДанных - это объект в памяти сервера 1С. Он ничего не блокирует на уровне СУБД." - это я и имел ввиду, когда обратил внимание на то, что в статье речь об объектных блокировках, которые отражаются на уровне СУБД.

Но в классических алгоритмах, для блокировки остатков перед чтением используется БлокировкаДанных, а это блокировка именно на уровне 1С, а не СУБД. И это не просто "память", это менеджер управляемых блокировок, чисто 1с-ный процесс. Как еще нам предотвратить неизменность остатков на время, пока мы с ними работаем? Фактически, никак.
Вот в чем суть. Мы на уровне 1С какие-то ограничения наложили, а СУБД об этом не в курсе.

"Я думаю, что без этого можно обойтись" - поэтому пока что-то я не вижу вариантов, как "глядя" запросом в СУБД, узнать какой набор данных, по каким разрезам у меня не подлежит изменению.

Поэтому здорово конечно, что есть такой хинт, но практическое применение пока сомнительно (по крайней мере вот в этой конкретной задаче с резервами).

Ситуаций, когда выполняется массовое обновление каких-то полей в таблице и мы можем наткнуться на блокировку СУБД - крайне мало в реальной жизни.
НаборЗаписейРН или НаборЗаписейРС записываются очень быстро, если только там не 100 тыс. строк. Ну а если там 100 тыс. строк - то это явно что-то большое и тяжелое, зачем во время запуска этого большого и тяжелого пытаться еще и другие алгоритмы, обновляющие ту же таблицу запускать?
9. acanta 56 21.05.19 17:56 Сейчас в теме
Этот тренд имхо очень перспективный. К примеру, часть такого кода может быть вынесена во внешние компоненты и отлаживаться в режиме реального времени, а по окончании тестовой эксплуатации выпущена без исходных текстов.
Вопрос в том, как может выглядеть программа, позволяющая редактировать исполняемый код подключаемой внешней компоненты без перезапуска сервера и пользователей?
10. zhichkin 486 21.05.19 19:14 Сейчас в теме
(9)
Вопрос в том, как может выглядеть программа, позволяющая редактировать исполняемый код подключаемой внешней компоненты без перезапуска сервера и пользователей?

Поясните, пожалуйста, подробнее что Вы имеете ввиду ? Я так понял вопрос: как сделать так, чтобы новая версия внешней компоненты была загружена в работающий процесс сервера или пользователей без перезагрузки сервера. Верно ?
12. zhichkin 486 21.05.19 22:20 Сейчас в теме
(8)
Поэтому здорово конечно, что есть такой хинт, но практическое применение пока сомнительно (по крайней мере вот в этой конкретной задаче с резервами).

Согласен. Задача резервирования гораздо сложнее на практике, чем в теории. Одним хинтом её не решишь.
Было бы интересно узнать подробности про Вашу систему:
1. Как хранятся остатки и резервы - в одной таблице или разных.
2. Допускается ли изменение остатков задним числом ? Что происходит с неактуальными резервами в результате этого ? И вообще что делается для обеспечения актуальности остатков и резервов. Насколько это вообще актуально.
3. Какое количество позиций резервируется в единицу времени ?
4. Какое количество конкурирующих между собой пользователей ?
5. Что происходит в момент реализации из резервов если реализация их использует частично ?
Наверное есть ещё какие-то интересные подробности ...
15. Dach 271 22.05.19 09:31 Сейчас в теме
(12) да, там много нюансов и тонкостей, боюсь в одном комментарии не смогу раскрыть, будет время - поделюсь в виде небольшой статьи. Но основная проблема именно в блокировках 1С. Я уже сетовал ранее на то, что нет никаких удобных инструментов для онлайн-контроля 1с-ных блокировок. Кстати, в одном из релизов 8.3.12 метод Заблокировать() стал работать процентов на 15-20 медленнее (вот именно сам метод!) и мы это тут же заметили, как только одна из продуктивных баз перешла на нее. Хотя на тестах, естественно, внимания особо на это не обратили. И лишь потом, специально сравнили несколько релизов и обнаружили просадку. Теперь всегда будем это проверять...
zhichkin; +1 Ответить
11. acanta 56 21.05.19 19:37 Сейчас в теме
Да, и без перезагрузки сеанса пользователя. Как альтернатива расширениям.
13. zhichkin 486 21.05.19 22:21 Сейчас в теме
(11) Это очень сложный вопрос. Нужен какой-то менеджер динамической загрузки библиотек. Может быть микросервисы использовать как вариант ?
14. acanta 56 21.05.19 22:26 Сейчас в теме
(13) возможно. А возможно это одна, постоянно загруженная длл, при каждом выполнении какого-либо модуля подхватвающая его последний, актуальный вариант.
Оставьте свое сообщение
Новые вопросы с вознаграждением
Автор темы объявил вознаграждение за найденный ответ, его получит тот, кто первый поможет автору.

Вакансии

Программист 1С
Москва
Полный день

Консультант-аналитик 1С
Москва
Полный день

Консультант ERP-систем
Москва
Временный (на проект)

Бизнес-аналитик 1С
Москва
зарплата от 90 000 руб. до 150 000 руб.
Полный день

Программист 1С
Москва
зарплата от 140 000 руб.
Полный день