Использовать БД только для складирования данных — это всё равно, что назвать Unix интерфейсом для работы с файлами. Посему, хочу напомнить об известных и не очень функциях БД, которые хотелось бы чаще встречать в боевых веб-приложениях.


tl;dr


Ниже будет про аутентификацию, пользователей, права доступа, целостность данных, FDW, логирование и статистику. Ничего нового.


Примечания


  • Буду иметь в виду Ruby on Rails и Postgres, но большинство упоминаний хорошо переносимо на другие языки и СУБД.
  • Ничего нового не скажу, всё это давно описано в документации и статьях. Просто хочу ещё раз напомнить об инструментах и о том, куда их можно применить, чтобы жизнь стала немного лучше.

Peer/ident аутентификация


Абсолютно здо?ровская штука, которой почти никто не пользуется. Она мапает пользователя юникса на пользователя БД. В первом случае мапает локального пользователя, а во втором — удалённого. Профит в том, что можно выкинуть из конфига хост, логин и пароль (да и имя БД можно выкинуть), но всё будет работать как раньше. Плюс, будет удобнее заходить в консоль для прямого дебага (просто psql из терминала вместо всех этих -h -U -W -d и тд).


Документация PG про peer и про ident.


Нюансы: подходит, если у вас не только root и superuser на сервере; а в случае с ident, вы контролируете сеть, железо и уверенны, что там нет засланцев и саботажников.


Примеры использования


Безопасность. Нельзя утащить пароль от БД и подключиться к ней из локального окружения или ещё откуда-либо. Пароля нет и утаскивать нечего.


Разграничение доступа. Если на продакшн или иной сервер есть несколько ролей доступа и они уже разделены на уровне unix-а, то к ним удобно привязать и пользователей БД. В этом случае одна и та же кодовая база будет подключаться под разными пользователями БД. Например, тех.поддержка и разработчики лезут в одну и ту же rails console, но у одних она readonly, а у вторых — полноценная.


Права доступа


В Unix все о них думают и на работу из-под root-а или на 'chmod 777' очень косо смотрят. А вот в БД всё как-то иначе. Superuser и в путь. Хотя там всё не менее (а может быть даже более) круто.


Там есть иерархия наследования ролей (немного похоже на group в юниксе), там есть доступы разного уровня: к конкретным объектам (вроде прав доступа к файлам), к конкретным операторам (наподобие правил в sudoers), даже к конкретным строкам. Короче, там всё есть. Пользуйтесь.


Области приложения


В минимальном варианте, вместе с вышеозначенными peer/ident можно разделить пользователя для миграций/деплоя и пользователя для повседневной работы приложения. Это, как минимум, убережёт от вызова DDL в рантайме. Конечно, есть много случаев модификации структуры БД "на горячую". Это и zero-downtime deploy, и разные хотфиксы, и ребилды индексов с concurency (а иногда и без). Но, в общем случае, приложение DDL делать не должно.


Ещё вариант: если у вас "микросервисы", но, почему-то, они пользуются одной БД, то явно разделить доступ к объектам БД — это очень хорошая идея. Ведь интерфейсы взаимодействия должны быть максимально локализованы, а анархический доступ ко всем данным способствует размыванию логики и ответственности.


Ограничение целостности


В Rails 5 хоть как-то началась работа с reference и целостностью данных. Но, в общем случае, многие разработчики считают, что валидации в модели или её окрестностях вполне достаточно для сохранения консистентного состояния данных. Увы, это совсем не так.


Валидации можно пропустить, можно зайти напрямую в БД и навыполнять sql-я, можно при миграции накосячить. В общем, много чего можно сделать. Поэтому всё, на что опирается бизнес-логика должно быть прибито констрейнтами в БД. Это единственный способ сохранить целостность данных и не получить "сюрпризов" при очередном деплое.


Foreign Data Wrapper


Это про подключение одной БД к другой БД, дабы получить доступ к удалённым таблицам как к своим собственным. Главный профит в том, что веб-приложение тут никак не участвует, зато есть много оптимизаций, при работе двух одинаковых БД (вообще, pushdown есть для разных адаптеров, но там всё сложно, поэтому проще считать, что связка PG-PG работает хорошо, а всё остальное — как получится).


