ЗАМЕР
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 — и всё идёт в никуда.
В кластере такого окна нет: вернувшийся узел узнаёт из шины, что
его слоты уже у другого, ещё до того, как примет первую команду.