170 похожих чатов

Ребята, кто шарит, Есть балансер, за ним 2-3 сервера, на которых

крутится Nodejs приложение.
Есть эндпоинт по которому выполняется долгий запрос в котором происходит много разных действий.

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

Думал через запись в БД лочить, но, она находится в другом месте и боюсь что могут быть задержки из-за пинга

Вопрос: как вы решаете такие задачи?

39 ответов

14 просмотров

Перед началом собственно логики обработки запроса проверяешь, что данных пользователя нет в условном редисе, если есть - отклоняешь, если нет - помещаешь. Перед выполненным запросом удаляешь из редиса данные

Самый простой вариант sticky sessions, запросы распределяются по нодам, но от одного юзера всегда идут к той же ноде В nginx есть поддержка скриптов lua и js, в них можно проверять в Redis статус запроса

Похоже на отдельную бизнес задачу. Сделай отдельный слой, который будет заниматься локом роутов. Впихни этот слой в свой монолит рядом с апликационным слоем, либо как отдельный микросервис gateway

большой объем запросов? можешь в памяти просто объект хранить с локнутыми юзерами и очищать по таймингу нужному

Несколько процессов не шарят память

да на балансере просто)

если это куки, то можно же очистить куки и заново отправить)

У меня такая задача лок через редис ван лав

Дело не в редисе и т.п. Мне кажется нужно подходить с точки зрения архитектуры приложения. Ему нужен отдельный слой, который будет выполнять задачу. А как он это сделает это уже другой вопрос. Можно сделать это как слой монолита, можно написать отдельный сервис под эти нужны, можно подключить модуль к nginx, рассмотреть готовые rate limiter'ы Короче вариантов куча, если понимать что это отдельный слой, а не часть бизнес слоя текущего монолита

это вполне же может быть частью бизнес логики в зависимости от задачи

Например когда? Из его слов: Нужно сделать так, чтобы одному пользователю нельзя было выполнить этот запрос больше одного раза одновременно, учитывая что балансер распределяет запросы рандомно на разные сервера. Вроде тут из контекста ясно, что дело касается около апликационного слоя (запросы). Не могу подобрать ситуацию, когда это касалось бы бизнес логики

сейчас сходу не придумаю, но в какой то предметной области такое полюбому есть)) но по идеи вы правы, там это по сути наверное одной мидлварой решается если тот же экспресс))

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

Ну если у него контроллеры и сервисы есть - слои уже есть)

Не, он спросил "как вы решаете такие задачи?"

И видимо по-вашему ответ на это "Решаю задачи на архитектурном уровне"?)

Решаю задачи на уровне разделения на 10050 слоев и создания миллиарда абстракций))

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

Это не про куки, а про IP

Ip может и поменяться, так что к нему точно не стоит привязываться (в контексте изначального вопроса)

по сабжу два ответа, простой способ и сложнее

Хз, по-моему там не нужны липкие сессии, и даже если на их основе делать, привязываться к айпи нельзя

большинство пользователей - добросовестные, и не пытаются что-то сломать, поэтому этот простой способ балансировки часто используют

Это не решает проблему. Плюс добавляет сложности. Помимо того, что нужно sticky session добавлять на уровне балансера, так еще и в коде приложения делать lock в памяти (который не имtт смысла без балансера со sticky session) Вроде простая задача, а всё усложнилось в разы на пустом месте

Да способ ок, но в конкретной ситуации не подходит потому что не даёт гарантию, которую ищет автор вопроса. Если делать липкость на основе юзерайди, это может решить проблему. А на основе ip - нет

читайте второй способ в треде )

И плюс мы залазим в работу балансера, у которого свои цели

Я подходящие варианты и так знаю. Просто посчитал важным для автора вопроса отметить то, что сессии не решат его проблемы

Как же сессии для юзера не решают проблему? U1 отправляется на N1 каждый раз, без сессии на логин, и потом снова на N1, профит

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

А где тут включается запрет на обработку запросов по роуту от одного юзера паралельно?

так тебе мало просто липкие сессии иметь тебе надо 1 - привязывать сессии к юзерайди (это уже скорее всего дополнительная работа) 2 - на каждом из серверов дать гарантии что операция для пользователя запускается только один раз то есть сами по себе сессии вообще не решают проблему, а только позволяют локализовать её и решать не для распределённой системы, а для локальной, плюс возможно добавляют работу по изменению алгоритма вычисления сервера

Sticky sessions это про раскидывание запросов по определенному сценарию, в конкретном случае, мапить юзера на одну ноду, где хранится состояние о задаче

и как итог - легко выявить - верное решение или нет в этом случае если балансировщик гарантировано отправит задачи по какому-то признаку на одну и ту же ноду а нода эта - выстроит выполнение этих задач последовательно (способ не важен) то и проблема будет решена

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

Я исхожу из того, что у топикстартера достаточно скилов, чтобы загуглить термин, и найдя огромное количество статей, довести до готовности

Он имеет ввиду что этот костыль вообще не надо доводить до ума. Это плохое решение и к нему можно прибегнуть в очень крайнем случае (я даже хз в каком)

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

Обсуждают сегодня

Всем привет! Имеется функция: function IsValidChar(ch: UTF8Char): Boolean; var i: Integer; ValidChars: AnsiString; begin ValidChars := 'abcdefghijklmnopqrstuvwxyzABCDE...
Евгений
44
> Копаем глубже > Следующий момент был, когда я спросил его, знает ли он JavaScript. Он ответил, что его учили работать с C#. Я тоже в университете писал на C#, но даже там мн...
Oleg Volkov
4
И никого не интересует какие пакеты кто использует. ((% Заходишь на сайт симфони и видишь поддержку Украины - по законам РФ это ж экстремизм. Только никто не отказывается от с...
Am Ambrion
11
лучше скажите, причём тут паскаль?
Alexey Kulakov
36
Чтобы перехватить все нажимания буков на форме, надо хук ставить? Пробовал на форме ОнКейДаун, оно ловит клаву если фокус не на компоненте с вводом текста
Serjone
15
Но, может, есть уже проверенная? Наши требования такие: 1. Сообщения должны приходить из Инста в CRM оду 2. Должна быть возможность подключить несколько экаунтов Инстаграм. Р...
Alexander Sharoiko MSE / Александр Шаройко
7
Народ! Впервые клиенту пришло письмо от РКН, у вас, дескать, есть яндекс метрика, а нигде не написано, что вы ее юзаете. Никто не сталкивался?
Sasha Beep
14
Всем привет! вывожу на общей стр дочерние ресурсыв каждом ресурсе галерея, и первая фотка должна выводиться на общей [!DocLister? &prepare=photo !]
Alekso
12
А можно вопрос? Мне сегодня сказали что у меня функция (которая просто заполняет массив значениями) не правильная void Full(double * arr, int n) { for (int i = 0; i < n; i...
† C E †
7
Добрый вечер. Хочу чтобы у меня в классе поле было функцией, которая возвращает строку. Делаю так: interface ... TGetOutPath = function : String of object; ... protec...
Kirill Filippenok
12
Карта сайта