Использование FDW


Вместо конфигов с координатами нескольких БД в веб-приложении несравнимо проще оставить одно подключение к БД и разрулить всё на уровне самой БД. Там же, сам собой, решится вопрос прав доступа и выбора объектов, к которым нужен доступ.


Плюс к этому, в будущем можно заменять external table на materialized view или на просто table, но ничего не менять в веб-приложении.


А ещё, можно подключаться к экзотике типа MS Access и исчезают проблемы с ограничениями на использование реляций в моделях. Ведь если у вас 2+ подключения, то джоин двух баз на уровне веб-приложения вы не сделаете, хотя ORM (в частности ActiveRecord) честно попытается это сделать… и отвалится. А на уровне БД это сделать можно, в некоторых случаях, почти без оверхеда.


Логирование


Про него почти все знают и все используют. Но на всякий случай напомню: не стесняйтесь логировать долгие запросы. Из коробки, в PG, оно выключено. Нужно потыкать log_min_duration_statement. Касаемо его значения есть много холиваров и, возможно, меня запинают, но для начала, поставьте пару секунд. Так как если у вас большое приложение, вы вряд ли это читаете и сами знаете что делать, а если маленькое, то вам некогда разбираться с небольшими тормозами и вас беспокоят только фатальные вещи.


Так же помните про N+1. БД вам про это ничего не скажет. Используйте сторонние инструменты. Например, bullet и здравый смысл.


Статистика


Нужно помнить что она есть и что она может стухнуть. На первых порах всё хорошо. Но со временем, обычно, получается следующее: скорость изменения данных, примерно, одинаковая, а размер таблицы всё больше. Следовательно, vacuum/analyze таблицы начинает происходить всё реже и в какой-то момент планировщик начинает промахиваться. В лучшем случае, запрос попадает в вышеозначенное логирование, в худшем — вы просто страдаете и не понимаете почему. В общем, смотрите в pg_stat_user_tables и соотносите даты вакуума/аналайза с нагрузкой на таблицы.


А ещё иногда можно использовать статистику для примерного count. Пригождается редко, но довольно метко, ибо PG не Oracle и count для всей таблицы выполняется не за O(1), хотя очень хочется.


Конец


Спасибо, что прочитали. Если не сложно, ответьте на вопрос ниже. В свете недавней статьи про GQL вместо SQL он меня начал волновать особенно сильно.

