Архитектуры ООСУБД. Анализ реализаций


Реализация запросов в архитектуре, основанной на контейнерах


В реализации архитектуры, основанной на контейнерах, используется обработка запросов на стороне клиента. «Клиент» является некоторым процессом, отличным от серверного процесса страниц NFS. Можно сопоставить это с традиционной РСУБД, архитектура которой имеет противоположную природу. В РСУБД все сосредоточено в серверном процессе: обработка запросов, индексация, блокировки и управление страницами, что делает ее реализацию сервер-ориентированной, а не клиент-ориентированной. В реализации архитектуры, основанной на контейнерах, все объекты базы данных, которые затрагиваются запросом, должны идентифицироваться некоторым контейнером базы данных. Этот контейнер содержит все потенциально полезные индексы и загружается в клиентский процесс для выполнения запроса. После загрузки всех потенциально требуемых объектов или индексов и выполнения запроса возвращаемые результаты являются контейнерами, содержащими результирующие объекты, которые удовлетворяют запросу. Тем самым, с точки зрения передачи по сети и блокировки результат может содержать много объектов, которые в действительности не удовлетворяют предикату запроса. Если клиент является удаленным, то результаты попадают в исходные запрашивающий пользовательский процесс через несколько звеньев. Эффективность выполнения запросов может обеспечиваться путем использования общесистемных идентификаторов, многопотоковой, удаленной и распределенной обработки, агрегирования.


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




В реализации архитектуры, основанной на объектах, используется процессор выполнения запросов, который выполняется в процессе сервера баз данных. Любой объект базы данных достижим через запрос, даже если у него отсутствует связь с другими объектами. Атрибуты объектов могут индексироваться при поддержке сервера баз данных. Запрос производится путем посылки серверу некоторого оператора, который выполняется на сервере с использованием оптимизатора и механизма индексации, и клиенту возвращается результирующий набор объектов. По сети передаются только оператор, который будет выполняться на сервере, и коллекция объектов, удовлетворяющих предикату, в качестве результата запроса. Эффективность выполнения запросов может обеспечиваться путем использования общесистемных идентификаторов, многопотоковой, удаленной и распределенной обработки, агрегирования.




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

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

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

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

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






«В реализации архитектуры, основанной на объектах, используется процессор выполнения запросов, который выполняется в процессе сервера баз данных.»

С теоретической точки зрения использование архитектуры, основанной на страницах, не исключает возможности выполнения запросов в процессе сервера баз данных. В статье Грина делается заключение, что в этом проявляется некоторая ограниченность архитектур, основанных на страницах, и его можно преодолеть, только обратившись к архитектуре, основанной на объектах. Но в действительности тот факт, что в некотором продукте ООСУБД обеспечивается обработка запросов на стороне сервера, характеризует только этот продукт и совсем не обязательно связан с тем, реализуется ли в этом продукте архитектура, основанная на страницах или объектах.

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

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

Прежде всего, хочу сделать небольшое логическое замечание относительно этого утверждения: использование архитектуры, основанной на страницах, не исключает возможности запросов в базе данных произвольных объектов. Имеется теоретическая и практическая возможность нахождения и обработки любого объекта в любом файле системы баз данных. Такую возможность можно, например, реализовать, хотя и не эффективно, путем последовательного перебора объектов всей базы данных. Обеспечивается ли такая возможность, и, если обеспечивается, то насколько эффективно,– это всего лишь характеристика конкретного продукта.

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




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

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

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


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

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

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

Прежде всего, из помещения этого утверждения в подраздел «Реализация запросов в архитектуре, основанной на объектах» и отсутствия упоминания оптимизации запросов в подразделе «Реализация в архитектуре, основанной на страницах» следует, что в системах объектных баз данных с архитектурой, основанной на страницах, во время выполнения запросов не может производиться оптимизация. Конечно, это не так.

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


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

При вызове метода запроса возвращается коллекция указателей на результирующий набор – набор персистентных объектов внутри базы данных. К этим объектам не производится доступ при обработке запроса; поэтому страницы, содержащие эти объекты, не передаются в клиентский процесс.

Здесь нужно отметить еще одну отличительную особенность ObjectStore, повышающую ее гибкость и общую производительность. Эта особенность основывается на идее специальной индексации. В архитектурах, в которых запросы выполняются на стороне сервера, индексы, естественным образом, используются на стороне сервера, но это обычно означает, что реальная структура этих индексов определяется поставщиком базы данных, а не пользователем. Обработка запросов на стороне сервера ограничивает возможность определения структур данных пользователем, реально использующим индекс. Поскольку в ObjectStore разрешается хранение реальных указателей и истинных массивов C++, программист может реализовать эффективные специальные индексные структуры, которые оптимально поддерживают конкретный сценарий использования. Если имеется несколько сценариев использования, для которых требуется максимальная производительность, то на целевые объекты могут ссылаться специальные индексы, специфичные и оптимизированные для каждого сценария использования. При этом подходе в базе данных различаются две основные группы объектов: бизнес объекты, в которых сохраняются реальные данные, соответствующие моделируемой предметной области, и заключается весь смысл системы; и структуры доступа, или индексы, которые поддерживают навигацию к бизнес-объектам, соответствующим конкретным вызовам сценариев использования, или запросам.


Программисты могут реализовывать оптимальные структуры данных для обработки объектов в базе данных, используя например, даже STL (Standard Template Library), точно так же, как если бы они являлись структурами данных в «куче». При выполнении запроса на стороне клиента эти структуры доступа считываются постранично, точно так же, как если бы они являлись индексами коллекций ObjectStore, и поэтому специальные структуры доступа полностью эквивалентны индексам на коллекциях, поскольку и те, и другие структуры оптимизируют доступ к бизнес-объектам, и одним и тем же образом. Я не думаю, что подобные специальные индексы можно реализовать, если не опираться на архитектуру запросов на стороне клиента, или если не компоновать каким-то образом пользовательский код на C++ в процесс на стороне сервера, что, как показывает опыт, порождает проблемы безопасности и надежности сервера.

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

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

В ObjectStore также обеспечиваются общесистемные идентификаторы, называемые «мягкими указателями» («soft pointer»), которые уникально идентифицируют любой персистентный объект во всех базах данных ObjectStore, глобально, в любой области видимости и независимо от контекста любого существующего процесса. Мягкие указатели на уровне схемы совместимы с обычными указателями C++ в 32- и 64-разрядных архитектурах.Они также очень эффективны в том отношении, что после первого использования работают с той же скоростью, что и прямые указатели C++.

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

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


Содержание раздела