Я не говорю, что вы говорите, что локи не нужны. Вы говорите, что локи не нужны до чтения данных. Я говорю, что нужны.
Только на момент изменения данных.
А какой смысл записывать данные, которые некорректно рассчитаны?
Когда работает в репозитории - лочите на время работы все объекты с которыми работаете?
В очередной раз повторяю - я не предлагаю блокировать данные на часы и дни.
а потенциальные конфликты решаете потом при мерже?
Решение конфликтов это ручное действие. Если вы хотите разбирать и исправлять некорректные данные в миллионах строк в базе вручную, то конечно можно не использовать локи.
А, ну если с блокировкой тогда другое дело конечно. Только если никто не вклинивался, то и блокировка от изменений в начале процесса никому не помешает. А если вклинивался, то повторять всё заново создаст бо́льшую нагрузку на сервер, чем просто ожидание одного из процессов, и в условиях большо́й нагрузки вообще может быть невозможным, потому что постоянно будет кто-то вклиниваться.
Просто отметил что архитектура и логика обработки была таковой, чтобы локи были короткие по времени. Иначе начинаются проблемы со взаимными блокировками записей.
Вот я и объяснил, что "взаимные блокировки" появляются не магически сами по себе, а из-за разного порядка блокировки. Один процесс блокирует записи в порядке "1, 2", другой "2, 1". Поэтому надо использовать одинаковый порядок.
Потому что в реальной жизни цепочка "прочитали - проверили - рассчитали - сохранили" может по времени занимать несколько часов. Или дней.
Нет, приложения так не работают. На веб-запросы от пользователей вида "хочу перевести деньги" вообще обычно ставится таймаут несколько десятков секунд. Я же объяснил, что говорю про обработку одного запроса в приложении, почему вы переводите речь на бизнес-процессы? Если ваш бизнес-процесс занимает несколько дней, там будет несколько запусков нескольких разных приложений по веб-запросу или по расписанию с несколькими разными транзакциями БД. Я говорю про один конкретный запуск. Нафига держать блокировку между запусками?)
Поэтому и вводится система холдов. Где в одной короткой транзакции деньги со счета переводятся на холд
Поэтому я объяснил, что в этом сценарии я говорю именно про момент "переводятся со счета на холд". Перевод со счета на холд это одна транзакция БД, перевод с холда еще куда-то это другая транзакция БД. Это разные действия разных процессов ОС. Последовательность "получение лока - снятие лока" находится в одном действии одного процесса. Между запусками процессов/обработчиков запроса блокировка не держится.
Вот в том и дело, что специфика бизнеса тут ни при чем. Если вы обновляете строки в базе из приложения, и у вас возможны параллельные процессы, вам нужны локи. В любом приложении и в любой предметной области.
Поскольку обработка поручения клиента может быть долгой (несколько часов, а то и дней) Вместо блокировки базы (операций) блокируется (переносится с баланса счёта на холд, как тут уже писали) соответствующая сумма на счёте.
Вы не понимаете, о чем идет речь. Я говорю про технические детали реализации действия "переносится с баланса счёта на холд". "Обработка поручения клиента" это совершенно не то, что я подразумеваю под выражением "операция с ресурсами". Я не предлагаю блокировать базу на несколько часов или дней.
Я же написал - таймаут ожидания мьютекса. 30-60 секунд обычно достаточно.
Если ждать достаточно долго, то Второй процесс ждет первого, третий ждет второго и далее по цепочке
В том сценарии, который я описал, эта цепочка не может замкнуться обратно на первый, поэтому это ничем не отличается от обычного запроса одного ресурса 2 процессами. Если у вас получается долгое ожидание, значит на какой-то ресурс слишком большая нагрузка, он является узким местом. Можно подумать о том, как изменить архитектуру, чтобы он не участвовал в таком количестве процессов, или оптимизировать сами процессы. Иногда можно заменить UPDATE (обновление существующего ресурса) на INSERT (создание нового ресурса).
Вы похоже не понимаете. Без локов в условиях большой нагрузки у вас данные будут некорректные. И какой-нибудь хакер найдет способ это использовать.
В итоге миллионы клиентов по всей стране не могут расплатиться картами банка
Значит надо разобраться и изменить архитектуру. Здесь участвует счет клиента и счет продавца, там миллионы клиентов и тысячи продавцов, каждая комбинация независима, они не должны друг друга тормозить.
Я вроде не говорил ничего про оценку количества приложений.
Там целый комплекс модулей-акторов, которые занимаются обработкой платежных документов.
Любые приложения, которые меняют что-то в базе, должны использовать локи, и если у них база общая, то одну и ту же систему локов.
И перевести деньги со счета на счет - это не одна операция, а цепочка последовательных операций
То, что я описал, подходит к любой операции в этой цепочке. В общем случае, к любой последовательности "прочитали - проверили - рассчитали - сохранили в одной транзакции БД".
Все описания в статье
Как я написал в первом комментарии, я говорю про любые параллельные операции на изменение данных, а не только про пример в статье.
А с холда они спишутся когда из другого банка подтверждение придет
Ну я про это и сказал, что это не входит в понятие "операция с ресурсами". Подтверждение из банка это другой API вызов, или там другое сообщение в Кафке, то есть это другая операция с ресурсами.
Компания распределяет з/п на счета своих сотрудников
Здесь подразумевалась долгая работа с БД в рамках одного бизнес-действия. Это тоже можно назвать "операция с ресурсами", но она состоит из более мелких независимых операций. Которые кстати можно распараллелить, и локи тут как раз помогут. Хотя наверно тут распараллеливание не даст большого эффекта.
employeeAccount - вообще может быть в другом банке, а не в нашей базе
В этом случае как раз и подразумевается "холд", про который была речь.
Вы не поняли. Я говорю про приложение на сервере внутри банка, которое переводит средства с аккаунта на аккаунт, а не про мобильное приложение для пользователей.
Если вы надолго залочили ресурс и при этом у вас высокая интенсивность работы с БД - рано или поздно вы столкнетесь с дедлоками
Поэтому я написал, что если в операции нужно изменять 2 ресурса, то надо блокировать id по возрастанию. Тогда дедлоков быть не должно, минимальный id из пересекающихся какой-то процесс запросит первым, другие процессы будут ждать, остальные id останутся свободными, и первый процесс сможет их заблокировать. Когда при операции блокируется только 1 ресурс, дедлоков быть не может. Может быть только таймаут ожидания мьютекса при большой нагрузке, тогда приложение покажет сообщение "Не удалось выполнить операцию, попробуйте еще раз". Если нагрузка большая, и мы и так подождали сколько можно, тут уже ничего не сделаешь.
И что, пока не распределит все, с ее счетом ничего нельзя сделать?
В данном случае "операция" это перевод на счет одного сотрудника.
Между точкой 2 на текущей итерации и 1 на следующей итерации аккаунт компании не заблокирован, его может заблокировать другая операция, тогда вызов в точке 1 будет ждать освобождения.
Поэтому еще раз - блокировка нужна, но она должна быть очень кратковременной.
Если у вас есть какие-то проверки в приложении при выполнении операции, то блокировка должна быть до чтения данных, участвующих в проверках. Иначе будет race condition. Если вам важна консистентность данных, то это единственный правильный вариант. Сколько времени он занимает это другой вопрос.
А в банке это поручение не приложение обрабатывает, а операторы вручную считают на бумаге и потом заносят получившееся значение в базу через SQL-клиент?
более 100 000 000 операций Делать все последовательно - просто времени не хватит.
Не надо делать все последовательно. В примере из статьи меняются 2 счета конкретных пользователей, это 2 отдельных ресурса. У других пользователей будут свои счета, это 2 других ресурса, операции с ними будут идти параллельно первым. Лок делается на связку "название сущности + id".
Со счета на холд перекинули сумму и дальше уже не держим запись.
Если расчеты происходят в приложении, то это и есть операция, в течение которой надо держать запись. После нее конечно держать не нужно. Это аналог примера из статьи, только вместо второго аккаунта некий "холд". Получили лок на id аккаунта, прочитали параметры аккаунта, проверили что сумма достаточная, перевели на холд, разблокировали. Надо ли делать лок на холд зависит от того как он устроен. Если это таблица, куда всегда делается только INSERT, то лок не нужен.
Ну так естественно, в том и смысл, чтобы операции с одним ресурсом выполнялись последовательно. Зачем их делать параллельно, а потом некоторые откатывать потому что version не совпадает. Если повторять все расчеты заново после отката, то нагрузка на сервер будет еще больше.
Как мне кажется, единственный логически правильный способ - для любых параллельных операций на изменение предотвращать чтение записей, которые меняются в текущей операции. Все действия на изменение с одним аккаунтом должны выполняться последовательно. Только так бизнес-проверки будут работать правильно.
FOR UPDATE примерно это и делает, но он требует открытую транзакцию на всё время обработки в приложении. Это не всегда удобно. Поэтому в приложении лучше использовать отдельную систему мьютексов, и блокировать id сущности перед чтением из базы для изменяющих операций. Также это будет работать, если вместо базы используется стороннее API.
Если в процессе операции обновляется более одной записи, как в примере из статьи, надо блокировать id записей в порядке возрастания, тогда не должно быть взаимных блокировок. В транзакции будет только фактическое обновление записей после всех расчетов.
Я именно про это и говорю. Поэтому утверждение "Сейчас нет, значит не появится" неверно. В опасениях, что нейросети заменят программистов или другие профессии, не подразумевается ChatGPT, это просто факт. Поэтому его нельзя опровергнуть перечислением возможностей ChatGPT. Так же как нельзя опровергнуть возможности автобуса возможностями велосипеда.
Это неважно. Важно, что этот вариант не фантастический, он реально возможен. ChatGPT 6 лет назад не было, а потом появился, и востребованность некоторых профессий стала меньше. Это уже реально произошло, поэтому этот вариант тоже не фантастический.
При чем тут фантастические версии? Опровергать возможности будущих технологий на основе существующих просто логически некорректно. И почему они фантастические? Интеллект уровня человека возможен в нашей реальности, у нас есть этому 100%-ное доказательство.
А это неважно. Важно, что опровергать высказывания про будущие версии на основе возможностей существующих это как делать прогнозы о развитии автобусов на основе возможностей велосипедов.
Я не говорю, что вы говорите, что локи не нужны. Вы говорите, что локи не нужны до чтения данных. Я говорю, что нужны.
А какой смысл записывать данные, которые некорректно рассчитаны?
В очередной раз повторяю - я не предлагаю блокировать данные на часы и дни.
Решение конфликтов это ручное действие. Если вы хотите разбирать и исправлять некорректные данные в миллионах строк в базе вручную, то конечно можно не использовать локи.
А, ну если с блокировкой тогда другое дело конечно. Только если никто не вклинивался, то и блокировка от изменений в начале процесса никому не помешает. А если вклинивался, то повторять всё заново создаст бо́льшую нагрузку на сервер, чем просто ожидание одного из процессов, и в условиях большо́й нагрузки вообще может быть невозможным, потому что постоянно будет кто-то вклиниваться.
Вот я и объяснил, что "взаимные блокировки" появляются не магически сами по себе, а из-за разного порядка блокировки. Один процесс блокирует записи в порядке "1, 2", другой "2, 1". Поэтому надо использовать одинаковый порядок.
Нет, приложения так не работают. На веб-запросы от пользователей вида "хочу перевести деньги" вообще обычно ставится таймаут несколько десятков секунд. Я же объяснил, что говорю про обработку одного запроса в приложении, почему вы переводите речь на бизнес-процессы?
Если ваш бизнес-процесс занимает несколько дней, там будет несколько запусков нескольких разных приложений по веб-запросу или по расписанию с несколькими разными транзакциями БД. Я говорю про один конкретный запуск. Нафига держать блокировку между запусками?)
Поэтому я объяснил, что в этом сценарии я говорю именно про момент "переводятся со счета на холд". Перевод со счета на холд это одна транзакция БД, перевод с холда еще куда-то это другая транзакция БД. Это разные действия разных процессов ОС. Последовательность "получение лока - снятие лока" находится в одном действии одного процесса. Между запусками процессов/обработчиков запроса блокировка не держится.
Вот в том и дело, что специфика бизнеса тут ни при чем. Если вы обновляете строки в базе из приложения, и у вас возможны параллельные процессы, вам нужны локи. В любом приложении и в любой предметной области.
Ну так после проверки и до записи они все равно могут измениться.
Вы не понимаете, о чем идет речь. Я говорю про технические детали реализации действия "переносится с баланса счёта на холд".
"Обработка поручения клиента" это совершенно не то, что я подразумеваю под выражением "операция с ресурсами". Я не предлагаю блокировать базу на несколько часов или дней.
Я же написал - таймаут ожидания мьютекса. 30-60 секунд обычно достаточно.
В том сценарии, который я описал, эта цепочка не может замкнуться обратно на первый, поэтому это ничем не отличается от обычного запроса одного ресурса 2 процессами. Если у вас получается долгое ожидание, значит на какой-то ресурс слишком большая нагрузка, он является узким местом. Можно подумать о том, как изменить архитектуру, чтобы он не участвовал в таком количестве процессов, или оптимизировать сами процессы. Иногда можно заменить UPDATE (обновление существующего ресурса) на INSERT (создание нового ресурса).
Вы похоже не понимаете. Без локов в условиях большой нагрузки у вас данные будут некорректные. И какой-нибудь хакер найдет способ это использовать.
Значит надо разобраться и изменить архитектуру. Здесь участвует счет клиента и счет продавца, там миллионы клиентов и тысячи продавцов, каждая комбинация независима, они не должны друг друга тормозить.
Я вроде не говорил ничего про оценку количества приложений.
Любые приложения, которые меняют что-то в базе, должны использовать локи, и если у них база общая, то одну и ту же систему локов.
То, что я описал, подходит к любой операции в этой цепочке. В общем случае, к любой последовательности "прочитали - проверили - рассчитали - сохранили в одной транзакции БД".
Как я написал в первом комментарии, я говорю про любые параллельные операции на изменение данных, а не только про пример в статье.
Ну я про это и сказал, что это не входит в понятие "операция с ресурсами".
Подтверждение из банка это другой API вызов, или там другое сообщение в Кафке, то есть это другая операция с ресурсами.
Здесь подразумевалась долгая работа с БД в рамках одного бизнес-действия. Это тоже можно назвать "операция с ресурсами", но она состоит из более мелких независимых операций. Которые кстати можно распараллелить, и локи тут как раз помогут. Хотя наверно тут распараллеливание не даст большого эффекта.
В этом случае как раз и подразумевается "холд", про который была речь.
Насколько я вижу, во всей этой ветке разговор только о транзакции БД.
Вы не поняли. Я говорю про приложение на сервере внутри банка, которое переводит средства с аккаунта на аккаунт, а не про мобильное приложение для пользователей.
Поэтому я написал, что если в операции нужно изменять 2 ресурса, то надо блокировать id по возрастанию. Тогда дедлоков быть не должно, минимальный id из пересекающихся какой-то процесс запросит первым, другие процессы будут ждать, остальные id останутся свободными, и первый процесс сможет их заблокировать.
Когда при операции блокируется только 1 ресурс, дедлоков быть не может. Может быть только таймаут ожидания мьютекса при большой нагрузке, тогда приложение покажет сообщение "Не удалось выполнить операцию, попробуйте еще раз". Если нагрузка большая, и мы и так подождали сколько можно, тут уже ничего не сделаешь.
В данном случае "операция" это перевод на счет одного сотрудника.
Между точкой 2 на текущей итерации и 1 на следующей итерации аккаунт компании не заблокирован, его может заблокировать другая операция, тогда вызов в точке 1 будет ждать освобождения.
Если у вас есть какие-то проверки в приложении при выполнении операции, то блокировка должна быть до чтения данных, участвующих в проверках. Иначе будет race condition. Если вам важна консистентность данных, то это единственный правильный вариант. Сколько времени он занимает это другой вопрос.
А в банке это поручение не приложение обрабатывает, а операторы вручную считают на бумаге и потом заносят получившееся значение в базу через SQL-клиент?
Не надо делать все последовательно. В примере из статьи меняются 2 счета конкретных пользователей, это 2 отдельных ресурса. У других пользователей будут свои счета, это 2 других ресурса, операции с ними будут идти параллельно первым. Лок делается на связку "название сущности + id".
Если расчеты происходят в приложении, то это и есть операция, в течение которой надо держать запись. После нее конечно держать не нужно. Это аналог примера из статьи, только вместо второго аккаунта некий "холд". Получили лок на id аккаунта, прочитали параметры аккаунта, проверили что сумма достаточная, перевели на холд, разблокировали. Надо ли делать лок на холд зависит от того как он устроен. Если это таблица, куда всегда делается только INSERT, то лок не нужен.
Ну так естественно, в том и смысл, чтобы операции с одним ресурсом выполнялись последовательно. Зачем их делать параллельно, а потом некоторые откатывать потому что version не совпадает. Если повторять все расчеты заново после отката, то нагрузка на сервер будет еще больше.
Как мне кажется, единственный логически правильный способ - для любых параллельных операций на изменение предотвращать чтение записей, которые меняются в текущей операции. Все действия на изменение с одним аккаунтом должны выполняться последовательно. Только так бизнес-проверки будут работать правильно.
FOR UPDATE примерно это и делает, но он требует открытую транзакцию на всё время обработки в приложении. Это не всегда удобно. Поэтому в приложении лучше использовать отдельную систему мьютексов, и блокировать id сущности перед чтением из базы для изменяющих операций. Также это будет работать, если вместо базы используется стороннее API.
Если в процессе операции обновляется более одной записи, как в примере из статьи, надо блокировать id записей в порядке возрастания, тогда не должно быть взаимных блокировок. В транзакции будет только фактическое обновление записей после всех расчетов.
Я именно про это и говорю. Поэтому утверждение "Сейчас нет, значит не появится" неверно. В опасениях, что нейросети заменят программистов или другие профессии, не подразумевается ChatGPT, это просто факт. Поэтому его нельзя опровергнуть перечислением возможностей ChatGPT. Так же как нельзя опровергнуть возможности автобуса возможностями велосипеда.
Это неважно. Важно, что этот вариант не фантастический, он реально возможен. ChatGPT 6 лет назад не было, а потом появился, и востребованность некоторых профессий стала меньше. Это уже реально произошло, поэтому этот вариант тоже не фантастический.
При чем тут фантастические версии? Опровергать возможности будущих технологий на основе существующих просто логически некорректно.
И почему они фантастические? Интеллект уровня человека возможен в нашей реальности, у нас есть этому 100%-ное доказательство.
А это неважно. Важно, что опровергать высказывания про будущие версии на основе возможностей существующих это как делать прогнозы о развитии автобусов на основе возможностей велосипедов.