Давайте честно: совместный доступ к документам — одна из главных «болей» для всех, кто хоть как-то связан с базами данных. Вроде бы оба пользователя могут работать с файлом, но есть один нюанс: например, количество предоставленных доступов может быть больше, чем их есть на самом деле. Или у документа и вовсе появляется несколько владельцев. Для всего этого требуется решение – и мы его нашли!

Меня зовут Владимир Ревякин, я старший инженер-программист компании «МойОфис», и вместе с QA-инженером Анной Рукавицыной мы подготовили этот материал, чтобы поделиться опытом реализации функции шаринга данных через графовую базу ArangoDB в рамках разработки платформы «Документы Онлайн». Если коротко — это продукт для совместной работы и хранения документов в рамках единой мультипродуктовой экосистемы.

В российских источниках не так много полезной информации по ArangoDB, и наша задача — исправить это недоразумение. Разберем главные нюансы работы с этой системой БД в разработке и тестировании, вспомним ее плюсы, минусы и потенциальные баги. Текст будет полезен как инженерам любых грейдов, которые связаны с работой над базами данных (сил вам...), так и классическим разработчикам продуктов.

Часть 1: Как это устроено у нас

Наш продукт «Документы Онлайн» — это набор приложений для структурированного хранения корпоративной информации и совместной работы с документами. В его составе веб-приложения для работы с текстовыми, табличными документами и презентациями, мобильное приложение «МойОфис Документы», интерактивная доска, а также серверные системы для обеспечения совместной работы и средства администрирования.

Ядро продукта построено на С++17. Веб-интерфейс разработан с использованием React, TypeScript и WebSockets для динамического взаимодействия в реальном времени. Серверная часть реализована на Java, Python C++17, Golang и OpenResty.

Один из базовых элементов «Документы Онлайн» — система хранения данных. В ней мы реализуем следующие функции:

  • хранение данных;

  • аутентификация;

  • авторизация пользователей;

  • разграничение прав доступа разных пользователей для совершения определенных действий;

  • производство файловых операций;

  • администрирования данных.

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

Также мы поддерживаем файлы разных форматов, создаем директории и, конечно, предоставляем разные права доступа. Ниже — пример панели, где предоставлены права доступа на конкретный объект. Они могут ранжироваться от запрета до управления файлом.

Но как вся эта структура выглядит изнутри? Здесь начинается самое интересное.

Часть 2: Что вообще такое этот ваш ArangoDB?

Это NoSQL-система управления базами данных. Важно, что она реализует два типа коллекций документов:

Вершины

  • пользователи;

  • директории;

  • файлы.

Ребра документы, соединяющие вершины в однонаправленные графы;

  • ACL (Access Control List).

Как работает шаринг объектов

Ранее указанный ACL — то самое ребро шаринга с необходимыми правами доступа. И помимо него, у нас есть другое ребро, которое соединяет объекты и файлы. Но что будет, если, например, файл-1 попробовать расшарить напрямую? Произойдет конфликт!

Суть конфликта: файл-1 имеет права на просмотр и на редактирование одновременно через два пути: ACL-3 и ACL-6. Так ACl=6 использует прямой шаринг, а ACL=3 – унаследованный (то есть, прошедший к пользователю через директорию, а не напрямую).

В итоге можно выделить следующие правила расчета прав доступа:

  • Прямой шаринг всегда преобладает над унаследованным. То есть мы шарим файл пользователю без посредников.

  • Эмпирическое правило: более короткий путь к файлу (с одним ребром) — обладает большим приоритетом.

  • Ну а если длина «шаринга» совпадает — преимущество получает вариант с наибольшим приоритетом ACL. Их иерархия — на таблице ниже:

Получается сложная иерархическая система, которую надо еще как-то тестировать. И вот какие тут есть нюансы.

Как тестировать

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

В таком кейсе у нас может быть три потенциальные методики:

  • конструктивная. Первый этап — построение графа с различными комбинациями (изображена на схеме).

  • модифицирующая. Изменяем существующие права доступа. Добавляем или удаляем отдельных пользователей из групп.

  • деконструктивная. При необходимости — «разбираем» граф и меняем его итоговые ребра: например, прекратить шаринг определенной группе — или убрать ее из системы целиком.

Построение графа с различными комбинациями
Построение графа с различными комбинациями

Что по инструментам

