Capstone: шардированный отказоустойчивый кластер

Рейтинг: 71.7% · 16 голосов
Исчерпывающий курс по Tarantool 3.x: модель данных, движки memtx и vinyl, Lua и файберы, транзакции и MVCC, SQL, конфигурация (box.cfg и декларативная 3.x), репликация и Raft, шардирование vshard, эксплуатация, безопасность. 47 уроков со схемами.
Ответить
Аватара пользователя
denis_tnt
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Capstone: шардированный отказоустойчивый кластер

Сообщение denis_tnt »

Оглавление курса (47)
  1. Что такое Tarantool: in-memory СУБД и сервер приложений
  2. Архитектура изнутри: процесс, потоки, event-loop
  3. Установка и первый запуск: tt CLI, пакеты, Docker
  4. Интерактив: консоль, admin-консоль, первые команды
  5. Спейсы и кортежи: форматы, типы данных
  6. Типы индексов и их применимость
  7. Движки хранения: memtx vs vinyl
  8. DDL: схема, создание спейсов и индексов, миграции
  9. DML и выборки: insert/update/upsert, итераторы
  10. Персистентность: WAL, снапшоты, recovery
  11. Внутренности memtx: аллокаторы slab/arena, память
  12. Внутренности vinyl: LSM, компакция, тюнинг
  13. Lua и LuaJIT в Tarantool: box, модули, rocks
  14. Файберы: кооперативная многозадачность, каналы
  15. Транзакции: ACID, изоляция, MVCC
  16. Хранимые процедуры, модули, организация приложения
  17. net.box: удалённые вызовы, async
  18. Пулы соединений, балансировка, реконнект
  19. Ошибки и диагностика: box.error, pcall
  20. Типы и сериализация: MsgPack, decimal, datetime, uuid
  21. SQL в Tarantool: возможности и связь с box
  22. SQL: таблицы, JOIN, подзапросы, представления
  23. SQL: подготовленные выражения, транзакции, Lua-интероп
  24. Классическая конфигурация box.cfg (legacy 1.x/2.x)
  25. Декларативная конфигурация 3.x: config.yaml, иерархия
  26. Роли и приложения в 3.x
  27. Централизованная конфигурация: etcd / config storage
  28. tt CLI глубоко: разработка, сборка, запуск
  29. Cartridge (официальный legacy) и миграция на 3.x
  30. Репликация: replicaset, топологии
  31. Механика репликации: WAL-стриминг, vclock
  32. Синхронная репликация и выборы лидера (Raft)
  33. Жизненный цикл узла: bootstrap, join, rejoin
  34. vshard: router/storage, виртуальные бакеты
  35. Решардинг и rebalancing бакетов
  36. Запросы поверх шардов: map-reduce, crud
  37. Мониторинг: метрики, Prometheus, Grafana
  38. Логирование и аудит
  39. Бэкапы и восстановление
  40. Безопасность: аутентификация, RBAC, TLS
  41. Производительность: профилирование, тюнинг
  42. Обновления: схема, rolling upgrade
  43. Деплой в продакшен: Docker, топология (официальные паттерны)
  44. Администрирование через официальный TCM (Tarantool Cluster Manager)
  45. Коннекторы: Python, Go, Java
  46. Ключевые модули (rocks): crud, metrics, queue, expirationd
  47. Capstone: шардированный отказоустойчивый кластер (вы здесь)
Зачем этот урок

Это финал курса. Мы не вводим новых сущностей - мы собираем все ранее пройденное в одну работающую картину: как vshard режет данные на шарды, как репликация держит каждый шард живым, как etcd раздает единую конфигурацию всем узлам, и как мониторинг показывает, что система здорова. Цель - чтобы вы держали в голове путь запроса от клиента до конкретного tuple и понимали, какой компонент отвечает за каждую гарантию.

