В IT-проектах код пишут все. Инженеры с помощью нескольких строк управляют Kubernetes кластерами, разгоняют облака Terraform'ом и ворочают тонны конфигураций на Ansible, Chef и Puppet. QA пишут понятные бизнесу тестовые сценарии на Spock и Cucumber. Аналитики свободно, часто лучше разработчиков, разговаривают на SQL. Проектная документация в форматах Markdown, AsciiDoc или LaTEX "компилируются" в нужный формат на билд-сервере. Ну а сами разработчики, эти укротители кода, владеют сразу россыпью языков на каждый жизненный случай — клиентский, серверный, скриптовый, функциональный и пр.
Код уже давно перестал быть загадочной тарабарщиной и теперь в том или ином виде доступен и понятен многим, даже премьер-министрам. И весь этот код участвует в стандартном жизненном цикле — находится под управлением VCS, подвергается code review, автоматизированному тестированию, CI, CD. Используются общие инструменты и подходы, метрики производительности и качества. А все вместе это носит гордое название — "Everything as code".
Однако мир БД традиционно стоит особняком вдалеке от этой феерии прогресса и технологий. Процесс разработки и сопровождения БД не меняется годами и продолжает вселять ужас и страх в разработчиков, администраторов и пользователей по всему миру. Но возможно ли представить БД в виде обычного кода? Приблизиться к основному процессу разработки, использовать общие инструменты и подходы? Об этом под катом.
Типичный проект
Большинству из нас ежедневно, хотим мы этого или нет, приходится сталкиваться с самыми разными БД. Проектировать, разрабатывать, администрировать, решать проблемы с производительностью, конкурентным доступом и вот это все. При этом требования к сбору, обработке и хранению данных постоянно ужесточаются — для одних нужна 100% консистентность, для других нет. Одни хранятся годами, другие несколько секунд. Потеря одних приведет к миллионным убыткам, тогда как потеря других не будет заметна для бизнеса.
В связи с этим давно появился и успешно используется подход Polyglot Persistence, в результате чего встретить в наши дни на каком-нибудь проекте одну единственную СУБД будет большой удачей. Вместо этого для каждой конкретной задачи подбирается наиболее подходящая база, без попыток как-то выкрутиться и решить все свои проблемы на старой доброй реляционке. А, например, микросервисная архитектура позволяет изолировать работу с конкретной СУБД в рамках одного сервиса и выжать из нее максимум пользы, без вреда для чистоты архитектуры всего проекта. В итоге "Реляционка" (куда ж без неё) + "Key-value DB" + "Wide Column DB" + "Document-oriented DB" + "Search engine DB" + "Graph DB" + "Какая-то еще DB" = "SUCCESS!". Помимо этого, увеличивается количество экземпляров (инстансов) этих БД — шардинг, репликации, распределенные СУБД. Плюс все это надо "растянуть" и поддерживать в разных средах — разработческой, тестовой, продовой и пр.
Чтобы не быть голословным, приведу несколько выдержек из свежего соцопроса от компании-гиганта по решениям в области управления и разработки БД Quest Software — Проблемы DBA: Тренды в администрировании БД (чтобы скачать, придется пройти несложную регистрацию, но оно того стоит):
Вопрос №2: "Сколько инстансов реляционных БД запущено в вашей компании?" — по результатам 24% респондентов используют от 100 до 500 инстансов, а 19% более 500.
Вопрос №4: "Сколько различных СУБД (SQL и NoSQL) используется в вашей компании?" — 56% используют от 2-х до 3-х различных СУБД, 40% более 5-и, и только у 4% опрошенных одна-единственная СУБД.
Вопрос №18: "Что происходит с количеством инстансов БД в ваших проектах?" — 2/3 респондентов отмечают ежегодное их увеличение.
Вопрос №30 (в качестве итога): "С какими главными проблемами столкнутся DBA в ближайшие 3 года?"
51% — "Увеличение количества инстансов СУБД"
40% — "Возможность администрировать новые нереляционные БД"
32% — "Сокращение IT-бюджета" (который, ожидаемо, распухает из-за первых двух проблем)
А мы готовы к этому?
Не секрет, что для эффективной работы с той или иной СУБД необходимы специализированные инструменты, такие, как IDE и DB-менеджеры, средства мониторинга, моделирования, миграции схем и многое другое. Однако большая часть таких инструментов и сред были придуманы и разработаны еще в те славные времена, когда любому проекту с головой хватало одной-единственной реляционной СУБД, а таких модных слов, как "Agile", "DevOps" и "CI/CD", еще не придумали. И с тех пор мало что изменилось, т.к. область разработки и сопровождения БД всегда являлась достаточно закрытой и консервативной, а у большинства разработчиков ассоциируются с чем-то древним, сложным и непонятным. Сегодня же, когда практически в любом проектном хозяйстве трудится сразу несколько самых разношерстных СУБД и десятки/сотни их инстансов, обычные повседневные проблемы разработчиков и DBA становятся еще более острыми.
Традиционно самым популярным и незаменимым инструментом для работы с БД являются всевозможные IDE. Обычно это комплексное решение, которое объединяет под своим интерфейсом, в основном графическим, самые разные функции для разработки и администрирования в единую рабочую среду, делает нашу работу с БД более продуктивной и комфортной — остается только клацнуть мышью на нужном пункте меню. И действительно, мало кто из нас обходится без таких крутых штук, как EMS SQL Manager, Toad, dbForge и многих других.
Одной из главных проблем таких "коробочек" является то, что под прессом новых фич и новых СУБД (которые не прекращают появляться на рынке) они получаются довольно сложными и продолжают усложняться с каждым разом. Причем как в использовании (зачастую людям приходится осваивать не особенности работы конкретной СУБД, а хитрости и фичи самой IDE), так и в их реализации (поэтому такие системы обычно закрытые и очень платные). Даже многими (включая меня) любимый DBeaver, флагман среди open sourse DB IDE, предоставляет поддержку NoSQL-решений (а какой проект сейчас обходится без них) только в своей Enterprise версии. В добавок ко всему этому сохраняется неиллюзорный риск того, что поддержку какой-либо очень нужной и интересной функциональности СУБД можно не дождаться в скором времени, пока разработчики IDE не посчитают нужным ее впилить (а могут вообще не посчитать и не впилить).
В ответ на сложившуюся ситуацию сами пользователи зачастую не дожидаются пока появится нужная фича или поддержка новой СУБД, а решают поступающие проблемы самостоятельно и наиболее подходящим для себя и своего проекта способом. GitHub просто кишит такими решениями разной степени сложности. В основном это наборы sql-скриптов на все случаи жизни (dataegret/pg-utils, NikolayS/postgres_dba, gwenshap/Oracle-DBA-Scripts, ktaranov/sqlserver-kit, lestatkim/opensql). Или консольные утилиты, такие, как top-подобные pg_activity и pgcenter. А также всевозможные web-based тулзы, начиная от вполне самостоятельных клиентов и средств мониторинга (pg_web, pg_hero) и заканчивая, например, просто html-обертками над системными таблицами (pg_web_stats, pg_stats_viewer). В результате чего складывается целый класс решений вида "programmers-for-programmers", "DBA-for-DBA", с помощью которых простые, и не очень, пользователи СУБД делятся своим опытом друг с другом непосредственно.
Everything as code
Похожая картина когда-то давным-давно наблюдались в области администрирования серверов и управления конфигурациями ПО. Тогда с постоянным появлением новых требований и технологий инфраструктура проектов стала заметно усложняться, резко увеличивалось количество серверов и софта, на нем работающего. А также появилась необходимость более частой, а затем и непрерывной поставки ПО с новыми бизнес-фичами заказчику. Существующие средства для конфигурирования и управления всем этим хозяйством плохо справлялись, в результате чего появился подход "Infrastructure as Code" и такие инструменты, как Ansible, Chef, Salt, Puppet и др., где конфигурирование инфраструктуры осуществляется на специальном DSL. Что даёт больше гибкости и свободы творчества. А код на таком DSL участвует в стандартном жизненном цикле наряду с основным кодом приложения (на Java, C#, Ruby или любом другом языке программирования), а именно — хранится в системе контроля версий (со всеми вытекающими — брэнчи, форки, code review), собирается в билды на сервере сборок, запускаются автоматические тесты и пр.
В дальнейшем влияние такого подхода стало заметно и в других областях:
Все больше людей уже не боятся писать код, это становится нормой. Это дает возможность более гибкой конфигурации, а также позволяет использовать общие инструменты (контроль версий, метрики, визуализация, отчеты, тестирование и пр.) в общем флоу. Во многих специализированных инструментах графический интерфейс заменяется или дополняется более гибким программным интерфейсом, различными DSL и конфигурационными файлами.
А что на этот счет в бескрайнем мире баз данных? Набрав в Google простое словосочетание "Database as code", я не нашел ничего интересного, кроме одного-единственного (но зато какого!) поста на DZone — "Database as Code: a Novel Concept".
Мы много говорим о database-first подходе. Мы много говорим о том, что данные — это самый ценный актив предприятия. Но как насчет концепции, представленной Dan North на третьем слайде его презентации? Что если относиться к базе данных как к коду?
Звучит заманчиво, а на слайдах #5 и #6 (к сожалению, видео я не нашел) описываются 2 подхода к управлению схемой БД "через код" — через инкрементальные миграции (Liquibase, Flyway) и идемпотентные DDL-скрипты (Redgate). Таким образом, схема — это тоже код, она находится под контролем VCS, собирается на билд-сервере, выполняются автоматические тесты и все такое.
Что нам необходимо, чтобы изменить наше мышление в области работы с базами данных? Мы должны прекратить относиться к нашей БД как к магическому артефакту или как к уникальному сценарию и взглянуть на нее под тем же углом, что мы смотрим на обычный код нашего приложения.
Снова мощно сказано, у меня аж слезы на глазах наворачиваются. К сожалению, и в докладе, и в самом посте, "как код" рассматриваются только изменения схемы БД (миграция схем БД):
Мы относимся к исходному коду нашего приложения как к сокровищу. И это абсолютно верно, код — это сердце любого приложения. Но не должны ли изменения базы данных также находиться под управлением системы контроля версий, быть автоматизированными, быть готовыми к релизу по первому требованию и подчиняться "DevOps-законам", как и основной код?
Но минуточку...
БД — это не только схема!
Большинство современных СУБД предоставляют свой язык запросов, с помощью которого мы можем не только получать и изменять хранящиеся в ней данные (т.н. DML) и оперировать их схемой (т.н. DDL), а вообще получить (не побоюсь этого слова) любую метаинформацию о текущей БД и ее состоянии (из системных таблиц и представлений) и выполнять практически любые операции над ней (запустить БД, остановить, перевести в read only, собрать статистику, управлять памятью и пр). И такой код тоже вполне себе подходит под концепцию, описанную в предыдущем параграфе.
А когда речь заходит о БД и языке запросов, то первым в голову приходит, конечно же, старый и добрый SQL. Но можем ли мы рассчитывать на него (а заодно и на реляционные БД, с которыми у большинства он плотно ассоциируется) сейчас и в ближайшем будущем, учитывая огромный рост спроса на NoSQL-решения?
"Ведь SQL уже всё? ..."
Вы можете справедливо меня спросить — о каком вообще SQL я тут разговариваю в эпоху NoSQL и schemaless databases, когда "пыльные реляционки доживают свой век исключительно в кровавом легаси Ынтерпрайзе". Ранний Хабр (как лакмусовая бумажка трендов в мире технологий) тоже когда-то был наполнен негативом по отношению к SQL и реляционкам и предвещал их скорейшую гибель (в скобках указаны количество голосов, а через слеш — количество комментариев):
Подтверждение этих настроений можно найти в недавних докладах Константина Осипова (kostja) "NewSQL: SQL никуда не уходит" и Андрея Николаенко "Нереляционный SQL". Возьму на себя ответственность привести краткое резюме из обоих выступлений:
"SQL в NoSQL" — SQL (как это не странно) довольно комфортно чувствует себя и в NoSQL-среде. Практически во всех NoSQL базах есть возможность использовать какой-либо sql-подобный query language, как, например, CQL в Cassandra и ScyllaDB, AQL в Aerospike и N1QL в Couchbase, а в некоторых и полноценный (или максимально приближенный к нему) ANSI SQL – как в Tarantool, ClickHouse и CrateDB.
"SQL в BigData" — SQL давно и плотно влился в инфраструктуру Hadoop. В далеком 2009 году появился Hive со своим HiveQL, а далее, год за годом, стали появляться решения, уже напрямую поддерживающие SQL — Impala (2011), Spark (2013), Kudu (2014), Presto (2015), Phoenix (2017).
"SQL в Поточниках" — SQL стал практически стандартом для потоковых обработчиков данных: Flink, Samza, Storm, Apex, а с недавних пор еще и Kafka.
"SQL в NewSQL" — Многие современные СУБД активно развиваются в сторону NewSQL, где совмещают в себе преимущества как NoSQL, так и классических реляционных решений, включая широкую поддержку SQL (CockroachDB, FoundationDB, MemSQL).
Нужно больше аргументов с картинками!
Дальше приведу еще немного аргументов, но если и так все понятно, то можно смело переходить к следующему параграфу.
Также в последнее время появляется много новых и модных СУБД, которые являются «надстройками» над известными и проверенными реляционными СУБД. Например Postgres-based (Timescale и ToroDB), MySQL-based (RadonDB) и даже на базе sqllite (которая всегда позиционировалась как простая и надежная embedded-база) появился rqlite – «легкое распределенное реляционное хранилище». Либо реализуют интерфейс какой-либо популярной базы (например, MySQL для InfiniDB и TiDB). Такой подход хорош тем, что при новой модели данных мы остаемся на той же привычной платформе, которую знаем как конфигурировать и администрировать.
Ну а для совсем уж "безсхемных" ребят тоже есть попытки создать общий универсальный язык "а-ля SQL", как, например, Eclipse JNoSQL, а точнее — его подпроект JNoSQL Aphrodite.
Google, который и является одним из родоначальников NoSQL-движения, также делает все больше акцентов на SQL. Сначала это был Spanner, а теперь активно развивается BigQuery:
SQL-интерфейсами обзаводятся не только хранилища и обработчики данных. Например, с помощью osquery (от самого Facebook) и fsql на языке SQL можно получить много всякой полезной информацию из любой ОС или выполнять различные операции с файловыми системами.
В общем, SQL вполне комфортно себя чувствует в современных условиях, в том числе далеко за пределами реляционок. Практически с любым источником данных можно "поговорить" на SQL или SQL-like языке, получить нужную информацию о данных или метаданных хранилища и выполнять какие-либо операции (например, что-нибудь создать, удалить, запустить, остановить и пр.)
Здесь и далее (для удобства и с вашего разрешения) под "SQL" я буду подразумевать не только "тот самый" стандартный реляционный SQL, но и все его подвиды (в т.ч. далеко не реляционные), да и вообще любой встроенный в БД QL, с помощью которого можно сделать что-нибудь полезное.
К чему все это?
А к тому, что в далеком 92-м году появился замечательный ANSI-стандарт, согласно которому любая реляционная СУБД обязана уметь описывать свою внутреннюю структуру в специальной схеме — Information schema. Т.о. с помощью стандартного языка запросов к служебным таблицам/представлениям можно получить метаданные любой БД — как в ней содержатся схемы, таблицы, индексы, колонки и пр. Но на самом деле одной схемой данных это не ограничивается, и таким же образом (пусть уже и за пределами стандарта) можно получить информацию о процессах, сессиях, планах выполнения запросов, дисковой подсистеме, утилизации памяти и еще много чего другого.
Несмотря на то, что этот стандарт появился почти четверть века назад и только для реляционных БД, почти все современные NoSQL и NewSQL базы тоже реализовывают что-то похожее. Например, в Cassandra есть сразу несколько системных схем (а точнее keyspace'ов – system, system_auth, system_schema, system_traces), доступ к которым можно получить с помощью уже упоминавшегося CQL. В ClickHouse есть специальная схема «system». Разработчики из CockroachDB вообще замахнулись на реализацию стандартной information_schema. И даже документный Mongo радует нас системными коллекциями.
При этом наблюдается постоянный рост количества и расширение таких системных представлений. Например, в Postgresql (как БД с одним из самых активных сообществ) помимо реализации самой information_schema, собственной схемы pg_catalog и pg_stat-представлений имеет несколько официальных расширений в виде преставлений pg_stat_statements и pg_buffercache. А также дополнительные сторонние представления, такие как pg_active_session_history, pg_store_plans и pg_stat_kcache.
Практически любому узлу соответствует какая-либо системная таблица, которая отображает его структуру и/или состояние. То есть о своем внутреннем устройстве и состоянии БД может рассказать сама посредством своего языка запросов. Помимо этого многие СУБД предоставляет возможность с помощью своего языка запросов не только получить полезные метаданные, но и выполнять служебные операции — что-нибудь остановить, запустить, очистить, собрать статистику и пр. Так в некоторых СУБД команду "ALTER" можно применить не только к таблицам или колонкам, но и к другим объектам, например, к сессии ("alter session set sql_trace = true"), датафайлам ("alter tablespace add datafile") или системе целиком ("alter system kill session").
Знание этих таблиц и запросов поможет как в разработке и администрировании, так и в освоении очередной новой СУБД. Понятно, что в одних базах такие возможности весьма развиты, и "кодом" можно сделать практически все, а в других гораздо скромнее, но определенно имеет место тенденция того, что все больше разработчиков СУБД будут развивать такие возможности в своих продуктах, а мы сможем более эффективно их эксплуатировать.
Вместо выводов и резюме
К сожалению, SQL уже давно и прочно воспринимается многими как язык "низкого уровня", некий "байт-код" для БД. Который не принято, а в некоторых обществах даже глубоко неприлично "писать руками" и вообще каким-либо образом контактировать с ним. Мы уже давно привыкли, что многочисленные DB-тулзы и фреймворки сами генерируют и выполняют за нас "хитрые и сложные" SQL-запросы к системе, и за этим процессом остается только наблюдать. Но давайте выйдем из зоны комфорта теплых ламповых графических интерфейсов и кодогенераторов и посмотрим на наши СУБД с точки зрения обычного кода. Тем более, что все необходимое для этого у нас есть.
Теперь по делу. Пользователи любой СУБД имеют возможность описать практически все аспекты работы со своей БД в виде кода, на простом, понятном и привычном многим языке. Это может быть не обязательно ANSI SQL, а любой SQL-like диалект, либо вообще свой собственный встроенный QL или API, в зависимости от используемой БД. Чем это полезно?
Не привязываясь к какому-либо инструменту, можно получить любую информацию о БД в нужном виде, либо выполнить любую операцию над БД;
Т.к. это все-таки обычный код, то и относиться к нему нужно как к любому другому "настоящему" коду. А именно, он должен быть понятен, структурирован и отформатирован по принятому стандарту, а также участвовать во всех этапах стандартного жизненного цикла кода — быть под контролем VCS, подвергаться Code review, участвовать в CI/CD pipeline'ах и пр. (а не "валяться" где-нибудь в папке под названием "SQL-tricks"). Что повысит его качество и ценность в команде.
Интересно ваше мнение на этот счет, пишите в комментариях — будем обсуждать.
В следующем посте я планирую на конкретных примерах проиллюстрировать описанные выше идеи, а также расскажу о том, как мы в КРОК пробуем применить их в экспериментальном графическом DB-manager'е с открытым исходным кодом, который разрабатывается в рамках одного из исследовательских проектов.