Комментарии (23)


  1. Vlad_fox
    12.09.2018 10:20
    +1

    кролики — это не только ценный мех, это еще и 2 а то и 3 килограмма мяса.
    Спасибо за внимание, ждите следующих статей.


    1. multik
      12.09.2018 18:29
      +1

      Кролик — это ещё и отличная шина обмена данными!


  1. valery1707
    12.09.2018 11:31

    Peer/ident аутентификация в действительности полезна в довольно узком круге окружений. Например сейчас, при развитии контейнерезации, в контейнере с СУБД будет только один пользователь. Да и просто в облачных СУБД у вас нет возможности настраивать пользователей сервера СУБД.
    Да и безопасность, в случае с ident, становится ниже, как вы и сами говорите.
    И масштабируется такой подход не очень хорошо: что будете делать с сотнями тысяч пользователей — каждому создавать пользователя?
    А разделение данных пользователей по разным физическим серверам?


    А всем остальным и так пользуются.


    1. Loriowar Автор
      12.09.2018 11:47

      В части облачных СУБД вы правы, там доступ только к БД и от ОС вы отделены.


      Касаемо безопасности внутри защищённого периметра — спорно. Если к вам во внутреннюю сеть влезли враги, то у вас уже всё плохо и наличие/отсутствие ident там погоды не сделает.


      Относительно масштабируемости я честно не знаю откуда сотни тысяч пользователей. Если у вас собственная инсталляция, то реальных пользователей БД (не веб-приложения) будет штук 5: для веб-приложения, для фоновых задач, для деплоя, для разработчиков, ридонли и ещё чего-нибудь. Поэтому вполне реально им права настроить.


      В случае шардирования по разным физическим серверам в PG, обычно, используют FDW и там свои особенности. А на аутентификацию к основному серверу БД это никак не влияет.


      1. valery1707
        12.09.2018 12:45

        А зачем тогда вообще peer/ident аутентификация, если пользователей всего 5 и это не столько пользователи, сколько роли?
        Для разработчиков: уж если и иметь аккаунт на машине, то лучше каждому свой чтобы можно было лишать доступа прицельно. При этом доступ к БД у вас получается всё равно групповой.
        Я про то что реальной пользы от peer/ident аутентификации сейчас нет.


        1. Loriowar Автор
          12.09.2018 12:52

          И где-то тут мы плавно перешли от ситуации "одна учётка на проде и 1 пользователь на всех" к ситуации "каждому свой аккаунт". Давайте будем последовательны и хотя бы на группы пользователей разобьём. Так же, в случае peer вполне себе можно иметь много пользователей с разными ssh ключами, которые ведут на одного юникс-пользователя. Там и логирование нормально настраивается на уровне системы, и групповые политики доступа к БД работать не перестают. Лично видел и работал с такими инсталляцими.


        1. maximw
          12.09.2018 14:12

          Пользователь может быть и один, а вот ключик ssh у каждого свой.


      1. dph
        12.09.2018 20:05

        «Касаемо безопасности внутри защищённого периметра — спорно. Если к вам во внутреннюю сеть влезли враги, то у вас уже всё плохо и наличие/отсутствие ident там погоды не сделает.»
        Тут все зависит от проекта. Если это соцсеточка, то можно надеяться на периметр, все равно безопасность никого не волнует. А вот если это финтех или приличный энтерпрайз, то уже неплохо бы защищаться и от собственных админов (и тут разделение паролей сильно помогает).


  1. iamsilent
    12.09.2018 12:19

    У такого подхода есть один существенный минус — подходит только для standalone-приложений, разработанных с нуля. Если вы разрабатываете софт на какой-либо платформе, включающей ORM, а тем паче саму такую платформу, то вы будете прибиты гвоздями к выбранной СУБД, либо будете вынуждены громоздить дополнительные слои абстракций, и поддерживать несколько реализаций.
    Все дело в том, что реализация описанных (и безусловно полезных) механизмов значительно отличается для разных СУБД.


    1. Loriowar Автор
      12.09.2018 12:26

      Да, в разных СУБД разные реализации и для ORM это не подходит, там свой дивный мир. Но по личному опыту, привязка к типу БД происходит почти всегда и смена БД в проекте — это скорее исключение, нежели правило. Поэтому, почему бы не воспользоваться доступными инструментами?


      1. iamsilent
        12.09.2018 12:42

        Ну, например потому, что я являюсь как раз разработчиком платформы, в которой описанное в статье реализовано чуть менее чем полностью, и еще многое другое. И многие заказчики прикладных решений на нашей платформе желают другую базу данных — например, потому, что у них имеются обученные админы. Что дает нам упущенную выгоду, к сожалению. И заставляет нас двигаться по тернистому пути громождения абстракций и поддержки реализаций.


        1. Loriowar Автор
          12.09.2018 12:46

          Значит у нас с вами просто разный опыт. Я, чаще всего, наблюдаю как разработчики хотят сохранить независимость от БД и громоздят абстракции на уровне веб-приложения, хотя нет никаких предпосылок или требований со стороны бизнеса к независимости от БД.


          1. kto-to_tam
            12.09.2018 20:06

            С другой стороны, если приложение зависит от одной базы, это знаете-ли еще то «удовольствие». Она, база, так быстро никуда не денется, но и переписать огромную софтину, которую писали десятилетиями, «быстро переписать» под другую базу не выйдет и за пару лет… И когда наблюдаешь тенденцию, что «твоя родная БД» превращается в какую-то дурнопахнущую жижу, становится как-то грустно.


            1. iamsilent
              13.09.2018 10:31

              К счастью, «родная БД» наоборот становится все лучше и лучше, однако от проблем это не избавляет — её всё равно не слишком хотят (и напрасно, кстати)


  1. Komesk
    12.09.2018 18:40

    Ограничение целостности...

    Достаточно спорно нынче стало все это.
    1. Проверка бизнес целостности на уровне БД при eventually consistent подходе невозможна, да и ссылочная тоже.
    2. При миграции большого кол-ва данных все constraints отключают для скорости и непрерывности процесса. А проверку проводят при подготовке данных.
    3. Тут как всегда панацеи нет — что-то должно быть реализовано на уровне БД, что-то на уровне контроллера. Но и размазывать логику тоже не хочется, поэтому все чаще и чаще логика переносится на котроллер


    1. Loriowar Автор
      12.09.2018 20:18

      Но, согласитесь, мигрировать данные так, что после миграции приложение их прожевать не сможет — глупое занятие. Поэтому и написал, что основа бизнес-логики должна быть прибита констрейнтами. Остальное — по вкусу. Эта же штука простимулирует правильную расстановку транзакций в приложении и хранение нецелостных данных в промежуточном месте. Например, последовательность шагов визарда складывать в редиску и только на последнем шаге всё сохранять, а не держать в базе неконсистентные данные, надеясь что визард успешно завершится и его не дропнут.


      1. Komesk
        12.09.2018 21:01

        Когда речь идет о серьезных объемах, и количестве связей — визард не прокатывает. bulk insert работает на порядки быстрее. И плюс миграция один в один очень редкое занятие- всегда есть хоть какая-то трансформация. Для этого, как правило создается отдельное приложение или несколько, которые в несколько этапов закачивают данные. И как уже сказал, констрейнты на этот период отключают.


      1. VolCh
        13.09.2018 06:02

        Ну почему сразу глупое? Нередко лучше иметь хоть какие-то битые данные, чем никаких. Ну, навскидку, данные об операциях по какому-то денежному счёту. Лучше записать сведения от контрагента об оплате со счёта 1000 рублей за товар без названия неизвестному продавцу, чем не записывать вовсе. По крайней мере баланс будет актуальным.


        1. Loriowar Автор
          13.09.2018 08:10

          Тут бабушка надвое сказала. Потом приходят гос.органы, запрашивают данные и нагибают вас за неполные/недостоверные/отсутствующие данные. Особенно весело, если это не проверка пришла, а по какой-нибудь уголовке нужно.


          1. VolCh
            13.09.2018 13:48

            А за какие из «неполные/недостоверные/отсутствующие» больше нагнут? Если одинаково, о этот фактор можно не учитывать при принятии решения о том, на каких уровнях контролировать целостность.


  1. KovVlad
    12.09.2018 18:59

    Я вам не скажу за всю Одессу Postgres, но DB-линки в Oracle — зло злейшее для высоконагруженных систем. При возникновении нагрузок (неоптимальный SQL-запрос, рост числа запросов от приложения etc) аффектятся обе базы. При том, что сам запрос не факт требует использования объектов из обеих БД.
    Так что не ведитесь на удобство конфигурирования, аукнется.
    Не думаю, что механизм FDW принципиально отличается от DB-линков, так что, скорее всего, вышесказанное применимо и к Postgres


    1. Loriowar Автор
      12.09.2018 20:14

      В любом случае аффектятся обе базы, всё зависит от пропорциональности аффекта и плана выполнения. Для начала, коннект внешней БД занимается, а он кушает ресурсы, которые всегда ограничены. Так же, например, с FreeTDS для MSSQL всё не очень и pushdown для многих вещей не работает, что влечёт выборку всей внешней таблицы там, где по здоровой голове 1 строка в результате должна быть. Так что волков бояться — в лес не ходить. В итоге мы приходим либо к комбинации DSL-команд, которые не работают физически, либо к запросам, которые съедают все ресурсы. Хрен редьки не слаще и тут уж локально выбор делается и панацеи нет.


      1. KovVlad
        12.09.2018 23:41

        Я вообще про вот эту вашу фразу:

        Вместо конфигов с координатами нескольких БД в веб-приложении несравнимо проще оставить одно подключение к БД и разрулить всё на уровне самой БД.
        Прочитал, как почти призыв использовать линки везде, где можно. Ибо (в том числе) это упрощает конфигурирование.

        С другой стороны, чаще всего запросы не требуют данных более чем одной базы. В противном случае это попахивает не очень хорошим проектированием этих самых БД.
        Потому утверждение
        В любом случае аффектятся обе базы
        немного преувеличено.
        Если приложение будет ходить в БД отдельно, то в большинстве случаев напрягаться будет только одна из них.