Промышленный кластер Tarantool 3.x - это не один процесс, а четыре слоя, которые работают вместе:
  • слой шардирования (vshard): router-ы и storage-узлы, разбиение данных по бакетам;
  • слой репликации: внутри каждого шарда - replica set с одним master и репликами;
  • слой конфигурации: etcd (или Tarantool-based config.storage) как единый источник топологии;
  • слой наблюдаемости: metrics + экспортер, алерты по лагу репликации и состоянию бакетов.
Как это устроено внутри

Слой 1. Шардирование (vshard). Весь датасет логически делится на фиксированное число виртуальных бакетов (bucket_count, например 30000). bucket_count - стратегический параметр: его задают на bootstrap и изменить потом нельзя. Правило - на 2-3 порядка больше, чем планируемое число узлов (100*M ... 1000*M), иначе пострадает гранулярность ребаланса.

Каждый tuple шардируемого спейса хранит свой bucket_id в отдельном поле. На стороне storage системный спейс _bucket хранит, какие бакеты сейчас лежат на этом шарде и в каком статусе. router держит routing table - карту bucket_id -> replica set - и не имеет персистентного состояния: он строит ее в рантайме. Специальный discovery fiber на router-е периодически обходит storage-узлы и обновляет карту, поэтому переезд бакета или смена master прозрачны для приложения.

Запрос всегда идет через router, и единственная операция router - call:

Код: Выделить всё

result = vshard.router.call(bucket_id, mode, func_name, {args}, {opts})
-- mode: 'read' (можно с реплики) или 'write' (только master)
router по bucket_id находит replica set, шлет туда вызов. storage проверяет: есть ли бакет в _bucket и в статусе ли он ACTIVE/PINNED (для чтения допустим SENDING). Если нет - ошибка "wrong bucket".

Слой 2. Репликация внутри шарда. Шард = replica set. Реплика тянет WAL master-а и применяет его: репликация row-based, каждая запись WAL - детерминированная DML-операция с растущим LSN. Вызовы хранимок в WAL не пишутся - пишутся их фактические изменения данных, чтобы недетерминизм Lua не рассинхронил реплики. Рекомендованная топология - full mesh (не каскад: на реплике реплики узел может не узнать чужой replica set UUID и получить отказ в подключении). Предел - 32 реплики в mesh.

Слой 3. Отказоустойчивость. В replication.failover есть режимы. Самый автономный - election: Tarantool сам выбирает лидера через модификацию Raft. Жизнь сета делится на термы (монотонно растущий номер); узел без лидера повышает терм и начинает голосование. Кто собрал кворум replication.synchro_quorum (для строгого Raft - N/2+1), тот лидер и шлет heartbeat-ы. Если heartbeat-ов нет в течение replication.timeout*4, начинаются перевыборы. Чтобы старый лидер при потере связи не остался writable и не возник split-brain, есть fencing (election_fencing_mode: soft по умолчанию, strict жестче). Альтернатива выборам - supervised failover с внешним координатором, который как stateboard использует etcd/config.storage.

