Всем привет! Я Ильшат, занимаюсь базами данных в #CloudMTS. За свою карьеру работал с различными СУБД (PostgreSQL, MongoDB, ClickHouse, Redis, MySQL, MariaDB, GreenPlum, etcd), и со временем у меня созрела методика добавления СУБД в стек эксплуатации. Сегодня хочу поделиться чек-листом, который поможет учесть все значимые аспекты работы базы данных. Он пригодится в следующих случаях:   уже есть база в продуктиве, и ее нужно забрать к себе на администрирование  ; нужно быстро разобраться в новом типе СУБД, с которой вы не работали ранее, но которая скоро будет использоваться в вашем проекте; у вас «зоопарк» из СУБД, и нужно стандартизировать подход к развертыванию баз данных.    провести аудит инфраструктуры СУБД. Статья пригодится не только DBA, но и тем, кто по долгу службы занимается поддержкой СУБД, например системным администраторам, а также инженерам, отвечающим за надежность инфраструктуры — DevOps и SRE.   Так как статья вышла довольно увесистой, в каждом разделе расписал две опции: в первой сформулировал базовые требования, которые помогут создать минимальный продукт (MVP), во второй — про более тонкие настройки и лучшие практики, ее спрячу под спойлер. Пару разделов «для продвинутых» отправлю под спойлер полностью.   Если вы ранее не работали с СУБД, которую вам предстоит запустить, то первый ваш шаг будет очень прозаичным. Это исследование. Тут нет никаких коротких путей — берете документацию, статьи и видео с хорошими рейтингами/просмотрами и погружаетесь.   Заложите бюджет времени на изучение от месяца. Добавлю неочевидный, но очень полезный ресурс знаний. Это репозитории с имеющейся автоматизацией по данной СУБД. Мне нравится Ansible Galaxy.   Дальше буду рассказывать исходя из того, что мы все действия будем автоматизировать (я предпочитаю Ansible и Terraform). Но в этой статье не будет кода. Мы рассмотрим сам подход, когда изначально все закладываем в автоматизацию, а Git используем как источник первичной информации по базам данных.    Прежде чем настраивать, стоит завести документацию по настройкам и обозначить причины выбора определенных настроек вместе с датами внесения изменений и ссылками на документацию, версию СУБД.   Вторым шагом изучаем ресурсы слоя под базой данных:   Какие варианты скейлинга он нам дает: можно ли увеличивать или уменьшать CPU/RAM/disk без перезагрузки инстанса.    Какие файловые системы нам доступны из коробки и какие нам стоит попросить добавить или добавить самостоятельно в конфигурации Terraform.    Какая у нас будет сеть между узлами: плоская или маршрутизируемая.    Если будут использованы инструменты для поддержания кворума вроде etcd или zookeeper, возможно ли их разместить на отдельных инстансах с отдельными дисками в случае высоких нагрузок на СУБД.   На третьем этапе определяемся с размерами датасета и требуемой производительностью (варианты скейлинга подробнее раскрою в части по настройке СУБД). Например, если предполагается нагрузка 1–10 транзакций в секунду, то не стоит тратить время для супертонкой настройки базы.    С другой стороны, мы должны закладывать возможность масштабируемости и продумать конфигурацию с прицелом на будущие нагрузки. На ранних этапах такой задел может показаться избыточным, но при достижении базы определенных размеров вам не придется делать перезагрузку, чтобы применить новые параметры.    Подобранную конфигурацию стоит сразу же автоматизировать. Для некоторых баз данных уже есть готовая автоматизация, например, у MongoDB это роль mongodb_linux в community коллекции mongodb в Ansible Galaxy.   Kernel   Transparent Huge Pages. Использовать или нет, с какими флагами. Swappiness, обычно 1 или 0. Лимиты на количественные показатели ulimit, такие как LimitFSIZE, LimitCPU, LimitAS, LimitMEMLOCK, LimitNOFILE, LimitNPROC. Актуальность версии ядра Linux. Настройки межпроцессного взаимодействия и общей памяти (kernel ipc, shmem), если параллелизм доступа к СУБД реализован с помощью linux ipc (привет, PostgreSQL). Compute    Некоторые специфичные настройки и параметры, например NUMA, выставленные флаги. Выбор scaling governor. Обычно ограничивается режимом максимальной производительности performance, чтобы система не уходила в режим энергосбережения. Memory   Vm.* параметры ядра (overcommit_memry, vm_dirty_ratio, vm_dirty_background_ratio). Возможно, потребуется специальный тюнинг в зависимости от типа аллокации памяти движком СУБД. Disk. Для СУБД это один из самых дорогих и медленных ресурсов, поэтому следует уделить особое внимание его настройке:     Выбор файловой подсистемы и ее параметров. Обычно в документации явно рекомендуют использовать одну из файловых подсистем либо на выбор предлагают две-три как равнозначные. Например, XFS очень быстро работает с очень большими файлами, но не умеет уменьшаться в размерах, а ext4 умеет, но работает хуже с большими файлами.  Выбор I/O scheduler зависит от используемого типа дисков (NVMe SSD/SSD/HDD). Обычно выбирают между noop или deadline. Выбор RAID-конфигурации. Лучше взять RAID10, но если дорого, то в каких-то случаях можно обойтись RAID5 или RAID6. SWAP. Я изначально ставлю акцент на кластеризуемом варианте деплоя СУБД. Если у вас нет реплик, то swap поможет продержаться дольше в случае нехватки памяти в ущерб производительности. Но в обычной жизни он почти всегда не нужен. Если мы можем пожертвовать небольшой порцией данных, потерянных перед смертью сервиса в результате out of memory killer (OOM) взамен на производительность и аптайм, то мы почти всегда так и сконфигурируем систему. Network   Firewall. Использование встроенного в firewalld, iptables и других программных фаерволов модуля conntrack может значительно снизить производительность сервера с СУБД. Если есть возможность использовать внешние решения, то лучше выбрать их.  Список используемых портов. С самого начала ведите отдельный трек используемых портов для поддержания работы экосистемы СУБД. Так, при харденинге сетевых взаимодействий меньше вероятности, что сетевые инженеры как-либо повлияют на работу СУБД. Если планируется использование ipv6, подготовьте конфигурацию сервиса СУБД и выясните нюансы его настройки. Net.* настройки ядра для большого количества открытых сокетов и другие настройки, если это требуется от базы (например, net.core.somaxconn, net.ipv4.tcp_fin_timeout, net.ipv4.tcp_keepalive_intvl, net.ipv4.tcp_keepalive_time, net.ipv4.tcp_max_syn_backlog). Общие ресурсы   NTP. Для баз данных очень важно, а в шардированных вариантах даже критично, иметь правильно настроенные сервера времени. DNS. Некоторые базы данных при интерсерверных коммуникациях полагаются на FQDN. Полезно дополнительно настраивать  /etc/hosts, чтобы не зависеть от сбоев и быстродействия DNS-серверов. В качестве дополнительной меры можно ставить immutable флаг на этот файл после настройки. Repository. Важно вести отдельный трек необходимых пакетов для поддержания работы СУБД с самого начала. Если сейчас нет своего сервера с репозиториями, то потом он может появиться, а если есть, то в случае его аварии можно будет быстро восстановить необходимые репозитории.  Почти в каждом гайде по конфигурированию СУБД пишут, что нет универсального рецепта по первичной настройке, а потом приводят рекомендации настройки в соответствии с одним или другим типом нагрузки, размером базы данных. Как я и говорил ранее, диски — это самый медленный и дорогой ресурс, поэтому условно базы данных можно поделить на три типа по использованию дисков и памяти:   Все данные из таблицы / коллекции / других сущностей влезают в ОЗУ.   Самый большой индекс влезает в ОЗУ.   Даже индексы настолько большие, что не влезают в ОЗУ.   В соответствии с этими постулатами я бы сделал три варианта конфигурации, где численные значения масштабировались бы автоматически с помощью коэффициентов в зависимости от типа конфигурации. Например, можно написать калькулятор shared_buffers для PostgreSQL. В зависимости от размера инстанса методики подсчета для размеров данных порядка нескольких гигабайт и терабайт будут разными. Это покроет 90% нужд, останется добавить четвертый кастомный тип конфигурации для специальных нагрузок.   При разработке автоматизации следует учитывать, что со временем придется вносить изменения в конфигурацию, поэтому изначально продумываем механизмы внесения изменения в:   RBAC и автоматизацию учетных записей; изменение и применение настроек;   тесты после применения настроек (интеграционные, нагрузочные, функциональные), бенчмаркинг.   Желательно, чтобы внесение изменений не вызывало даунтаймы для пользователей и чтобы клиент СУБД вообще ничего не заметил.  Перед внесением изменений продумайте план отката на каждый шаг внесения изменений. В минимальном варианте необходимо написать автоматизацию по деплою кластера БД или взять готовую и адаптировать переменные под свою инфраструктуру и двигаться к следующему пункту. А все, что под катом, пойдет в бэклог и будет реализовано в процессе внедрения.    Перед внесением СУБД в стек изучите доступные методы репликации и переключения нагрузки. Следует продумать следующие сценарии:  плановое переключение нагрузки руками; автоматическое переключение нагрузки после однократного срабатывания; поведение при многократных перебоях сети недетерминированной длительности; остановка автоматизации переключения нагрузки (полезно при проведении работ). Вот примерный список вопросов, на которые нужно знать ответ: Нужна ли синхронная репликация (если она вообще поддерживается СУБД). Как обрабатываются ошибки репликации и связности. Например, если связь с клиентом потерялась, транзакция была выполнена и отправлен коммит, но не пришел ответ, что коммит дошел. Есть ли более мягкая альтернатива синхронной репликации, например как  readPreference/writePreference как в MongoDB. Какие допустимые RPO на переключение нагрузки и каким образом выбирается реплика для переключения нагрузки. Какие механизмы кластеризации использовать. Договориться использовать mongodb URI, postgresql URI  или их аналоги, если есть, а если нет, то переключать виртуальный IP-адрес с помощью keepalived, vip-manager.  А еще можно поставить прокси для запросов, не забыв и его кластеризовать. В качестве прокси может выступить  nginx/haproxy или специальный прокси под конкретную СУБД. Продумать сценарии недоступности, как их отработает кластеризация? Например, самое тяжелое — многократные разрывы связи по сети между узлами произвольной длительности. Какую систему по CAP-теореме (CA/AP/CP). Как будет работать резервное копирование после переключения нагрузки. Как будет работать мониторинг после переключения нагрузки (настройте  алертинг на событие фейловера).  В самом простом варианте реализуем резервное копирование средствами, поставляемыми совместно с СУБД. Важно следовать документации и по возможности снимать резервные копии с реплики, озаботиться механизмом выбора реплики для снятия резервной копии. Если документация рекомендует снимать резервную копию с главного узла в кластере репликации, то сделать механизм верификации, что узел главный в кластере, и снимать с нее копию. После снятия резервной копии, в зависимости от размера базы, можно применить сжатие во время отправки на удаленный сервер.   Собираем у бизнеса информацию по RPO (сколько данных допустимо потерять) и RTO (за сколько происходит восстановление): сколько компания будет готова обходиться без какой-то бизнес-функции.Убеждаемся, что бизнес понимает, что цифра по RPO и RTO учитывает не только вашу СУБД, но и эти же показатели у всех связанных систем.Также закладываем время на случай ошибки при развертывании из бэкапа.Отталкиваясь от этих метрик, будем строить систему резервного копирования. Обычно это утилиты, позволяющие снять резервную копию в логическом или физическом виде с поддержкой восстановления к моменту времени или без него. RTO: Если база большая, в самом требовательном варианте одну или несколько копий можно хранить локально на ноде с теми же характеристиками ресурсов, что и главный узел в кластере репликации. Далее идет быстрый s3 и другие методы хранения резервных копий. RPO: Хорошие показатели можно обеспечить в экстремальном варианте, например в Postgres, вдохновившись докладом «КУК без потерь». Также если данные вставляются из кафки, то можно поручиться у ее администраторов, что кафка бекапится и хранит данные в течение длительного времени, получить одобрение у заказчиков, что восстановление к моменту времени будет осуществляться с помощью резервной копии БД + повторной вставки данных из кафки. В этом случае можно снимать резервную копию всего раз в день. Система резервного копирования также должна мониториться и проходить через планирование потребления ресурсов.  Важно продумать сценарии автоматизированного восстановления, когда необходимо: Восстановить одну ноду в кластере. Тут обычно три сценария: доливка данных из соседней реплики, снятие резервной копии с соседней ноды и ее восстановление на поврежденной или восстановление из резервной копии. Восстановить все ноды в кластере  поверх того же самого кластера. Это самый болезненный случай. Например, разработчик случайно испортил или удалил данные. Это может быть, когда, например, вызвали delete без условия в PostgreSQL, в MongoDB в aggregation pipeline вызвали out вместо merge. Восстановить данные в тестовую среду с обфускацией уязвимых данных.  Система мониторинга должна включать в себя: Системные метрики, де-факто стандарт тут Prometheus Node Exporter. Можно использовать и другой мониторинг, снимая фактически те же самые метрики потребления ресурсов, то есть CPU, RAM, network, disk. Аналитику по запросам. Сбор логов ошибок и тяжелых запросов. Стандартный мониторинг и алертинг виртуальной машины можно реализовать с помощью стека Prometheus/VictoriaMetrics + Alertmanager, Zabbix. Логирование — с помощью ELK-cтека или по старинке, journald. Кроме того, под каждую базу данных существуют свои решения для процессинга логов и аналитику запросов.    Для сбора логов можно также использовать Percona Monitoring and Management для MySQL, MongoDB, PostgreSQL.Pgwatch2 и pgbadger для PostgreSQL. На всякий случай проговорю очевидное — логи складываем на удаленных серверах. Как говорил мой коллега, который препарирует трупики умерших Postgres, важно снять диагностику на сервере во время предсмертной агонии, перед тем как окончательно сносить. Две минуты сбора информации дадут много полезного для постмортема, а обзавестись инструментами для сбора метрик перед принятием СУБД в стек хорошая практика. Например, кроме системных трейсов, PostgreSQL можно дебажить c помощью pgcenter, а MySQL — с помощью pt-stalk. Продумать подобный инструментарий стоит и для всех элементов инфраструктуры вокруг СУБД. Пробежимся по нему ближе к концу статьи. Я бы выделил несколько уровней обеспечения безопасности. Для каждого из них свой список мер:   Минимально допустимый уровень   Используется аутентификация с помощью актуальных алгоритмов. На момент написания статьи это от scram sha 256 и выше. Возможна аутентификация по ключу или с помощью AD/Kerberos. Настроена и используется ролевая модель, описанная ранее. Ограничение доступа по IP-адресам как на уровне СУБД, так и на уровне фаервола, отдельных подсетей. Уязвимые данные обфусцируются при копировании в тестовые среды. Настроен мониторинг, относящийся к безопасности. В базовой реализации это включение демона auditd и обработка его журналов, настройки или внешние инструменты аудита деятельности пользователей в СУБД. Отключен неиспользуемый функционал в СУБД, например интеграции по сетевым портам. Регулярный аудит security патчей, применение обновлений. Кеширование репозиториев. Кеширование репозиториев. Средний  Ко всему вышеперечисленному добавляется: Клиент-серверное взаимодействие идет с помощью механизмов SSL/TLS актуальных версий. Межсерверное взаимодействие шифруется SSL/TLS. Применение многофакторной аутентификации. Высокий    Проверка и приведение в соответствие параметрам ФЗ-152, PCI DSS, GDPR и другим нормативно-правовым актам.  Используются механизмы шифрования дисковой подсистемы. Резервные копии шифруются, ключи шифрования хранятся раздельно от резервных копий. Данные в базе шифруются клиентским ключом. Удаление ключа приводит в непригодность данные даже на резервных копиях. RBAC настроен таким образом, что администратор инфраструктуры баз данных не имеет доступа к самим данным. Настроен row level security, column level security. Настроен аудит запросов, расширенное журналирование, к журналам применены те же требования, что и к данным в базе. Изоляция СУБД как физически, так и в изолированном от интернета сегменте, обслуживание с авторизованных рабочих мест. В продолжение темы безопасности важно сразу заложить понятную ролевую модель доступа к данным. Вот профили нагрузки, для которых я готовлю роли: username_dbadm —  для внедрения изменений в БД (DDL для релизов); username_rw — для работы сервиса; username_ro — для аналитиков и «на посмотреть».  Важно ограничивать скоуп привилегий, ролей, учетных записей в рамках одной БД внутри СУБД. То есть если у пользователя есть роль username_dbadm, то она должна распространяться на конкретную базу, а не на все, что есть внутри СУБД.   Помним и про ограничение доступа по IP-адресам, чтобы разработчик, даже зная пароль от СУБД, для работы сервиса не смог в ней авторизоваться со своего рабочего места.  Например, в стандартной ansible role из коллекции community ansible для MongoDB нет поддержки этого функционала, а в синтаксисе самого MongoDB есть. В PostgreSQL тяжело автоматизировать добавление записей в hba через патрони. В Clickhouse вообще мало готового на ansible, особенно для RBAC, который и появился в СУБД пару лет назад.  В некоторых базах есть возможность логически организовать содержимое БД по различным пространствам имен с помощью схем (database schema). Если эта сущность есть в вашей СУБД, ее стоит использовать.  Секреты лучше всего автоматически генерировать и публиковать в хранилище паролей или использовать AD/Kerberos. Я специально вынес отдельно этот пункт, потому что durability — это одно из фундаментальных свойств в базах данных. В общем виде необходимо ответить на несколько вопросов: Как осуществляется журналирование? Есть ли у базы данных механизм предзаписи? Часто это write-ahead logging, иногда встречается в виде  redo log + undo log. Отдельно можно выделить механизм binary log в MySQL, oplog — в MongoDB.  Есть ли у базы данных механизм контрольных точек? Используется ли snapshotting? Подсчитываются ли контрольные суммы на различных этапах записи данных на диск? Как настраивается репликация? Нужен ли нам синхронный режим? Мультимастер? (На этом пункте уже останавливались довольно подробно.) Особенности движков по управлению данными по части durability (MySQL InnoDB, MongoDB WiredTiger). Поддерживается ли транзакционность DDL-запросов? Алгоритмы консенсуса и поддержания кворума, если есть. Поддерживается ли шардинг. Тут необходимо изучить механизмы поддержания durability в шардированном варианте СУБД. Каким образом осуществляется версионирование и устаревание данных?  Для каждого элемента экосистемы необходимо пройти все то же самое, что и для подготовки самой СУБД. Сюда мы отнесем: Средства резервного копирования, которые поставляются отдельно от СУБД Средства мониторинга и алертинга Системы проксирования и мультиплексирования запросов Анализаторы логов Инструменты для поддержания кворума (etcd, ZooKeeper, consul, whatever) Большой огромный мир всего остального, что хоть как-то может быть связано с вашей СУБД. Например, из https://mad.firstmark.com/ Вся экосистема должна удовлетворять требованиям безопасности, быть зарезервированной бекапами и автоматизирована. Понимаю, что список всего, что нужно учесть и знать про СУБД, может пугать, но при таком подходе ничего важного не останется за пределами вашего внимания.  Каждый раздел в этом чек-листе — это отдельный разговор, поэтому ждите статьи по каждому из них. В них я постараюсь подробно рассказать про детали и автоматизацию настроек на примере одной из СУБД. Тут у вас есть возможность повлиять на то, что за СУБД это будет. СУБД — победитель опроса ниже — и станет героем цикла статей.    Выражаю благодарность Алексею @lesovskyза полезные замечания по статье.  DBA