Для функционального тестирования мы используем следующие решения:

Автотесты на базе Python + Robot Framework

Главный плюс фреймворка – он полностью ориентирован на Python (как и наше приложение), да и в целом интуитивно понятный. С Robot Framework типичные шаги тестов выглядят так:

  • создаем новую группу;

  • добавляем в нее пользователей;

  • предоставляем конкретное право группе.

Затем все тесты мы обрабатываем через CI/CD интеграцию.

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

С другой важной частью шаринга — нагрузочным тестированием — уже все сложнее.

Здесь наш ключевой инструмент – Gatling, который позволяет писать нагрузочные скрипты, проводить нагрузочные испытания и мониторить ресурсы.

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

Что тут важно:

С точки зрения нагрузки, тесты делятся на два типа:

  • инвазивные — добавляют новые объекты в базу;

  • неинвазивные — не добавляют.

При добавлении и редактировании объектов общая нагрузка может меняться.

На изображении яркий пример из Gatling. Наибольшая нагрузка происходит во время шаринга директории (и добавления ребра), после чего она снова спадает: корреляция налицо. Это и есть инвазивный тест.

Тут же не менее важен классический детальный мониторинг, нацеленный на анализ утилизации ресурсов на разных сервисах и виртуальных машинах.

Весь этот функционал помогает эффективно находить нам баги – и с ними все тоже не менее интересно.

Часть 3: Ловим баги

Увы, вся эта система не может обойтись без багов. И их понимание может дать много полезного для работы как с ArangoDB, так и с правами доступа в целом.

Есть немало необычных примеров багов, но самый интересный из них – ниже (тем более, что с ним сталкивались мы сами).

Менеджер выдает право на владение

Сценарий в таких случаях, как правило, примерно такой.

Дано:

Один файл и два пользователя, которым надо получить на него права.

Что получается:

Пользователю-1 предоставляется право на управление файлом (дается ACL=8). Затем Пользователь-1 со своим токеном дает Пользователю-2 право на владение файлом (ACL=9).

В итоге мы получаем ситуацию, где юзеры предоставляют больше прав, чем у нас есть на деле, из-за чего у файла возникает несколько владельцев.

Решение:

Теперь мы руководствуемся двумя железными правилами: мы не можем предоставить больше прав, чем имеем сами. Кроме того – мы не предоставляем права «выше», чем права на управление (ACL=8), и таким образом гарантируем, что у файла будет только один владелец.

Часть 4: Плюсы и минусы работы с ArangoDB для разработчика и тестировщика

Сначала поговорим о плюсах (они все-таки перевешивают издержки):

  • Документация

    Согласитесь, это база для любого инструмента. Но тут она не только понятная и удобная — разработчики ArangoDB добавили туда небольшие тестовые курсы на понимание работы самой системы. Будет полезно как для новичков, так и для опытных в базах данных прогерах.

  • Синтаксис

    Тут и говорить особо не о чем — просто покажу пример запроса. На второй строчке можно видеть конструкцию «for d in Dirs», которая идентична для многих языков программирования, а для Python и вовсе базовая. В общем синтаксис максимально доступный.

  • Движок RocksDB

Это официальный форк LevelDB для key-value ориентированных хранилищ. Конкретно этот инструмент помогает подстраивать ArangoDB под отдельные собственные нужды, а кастомизация — наше все :)

Теперь про минусы

  • Недостаточно функциональная библиотека

    Поскольку наше приложение написано на Python, большую часть времени мы работаем с библиотекой Python-Arango, которая, увы, не может похвастаться разнообразным функционалом: приходится часто залезать под капот. Например, стоит учитывать, что библиотека не так хорошо адаптирована для асинхронного кода.

  • Слабое русскоязычное сообщество

    Хабравчанам на заметку: на отечественных блогах и площадках слишком мало рассказывают про Arango и его особенности, из-за чего найти какую-то полезную информацию без обращений к старому-доброму ГПТ становится все сложнее. Но если кто-то со мной не согласен и готов поделиться ценной фактурой — жду вас в комментариях!

А по тестировщикам?

В этой части тоже есть свои особенности:

Плюсы

Web-интерфейс

У «Аранги» очень понятный веб-интерфейс. Это удобно для тестировщиков, так как можно быстро посмотреть все необходимые характеристики. Например, зафиксировать, как долго выполняется запрос внутри базы, сколько там соединений и т.д. Также можно подключать сторонние программы и сервисы для мониторинга и аналитики — и все это через платформу!