Слой 4. Единая конфигурация (etcd). В 3.x вся топология - декларативный YAML. Чтобы не раскладывать идентичный файл руками на каждый узел, его кладут в централизованное хранилище (etcd или Tarantool config.storage, доступно в Enterprise Edition). Все инстансы при старте тянут конфиг по пути prefix/config/*. etcd параллельно может работать stateboard-ом для supervised failover - то есть один внешний слой и про топологию, и про выбор мастера.

Слой 5. Мониторинг. Встроенный модуль metrics отдает счетчики и собирает специфику vshard/репликации. Ключевые сигналы: box.info.replication[n].upstream.status и lag (отставание реплики), состояние бакетов и наличие застрявших в SENDING/RECEIVING, дисбаланс replica set. Экспортер отдает это в Prometheus, поверх - алерты.

Изображение
Сквозная архитектура: vshard, репликация, etcd, мониторинг

Ключевой код и команды

Декларативный 3.x: подключение узла к конфигу в etcd (фрагмент локального config.yaml):

Код: Выделить всё

config:
  etcd:
    endpoints:
      - http://192.168.0.10:2379
      - http://192.168.0.11:2379
    prefix: /myapp
    username: tarantool
    password: secret
    http:
      request:
        timeout: 3
Публикация общей топологии в etcd (ключ prefix/config/all):

Код: Выделить всё

$ etcdctl put /myapp/config/all < cluster.yaml
Классический трек (box.cfg, 1.x/2.x) - те же гарантии задаются напрямую:

Код: Выделить всё

box.cfg{
  listen = 3301,
  replication = {'replicator@host1:3301','replicator@host2:3301','replicator@host3:3301'},
  election_mode = 'candidate',     -- участвовать в выборах
  replication_synchro_quorum = 2,  -- N/2+1 для N=3
  read_only = false,
}
Диагностика прямо из консоли инстанса:

Код: Выделить всё

box.info.replication           -- статус и lag всех upstream/downstream
box.info.election              -- term, state (leader/follower/candidate), vote
vshard.storage.info()          -- статус бакетов, алерты этого шарда
vshard.router.info()           -- доступность шардов, известные бакеты
vshard.router.bucket_count()   -- всего бакетов
Формула дисбаланса, по которой просыпается rebalancer:

Код: Выделить всё

disbalance = |etalon_buckets - real_buckets| / etalon_buckets * 100
если > порога конфигурации -> запускается миграция бакетов
Частые заблуждения и грабли
bucket_count можно подкрутить позже. Нет. Он фиксируется на bootstrap. Заложите запас сразу: слишком мало - грубый ребаланс, слишком много - лишняя память под routing table.
  • router на storage-узле. Технически можно, в проде - нет. Разносите router и storage по разным инстансам, иначе одна перегрузка валит оба слоя.
  • Меньше трех реплик в шарде. Для election и для переживания отказа нужен кворум. Два узла дают failover, но не дают надежного кворума при сетевых разрывах - норма для прода 3+.
  • Каскадная репликация. Реплика реплики не узнает UUID всех узлов через _cluster и при смене топологии получит отказ. Только full mesh (или временно ring, потом разрыв).
  • Master-master с некоммутативными операциями. Асинхронный мультимастер безопасен только если изменения коммутативны. UPDATE-ы (присваивание, инкремент) легко уводят реплики в рассинхрон.
  • Забыли про fencing. Без него потерявший связь лидер может остаться writable - привет split-brain. Для важных данных - strict.
  • Разные конфиги на узлах. При ручной раскладке файлы расходятся. Единый источник (etcd) этого не допускает - в этом его смысл.
  • Мониторят только CPU. Главный ранний сигнал - lag репликации и бакеты, застрявшие в SENDING/RECEIVING. Алертьте именно их.
Мини-лаба

Поднимите на одной машине кластер из двух шардов (по 2 инстанса) + 1 router, любым знакомым способом (tt + локальный config.yaml). Затем на router-е выполните vshard.router.info() и vshard.router.bucket_count(), а на одном из storage - vshard.storage.info() и box.info.replication. Задание: найдите в выводе, как бакеты распределились между двумя шардами, и кто из двух инстансов каждого шарда является master (read_only = false). Остановите master одного шарда и посмотрите через box.info.election, как роль leader переходит на реплику.

Контрольные вопросы
  • Почему bucket_count выбирают сильно больше числа узлов и почему его нельзя менять после bootstrap?
  • Что именно делает discovery fiber на router-е и почему благодаря ему failover и переезд бакета прозрачны для приложения?
  • Какую роль играет etcd одновременно для конфигурации и для supervised failover?
  • Что такое fencing в выборах лидера и от какой проблемы он защищает?
👍4 ❤️ 🔥5 😄 🤔
Ответить
← Предыдущая глава
Ключевые модули (rocks): crud, metrics, queue, expirationd

Все главы курса «Tarantool: in-memory СУБД и сервер приложений с нуля до продакшена»

Поделиться темой: ✈ Telegram VK

Вернуться в «Tarantool: СУБД и сервер приложений»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость