|
Разбор и анализ взаимоблокировок и таймаутов | ☑ | ||
---|---|---|---|---|
0
К_Дач
06.04.15
✎
16:59
|
Прошу помочь разобраться. Читал статьи и книги, но вопросы остались. Применительно к режиму управления блокировками "Управляемый" и клиент-серверному варианту развертывания БД.
В результате чего может возникнуть таймаут: например один сеанс долго пишет какой-то набор данных, другой сеанс в это же время пытается записать другой набор, часть строк которого имеет вхождения в первый набор. Соответственно, второй сеанс ждет, пока первый не закончит запись и если не успевает дождаться - возникает таймаут. 1. Верно понимаю, что если второй сеанс пытается читать данные, среди которых есть записываемые первым сеансом сейчас - это тоже самое, он будет ждать, пока первый не закончит запись? 2. Если в транзакции записи (например неявной, которая открывается при проведении документа) есть запись набора записей регистра например - блокируется ли набор регистра на все время транзакции? Особенно если явно в коде блокировка не задана. 3. Например я знаю, у какого сеанса и на каком конкретном куске кода возник таймаут, то есть я знаю конкретную таблицу и отловил ошибку в ТЖ и даже посмотрел трассу в профайлере. Как узнать, кто вызвал эту блокировку, то есть кто писал в этот момент данные, какой конкретный кусок кода? Ведь у того, кто писал - ошибок не возникло... Взаимоблокировки возникают, когда осуществляется попытка чтения после записи движений при включенном разделении итогов. Разделение итогов позволяет писать параллельно даже одинаковые наборы данных (по измерениям). То есть чтение общей области данных после разделяемой записи вызовет взаимоблокировку. 4. Опять-таки, я знаю запрос, который вызвал взаимоблокировку. Как узнать, кто писал и стал виновником? И последний вопрос. Есть примерно такой код: - Транзакция открыта. - Читаем таблицу А - Пишем в таблицу Б. - Что-то очень долго делаем, выполняем какой-то алгоритм. - Долго пишем в таблицу С по результатам расчета - Закрываем транзакцию. 5. Будет ли на все время транзакции заблокирована таблицы Б и С, и что насчет таблицы А - с ней проблем быть не должно? Если где-то не прав в своих рассуждениях - поправьте |
|||
1
1976vas
06.04.15
✎
17:05
|
на 5 сходу отвечу, на то она и транзакция, чтобы откатить изменения всех регистров, значит будет блокировать.
|
|||
2
К_Дач
06.04.15
✎
17:08
|
(1) но ведь блокировать можно по разному - можно исключительно (тогда никто не сможет читать), а можно разделяемо (тогда другие по идее должны мочь читать). Уровень изоляции транзакции у нас в управляемом режиме ниже исключительного...
Как все происходит внутри неявной транзакции записи документа, если нигде в коде явно блокировки не прописаны. Кто и как решает, какой уровень у вот этой конкретной транзакции должен быть? |
|||
3
D_E_S_131
06.04.15
✎
17:12
|
http://v8.1c.ru/metod/books/book.jsp?id=452
Вот хороший материал. |
|||
4
К_Дач
06.04.15
✎
17:13
|
(3) у меня есть эта книга, держу в качестве настольной. Но ответов на свои вопросы я там не нашел...
|
|||
5
H A D G E H O G s
06.04.15
✎
17:24
|
(4) И не найдешь.
|
|||
6
fisher
06.04.15
✎
17:29
|
Уровень изоляции транзакций в MSSQL и Postgres сейчас используется read committed snapshot в режиме управляемых блокировок. Т.е. чтение запросом блокироваться и ждать вообще не должно никогда. Параллельная транзакция должна просто старую версию данных прочитать.
Соответственно ожидание при чтении может возникнуть только на конфликте управляемых блокировок. |
|||
7
H A D G E H O G s
06.04.15
✎
17:30
|
1. Не верно для 8.3. Не верно для 8.2, когда 2-ой сеанс пытается читать вне транзакции.
2. Блокировка будет на уровне платформы. Как управляемая, так и СУБД. 3. В ТЖ есть виновник для управляемой блокировки. в DMV есть виновник для блокировки СУБД. ТЖ лучше разбирать инструментами разработчика от Тормозита. 4. пшшшшшш. Ниче не понял. 5. Все так и есть. |
|||
8
H A D G E H O G s
06.04.15
✎
17:32
|
(0) Самый самый самый первый шаг - смотрим текст ошибки по таймауту/взаимоблокировки.
Если он написан человечьим языком - это коллизия управляемых блокировок, если в тексте есть MS SQL HRESULT и прочее - это коллизия блокировок СУБД. |
|||
9
H A D G E H O G s
06.04.15
✎
17:33
|
Потом читаем статью одного хорошего специалиста по 2-м типам взаимоблокировок.
Читаем ее не применительно к 1С, а применительно к физике этого мира, пытаясь понять, для чего же блокировки нужны. |
|||
10
К_Дач
06.04.15
✎
17:41
|
Dmv - это речь про трассу запроса? А что за статья или хотя бы имя автора?
|
|||
11
H A D G E H O G s
06.04.15
✎
17:49
|
||||
12
D_E_S_131
06.04.15
✎
17:59
|
Вчитался внимательнее в (0). Выдвину свою "версию" :):
1. Зависит от того какая блокировка установлена и какую пытается установить "второй сеанс". 2. Зависит от режима управления блокировками. 3. А с чего это при таймауте будет возникать ошибка у другого, у кого данные прекрасно и надежно заблокированы? И тут надо искать не "из-за кого", а у кого выполнялась долгая блокировка. 4. Это логировать и разбирать техно.журнал надо. 5. Такие же вопросы как с п.п.1,2. |
|||
13
К_Дач
06.04.15
✎
18:24
|
(7) а почему утверждение 1 неверно для 8.3?
|
|||
14
H A D G E H O G s
06.04.15
✎
18:33
|
(13) Потому что в режиме Read_Commited_Snapshot блокировки нет.
|
|||
15
D_E_S_131
06.04.15
✎
18:39
|
(14) "Снэпшота" еще добиться надо. :)
|
|||
16
К_Дач
06.04.15
✎
18:39
|
(14) ясно, ну да, в 8.2 же просто Read_Commited
|
|||
17
fisher
07.04.15
✎
09:05
|
(15) В смысле - "добиться"? В последних релизах 8-ки это разве не дефолт? А в постгри так и давным давно.
|
|||
18
fisher
07.04.15
✎
09:06
|
(17) + Имелось в виду - дефолт для MSSQL
|
|||
19
D_E_S_131
07.04.15
✎
09:58
|
(18) А как будет работать "снэпшот" если в базе постояяно эскалации возникают?
|
|||
20
fisher
07.04.15
✎
10:13
|
(19) Ничего не понял.
1. Эскалации каких именно типов блокировок у вас постоянно возникают и почему? 2. Каким образом это связано с установленным уровнем изоляции транзакций или как эти эскалации могут помешать чтению данных запросом в транзакции при read committed snapshot. |
|||
21
К_Дач
09.04.15
✎
14:05
|
Дабы не плодить темы, спрошу здесь:
В литературе и других источника, особенно по работе СУБД для уровней изоляции транзакций RC и RC_Snapshot сказано, что "блокировка читаемых данных снимается в момент окончания выполнения запроса". В книге 1С:Эксперт, например говорят, что "это накладывает дополнительные требования к качеству кода, т.е. по качеству наложенных управляемых блокировок". Имеют ввиду, что разработчик должен сам позаботиться о том, чтобы заблокировать прочитанные данные. Однако на ИТС и в источниках по 1С везде есть упоминание о "блокирующем чтении", в частности они пишут о "блокирующем чтении в начале транзакции", подразумевая этим, что чтение остатков запросом в транзакции блокирует эти самые прочитанные остатки на все время выполнения транзакции. http://its.1c.ru/db/metod8dev#content:4053:hdoc И как известно, рекомендует переносить контроль остатков как можно ближе к концу транзакции, отсюда родилась новая методика проведения документов (где есть контроль остатков): сначала пишем, потом читаем, если ушли в минус - отменяем. И даже все задачи на спеца решаются именно по новой методике. То есть в одних источниках утверждают, что блокировка снимается сразу после выполнения запроса, в других - что прочитанные данные заблокированы на все время выполнения транзакции.... Как-то не очень понятно... Есть догадка, что все-таки прочитанные данные заблокированы на все время выполнения транзакции, но делается это не средствами СУБД, а менеджером транзакционных блокировок самой платформы 1С. Верно или нет? |
|||
22
H A D G E H O G s
09.04.15
✎
14:12
|
(21)
а) Автоматический режим, RepeatableRead - S (X при ДЛЯ ИЗМЕНЕНИЯ) блокировка СУБД на время транзакции. б)Управляемый режим, ReadCommited - S блокировка СУБД на время выполнения запроса. Нужны доп. управляемые блокировки для корректности логики работы. в) Управвляемый режим 8.3, ReadCommitedSnapshot - никаких блокировок СУБД... |
|||
23
К_Дач
09.04.15
✎
14:15
|
(22)
это я уже уяснил. Объясни, плз, надо ли в случаях б) и в) самому заботиться о том, чтобы заблокировать явно прочитанные данные или это за меня сделает платформа? Не просто же так на ИТС пишут о "блокирующем чтении" ? |
|||
24
H A D G E H O G s
09.04.15
✎
14:54
|
(23) Надо самому.
|
|||
25
К_Дач
09.04.15
✎
15:00
|
(24) а вот я не верю! ты сам так учил))) ушел проверять, отпишусь по результатам
|
|||
26
К_Дач
09.04.15
✎
15:33
|
Результаты теста:
Нарисовал простецкую конфу, 1 регистр, 1 документ. У регистра включил разделение итогов. Платформа 8.3, без совместимости с 8.2, то есть изоляция транзакций Read_Commited_Snapshot 1. Наделал движений документом в регистр 2. Накидал обработку, где такой код: НачатьТранзакцию(); ЗапросЧтенияДанных; //бла-бла-бла выполнить запрос ЗафиксироватьТранзакцию() 3. Выполняем этот код, ставим брекпойнт на ЗафиксироватьТранзакцию(), то есть у нас чтение в незавершенной транзакции. 4. Открыл SQL MenStud, таблица итогов регистра прекрасно читается SELECT * FROM ...... 5. Открыл еще один сеанс, начал писать еще движения. Все пишет, никаких проблем, никаких тебе блокировок. 6. Заглянул в таблицу итогов, там вот такая картина: http://itmages.ru/image/view/2443417/ca47bd9e Обратите внимание, по одинаковым значениям несколько строк, так как транзакция чтения заблокировала у меня предыдущие записи, соответственно, другие транзакции дописали просто с другим значением сплиттера. Вывод: фразу "блокирующее чтение" применительно к 8.3 надо понимать глубже, чем пишут на ИТС. Да, действительно, ПРОЧИТАННЫЕ записи таблицы итогов заблокированы от изменения другими транзакциями, но в тоже время это не мешает им спокойно писать такие же наборы данных... |
|||
27
К_Дач
09.04.15
✎
15:36
|
Далее.
Стоило перед ЗафиксироватьТранзакцию() вставить вот такой код: ____________________ БлокировкаДанных = Новый БлокировкаДанных; ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрНакопления.ТестовыйРегистр"); ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; ЭлементБлокировки.ИсточникДанных = РезультатЗапроса; ЭлементБлокировки.ИспользоватьИзИсточникаДанных("СимвольнаяСтрока", "СимвольнаяСтрока"); БлокировкаДанных.Заблокировать(); _______________________________ как произошло вот что: на уровне СУБД таблица итогов регистра по прежнему прекрасно читается SELECT. А вот при попытке добавить движение с таким же измерением из другого сеанса привел к "таймауту" |
|||
28
H A D G E H O G s
09.04.15
✎
15:48
|
(26) (27) И?
|
|||
29
К_Дач
09.04.15
✎
15:50
|
В режимах совместимости 8.2.16 и 8.2.13 поведение абсолютно точно такое же.
Я для себя делаю такой вывод: если алгоритм предполагает неизменность прочитанных остатков в текущей транзакции, теперь сам всегда явно буду накладывать блокировку по всему прочитанному диапазону ключей. Непонятно только по прежнему, почему ИТС свои статьи про "блокирующее чтение" не отредактирует... |
|||
30
H A D G E H O G s
09.04.15
✎
15:53
|
(29) "В режимах совместимости 8.2.16 и 8.2.13 поведение абсолютно точно такое же. "
Да, так и есть. |
|||
31
К_Дач
09.04.15
✎
15:54
|
Что интересно, кстати, во время брейкпойнта на ЗафиксироватьТранзакцию() я спокойно сделал DELETE всех строк из таблицы итогов регистра. В тоже время, как видно на картинке из (26), новые строки добавляются, а не изменяются старые.
Вывод: всей этой ботвой с блокировками занимается 1С-ный менеджер транзакционных блокировок. А на уровне SQL действительно блокировка снимается в момент окончания выполнения запроса, как и должно быть (для RC) |
|||
32
H A D G E H O G s
09.04.15
✎
15:59
|
(31) Выполни строчку кода
Движения.ТвойРегистр.Записать(); перед ЗафиксироватьТранзакцию() |
|||
33
К_Дач
09.04.15
✎
16:22
|
Вставил перед ЗафиксироватьТранзакцию() вот такой код:
ДокДвижение = Документы.ДокументДвижение.СоздатьДокумент(); ДокДвижение.Дата = ТекущаяДата(); ДокДвижение.СимвольнаяСтрока = "Объект1"; ДокДвижение.Количество = 56789; ДокДвижение.Записать(РежимЗаписиДокумента.Проведение); Останов на ЗафиксироватьТранзакцию(). Попытка сделать SELECT к таблице итогов привела к тому, что запрос просто повис. Запустил еще один сеанс 1С, там попытался прочитать остатки из регистра, получил: "Конфликт блокировок при выполнении транзакции. Lock request time out...." Таймаут СУБД в чистом виде |
|||
34
К_Дач
09.04.15
✎
16:24
|
Все, ну наконец то все теперь понятно. Картинка сложилась.
"Блокирующее чтение" - это они имеют ввиду, когда мы читаем и пишем внутри одной транзакции (верхнего уровня). |
|||
35
MrStomak
09.04.15
✎
16:30
|
(34) Блокирующее чтение - это они как раз имеют ввиду - "позаботься о наложении блокировки сам, если хочешь, чтобы прочитанные тобою данные до конца транзакции не изменились". Ровно о том же пишут в книге 1С:Эксперт.
|
|||
36
fisher
09.04.15
✎
16:33
|
(34) Нифига не понял. Что еще за "блокирующее чтение"? Чтением никак не заблокируешь. Только руками управляемую блокировку воткнуть. И только другой управляемой блокировкой это проверять.
|
|||
37
MrStomak
09.04.15
✎
16:35
|
(36) В автоматическом режиме "Для изменения".
Термин на сайте 1с представлен, тоже считаю что дурацкий. Подразумевается, что нужно прочитать и гарантировать, что прочитанное никто другой больше не прочитает. |
|||
38
fisher
09.04.15
✎
16:36
|
(37) Обсуждение в этой ветке идет в контексте управляемых блокировок.
|
|||
39
Гёдза
09.04.15
✎
16:37
|
(36) заблокируешь от записи
|
|||
40
Гёдза
09.04.15
✎
16:38
|
если в одной транзакции прочитаешь, что в другой изменить уже не сможешь
|
|||
41
fisher
09.04.15
✎
16:39
|
(39) На 8.3 чтение запросом в транзакции от записи не блокирует.
|
|||
42
H A D G E H O G s
09.04.15
✎
16:40
|
(41) В 8.2 тоже.
|
|||
43
Гёдза
09.04.15
✎
16:40
|
(41) это если версионирование включено
|
|||
44
MrStomak
09.04.15
✎
16:41
|
(38) Термин из статьи 1с взяли, что подразумевают я объяснил.
|
|||
45
MrStomak
09.04.15
✎
16:42
|
(43) В управляемом режиме как минимум будет read committed. Это значит, что блокировка на чтение снимется сразу. И на 8.2, и на 8.3.
|
|||
46
fisher
09.04.15
✎
16:42
|
(43) Это на 8.2
А на 8.3 пофигу ваще. Это если на MSSQL. А в постгри и на 8.2 должно быть пофигу. |
|||
47
fisher
09.04.15
✎
16:43
|
(45) Нет. Именно БЛОКИРОВКА в read committed сохраняется до конца транзакции. А вот read committed snapshot блокировки как таковой нет.
|
|||
48
MrStomak
09.04.15
✎
16:45
|
(47) Нет, именно блокировка в read commited снимется сразу после окончания запроса, а в snapshot ее не будет.
|
|||
49
fisher
09.04.15
✎
16:46
|
(48) Нет. В транзакции блокировки сохраняются до конца транзакции. Иначе толку от транзакционных блокировок?
|
|||
50
К_Дач
09.04.15
✎
16:46
|
не блокирует?)))
Вот такой код, запущенный из двух сеансов (в 1-м стоит останов на зафиксироватьтранзакцию ) вызывает таймут во 2-м сеансе в чистом виде: НачатьТранзакцию(); Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | ТестовыйРегистрОстатки.СимвольнаяСтрока, | ТестовыйРегистрОстатки.КоличествоОстаток |ИЗ | РегистрНакопления.ТестовыйРегистр.Остатки КАК ТестовыйРегистрОстатки"; РезультатЗапроса = Запрос.Выполнить(); // Создать объект блокировка данных //БлокировкаДанных = Новый БлокировкаДанных; //ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрНакопления.ТестовыйРегистр"); //ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; //ЭлементБлокировки.ИсточникДанных = РезультатЗапроса; //ЭлементБлокировки.ИспользоватьИзИсточникаДанных("СимвольнаяСтрока", "СимвольнаяСтрока"); //БлокировкаДанных.Заблокировать(); ДокДвижение = Документы.ДокументДвижение.СоздатьДокумент(); ДокДвижение.Дата = ТекущаяДата(); ДокДвижение.СимвольнаяСтрока = "Объект1"; ДокДвижение.Количество = 56789; ДокДвижение.Записать(РежимЗаписиДокумента.Проведение); ЗафиксироватьТранзакцию(); |
|||
51
К_Дач
09.04.15
✎
16:47
|
А вот такой код (все тоже самое) - никаких блокировок не вызывает:
НачатьТранзакцию(); //Запрос = Новый Запрос; //Запрос.Текст = // "ВЫБРАТЬ // | ТестовыйРегистрОстатки.СимвольнаяСтрока, // | ТестовыйРегистрОстатки.КоличествоОстаток // |ИЗ // | РегистрНакопления.ТестовыйРегистр.Остатки КАК ТестовыйРегистрОстатки"; // //РезультатЗапроса = Запрос.Выполнить(); // Создать объект блокировка данных //БлокировкаДанных = Новый БлокировкаДанных; //ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрНакопления.ТестовыйРегистр"); //ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; //ЭлементБлокировки.ИсточникДанных = РезультатЗапроса; //ЭлементБлокировки.ИспользоватьИзИсточникаДанных("СимвольнаяСтрока", "СимвольнаяСтрока"); //БлокировкаДанных.Заблокировать(); ДокДвижение = Документы.ДокументДвижение.СоздатьДокумент(); ДокДвижение.Дата = ТекущаяДата(); ДокДвижение.СимвольнаяСтрока = "Объект1"; ДокДвижение.Количество = 56789; ДокДвижение.Записать(РежимЗаписиДокумента.Проведение); ЗафиксироватьТранзакцию(); |
|||
52
К_Дач
09.04.15
✎
16:48
|
Кому интересно, могу конфу выложить, она простая как 5 копеек...
|
|||
53
H A D G E H O G s
09.04.15
✎
16:48
|
(49) Чтобы не было изменений на время выполнения запроса.
|
|||
54
H A D G E H O G s
09.04.15
✎
16:48
|
(48) прав.
|
|||
55
MrStomak
09.04.15
✎
16:48
|
(49) Ты скажи какой тогда для тебя смысл read committed, если ты описываешь поведение системы на уровне repeatable read, т.е. в терминах 1с - в автоматическом режиме блокировок.
|
|||
56
H A D G E H O G s
09.04.15
✎
16:48
|
(51) Там у тебя есть запись.
|
|||
57
К_Дач
09.04.15
✎
16:50
|
у меня и в (50) и в (51) есть запись. Только в (51) чтения нет, а в (50) - есть.
Для (50) возникает таймаут у 2-го сеанса Для (51) ничего не происходит, блокировок нет |
|||
58
fisher
09.04.15
✎
16:50
|
(55) Ты прав. Попутал.
|
|||
59
H A D G E H O G s
09.04.15
✎
16:52
|
(57) В первом случае, когда есть запрос - этот запрос пытается установить блокировку на время выполнения запроса.
У тебя 8.2, не снапшот. |
|||
60
fisher
09.04.15
✎
16:53
|
(52) Выложи. Я на postgres проверю.
|
|||
61
fisher
09.04.15
✎
16:54
|
(59) Вроде говорил, что snapshot.
|
|||
62
H A D G E H O G s
09.04.15
✎
16:55
|
(61) Ну ничто не остается постоянным.
|
|||
63
К_Дач
09.04.15
✎
16:56
|
(59) не 8.3, ты хотел сказать, да - в режиме совместимости 8.2.
И вот в этом режиме возникает таймаут, если параллельно выполнить код из (50). Для 8.3 чисто, без совместимости - ничего не будет Я это к чему говорю, статьи на ИТС эти - для 8.2 написаны |
|||
64
MrStomak
09.04.15
✎
16:57
|
(63) В статье не написано, что чтение блокирует. Там просто использован сбивающий тебя с толку термин "блокирующее чтение"
|
|||
65
H A D G E H O G s
09.04.15
✎
16:57
|
(63) Ну ты понял, почему так?
|
|||
66
К_Дач
09.04.15
✎
16:57
|
(61) я переключал в совместимость с 8.2, чтобы проверить поведение для Read_Commited
|
|||
67
К_Дач
09.04.15
✎
16:58
|
(65) да, да, теперь то понятно все. Теперь и твои предыдущие посты стали понятны
|
|||
68
MrStomak
09.04.15
✎
17:00
|
(67) Для контроля остатков что на 8.3 (снэпшот), что на 8.2(управляемые), что на 8.0 (автоматические) всегда нужно использовать инструменты, чтобы заблокировать чтение этих данных. Иначе будет косяк.
|
|||
69
К_Дач
09.04.15
✎
17:03
|
(60) из дома вечером выложу, на работе доступ закрыт к файлобменникам, а гугл-диска у меня нет
|
|||
70
fisher
09.04.15
✎
17:03
|
(63) Не забывай про другие СУБД. В postgres и на 8.2 ничего не будет. По идее :) А вот про oracle не скажу. Он же вроде как MSSQL хитрый. И так и эдак может.
|
|||
71
fisher
09.04.15
✎
17:04
|
(69) Уже не надо.
|
|||
72
К_Дач
09.04.15
✎
17:06
|
Ладно, всем большое спасибо. Продрался наконец-таки сквозь термины и все такое
|
|||
73
fisher
09.04.15
✎
17:07
|
А IBM DB2 и на 8.3 должен себя вести как в (50). Это вроде чистый блокировочник.
|
|||
74
vi0
09.04.15
✎
17:25
|
(73) здесь все четко описано
http://its.1c.ru/db/v83doc#bookmark:dev:TI000000533 |
|||
75
rsv
09.04.15
✎
17:35
|
(0) Да... любой отчет в 1С работает через (nolock) так штаааа чтение незакомиченных данных - это нормально.
|
|||
76
rsv
09.04.15
✎
17:37
|
+(75) А так копать тему Уровни изоляции транзакций т.к. блокировки и прочее это производные от уровня оных.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |