Порой в процессе развития высоконагруженного проекта наступает момент, когда необходимо масштабирование. Возможно, ваш проект впервые упёрся в производительность железа (и таким образом перешёл в разряд высоконагруженных); возможно, это уже не первое масштабирование — не важно. Какие же проблемы могут возникнуть?
Во-первых, если вы увеличиваете количество бэкенд-серверов, и, соответственно, количество рабочих процессов, то с ростом количества одновременных клиентских подключений вырастают и накладные расходы на базах данных.
Во-вторых, достаточно быстро может кончиться ресурс in-memory баз данных. Потребуется создать (либо увеличить) кластер, а это каждый раз влечёт за собой необходимость модифицировать логику приложения.
В-третьих, чем больше серверов, тем больше вероятность, что один из них выйдет из строя. Поэтому неплохо задуматься о том, как обеспечить отказоустойчивость, а это, опять же, потребует модифицировать логику приложения.
В этом докладе я расскажу, как и какими инструментами можно легко решить все вышеперечисленные проблемы: уменьшить накладные расходы от большого количества подключений к базам данных, создать/модифицировать кластер БД прозрачно для приложения, а также прозрачно добавить устойчивость к падениям серверов БД.
План доклада:
- Введение. Методы масштабирования БД: репликация, шардирование.
- Создаём шардированные кластеры in-memory БД прозрачно для приложений: Twemproxy, Redis-proxy, Mcrouter.
- Уменьшаем накладные расходы от большого количества одновременных подключений на PostgreSQL с помощью PgBouncer.
- Создаём шардированный кластер PostgreSQL с помощью PL/Proxy.
- Добавляем прозрачную для приложения отказо�
2. Содержание
● Как начинается Highload? (6 слайдов)
● Балансируем нагрузку на Backend (2 слайда)
● Методы масштабирования БД (3 слайда)
● Создаём кластер Redis/Memcached/Tarantool (12 слайдов)
● Создаём кластер PostgreSQL (9 слайдов)
2/36
3. Немножко статистики Avito
● 1M+ запросов в минуту к Backend
● 1Gb/s+ исходящий трафик (не считая картинки)
● 100K+ запросов в секунду на nginx-балансеры
● Терабайты или миллиарды картинок
3/36
16. Создаём кластер Redis/Memcached/Tarantool
16/36
Решаем проблемы с помощью Twemproxy:
● Прозрачно проксирует на уровне протокола
Memcached/Redis/Tarantool*
● Держит постоянное подключение к серверу
● Устанавливает мало подключений к серверу,
через них мультиплексирует много клиентских
подключений
* нужен патч
20. Создаём кластер Redis/Memcached/Tarantool
20/36
Добавляем отказоустойчивость Redis-кластера
с помощью MSR, Sentinel и HAProxy:
● Master-Slave Replication средствами Redis
● Автоматическое переключение в случае отказа
мастера с помощью Redis Sentinel
● Прозрачное для клиента переключение с помощью
HAProxy
22. Создаём кластер Redis/Memcached/Tarantool
22/36
Redis Sentinel
● Мониторит состояние всех нод кластера
● Уведомляет об ошибках
● Автоматически промотирует slave до master в случае
падения master
● Выступает в качестве провайдера конфигурации
27. Создаём кластер PostgreSQL
27/36
Проблемы:
● Одно подключение – один процесс, создание
процесса – дорогостоящая операция
● Больше подключений – больше накладных
расходов на сервере
● План запросов и т. п. кэшируется внутри
процесса, новое подключение – пустой кэш
● Срок жизни подключения – не дольше, чем
работает скрипт
28. Создаём кластер PostgreSQL
28/36
Решаем проблемы с помощью PgBouncer:
● Прозрачно проксирует на уровне протокола
PgSQL
● Держит постоянное подключение к серверу
● Мультиплексирует клиентские подключения в
трёх режимах: session, transaction, statement
pooling
● Выполняет запросы до и после подключения
29. Создаём кластер PostgreSQL
29/36
Решаем проблемы с помощью PgBouncer:
pgbouncer.ini:
[databases]
main = host=db-main pool_size=5 connect_query=
'select prepare_statements_and_stuff()'
[pgbouncer]
listen_port = 6432
listen_addr = *
pool_mode = transaction
max_client_conn = 1024
30. Создаём кластер PostgreSQL
30/36
Синхронная и асинхронная репликация
Синхронная:
● Мастер ждёт, пока все слейвы получат данные
● Надёжная, но медленная
Асинхронная:
● Мастер отправляет данные в очередь и не ждёт
● Быстрая, но ненадёжная, теряет ACID, так как
слейвы отстают
31. Создаём кластер PostgreSQL
31/36
Физическая и логическая репликация
Физическая:
● Полная копия всех данных
● Загружает I/O
Логическая:
● Можно выбирать, какие данные копировать
● Загружает CPU
32. Создаём кластер PostgreSQL
32/36
Создаём MSR-кластер
1 master, 1 slave:
● Распределяем нагрузку на чтение
● Нет отказоустойчивости
1 master, 2+ slave:
● Можем выдержать падение мастера
33. Создаём кластер PostgreSQL
33/36
Создаём отдельную реплику для индексации
● Не вымывается кеш на мастере
● С помощью логической репликации копируются
только нужные данные
● Данные умещаются в RAM – нет медленного I/O
35. Создаём кластер PostgreSQL
35/36
Шардируем с помощью PL/Proxy
● Языковое расширение PostgreSQL
● Устанавливается на одной прокси-ноде
● Вся логика шардирования описывается в
хранимых процедурах PostgreSQL
● Можно реализовать поддержку шард с MSR
36. Подведём итоги
36/36
● Много кратковременных подключений к серверу – плохо,
используем прокси
● Нужна отказоустойчивость – используем Master-Slave
Replication, делаем несколько слейвов
● Слейвы должны быть не слабее мастера
● Данные не умещаются на одном сервере – шардируем на
несколько серверов
● Все эти подходы можно комбинировать