Атомарность одной команды

Предпосылки: Event loop.

Sub | EXEC

Почему одна команда всегда атомарна

Тысяча клиентов одновременно отправляет INCR counter. В многопоточной системе это гонка: два потока читают одно значение, оба увеличивают, оба записывают — один инкремент потерян. В Redis такая ситуация невозможна.

Redis выполняет все команды в одном потоке, последовательно. Между началом и концом выполнения одной команды никакая другая команда не может вклиниться. Это та же идея атомарности, что и на уровне процессора — для любого наблюдателя операция либо ещё не произошла, либо уже завершена целиком. Только вместо аппаратного захвата кеш-линии неделимость обеспечивает однопоточный event loop. INCR counter — не «прочитать, увеличить, записать» как три отдельных шага, а одна атомарная операция. Тысяча конкурентных INCR выполнится строго по очереди: каждый увидит результат предыдущего.

То же относится к LPUSH (добавление в список), SADD (добавление в множество), HSET (установка поля хеша) и любой другой команде. Атомарность одной команды — бесплатная гарантия, не требующая транзакций или блокировок.

Составные команды с встроенной атомарностью

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

Паттерн «проверить и записать» реализует SET key value NX EX 30 — установить значение только если ключ не существует, с TTL 30 секунд. Проверка, запись и установка TTL выполняются как одна операция. Это основа распределённых блокировок.

Паттерн «прочитать и заменить» — SET key value GET (Redis 6.2+): атомарно установить новое значение и вернуть старое. Эта форма заменила устаревшую команду GETSET. Из того же семейства: GETDEL key (прочитать и удалить) и GETEX key EX 100 (прочитать и обновить TTL).

Паттерн «переместить между структурами» — RPOPLPUSH source destination: атомарно забрать элемент из конца одного списка и добавить в начало другого. В Redis 6.2+ его заменил более гибкий LMOVE, позволяющий выбрать сторону списка. Используется для построения надёжных очередей.

Когда одной команды недостаточно

Атомарность одной команды не помогает, когда нужно выполнить несколько команд как единое целое. «Прочитать значение A, на его основе вычислить B, записать B» — между чтением и записью другой клиент может изменить A. Для таких случаев Redis предоставляет EXEC и Lua-скрипты.

Sources


Sub | EXEC