Как обеспечить согласованность данных для параллельных выводов?

база данных SQL

Продолжайте отвечать на вопросы от планетарных водных друзей.
Шен, учитель, у нас есть бизнес, при одном и том же пользовательском параллелизме «запрос, логика расчета, вывод» баланс может показаться непоследовательным, есть ли способ его оптимизировать?

Каков бизнес-сценарий вычета?

В процессе покупки товаров пользователям необходимо запрашивать и изменять баланс.Общий бизнес-процесс выглядит следующим образом:

первый шаг, запросите текущий баланс пользователя из базы данных:
_SELECT money FROM t_yue WHERE uid=uid;НетДавайте настроим запросUID; _ может пожелать настроитьold_money=100 юаней.

второй шаг, бизнес-уровень реализует вычисления бизнес-логики, такие как:
(1) первый запрос цена покупки товаров, например, 80 юаней;
(2) Запросите, активен ли продукт, а также действия, например, скидка 10%;
(3) соотношение адекватности баланса, достаточно только для снижения;

if(old_money> 80*0.9){     new_money=$old_money-80*0.9=28
} else {
return "Not enough minerals";
}

третий шагизменить баланс в базе данных.
UPDATE t_yue SET money=newmoneyWHEREuid=new_money WHERE uid=uid;

В случае низкого параллелизма с этим процессом проблем нет.Первоначальная сумма составляет 100 юаней, и покупается скидка 10% (72 юаня) на 80 юаней, а остальные 28 юаней.

**В чем может быть проблема параллельного отчисления для одного и того же пользователя?
**

В распределенной среде при большом количестве параллелизма этот «запрос + изменение» в бизнесе имеет определенную вероятность несогласованности данных.
Под ограничениями этот ненормальный процесс может возникнуть:

шаг первый, бизнес 1 и бизнес 2 одновременно запрашивают баланс, который составляет 100 юаней.

_
_

Голос за кадром: эти параллельные запросы выполняются на разных экземплярах сайта/экземплярах службы, и мьютекс в процессе определенно не будет разрешен.

Шаг 2, Предприятие 1 и Предприятие 2 одновременно выполняют логические вычисления для расчета баланса соответствующих предприятий.Предположим, что баланс, рассчитанный предприятием 1, составляет 28 юаней, а баланс, рассчитанный предприятием 2, составляет 38 юаней.

Шаг 3, Business 1 сначала изменяет баланс в базе данных и устанавливает его на 28 юаней.

Бизнес 2 изменен после того, как баланс в базе данных установлен на 38 юаней.

В этот раз произошло исключение: первоначальная сумма составляла 100 юаней, из дела 1 было вычтено 72 юаня, из дела 2 было вычтено 62 юаня, и, наконец, осталось 38 юаней.
_Голос за кадром: _Предположим, что предприятие 1 списывает баланс первым, а предприятие 2 возвращает сальдо.

Общее решение?

Для этого есть небольшая вероятность того, что исключение произойдет, когда тот же пользователь списан одновременно. Распределенные замки могут быть взаимоисключающими для каждого пользователя. Например, операция может быть продолжена только после захвата ключа в Redis / ZK, В противном случае операция запрещена.,
этопессимистический замокРешение работает, но требует дополнительных компонентов (redis/zk) и снижает пропускную способность.
Существует ли оптимальное решение для блокировки несоответствий с малой вероятностью?

Дальнейший анализ одновременных дебетов показал:

(1) Когда бизнес 1 перезаписывается, старый баланс равен 100, что является начальным состоянием, новый баланс равен 28, что является конечным состоянием. Теоретически новый баланс должен быть успешно перезаписан только в том случае, если старый баланс равен 100.
Когда бизнес 1 выполняет обратную запись одновременно, старый баланс действительно равен 100, и обратная запись должна быть успешной.

(2) Когда дело 2 списывается обратно, старый баланс равен 100, что является начальным состоянием, новый баланс равен 28, что является конечным состоянием. Теоретически новый баланс должен быть успешно перезаписан только в том случае, если старый баланс равен 100.
Но на самом деле сумма в базе данных в это время стала 28, поэтому параллельная обратная запись дела 2 не должна увенчаться успехом.

Как реализовать оптимистическую блокировку с минимальными затратами?

Когда набор записывается обратно, плюс условие сравнения начального состояния, только когда начальное состояние остается неизменным, набор может быть успешно записан обратно Сравнить и установить (CAS) — это распространенный способ уменьшить конфликты блокировок чтения-записи. и обеспечить согласованность данных методом пола.

Как изменится бизнес в это время?

Чтобы использовать CAS для решения проблемы согласованности данных при высоком уровне параллелизма, вам нужно только сравнить начальное значение во время операции установки.Если начальное значение изменится, установка не будет допущена к успеху.

Конкретно для этого случая нужно только:
UPDATE t_yue SET money=newmoneyWHEREuid=new_money WHERE uid=uid;
Обновитесь до:

UPDATE t_yue SET money=newmoneyWHEREuid=new_money WHERE uid=uid AND money=$old_money_;__
Вот и все.
_

Когда происходят параллельные операции:

Бизнес 1 выполняет:
UPDATE t_yue SET money=28 WHERE uid=$uid AND money=100;

Бизнес 2 выполняет:
UPDATE t_yue SET money=38 WHERE uid=$uid AND money=100;

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

Как определить, какое параллельное выполнение выполнено успешно, а какое нет?

На самом деле, операция множества не имеет значения, успешна она или нет.О бизнесе можно судить по влияющим строкам:

  • Обратная запись успешна, влияет на строки 1

  • Не удалось выполнить обратную запись, затронутые строки равны 0

Суммировать

В высокопараллельных сценариях «запросить и изменить» проблему согласованности данных можно решить с помощью CAS (сравнить и установить). Соответствующее бизнесу, то есть при задании добавить сравнение начальных условий.
Оптимизация не сложная, изменена только половина строки SQL, но это действительно может решить проблему.
Но я надеюсь, что каждый может что-то получить **, идеи важнее выводов**.

Операция, почему нельзя использовать:
UPDATE t_yue SET money=money-$diff;