Как масштабировать систему с шардированием и репликацией при росте запросов к базе
Что проверяют
Понимаете ли вы порядок шагов: что делать до шардирования и какую цену приложение платит за реплики и шарды. Следом обычно спрашивают, как вы выберете ключ шардирования и что будет с чтением сразу после записи.
Как отвечать
Покажите лестницу, по которой вы идёте, пока хватает предыдущей ступени:
- разобраться с запросами:
pg_stat_statements,EXPLAIN ANALYZE, индексы, N+1 в ORM (select_related/prefetch_relatedв Django,selectinloadв SQLAlchemy); - пул соединений: PgBouncer перед PostgreSQL, особенно если воркеров Gunicorn или Celery много;
- кэш: Redis для горячих чтений;
- реплики чтения: асинхронная потоковая репликация, запись в primary, чтение с реплик. В Django это несколько записей в
DATABASESи роутер сdb_for_read/db_for_write, в SQLAlchemy отдельные engine; - партиционирование: декларативные партиции PostgreSQL по дате или ключу, всё ещё одна база;
- шардирование: когда запись или объём не влезают в один сервер. Ключ выбирают по основному пути доступа, обычно
user_idилиtenant_id, распределение хэшем. Готовые решения: Citus для PostgreSQL, Vitess для MySQL.
У реплик цена в отставании. Пользователь сохранил профиль, обновил страницу, а реплика ещё не догнала. Лечится чтением с primary какое-то время после записи или синхронной репликацией (synchronous_commit) ценой задержки записи.
У шардов цена выше: запросы и транзакции через несколько шардов, решардинг, генерация идентификаторов. Автоинкремент в каждом шарде даст коллизии, нужны UUIDv7 или идентификаторы в духе snowflake.
Где спотыкаются
Начинают с шардирования. Большинству систем реплик, пула и индексов хватает надолго, а шарды навсегда усложняют каждую миграцию и каждый отчёт.
Выбирают ключ по дате или по стране. Вся свежая запись идёт в один шард, крупная страна перегружает свой, и выигрыша нет.
Забывают про отставание реплик и отказ primary. Без Patroni или управляемого failover реплика сама мастером не станет, а приложение продолжит писать в недоступный узел.