AQL-запросы

Отличный инструмент, чтобы оценить состояние вашей базы до и после теста. Делается это с помощью простых трехстрочных запросов, что очень актуально, если мы добавляем новые объекты.

Например, в запросе на этом скрине мы считаем общее количество файлов и директорий базы.

Если же мы говорим про шаринг (например, нам интересно, сколько у нас шарингов внутри базы), это выполняется таким коротким запросом:

Получается, у нас всего 32 ребра шаринга. Если что-то будем менять, то это число станет другим.

Если вам вдруг интересно залезть внутрь запроса, можем всегда произвести explain и посмотреть, на какие шаги делится этот запрос, какие дергаются ноды, какие используются правила внутри базы данных.

Arangobench

Этот инструмент тестирует производительность базы данных отдельно от вашего приложения.

Что полезно: у него уже есть преднаписанные 10−15 тест-кейсов. Они содержат зашитые конкретные параметры, из-за чего их зачастую можно без лишних сложностей просто взять и запустить.

Ниже, например, приведены команды по запуску документных тестов — можно запускать их в различное количество запросов и потоков. При этом поддерживается асинхронный режим и запуск в виде батчей.

А так выглядит общий вид запуска этого инструмента внутри контейнера ArangoDB: в итоге мы получаем лаконичный репорт вместе с полезными параметрами — средние значения производительности по времени выполнения запросов базы, перцентили выполнения запросов. И все это получается за считанные секунды.

Минусы:

Зависимость производительности от размера БД

Это усложняет тестирование, так как его успешность зависит от дополнительных факторов: наполнения и объема баз данных.

Я уже говорил, что наши тесты могут добавлять дополнительные объекты в базу, то есть они инвазивные и неинвазивные, из-за чего методики их проведения различаются.

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

Бэкапы и дампы необходимы!

Восстановление из дампа — это процедура, когда мы восстанавливаем состояние нашей базы до исходной или до какого-то определенного состояния, которое для нас важно.

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

Команды для бэкапирования и восстановления уже преднаписаны и идут в комплекте с Arango, но для еще более быстрого процесса необходимо это автоматизировать в виде парочки Shell'овских скриптов. Поверьте, как только вы это сделаете, все процедуры бэкопирования и восстановления будут проходить очень быстро.

Часть 5. Практическая: как сформировать графовую связь в реляционной БД

Однако графовую структуру можно реализовать не только через ArangoBD, но и благодаря реляционным БД. Это может пригодиться в случаях работы с уже существующими проектами: еще один инструмент добавить не получится, а реализовать «граф» необходимо.

Чтобы реализовать традиционную древовидную структуру нам в первую очередь нужны таблицы.

Первая таблица у нас будет содержать объекты: директории, файлы и так далее. А вторая — промежуточная — будет реализовывать данную структуру, а именно: ребро связи. В этом случае, у нас взаимодействие «один ко многим», и промежуточная таблица нужна как раз для реализации такого взаимодействия.

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

Как читатель может увидеть — запрос получается большой.

В первую очередь, внимание стоит обратить на ключевое слово «recursive». Оно помогает нам рекурсивно (кто бы сомневался) обходить каждый раз эту древовидную структуру, то есть, из точки, А напрямую в точку В и так далее. И второе ключевое слово union сцепляет наши древовидные обходящие данные с начальной точкой входа. Ну и затем мы, соответственно, можем все, что нам нужно, взять из получившейся выборки.

Надеюсь, вы не уснули после всех этих длинных строк кода. Для людей, ранее не сталкивавшихся с Arango, описанные нюансы могут звучать слишком сложно и непонятно. Но специально по такому случаю мы написали небольшой тестовый фреймворк, в котором простым Python-овским языком сравнивается реализация ArangoDB и PostgreSQL.

Если же вы все-таки хотите остаться в рамках ArangoDB, вот ключевые аспекты, которые стоит учитывать при работе с системой.

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

Основных два:

  • Breadth-first search поуровневое исследование графа, здесь мы ищем конкретный элемент через разные ветки.

  • Depth-first search глубинное исследование графа, по сути «идем» вглубь графа, насколько это возможно.

Разница между ними выглядит примерно так:

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

