@saneok44

Как избежать коллизии по данным?

На работе используем MS SQL Server. Приложения работают на C# ASP Net. Архитектура базы данных реляционная с объектно-ориентированным подходом (если правильно написал). Запросы к базе данных идут асинхронно с клиентской стороны через js. При высокой нагрузке близкой к 100% пользователь может совершить транзакцию на создание объекта в базе. Сама транзакция может подвиснуть. Пользователь не дожидаясь ответа обновляет страницу и снова создает объект. Получается уже две транзакции в очереди. По итогу когда очередь доходит до выполнения имеем в базе два одинаковых объекта (созданных вплоть до ms) что ломает логику программы. Когда в нормальных условиях создастся должен только один объект (уникальность на уровне логики пользователя). Т.е. по логике пользователь создает объект получает результат и больше не создает (но если захочет может добавить такой же). Что имеем по итогу при 100% нагрузки получаем логические коллизии по данным. Пытались через интерфейс блокировать клики пока не придет результат, но это не вариант. Обновляешь страницу ничего не видишь потому что операция подвисла.
Как можно решить проблему данного характера? Она появилась именно когда на сервере появилась большая нагрузка.
  • Вопрос задан
  • 488 просмотров
Пригласить эксперта
Ответы на вопрос 4
mayton2019
@mayton2019
Bigdata Engineer
При высокой нагрузке близкой к 100% пользователь может совершить транзакцию на создание объекта в базе. Сама транзакция может подвиснуть. Пользователь не дожидаясь ответа обновляет страницу и снова создает объект. Получается уже две транзакции в очереди. По итогу когда очередь доходит до выполнения имеем в базе два одинаковых объекта (созданных вплоть до ms) что ломает логику программы.


Очень плохо что вы довели систему до нагрузки 100%. Обычно concurrency работает хорошо когда мы не доводим до такого состояния. Есть даже такой термин thread starvation (голодание потоков) когда потоки никак не могут получить квант времени.

Без кода и лог-файлов тут нечего обсуждать. Я просто могу дать несколько направлений на подумать.

1) CQRS (Command-Query-Separation) - это шаблон разработки при котором команды на изменение данных и запросы на их чтение идут независимо и существуют как-бы в разных временных эпохах. Это дает возможность масштабировать системы довольно сильно. И такие системы обычно лишены блокирок.

2) Idempotency- это два свойства бизнес операций. Идемпотентность например предполагает что если платежная система дважды продублировала ваш платеж (MQ/сетевые replays) за покупку чашки Кофе например то это не означает что с вас банк снимет дважды деньги. На самом деле каждая ваша карточная операция имеет уникальный ID и с точки зрения биллинга будет применение платежа только 1 раз с одним уникальным ID. Второй платеж-дубль будет проигнорирован. Это свойство часто используется в Apache Kafka как один из способов поднять скорость и надежность.

3) Когда ваша база или сервер приложений находтся в состоянии как-бы "агонии" то не стоит пытатся добивать ее повторами операций. А стоит на некоторое время прикрыть канал операций. Или разорвать цепь предохранителя. Как делают в электрике при повышенной нагрузке. Есть такой шаблон Cirquit Breaker. Аварийный размыкатель. Netflix его активно использует.

Вот подумайте.
Ответ написан
Alex_Geer
@Alex_Geer
System Engineer
Для решения данной проблемы можно использовать механизм блокировки, который позволит избежать создания дубликатов объектов в базе данных при высокой нагрузке. Также можно оптимизировать запросы к базе данных и настроить ее на работу с большой нагрузкой. Для этого можно применить индексы, кластеризацию таблиц и другие методы оптимизации. Кроме того, можно использовать технологии кэширования, которые помогут ускорить доступ к данным и снизить нагрузку на сервер.
Ответ написан
Комментировать
@res2001
Developer, ex-admin
Сделать в таблице уникальный индекс по одному или нескольким полям, которые образуют уникальный ключ для объекта. В этом случае при попытке создать в базе запись с таким же уникальным ключом будет ошибка.

Вообще нагрузка 100% - это повод задуматься о масштабировании приложения или оптимизации базы, не понял где у вас нагрузка 100%.
Необходимость масштабирования не отменяет создания уникального индекса.
Ответ написан
tsklab
@tsklab
Здесь отвечаю на вопросы.
Свойства уникальны в пределах объекта. Т.е. уникальность на уровне свойств имеется. Уникальность у объекта только по id
Значит собираете все свойства в "цифровой отпечаток" и блокируете объект по нему.

два одинаковых объекта
Они не будут одинаковыми, так как и них разный "отпечаток". А значит нужно оставлять только тот, который имеет более полный и используется для операций.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы