Deep Engineering

ЗАМЕР

bench/valkey-cluster/runs/failover.txt

Скрипт, которым получены числа в статье, и запись прогона. Файл читается на сборке из репозитория — это тот самый код, который запускали, а не его копия.

Цитируется в статье
/ru/system-design/caching/valkey-clustering

Запись прогона

У этого замера записи прогона нет — только скрипт.

Скрипт

94 строк
Valkey 9.1.2 · один хост, процессы на случайных портах
отказ мастера в обоих режимах: что приходит клиенту по проводу

8. ОТКАЗ МАСТЕРА В КЛАСТЕРЕ ГЛАЗАМИ КЛИЕНТА
----------------------------------------------------------------------
  слот ключа принадлежит        127.0.0.1:36355
  опрашивается живой узел       127.0.0.1:47039
  cluster-node-timeout          2000 мс

  t=0.00  узел 36355 убит
  t= 0.00  MOVED 12182 127.0.0.1:36355
  t= 3.39  CLUSTERDOWN The cluster is down
  t= 3.49  MOVED 12182 127.0.0.1:39129

  слот перешёл к                127.0.0.1:39129

  вернувшийся узел: его роль    slave
  вернувшийся узел: SET foo     MOVED 12182 127.0.0.1:39129

  Клиент всё это время получал от живого узла ОСМЫСЛЕННЫЕ ответы: пока
  переключение не произошло — старый адрес слота, после него — новый.
  Гадать не пришлось ни секунды: узел, до которого клиент дозвонился,
  знает состояние всего кластера, потому что узлы непрерывно
  обмениваются им по шине. (Если заглянуть в промежуток поточнее, там
  бывает и CLUSTERDOWN — тоже осмысленный ответ: «слот сейчас не
  покрыт никем».)
  
  Заметьте, чего здесь НЕ произошло: никто не спрашивал внешнюю
  службу. Реплику повысили сами узлы, большинством голосов мастеров,
  и они же разнесли новость. Кластер сам себе и наблюдатель, и арбитр.
  
  Две последние строки — про вернувшийся узел, и их стоит запомнить до
  блока 10. Поднявшись, он не стал ни мастером своих слотов, ни местом,
  куда можно записать: из шины он узнал, что слоты уже у другого, и
  сразу отдаёт клиенту адрес нового владельца.

9. ОТКАЗ МАСТЕРА ПОД SENTINEL ГЛАЗАМИ КЛИЕНТА
----------------------------------------------------------------------
  мастер по мнению sentinel     127.0.0.1:44393
  down-after-milliseconds       1000 мс

  t=0.00  узел 44393 убит
  t= 0.00  старый адрес: Could not connect to Valkey at 127.0.0.1:44393
  t= 2.30  sentinel называет мастером 127.0.0.1:41979
  новый мастер отвечает на запись OK
  вторая реплика 49651          READONLY You can't write against a read only replica.

  что sentinel записал у себя в журнале:
    +sdown master cache 127.0.0.1 44393
    +vote-for-leader fa6dddf09e3a81d134f9f92c2daa923019fda950 1
    +odown master cache 127.0.0.1 44393 #quorum 3/2
    +switch-master cache 127.0.0.1 44393 127.0.0.1 41979

  Разница с предыдущим блоком не в секундах, а в том, ЧТО получил
  клиент. Старый адрес не отвечал вовсе — там никого нет. Ни один
  узел данных не сказал клиенту нового адреса и не мог: узлы под
  sentinel про свою пару не знают, а служба, которая знает, клиенту
  сама не звонит. Клиент обязан спросить сам.
  
  В журнале видна и вся процедура: сначала один sentinel решает, что
  мастер молчит (+sdown), потом кворум подтверждает (+odown), потом
  выбирается ведущий (+vote-for-leader, +elected-leader) и только он
  повышает реплику. Два шага — «сломалось» и «кто чинит» — здесь
  разнесены намеренно, и в следующем блоке видно, зачем.

10. СТАРЫЙ МАСТЕР ВЕРНУЛСЯ: САМОЕ ОПАСНОЕ МЕСТО РЕЖИМА SENTINEL
----------------------------------------------------------------------
  мастер сейчас                 127.0.0.1:41979

  t=0.00  узел 44393 поднят обратно
  t= 0.06  роль master, запись -> OK
  t=10.10  роль slave, запись -> READONLY You can't write against a read only replica.

  переведён в реплику через     10.10 с
  сразу после перевода: GET who old
  после синхронизации: GET who  (её нет)

  Вот окно, ради которого блок и написан. Вернувшийся узел поднимается
  МАСТЕРОМ — он таким себя помнит — и принимает записи. Sentinel
  переводит его в реплику не мгновенно, а обнаружив.
  
  Две последние строки надо читать вместе, и именно в таком порядке.
  Сразу после перевода запись ещё на месте: узел уже реплика, но
  синхронизация только началась. А после неё ключа нет — данные
  заменены копией настоящего мастера. То есть клиент получил на свою
  запись OK, и запись исчезла; никакой ошибки он при этом не видел.
  
  Опасность не в самом окне, а в том, кто в него попадает: клиент,
  который держит адрес данных напрямую и не спрашивает sentinel. Для
  него старый адрес снова живой, отвечает OK — и всё идёт в никуда.
  В кластере такого окна нет: вернувшийся узел узнаёт из шины, что
  его слоты уже у другого, ещё до того, как примет первую команду.