Что еще важно учитывать. У ArangoDB, как и у многих других сервисов, есть разные методы инсталляции. Основные из них — сингл и кластерные варианты развертывания. Сингл вариант это один контейнер, который крутится на одной виртуальной машине. Кластерный вариант же представляет собой различные роли. Это как раз координаторы, DB-сервера и агенты, которые крутятся в виде различных контейнеров на виртуальных машинах.

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

При этом функциональные вещи и настройки производительности могут совершенно по-разному работать на различных типах инсталляции. Здесь мы говорим про еще одно очень важное направление тестирования: инсталляционное или конфигурационное. Это очень важно делать, если вы работаете с графами базы данных, конкретно с ArangoDB.

Также настоятельно рекомендую учитывать различные настройки, которые могут быть применимы к вашей базе. Например, здесь рассмотрим настройку кэширования запросов.

Вот такую картину мы имели до того, как включали кэширование. То есть здесь представлено среднее время выполнения запроса в базе. Как только мы включали кэширование, то получали снижение выполнения запроса в базе примерно в три раза.

И примерно во столько же раз у нас уменьшалось время ответа самого приложения. Соответственно, на различных типах инсталляции эта настройка может работать по-разному, но очень важно эти настройки проверять еще изнутри базы данных. Если вы занимаетесь полномасштабным тестированием, обязательно обращайте на это внимание.

Резюмируя: что надо помнить о работе с ArangoDB

  • Система требует определенной архитектуры приложения — классические orm, к которым мы привыкли при использовании реляционных БД, не будут доступны из «коробки» библиотеки «аранги». Поэтому будьте готовы к написанию сырых запросов. То же самое касается подхода к миграциям, поскольку готового инструмента для них у системы нет.

  • Типы связи — графы подходят для работы со связями «один-ко-многим», «многие-ко-многим», что позволяет реализовывать древовидную структуру. Но она, в свою очередь, накладывает ряд ограничений: недостаточно функциональные алгоритмы поиска, вычислительная сложность и т.д. Поэтому использование графов предполагает, что сформированы четкие требования и критерии, согласно которым графы применимы для реализуемой модели данных.

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

Кстати о тестировании. Для связанного с ним читателя у нас отличная новость: в команду «Документы онлайн» мы ищем Senior Manual QA Engineer - специалиста, который сможет профессионально тестировать сложные сценарии.

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


  1. XelaVopelk
    14.05.2025 14:32

    А всё-таки, каковы основные причины что вы решили пойти в историю с ArangoDB кроме того, что рекурсивный запрос postgre выглядит не сильно красиво?


    1. revareva96 Автор
      14.05.2025 14:32

      Добрый день! Ранее уже был опыт использования ArangoDB внутри компании. Также большая часть функционала хорошо ложилась для реализации в древовидной структуре.


    1. 3735928559
      14.05.2025 14:32

      У нас был подобный опыт с Neo4j. Это немного другая СУБД, полностью графовая и с более декларативным языком запросов. Очень помогла на этапе разработки и отладки прототипа, но когда мы поняли, какие запросы на графе нам нужны, то переписали соответствующий слой для реляционной модели, чтобы избежать vendor lock-in и лишних трат времени и денег на администрирование. Запросы очень нетривиальные, но и очень специфические, и Postgres оказался производительнее.


  1. EvgenyVilkov
    14.05.2025 14:32

    А теперь а самых главных минусах.- Open source Arango DB закончился года полтора назад. Бесплатная версия ограничивается теперь по размеру. Как вы дальше с ней живете? Перешли на свой форк или остались на 3.11 со всем текущим багажом проблем?

    RocksDB своя сборка, как вы правильно указали, но никак недоступная из вне самой аранги. Просто интересно, как вы туда зашли с кастомизацией ?

    Рускоязыное сообщество дейтсвительно отсуствует, но и откуда ему взяться, если аранго теперь уже и в open source недоступна.

    Теперь о хороших новостях. Core команда разработчиков Arango - корнями из РФ. Ребята покинули Arango год назад и пилят свой поисковый движок во строенными методами работы с проверти графами.


    1. revareva96 Автор
      14.05.2025 14:32

      Добрый день! спасибо за информацию.

      1. Перешли на свой форк.

      2. Видимо, неправильно поняли. Хотели подчеркнуть, что в основе arangodb движок rocksdb. Все настройки через обычный конфиг.