Есть ли способ получить блокировку в Redis?(Node.js) - PullRequest
1 голос
/ 26 июля 2011

Приложение My Node.js принимает подключения извне. Каждый обработчик соединения читает SET на Redis, в конечном итоге изменяет сам набор, а затем продолжает. Проблема состоит в том, что в то же время другое асинхронное соединение может попытаться прочитать тот же самый SET и попытаться обновить его или решить его следующий шаг на основе того, что оно читает.

Я знаю, что Redis старается быть атомарным, но этого недостаточно для моего случая использования. Подумайте об этом: набор читается, чтобы понять, является ли он ПОЛНЫМ (для этого есть бизнес-правило). Если он ПОЛНЫЙ, то что-то происходит. Проблема в том, что если остался только один слот, два полуконкурентных соединения могут считать каждое последним. И я получаю переполнение.

Есть ли способ удерживать соединение "в ожидании" в течение очень короткого времени, когда другому в конечном итоге потребуется обновить установленное состояние?

Я думаю, что это угловой случай, очень-очень неудачно ... но вы знаете:)

Использование другого ключа в качестве «замка» является опцией, или он воняет?

Ответы [ 2 ]

3 голосов
/ 26 июля 2011

Как насчет использования blpop для блокировки. blpop key 5 ждать 5 секунд key. При запуске ставить пункт (чтобы определить, что очередь не пуста) в ключ. Соединение, получающее блокировку, должно удалить предмет из ключа. Следующее соединение не может получить блокировку, потому что пусто, но blpop имеет следующее приятное свойство:

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

Когда соединение, которое получило блокировку, завершило задачу, оно должно вернуть элемент обратно в очередь, тогда следующее ожидающее соединение может получить блокировку (элемент).

2 голосов
/ 03 августа 2011

Возможно, вы ищете WATCH с MULTI/EXEC.Вот шаблон, которому следуют оба потока:

WATCH sentinel_key
GET value_of_interest
if (value_of_interest = FULL)
    MULTI
    SET sentinel_key = foo
    EXEC
    if (EXEC returned 1, i.e. succeeded)
        do_something();
    else
        do_nothing();
else
    UNWATCH

Способ, которым это работает, заключается в том, что все команды между MULTI и EXEC ставятся в очередь, но фактически не выполняются до тех пор, пока не будет вызван EXEC.Когда вызывается EXEC, перед фактическим выполнением команд в очереди он проверяет, изменился ли sentinel_key вообще с момента установки WATCH;если он имеет, он возвращает (nil) и команды в очереди отбрасываются.В противном случае команды выполняются атомарно как блок, и он возвращает количество выполненных команд (в данном случае 1), давая вам знать, что вы выиграли гонку, и можно вызвать do_something().

Это концептуально аналогичноfork()/exec() системные вызовы Unix - возвращаемое значение из fork () сообщает вам, какой процесс вы (родительский или дочерний).В этом случае он сообщает вам, выиграли вы или нет.

...