Попытался "быстренько" пробежаться по всем СУБД с которыми работал за 20 лет и постараться вложить слушателям мысль что СУБД надо выбирать под нагрузку
и что для СУБД надо знать "алгоритмы" и "эксплуатацию"
2. С какими системами я работал
OLTP SQL – MySQL, PostgreSQL, MSSQL, Firebird
OLAP – MS OLAP (мало)
Колоночные – Vertica, Clickhouse
NoSQL – Redis (много), MongoDb (мало), Tarantool (очень мало)
3. По каким граблям ходят разработчики всех
СУБД ;) RUM теорема
R (read) U (update) M (memory) overheads
4. Что должен знать «обычный» программист
про используемые СУБД
Алгоритмы
•Как БД «пишет», «хранит» и «читает» данные?
•Под какой тип нагрузки оптимизирована БД?
•Как обрабатывается конкурентный доступ к
данным?
5. Что должен знать «обычный» программист
про используемые СУБД
Эксплуатация
• Насколько легко эту БД «мониторить» и «отлаживать»?
• Насколько легко эту БД «обновлять»?
• Насколько легко изменять «схему данных» в данной БД?
• Насколько стабильны драйверы БД в вашем языке?
• Как сделать горизонтальное масштабирование?
6. Как БД «пишет», «хранит» и «читает» данные?
MySQL, PostgreSQL – нагрузка OLTP
• Запись
mem buffer -> transaction log (innodblog, WAL) -> table space
(innodbdata, base)
• Хранение - «страницы» в них «строки (tuples)» (целиком)
отдельные страницы для «индексов»
отдельные страницы для «жирных столбцов» (BLOB, JSON, any
extended storage)
• Чтение - постранично в память, cache в памяти «для горячих данных»
MySQL - innodb buffer pool + O_DIRECT
Postgres – shared buffers + кеш средствами OS
сортирует и фильтрует в одном ядре (почти всегда ;)
7. Как БД «пишет», «хранит» и «читает» данные?
Clickhouse – нагрузка OLAP
• Запись
«пишет пачками по XXX записей» сразу на диск
входные данные в «большие» (1M на столбец) буфера в памяти и потом в
каждый столбец отдельно, без transaction log
• Хранение
каждый столбец отдельно и сжато (zstd), нет дельта-кодирования для чисел
(скоро будет), данные разбиты по «партициям» и «отсортированы по первичному
ключу» (легче фильтровать), «новые данные» сливаются со старыми в фоновом
режиме
• Чтение
- большими кусками последовательно, кеширует средствами OS, сортировка и
группировка много ядер (потоки)
8. Как БД «пишет», «хранит» и «читает» данные?
Redis – in-memory OLTP
• Запись
каждая команда изменяющая данные (кроме PUBSUB) сразу в память и в AOF
файл (если включен)
• Чтение - Глобальная «хеш» таблица
«читает» только из памяти
• Хранение
«хранит» AOF файл, либо > Fork -> Copy on write -> RDB файл
• Есть disk based аналоги - http://ssdb.io/, https://github.com/yinqiwen/ardb
9. Как БД «пишет», «хранит» и «читает» данные?
MongoDb – OLTP schema less
• Запись
сначала в буфер в памяти -> паралельно WAL + Document Storage (сжатие)
• Хранение
«страницы» в них версии документов + «вторичные индексы»
• Чтение
- кеш в памяти (в памяти тоже сжатие) + файловый кеш OS
10. Как обрабатывается
конкурентный доступ к данным?
MySQL – thread per connect (+отдельный accept thread) + storage thread pool
PostgreSQL – process per connect (+ auto vacuum)
ClickHouse – thread pool per connect
Redis – single thread to all connection
Mongodb – thread per connect
11. Насколько легко эту БД «мониторить» и
«отлаживать»?
«Мониторить» легко в принципе всех, инструментов много
Лично мой выбор это Prometheus
Mongo + MySQL https://www.percona.com/software/database-tools/percona-monitoring-and-
management
PostgreSQL http://dalibo.github.io/powa/
Clickhouse https://github.com/f1yegor/clickhouse_exporter
Redis https://github.com/oliver006/redis_exporter
«Отлаживать» уже гораздо сложнее, но инструменты тоже есть
УЧИТЕ EXPLAIN!!!
MySQL Performance Schema
PostgreSQL pg_stat_activity, pg_stat_statement
Redis https://github.com/facebookarchive/redis-faina
https://github.com/gamenet/redis-memory-analyzer
Больше всего не хватает возможности через драйвер вставить место в коде где идет «вызов
запроса»
12. Насколько легко эту БД «обновлять»?
Обновляться «сложно», но можно ;)
Самое сложное обновлять все БД без «downtime» и без «dump/restore» да еще и
желательно на одной машине
MySQL – логическая репликация + mysql_upgrade
PostgreSQL – pglogical + pg_upgrade
Clickhouse – apt-get upgrade
Redis – apt-get upgrade
MongoDb – после 3.x версии apt-get upgrade сначала для secondary, потом primary
нод, без ReplicaSet
13. Насколько легко изменять
«схему данных» в БД?
• MySQL – pt-online-schema-change
• PostgreSQL – CREATE INDEX CONCURENTLY + ALTER TABLE бесплатен
для DEFAULT NULL
• Redis – схему ключей надо менять руками
• Clickhouse – ALTER TABLE бесплатен, но ограничен по функционалу
• Mongodb – schema less из коробки, но схему документов все равно
надо «дизайнить»
14. Насколько стабильны драйверы БД в Python?
Чтобы оценить обычно я иду в github для соответсвующего
драйвера и смотрю issues и history
В python с драйверами все хорошо ;) С багами в них тоже ;)
• MySQL – MySQLdb, aiomysql
• PostreSQL – psycodb2, aiopg
• Clickhouse – clickhouse-driver, aioch
• Redis – драйверов вагон ;)
• MongoDb – pymongo
15. Как сделать горизонтальное масштабирование?
На самом деле ответ 42 или k8s ;)
• MySQL – http://github.com/youtube/vitess/
• PostgreSQL – https://github.com/zalando/patroni
• Clickhouse https://github.com/count0ru/k8s-clickhouse
• Redis - https://github.com/sobotklp/kubernetes-redis-cluster
• MongoDb – http://k8smongodb.net
16. Грабли на которые наступал я - MySQL
• row based репликация + mysql_upgrade + xtrabackup
• Single Thread MySQL Replication – LAG
• «сломанная репликация» при ротации binlog
• GROUP BY упирающийся в одно ядро
• Включайте innodb_file_per_table
• Осторожнее с innodb_flush_log_at_trx_commit
• Осторожнее с sort_buffer
• Поймите что такое data cardinality и не пытайтесь мучить индекс ;)
17. Грабли на которые наступал я - PostgreSQL
• Ломается Streaming Replication – max_wal_size и replication slots
• Autovacuum vs JSONB размером в 1Mb
• Берегите pg_xlog также как base ;)
• Wal-e + swift – восстановление в один поток
• pgbouncer pause – «не савсем pause»
• Patroni гибче чем repmgr
• «Длинный SELECT» на standby - max_standby_streaming_delay один
на всех
• Учитесь правильно считать размер shared_buffers
• GROUP BY в один поток
18. Грабли на которые я наступал - Redis
• Не допускайте ситуации когда «все ломятся в один ключ»
• Не пытайтесь хранить больше 2-5kb на ключ
• На 32G и выше лучше 4 ноды по 8Gb чем 1 по 32G
• Пользуйтесь KEYS только в самом крайнем случае
• Смотрите «сложность алгоритмов» в документации
• PUBSUB – не очень эффективен по памяти, не пытайтесь через него
гонять данные (чат), только id и не пиками
• AOF может ломаться и это надо отдельно мониторить
• Twemproxy и Codis – стоит присмотреться
19. Грабли на которые я наступал в Clickhouse
• Не работает с zetcd ;)
https://github.com/yandex/ClickHouse/issues/777
• «Большие буфера» на вставку
https://github.com/yandex/ClickHouse/issues/868
• Репликация «асинхронная», данные до некоторых реплик могут
доехать не сразу
• Float32, Float64 – это не numeric с фиксированной точностью
https://github.com/yandex/ClickHouse/issues/1665
20. Как выбрать СУБД?
Прежде всего поймите какой у вас тип нагрузки в приложении!
Могут быть разные типы нагрузки в разных частях приложения.
Значит нужны РАЗНЫЕ СУБД!
Ответьте на вопросы:
Чего больше? Чтения или записи?
При чтении данные должны быть актуальны?
При чтении данные группируются? Сортируются? Фильтруются?
Сколько данных читается за один запрос?
Сколько данных пишется за один запрос?
Как долго нам хватит диска по размеру? и т.д. и т.п.
21.
22. ORM vs Plain SQL
• за «Object Mapping» приходится платить
• IMHO Raw SQL просто надо сделать “prepared” и вынести в
классы моделей
23. Логика в Базе данных
• В SQL сложную логику писать «не очень» и надо научиться
«обновлять stored процедуры»
• Но вот есть tarantool и там через Lua очень хорошо реализован
hot reload lua кода
• Для «чтения» есть Materialized View и Temporary Tables, но это
«дорого» и может быть по Space и Write
24. Вопросы из зала?
Пара ссылок на последок
https://github.com/onurakpolat/awesome-bigdata
https://github.com/igorbarinov/awesome-data-engineering
Со мной можно связаться
bloodjazman@gmail.com
https://t.me/bloodjazman