Синтез с выбором ответа по юниту строительных блоков: гонка rate limiter, упорядоченные по времени против случайных ID, односторонняя гарантия фильтра Блума, проблема границы geohash и split-brain, который побеждают fencing token'ы.
SDSenior◷ 13 min
Уровень
ОсновыJuniorMiddleSenior
Пять вопросов, режущих весь юнит. Каждый — решение, что ты принимаешь, когда тянешься к готовому механизму — лимитеру, схеме ID, фильтру членства, пространственному индексу, координатору — и берёшь верно тонкую часть, а не очевидную.
Подтверди, что замечаешь гонку распределённого счётчика, выбираешь упорядоченный по времени против случайного ID под ситуацию, рассуждаешь от гарантии «нет ложноотрицательных» фильтра Блума, побеждаешь проблему границы geohash и делаешь split-brain безвредным через fencing token.
Викторина
Completed
Rate limiter работает на 40 серверах, каждый делает GET-счётчик → проверка < лимита → SET счётчик+1 к общему Redis. Клиенты превышают лимит под нагрузкой. Какова минимальная корректная починка?
Heads-up Статическое деление тратит ёмкость при неравном балансе и всё равно дрейфует. Баг — гонка read-modify-write на общем счётчике; починка — атомарная инкремент-и-проверка, не дробление лимита.
Heads-up Лок на запрос сериализует весь флот и становится узким местом. Нужен атомарный примитив (INCR/Lua), дающий корректность без сериализации каждого запроса.
Heads-up Это прячет баг вместо починки и сводит на нет смысл лимитера. Перелив — гонка потерянного обновления; закрой её атомарностью.
Викторина
Completed
OLTP-таблица на кластеризованном индексе принимает миллионы строк/час, и нужна децентрализованная генерация ID по регионам без фрагментации индекса. Какая схема ID подходит лучше всего?
Heads-up Центральный sequence — узкое место и SPOF на пути записи, противоположность децентрализации. Используй упорядоченный по времени ID без координации, чтобы каждый регион выпускал свой, не фрагментируя индекс.
Heads-up UUIDv4 децентрализован, но его случайность фрагментирует кластеризованное B-дерево (расщепления страниц, потеря локальности кэша) — ровно та проблема пропускной способности, которой ты избегаешь. UUIDv7 сохраняет децентрализацию И вставки у правого края.
Heads-up Локальные счётчики сталкиваются по шардам (два шарда оба выдают id 1), так что ID не глобально уникальны. Упорядоченный по времени распределённый ID избегает и коллизии, и фрагментации.
Викторина
Completed
Ты хочешь стеречь дорогое чтение базы фильтром Блума, но коллега боится, что ошибочный ответ вредит. Когда фильтр здесь безопасен?
Heads-up У фильтров Блума НЕТ ложноотрицательных — «точно нет» всегда верно. Единственная ошибка — ложноположительный (безвредный лишний поиск). Поэтому они и безопасны как страж чтения.
Heads-up Удаление нерелевантно безопасности стража чтения (и простой фильтр всё равно не удаляет). Безопасность идёт из односторонней гарантии: ложноположительный вызывает лишь безвредное fallback-чтение.
Heads-up Они безопасны везде, где ложноположительный дёшев (fallback к истине). Небезопасны лишь как ЕДИНСТВЕННЫЙ авторитет для вредного «да» — страж чтения это безопасный случай.
Викторина
Completed
Запрос «водители рядом» выбирает лишь собственную ячейку geohash пассажира и пропускает водителя в 20 м через улицу. В чём починка?
Heads-up Точность это не чинит — водитель чуть за ЛЮБОЙ границей ячейки всё равно имеет другой код. Проблема границы решается расширением к 8 соседним ячейкам, не сменой точности.
Heads-up Обычный строковый/B-tree индекс отлично справляется с prefix-сканами geohash. Баг — запрос одной ячейки; починка — включить 8 соседей, независимо от типа индекса.
Heads-up Это выбрасывает весь смысл geohashing (индексированный prefix scan). Оставь индекс; просто расширь до ячейки пассажира плюс её 8 соседей и затем ранжируй по точному расстоянию.
Викторина
Completed
Лидер берёт лок, страдает долгую паузу GC за свой lease, избирается новый лидер, а старый просыпается, всё ещё действуя как лидер. Оба пишут. Что на деле предотвращает порчу?
Heads-up Никакой таймаут не отличит «мёртв» от «заморожен», а более длинный lease лишь замедляет failover, всё ещё допуская произвольно долгие паузы. Настоящая починка — fencing token на ресурсе.
Heads-up Больше узлов не остановят устаревшего лидера от действий после истечения lease. Починка — fencing token'ы, чтобы ресурс отвергал операции с устаревшим token.
Heads-up Он действует до того, как заметит; в этом опасность. Надо отгораживать его устаревшие записи на ресурсе монотонно растущим token, а не надеяться на самокоррекцию.
Вспомните перед уходом
01
Почему распределённый rate limiter переливает и какова однострочная починка?
02
Когда фильтр Блума безопасен, а когда нет?
03
Сформулируй правило fencing token, бьющее split-brain.
Итог
Сквозная линия юнита в том, что у каждого строительного блока очевидная поверхность и тонкое ядро корректности. Rate limiter тривиален на одном узле, но гоняется на флоте — починка это атомарная инкремент-и-проверка на одном общем счётчике (и fail open при падении). Генерация ID тривиальна с одним писателем, но нужна упорядоченная по времени схема (Snowflake/UUIDv7), чтобы остаться без координации, не фрагментируя индекс. Фильтр Блума — быстрая предпроверка членства, безопасная лишь где ложноположительный дёшев, ведь он гарантирует нет ложноотрицательных, но не нет ложноположительных. Geohashing превращает близость в prefix scan, но должен запрашивать ячейку плюс её 8 соседей, чтобы побить проблему границы. А выбор лидера прост до split-brain, который не предотвратит никакой таймаут — лишь fencing token на ресурсе делает устаревшего лидера безвредным. Бери тонкую часть, не только очевидную.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.