Pull to refresh

Comments 13

Смысл транзакции redis в том, что все команды из неё откладываются и потом атомарно выполняются. Это относится к модифицирующим командам, но не к командам чтения т.к.
$value = $rediska->get('test_value');

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

Если бы были блокировки, клиенты бы дрались за них и работали бы медленее. Да еще было бы очень просто попасть в deadlock. Разработчикам надо было бы писать немало кода, эти блокировки реализующего, а также ищущего deadlock'и. В NoSQL от этих вещей как раз и пытаются избавиться.

Кроме того, такие частые конфликты скорее всего говорят о неправильном дизайне приложения. Часто вероятность конфликта мала и в таком случае рулят оптимистичные блокировки, которые и делает watch.
Вы по моему не поняли цель статьи. Целью было разъяснить как работает на самом деле, т.к. в документации на мой взгляд этот вопрос разъяснен недостаточно четко.
Вот из официальной доки по транзакциям:

The first try may be the following:
val = GET mykey
val = val + 1
SET mykey $val

This will work reliably only if we have a single client performing the operation in a given time…

Thanks to WATCH we are able to model the problem very well:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

Using the above code, if there are race conditions and another client modifies the result of val in the time between our call to WATCH and our call to EXEC, the transaction will fail.

Таким образом, транзакции — это всего лишь элементы в очереди, чтение в очередь не ставится, т.к. иначе не нужен был бы WATCH. В целом, в доке более понятно, как оно работает и почему, нежели в приведенном исследовании.
Если кому интересно, то вот тут я реализовал транзакционный интерфейс работы с редис через расширение phpredis.
Прочитал документацию и у меня сложилось впечатление, что там достаточно последовательно все описано.

Там написано что есть две фазы — serialized и executed. И что фаза execute — атомарна. И что можно использовать оптимистическую блокировку (если есть желание) с помощью watch. Мы же помним что такое оптимистическая и пессимистическая блокировка, правильно?

То есть на мой взгляд из документации достаточно очевидно, что пока редис отвечает queued, никто ничего никому не запрещает менять. А когда exec — то все разом и выполнится. Или разом невыполинтся.

Хм, что-то странный у вас пример, в редис для таких вещей и придумали incr и decr. Скорее всего у вас проблема в архитектуре и вы что-то используете не по назначению.
Я в курсе про incr и decr, а пример такой же как и в документации на официальном сайте редиса.

> For example, imagine we have the need to atomically increment the value of a key by 1 (let's suppose Redis doesn't have INCR).
В документации это просто пример, вот не поленился написал скрипт:

# -*- coding: utf-8 -*-

import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0)

# Test
for  i in xrange(1, 10001):
    print r.incr('test-key')


Запуск:

python test.py &
python test.py &
python test.py &
python test.py &


Результат: 40000. Что не так?
Ну так и у меня это тоже просто пример, на примере которого я показал как на самом деле работают транзакции. Это не реальный пример из практики.
Так а в реальном примере что нужно менять? Я просто не могу придумать для чего это нужно.
Что значит для чего нужно? Если у вас в реальной задаче нужно менять значение одного и того-же ключа в несколько потоков.
> Это скрипт запускал в два потока из командной строки, т.е. по идее в итоге должен был получить значение у ключа «test_value» равное 20 тысячам, но в реальности там в среднем выходило около 12 тысяч. Т.е. никакой блокировки нет.

Я в таких случаях всегда юзаю sleep() когда надо проверить параллельные транзакции. 10К итераций это немного костыль и в некоторых случаях придется довольно долго ждать)
Sign up to leave a comment.

Articles