54:10 - "произошел deadlock". Строго говоря, на уровне базы данных, да и по определению - deadlock-а здесь нет. Deadlock подразумевает, что заблокированы обе транзакции. А у нас здесь заблокирована только вторая транзакция. Первая - просто простаивает. Tx1 выполнила "select where id = 1 for update" и заблокировала строку. Сама транзакция не ждет в очереди ожидания на блокировку. Она ей владеет. Но дальше в коде мы СИНХРОННО стартуем вторую транзакцию Tx2. Tx2 тоже делает "select where id = 1 for update", и вот она встает в очередь на ожидание блокировки. Tx2 заблокирована, а Tx1 - нет. Она просто не может выполняться из-за криво написанного кода. По поведению - да, это похоже на дедлок. Но это ХУЖЕ чем дедлок. Дело в том, что для реального дедлока нужно как минимум две транзакции и как минимум два ресурса (две строки). Tx1: UPDATE accounts set amount = amount + 100.0 where id = 2; UPDATE accounts set amount = amount + 100.0 where id = 1; Tx2: UPDATE accounts set amount = amount + 100.0 where id = 1; UPDATE accounts set amount = amount + 100.0 where id = 2; Вот здесь будет дедлок. И PostgreSQL автоматом его задетектит и устранит. СУБД выкинет ошибку, и в приложении ее можно будет отловить. А в примере в видео - не дедлок. Там просто долго (потенциально бесконечно, если не установили таймаут) выполняющаяся Tx1, и Tx2, которая ее ждет. И такие ситуации PostgreSQL автоматом не разрулит. Можно настроить логирование долгих локов (В самом PostgreSQL), и тогда в логи будет спам сообщений о том, что транзакция слишком долго держит лок.
На уровне БД дедлока нет. Но на уровне системы есть. Один поток захватил запись в БД и ждет окончания работы второй транзакции. Вторая транзакция ждет, когда отпустят запись из БД, и не завершает работы. Ни одна из транзакций не может прервать другую. На программном уровне все четыре условия дедлока соблюдены. БД-шечка отвалит одну из транзакций по таймауту. Если бы таймаута не было, то так бы и висели.
@@hlystomv тут вопрос семантики, но вроде как простой и ожидание это разные вещи, и дедлок требует именно ожидания. И в данном случае из-за кривого кода получается что вторая транзакция действительно ждёт пока отпустится блокировка, а вот первая не ждёт а находится в состоянии простоя потомучто транзакции запущены синхронно [тут самое кривое место в коде на мой взгляд], поэтому если придираться до самой последей буквы) то получившкюся картину нельзя назвать дедлоком
Это видео надо дать посмотреть всем любителям побыть умными на собесе и поспрашивать кандидата по поводу транзакций. Даже если в теории кандидат и ответит, не факт что на практике это всё будет работать как в теории. У нас тоже был один такой, кто любил засыпать кандидатов вопросами по транзакциям, дабы снизить их ожидания по ЗП. Зато когда были баги, сам лез в гугл и удивлялся новому по теме транзакций в спринге и хибере. ЗП же однако получал как за двоих, так как на собесах сбивал ЗП кандидатам. Вот такие есть токсичные недоучки в лидах.
@@irinav3776 Довольно часто ) Так что учите транзакции и конкурентный доступ. Если вы их очень хорошо освоите, то любой собес будет по плечу. Ну и в работе потом будет меньше нежданов.
на такие офферы потом лучше и не соглашаться - мне наоборот повысили зп после оффера, 4 года работаю в это компании. на собеседовании обе стороны смотрят - готовы ли они вместе работать.
54:05. Советую разобраться с темой дедлоков и не путать слушателей! Дедлока тут нет, тут обычная ожидающая блокировка. У вас нет взаимной блокировки ресурсов. Первая транзакция не заблокирована ожиданием возможности заблокировать новый ресурс, а вторая при этом не заблокировала ресурсы, необходимые первой. И причем тут вообще таймаут на запросы и дедлок? У постгреса есть свойство, где указывается таймаут именно для дедлоков.
Менеджер трат - самое бесполезное что есть в банковских приложениях. Один из банков мне каждый месяц сообщал что 90% моих расходов уходит на путешествия и развлечения. Я обрадовался, да я ж счастливый человек, правда путешествия это были поездки на метро до работы, а развлечения - обед рядом с работой.
49:00 Какой бред. Уровень Serializable уже блокирует данные при чтении, так как он решает проблему неповторяемого чтения. Какая еще блокировка?! Блокировки используют тогда, когда хотят вручную управлять уровнями изоляции, при этом уровень изоляции СУБД ставят на возможный минимум. Ну ладно, потом докладчик догадался проверить уровень. Подготовка материала и понимание докладчиком темы - на низком уровне, как будто сам только вчера разобрался с транзакциями.
Чувак похож на того над кем он там смеялся из стаковерфлоу, в разрезе чтобы избежать дедлока на транзакции что нужно выбрать ту же строку но другим методом. Дядь, ты серьезно???? Она у тебя уже залочена в базе, але Да и как бы коль не хочешь чтобы были дэдлоки то будь добр в нативку и nowait или skip locked
Спасибо за доклад! Хорошо разобраны основные ошибки при работе с транзакциями. Несмотря на то что я хорошо знаком с тразакциями, некоторые нюансы я взял на заметку. Единственное что хотел отметить, следует быть осторожным с запуском CompletableFeature.runAsync(...), т.к. паралельные потоки съедают пул подключений к БД, а это в нагруженных приложениях это дефицитный ресурс. Иногда лучше сохранять в последовательных транзакциях, а лучше батчем в одной транзакции.
Очень полезный материал, спасибо ! Единственное, что непонятно На 13.00 минуте Никита говорит про dirty read(про откат транзакции), а на примере показывает lost update(чтение одного и того же ресурса), действительно read committed решат lost update, но все же это путает :)
Вот что бывает, когда полагаешься на магию спринга. Вместо кода пробуешь заклинания одно за другим.Все по Е.Борисову. Точнее сказать, костыльный подход теперь не на уровне кода, а на уровне настройки аннотаций
Отличный доклад, спасибо ! 😊 По поводу проблемы с сохранением слишком большого количества записей в историю при использовании метода @Recover, кажется мне удалось понять почему он работал не так как надо в докладе При использовании @Recover - сначала выполняются все попытки в Retryable, и только потом выполняется Recover метод, из-за этого в таблицу с историей попали дополнительные записи
14:33. Уважаемый докладчик, вы перепутали все уровни изоляции транзакций. Вашу проблему (Lost Update ) решает уровень изоляции Read uncommitted. Именно для этого он и предназначен. Уровень Read committed так же решает эту проблему + решает проблему Uncommitted Dependency Problem (Грязное чтение). Repeatable read это еще более строгий уровень изоляции и в данном примере он не нужен. Более того, ваш пример не демонстрирует этот уровень. Вы рассуждаете об уровнях изоляции, применимых конкретно к PostgreSQL, но не отмечаете это в докладе. Лучше было бы рассказать про стандартное описание уровней, а потом уже отметить особенности PostgreSQL. Ну и поработать с примерами получше. У вас не заработал изначально RC так как параллельные транзакции считывают одни и те же данные и инкриментируют их в результате получается результат меньше, чем должен быть. Для решения этой проблемы нужна блокировка данных уже при чтении, а не только при записи. Поэтому уровень RR и заработал, но вы объяснили и показали совсем другие проблемы.
1:01:14 а что если ООМ произойдет после коммита в БД и до коммита оффсета в кафку? Так же тоже может произойти даже если мы повесим @Transactional на консьюмера?
@Transactional не сделает за нас распределенную транзакцию, к сожелению :) После повторного поднятия приклада произойдет повторное обновление значения в БД, если отсутствует механизм дедубликации. Можно накрутить лайков, эксплуатируя OOM.
@@kotbajan да, верно, поэтому пример с ООМ из доклада видится не очень удачным, в том смысле что предложенное решение от последствий ООМ спасет не всегда)
@@cheese054 , твоя правда, в этом месте доклада есть сомнительное утверждение. Скорее всего, оно основано на том, что ООМ случается обычно в прикладном коде. Если совместить границы Listener и Transactional, то между коммитами будет только хорошо оптимизированный библиотечный код, где меньше вероятность получить такую проблему.
Спасибо, доклад очень интересный. Работаю с БД очень давно, более 20 лет. 13:20 - смутил кейс, т.к. постоянно работаю в таких условиях, но не сталкивался с ситуацией перетирания значений. Решил проверить при ReadCommitted. Вторая транзакция на моменте update повисает и ждет пока отпустит первая. Такая ситуация при RC допустима только, если T1 закомититься после select T2 и при условии чтения значения в переменную. Если update будет value+=int4 - то тут всё будет ок. При Repeatable read - так же вторая транзакция на update подвисает (ждет блокировки - завершения первой). Может что не так делаю? --connect 1 select current_setting('transaction_isolation') -- read committed create table test_table ( fkey int4 not null, fvalue int4 not null, constraint pk_test_table primary key(fkey) ); insert into test_table(fkey, fvalue) values (3,5); start transaction; select * from test_table where fkey=3; update test_table set fvalue=fvalue+6 where fkey = 3; -- connect 2 start transaction; select * from test_table where fkey=3; update test_table set fvalue=fvalue+3 where fkey = 3; -- тут висим до завершения транзакции с connect 1 commit
Он там все напутал в своем докладе. У него проблема в том, что транзации сначала читают данные, а потом делают инкримент. Ему нужна блокировка на уровне чтения, поэтому он ставит RR, но объясняет это совсем неправильно с кривыми примерами.
если задача стоит в инкременте поля в табличке, можно выкинуть к чертям ORM и написать простенький sql update likes set count = count + 1 и не надо так загоняться с блокировками транзакциями и прочими штуками ))
да но тут говнокод нарушает сингл респонсибилити + делает ересь сперва деля селект а потом апдейт и трансакция оборачивается сначала вокруг селект потом после закрытияселекта вокруг апдейта и изза этой тупости мы и получили такой кривой доклад который чинит баг которого нет)
Никита, при упоминании аномалий, вы не упомянули про LOST UPDATE. Эта аномалия у вас в примере собственно и возникает и REPEATABLE READ ее решает в PostgreSQL
@@dmitriys2190 SQL стандарт запрещает Lost Update для любого уровня изоляции, но в Постгре автоматическое обнаружение Lost Update работает только на Repeatable Read
1:01:30 ну вот эта магия лишь заметает под ковер реальные проблемы, создавая ложное ощущние надежности. Скоординированно закоммитить в два ресурса -- базу и кафку, требует дополнительных танцев с бубном по поводу включения two-phase commit.
@@ЕвгенийАлексеев-о9э могу ошибаться, но вроде как был. Даже доку по этой теме видел. Внутренне эмулируется при помощи дополнительных сообщений типа commit/rollback.
магия спринта что он вроде как сделан для удобства типа фреймворк, но чтобы им пользоваться гарантировано надежно нужно знать кишочки это имхо в корне неправильно.
постоянно упоминается что какой-то лак рабирается. Спасибо Google нашел Kafka consumer lag gives the offset difference between last produced message and the last consumed message. If the rate of production is higher than the rate of consumption then consumer groups will exhibit lag Но так и не понимаю как он может разгребаться/разгружаться.
Ф Кафке собирается очередь сообщений - а cansumer их вычитывает и обрабатывает в логике приложения. Если лаг (очередь) разгребается медленно, значит что то в коже не так
В джаве как всегда - миллион аннотаций во всех местах, странные ошибки, названия методов в строках и прочая неявщина и магия, еще кафка теперь, ну чтобы наверняка. Автор почему-то считает, что select for update более опасен, чем все его предыдущие манипуляции, а это совершенно не так, почти все, что тут показано приведет к повреждению нижних конечностей.
использование буфера в виде kafka + batch + минимизация конкурентного обращения к одним и тем же записям минимизируют накладные расходы на выполнение кода, но максимизируют расходы на его написание
Программируй на примере" Автоматов жизнъ~игра" Алгоритмы их на деле " Разновекторн.иногда.. Аналит.вот направлений" Принцип хода у фигур " Где скачком а где линейней" Глайдр выстроит структур?!.👨👩👧👧🖐
Падает т.к. конкурентные транзакции пытаются обновить одни и те же записи в БД. Retry использовался для того чтобы повторить попытку записи. Слушал в пол уха, могу ошибаться, но скорее всего все транзакции использовали паттерн записи x+=y. Т.е. мы должны сначала прочесть текущее значение, потом к нему прибавить что-то, а потом записать итоговое значение обратно в БД. И вот тут то может случиться так что то значение к которому мы прибавляли число, уже не актуально, следовательно нам нужно откатить текущую транзакию, но можно сделать еще одну попытку (повторить цикл, чтение - изменение - запись).
@@levaryazan Не должно быть ошибок при вставке. Повторы это погрев процессора. Можно сделать insert и периодически обновлять основной счетчик. А можно применить Kafka stream и минимизировать количество вставляемых данных. Много вариантов, главное на процессоре чай не заваривать.
@@erikivanov1 Пример со счетчикам лайков был выбран только ради наглядности отображения проблемы и одного из возможных решений при помощи транзакции. В реальной ситуации и правда есть большое количество способов решения проблемы, в том числе и ключи сообщений кафки, и как следствие последовательное вычитываени сообщений по одному id из партиции.
@Erik Ivanov , выложите пожалуйста свой доклад - как должно было быть по вашему сценарию. Мне было бы очень интересно посмотреть, да и не только мне , как кажется.
54:10 - "произошел deadlock".
Строго говоря, на уровне базы данных, да и по определению - deadlock-а здесь нет.
Deadlock подразумевает, что заблокированы обе транзакции.
А у нас здесь заблокирована только вторая транзакция. Первая - просто простаивает.
Tx1 выполнила "select where id = 1 for update" и заблокировала строку. Сама транзакция не ждет в очереди ожидания на блокировку. Она ей владеет.
Но дальше в коде мы СИНХРОННО стартуем вторую транзакцию Tx2.
Tx2 тоже делает "select where id = 1 for update", и вот она встает в очередь на ожидание блокировки.
Tx2 заблокирована, а Tx1 - нет. Она просто не может выполняться из-за криво написанного кода.
По поведению - да, это похоже на дедлок. Но это ХУЖЕ чем дедлок.
Дело в том, что для реального дедлока нужно как минимум две транзакции и как минимум два ресурса (две строки).
Tx1:
UPDATE accounts set amount = amount + 100.0 where id = 2;
UPDATE accounts set amount = amount + 100.0 where id = 1;
Tx2:
UPDATE accounts set amount = amount + 100.0 where id = 1;
UPDATE accounts set amount = amount + 100.0 where id = 2;
Вот здесь будет дедлок. И PostgreSQL автоматом его задетектит и устранит. СУБД выкинет ошибку, и в приложении ее можно будет отловить.
А в примере в видео - не дедлок. Там просто долго (потенциально бесконечно, если не установили таймаут) выполняющаяся Tx1, и Tx2, которая ее ждет.
И такие ситуации PostgreSQL автоматом не разрулит.
Можно настроить логирование долгих локов (В самом PostgreSQL), и тогда в логи будет спам сообщений о том, что транзакция слишком долго держит лок.
спасибо за комментарий, очень полезно
На уровне БД дедлока нет. Но на уровне системы есть. Один поток захватил запись в БД и ждет окончания работы второй транзакции. Вторая транзакция ждет, когда отпустят запись из БД, и не завершает работы. Ни одна из транзакций не может прервать другую. На программном уровне все четыре условия дедлока соблюдены. БД-шечка отвалит одну из транзакций по таймауту. Если бы таймаута не было, то так бы и висели.
@@hlystomv тут вопрос семантики, но вроде как простой и ожидание это разные вещи, и дедлок требует именно ожидания. И в данном случае из-за кривого кода получается что вторая транзакция действительно ждёт пока отпустится блокировка, а вот первая не ждёт а находится в состоянии простоя потомучто транзакции запущены синхронно [тут самое кривое место в коде на мой взгляд], поэтому если придираться до самой последей буквы) то получившкюся картину нельзя назвать дедлоком
41 минута - вот почему лучше всегда отставлять явный save; если какая-то логика выполняется, то пусть она будет явной
лучше не использовать орм
@@klerg321 а что тогда использовать?
@@12453656 не слушать подобных экспертов, а использовать то, чего требует задача :)
согласен, тоже когда код идет на ревью - говорю, чтобы писали явно save - это намного удобнее при чтении кода
вот почему нужно писать тесты, а дергать save() который вызывает мерж сущности это лишний оверхед, причем рекурсивный
Это видео надо дать посмотреть всем любителям побыть умными на собесе и поспрашивать кандидата по поводу транзакций. Даже если в теории кандидат и ответит, не факт что на практике это всё будет работать как в теории.
У нас тоже был один такой, кто любил засыпать кандидатов вопросами по транзакциям, дабы снизить их ожидания по ЗП. Зато когда были баги, сам лез в гугл и удивлялся новому по теме транзакций в спринге и хибере. ЗП же однако получал как за двоих, так как на собесах сбивал ЗП кандидатам. Вот такие есть токсичные недоучки в лидах.
Часто встречаются такие спрашивающие? Надеюсь что хоть не в каждой первой конторе))
@@irinav3776 Довольно часто ) Так что учите транзакции и конкурентный доступ. Если вы их очень хорошо освоите, то любой собес будет по плечу. Ну и в работе потом будет меньше нежданов.
@@irinav3776 очень часто и это на джунских собесах
на такие офферы потом лучше и не соглашаться - мне наоборот повысили зп после оффера, 4 года работаю в это компании. на собеседовании обе стороны смотрят - готовы ли они вместе работать.
54:05. Советую разобраться с темой дедлоков и не путать слушателей! Дедлока тут нет, тут обычная ожидающая блокировка. У вас нет взаимной блокировки ресурсов. Первая транзакция не заблокирована ожиданием возможности заблокировать новый ресурс, а вторая при этом не заблокировала ресурсы, необходимые первой.
И причем тут вообще таймаут на запросы и дедлок? У постгреса есть свойство, где указывается таймаут именно для дедлоков.
Круто что доклад затрагивает локи, изоляции и т д. Спасибо!
Молодой Адам Сендлер жестко пояснил про транзакции
Менеджер трат - самое бесполезное что есть в банковских приложениях. Один из банков мне каждый месяц сообщал что 90% моих расходов уходит на путешествия и развлечения. Я обрадовался, да я ж счастливый человек, правда путешествия это были поездки на метро до работы, а развлечения - обед рядом с работой.
49:00 Какой бред. Уровень Serializable уже блокирует данные при чтении, так как он решает проблему неповторяемого чтения. Какая еще блокировка?! Блокировки используют тогда, когда хотят вручную управлять уровнями изоляции, при этом уровень изоляции СУБД ставят на возможный минимум. Ну ладно, потом докладчик догадался проверить уровень.
Подготовка материала и понимание докладчиком темы - на низком уровне, как будто сам только вчера разобрался с транзакциями.
Чувак похож на того над кем он там смеялся из стаковерфлоу, в разрезе чтобы избежать дедлока на транзакции что нужно выбрать ту же строку но другим методом. Дядь, ты серьезно???? Она у тебя уже залочена в базе, але
Да и как бы коль не хочешь чтобы были дэдлоки то будь добр в нативку и nowait или skip locked
Сейвпойнты не помешали бы в докладе - когда пример не работает, можно из гита свичнуться на заренее закоммиченный пример)
Лучше уже ветки создавать на каждый пример
Спасибо за доклад!
Хорошо разобраны основные ошибки при работе с транзакциями.
Несмотря на то что я хорошо знаком с тразакциями, некоторые нюансы я взял на заметку.
Единственное что хотел отметить, следует быть осторожным с запуском CompletableFeature.runAsync(...), т.к. паралельные потоки съедают пул подключений к БД, а это в нагруженных приложениях это дефицитный ресурс. Иногда лучше сохранять в последовательных транзакциях, а лучше батчем в одной транзакции.
Лучшая оптимизация транзакции это отсутствие транзакции. В данном примере проблема решается нативным sql атомарным инкрементом.
даже страшно приставить код в ентерпрайз проекте такой
@@ВасилийГоловко-д9ино делать ретраи или блокировки(а как показано, пессимистичная ещё и к локу может привести) - тоже такое себе
Классное видео! Спасибо большое за ваш труд)
Спасибо, очень интересный и приятный доклад!
Очень полезный материал, спасибо !
Единственное, что непонятно
На 13.00 минуте Никита говорит про dirty read(про откат транзакции), а на примере показывает lost update(чтение одного и того же ресурса), действительно read committed решат lost update, но все же это путает :)
Да, с уровнями и примерами у него все напутано и видно, что он сам не понимает, о чем говорит
Спасибо за доклад, очень полезная тема была разобрана. Продолжайте в том же духе
Вот что бывает, когда полагаешься на магию спринга. Вместо кода пробуешь заклинания одно за другим.Все по Е.Борисову. Точнее сказать, костыльный подход теперь не на уровне кода, а на уровне настройки аннотаций
Отличный доклад, спасибо ! 😊
По поводу проблемы с сохранением слишком большого количества записей в историю при использовании метода @Recover, кажется мне удалось понять почему он работал не так как надо в докладе
При использовании @Recover - сначала выполняются все попытки в Retryable, и только потом выполняется Recover метод, из-за этого в таблицу с историей попали дополнительные записи
14:33. Уважаемый докладчик, вы перепутали все уровни изоляции транзакций. Вашу проблему (Lost Update ) решает уровень изоляции Read uncommitted. Именно для этого он и предназначен. Уровень Read committed так же решает эту проблему + решает проблему Uncommitted Dependency Problem (Грязное чтение). Repeatable read это еще более строгий уровень изоляции и в данном примере он не нужен. Более того, ваш пример не демонстрирует этот уровень.
Вы рассуждаете об уровнях изоляции, применимых конкретно к PostgreSQL, но не отмечаете это в докладе. Лучше было бы рассказать про стандартное описание уровней, а потом уже отметить особенности PostgreSQL. Ну и поработать с примерами получше.
У вас не заработал изначально RC так как параллельные транзакции считывают одни и те же данные и инкриментируют их в результате получается результат меньше, чем должен быть. Для решения этой проблемы нужна блокировка данных уже при чтении, а не только при записи. Поэтому уровень RR и заработал, но вы объяснили и показали совсем другие проблемы.
В Postgres нету уровня read uncommitted, поэтому для устранения lost updates используем либо repeatable reads, либо select for update.
1:01:14 а что если ООМ произойдет после коммита в БД и до коммита оффсета в кафку? Так же тоже может произойти даже если мы повесим @Transactional на консьюмера?
@Transactional не сделает за нас распределенную транзакцию, к сожелению :) После повторного поднятия приклада произойдет повторное обновление значения в БД, если отсутствует механизм дедубликации. Можно накрутить лайков, эксплуатируя OOM.
@@kotbajan да, верно, поэтому пример с ООМ из доклада видится не очень удачным, в том смысле что предложенное решение от последствий ООМ спасет не всегда)
@@cheese054 , твоя правда, в этом месте доклада есть сомнительное утверждение. Скорее всего, оно основано на том, что ООМ случается обычно в прикладном коде. Если совместить границы Listener и Transactional, то между коммитами будет только хорошо оптимизированный библиотечный код, где меньше вероятность получить такую проблему.
Вставка о СТО 6:51 не подходит: согласно СТО ваши события могут произойти одновременно, т.к. события у вас не разделены в пространстве (одна БД)
Смотря на код сразу возникает мыль - почему не сделать через update с условием? Все проблемы из-за хибернейта
Спасибо, доклад очень интересный. Работаю с БД очень давно, более 20 лет.
13:20 - смутил кейс, т.к. постоянно работаю в таких условиях, но не сталкивался с ситуацией перетирания значений. Решил проверить при ReadCommitted. Вторая транзакция на моменте update повисает и ждет пока отпустит первая. Такая ситуация при RC допустима только, если T1 закомититься после select T2 и при условии чтения значения в переменную. Если update будет value+=int4 - то тут всё будет ок. При Repeatable read - так же вторая транзакция на update подвисает (ждет блокировки - завершения первой).
Может что не так делаю?
--connect 1
select current_setting('transaction_isolation') -- read committed
create table test_table (
fkey int4 not null,
fvalue int4 not null,
constraint pk_test_table primary key(fkey)
);
insert into test_table(fkey, fvalue) values (3,5);
start transaction;
select * from test_table where fkey=3;
update test_table set fvalue=fvalue+6 where fkey = 3;
-- connect 2
start transaction;
select * from test_table where fkey=3;
update test_table set fvalue=fvalue+3 where fkey = 3; -- тут висим до завершения транзакции с connect 1
commit
в твоем примере все ништяк )) за исключением одного )) орм делает не так как ты описал ) он делает update test_table set fvalue=10 where fkey = 3;
И тут проблема как раз в том, что докладчик слишком упростил написание в примерах и сделал это зря - поменял смысл.
@@KavboiHaggis поэтому иногда фреймворку нужно помочь, и написать запрос ручками
Он там все напутал в своем докладе. У него проблема в том, что транзации сначала читают данные, а потом делают инкримент. Ему нужна блокировка на уровне чтения, поэтому он ставит RR, но объясняет это совсем неправильно с кривыми примерами.
Слабый доклад. С множеством ошибок. Автор плохо подготовился или сам не до конца понимает предмет.
Большое спасибо за доклад, крайне полезный при подготовке к собеседованиям!
😊 доклад супер: всё наглядно и хорошее аудио сопровождение скринкаста.
Для Junior и Middle ребят будет сверх познавательно.
если задача стоит в инкременте поля в табличке, можно выкинуть к чертям ORM и написать простенький sql update likes set count = count + 1 и не надо так загоняться с блокировками транзакциями и прочими штуками ))
а здесь не нужна будет блокировка или она автоматом?
@@maksimus.ssirotkin1124 оно все само разрулит при таком запросе
Разве методы интерфейса repository по умолчанию не @Transactional ?
да но тут говнокод нарушает сингл респонсибилити + делает ересь сперва деля селект а потом апдейт и трансакция оборачивается сначала вокруг селект потом после закрытияселекта вокруг апдейта и изза этой тупости мы и получили такой кривой доклад который чинит баг которого нет)
Разобрались почему Retrayble не заработал?
Если кому-то надо более понятное объяснение с примерами: th-cam.com/video/ZVYzVqqVrms/w-d-xo.htmlsi=lXRST4tRp2VyMsoo
о посмотрю, а то после этого видео еще больше запутался
Стоит лучше готовиться к докладам, чтобы не тратить время слушателей впустую
Никита, при упоминании аномалий, вы не упомянули про LOST UPDATE. Эта аномалия у вас в примере собственно и возникает и REPEATABLE READ ее решает в PostgreSQL
LOST UPDATE решает уровень Read uncommitted. Докладчик вообще все напутал. REPEATABLE READ решает проблему Inconsistent Analysis Problem
Ну как решает - postgres кидает исключение, как и показал Никита. Поэтому он поставил ретраи, которые почти решили проблему
@@dmitriys2190 SQL стандарт запрещает Lost Update для любого уровня изоляции, но в Постгре автоматическое обнаружение Lost Update работает только на Repeatable Read
Дискуссионную зону тож можно было выложить
Вчера посмотрел видео
Сегодня был собес и 50% времени обсуждали транзакции
Легко прошёл)
Спасибо каналу
По - моему данный доклад ? только путает
Очень плохое объяснение
Хорош))
27:00 - циркулярная зависимость вовсе не обязательна. Можно лениво подружать через сеттер или поле.
никогда не слышал, чтобы называли циркулярная зависимость. От слова циркулярка? циклическая же правильно
Отличный содержательный доклад, спасибо!
Уровень доклада "для начинающих", этот кейс на собеседованиях спрашивают
именно этим доклад и ценен
Доклад не плохой, правда спикер много информации не договаривает или не раскрывает для большего понимания, как мне лично показалось
так мелко ничего не видно
можно было уменьшить место неиспользованное
1:01:30 ну вот эта магия лишь заметает под ковер реальные проблемы, создавая ложное ощущние надежности. Скоординированно закоммитить в два ресурса -- базу и кафку, требует дополнительных танцев с бубном по поводу включения two-phase commit.
У кафки нет такого механизма
@@ЕвгенийАлексеев-о9э могу ошибаться, но вроде как был. Даже доку по этой теме видел. Внутренне эмулируется при помощи дополнительных сообщений типа commit/rollback.
магия спринга, явных ошибок нет, причину проблему локализовать очень трудно
магия спринта что он вроде как сделан для удобства типа фреймворк, но чтобы им пользоваться гарантировано надежно нужно знать кишочки это имхо в корне неправильно.
Одного не понял: зачем отдельно сохранять лайки и историю?
для примера было придумано просто. но докладчик больше запутал, чем объяснил
очень доступно, спасибо. уже вижу легаси, в котором неправильно расставлены аннотации у нас на проекте. а что всё таки было с рекавером?
Nikolay Panyukov выше ответил.
Recover срабатывает только после того как все попытки в max_attemps отработают
постоянно упоминается что какой-то лак рабирается. Спасибо Google нашел
Kafka consumer lag gives the offset difference between last produced message and the last consumed message. If the rate of production is higher than the rate of consumption then consumer groups will exhibit lag
Но так и не понимаю как он может разгребаться/разгружаться.
Ф Кафке собирается очередь сообщений - а cansumer их вычитывает и обрабатывает в логике приложения. Если лаг (очередь) разгребается медленно, значит что то в коже не так
Вывод: уровень доклада и понимания автором темы - школьник.
Можете пояснить почему такой вердикт?
В джаве как всегда - миллион аннотаций во всех местах, странные ошибки, названия методов в строках и прочая неявщина и магия, еще кафка теперь, ну чтобы наверняка. Автор почему-то считает, что select for update более опасен, чем все его предыдущие манипуляции, а это совершенно не так, почти все, что тут показано приведет к повреждению нижних конечностей.
есть альтернативы получше?
select for update либо update set value = value + 1@@ВиталийГудзь-г4ъ
про блокировки на 39:21
Я так и не понял, какой же способ позволяет все сохранить с минимальными накладными расходами?..
использование буфера в виде kafka + batch + минимизация конкурентного обращения к одним и тем же записям минимизируют накладные расходы на выполнение кода, но максимизируют расходы на его написание
@@kotbajan Здесь не до конца понял как это сделать.?
у вас так же не компилируется код с репозитория? я знаю как это решить, просто вопрос зачем такое коммитить \=
Рассказывай)
@@savoook накидать немного дополнительных зависимостей и убрать redis conf
а где ссылка на github?
Здравствуйте! Ссылка на github есть в презентации. Скачать презентацию можно по ссылке из описания.
Программируй на примере"
Автоматов жизнъ~игра"
Алгоритмы их на деле "
Разновекторн.иногда..
Аналит.вот направлений"
Принцип хода у фигур "
Где скачком а где линейней"
Глайдр выстроит структур?!.👨👩👧👧🖐
Requires_New, автор не знает основные пропогейшн!
Кансюмеры. 😀
красава
Непонятно, почему выполняемая транзакция все время падает? Зачем использовать Retryable?
Падает т.к. конкурентные транзакции пытаются обновить одни и те же записи в БД. Retry использовался для того чтобы повторить попытку записи. Слушал в пол уха, могу ошибаться, но скорее всего все транзакции использовали паттерн записи x+=y. Т.е. мы должны сначала прочесть текущее значение, потом к нему прибавить что-то, а потом записать итоговое значение обратно в БД. И вот тут то может случиться так что то значение к которому мы прибавляли число, уже не актуально, следовательно нам нужно откатить текущую транзакию, но можно сделать еще одну попытку (повторить цикл, чтение - изменение - запись).
Один из худших докладов, которые довелось смотреть(
А жалко, тема то очень важная
Как много гемора, может лучше не юзать Spring или вообще без JAVA обойтись?
Назад на c?
😂
Позор. Подход не верен в принцепе.
А какой верен и где можно почитать?
@@levaryazan Не должно быть ошибок при вставке. Повторы это погрев процессора. Можно сделать insert и периодически обновлять основной счетчик. А можно применить Kafka stream и минимизировать количество вставляемых данных. Много вариантов, главное на процессоре чай не заваривать.
@@erikivanov1 Пример со счетчикам лайков был выбран только ради наглядности отображения проблемы и одного из возможных решений при помощи транзакции. В реальной ситуации и правда есть большое количество способов решения проблемы, в том числе и ключи сообщений кафки, и как следствие последовательное вычитываени сообщений по одному id из партиции.
@Erik Ivanov , выложите пожалуйста свой доклад - как должно было быть по вашему сценарию. Мне было бы очень интересно посмотреть, да и не только мне , как кажется.
Нет здесь никакого позора, очевидно же, что разбирается проблема конкурентного обновления состояние базы, а не как лайки считать. Доклад прекрасен.
Cqrs, не не слышал